diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000000..2e6b5f64eb5b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**What version of pinpoint are you using?** +master/v1.7.3/v1.7.2 etc. + +**Describe the bug** +A clear and concise description of what the bug is. + +**What did you do to trigger the bug?** +Steps to reproduce, for example: +1. Ran '...' with agent attached +2. '...' method invoked +3. '...' interceptor threw '...' exception + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Logs** +If applicable, please attach agent/collector/web DEBUG log that includes the code execution that led to the bug. In case of agents, including the start-up log may be of great help. + +**Additional context** +Add any other context about the problem here, such as affected library for agents, how your collector/web/hbase is set up if applicable. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000000..a8fba52bf2fe --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Which module is your feature request related to?** +Plugin/UI etc + +**Is your feature request related to a problem?** +A clear and concise description of what the problem is. + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 000000000000..c2af6232f7a3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,9 @@ +--- +name: Question +about: Questions + +--- + + diff --git a/.github/ISSUE_TEMPLATE/troubleshooting.md b/.github/ISSUE_TEMPLATE/troubleshooting.md new file mode 100644 index 000000000000..c1b53ddbeae8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/troubleshooting.md @@ -0,0 +1,27 @@ +--- +name: Troubleshooting +about: For when something doesn't work + +--- + +**What version of pinpoint are you using?** +master/v1.7.3/v1.7.2 etc. + +**Describe your problem** +A clear and concise description of what is not working. + +**What have you done?** +Steps you have taken to trigger the problem, for example: +1. Launched '...' with agent +2. Tried tracing '...' (see agent log below) +3. Collector outputs trace log (see collector log below) +4. No trace shows up in the web UI (see web log below) + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Logs** +If applicable, please attach agent/collector/web DEBUG log that includes the part where you have encountered the problem. In case of agents, including the start-up log may be of great help. + +**Additional context** +Add any other context about the problem here, such as affected library for agents, how your collector/web/hbase is set up if applicable. diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000000..ff2a19fd2771 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,38 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 30 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 20 + +# Issues with these labels will never be considered stale +exemptLabels: + - "proposal" + - "module:agent" + - "module:collector" + - "module:flink" + - "module:web" + - "module:plugin" + - "module:project-common" + - "bug" + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: true + +# Limit to only `issues` or `pulls` +only: issues + +# Label to use when marking an issue as stale +staleLabel: stale + +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue/proposal has been automatically marked as stale because it hasn't had any recent activity. + It will automatically be closed if no further activity occurs for 20days. + If you think this should still be open, or the problem still persists, + just pop a reply in the comments and one of the maintainers will (try!) to follow up. + Thank you for your interest and contribution to the Pinpoint Community. + +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 \ No newline at end of file diff --git a/.gitignore b/.gitignore index d631846d5320..91e6c2726213 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,4 @@ out/ /src/main/webapp/lib/js/**/*.js /src/main/webapp/lib/js/**/*.map -/src/main/webapp/lib/css/**/*.css +/src/main/webapp/lib/css/**/*.css \ No newline at end of file diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 000000000000..d475a89ce1d2 --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,110 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar index c6feb8bb6f76..08ebbb67f088 100644 Binary files a/.mvn/wrapper/maven-wrapper.jar and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 6637cedb28e9..42fa4da21999 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip \ No newline at end of file +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 3fa9735b5f6d..fe624c7ece79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,24 +7,35 @@ addons: - openjdk-6-jdk jdk: - - openjdk7 + - oraclejdk8 -env: JAVA_6_HOME=/usr/lib/jvm/java-6-openjdk-amd64 JAVA_7_HOME=/usr/lib/jvm/java-7-openjdk-amd64 JAVA_8_HOME=/usr/lib/jvm/java-8-oracle +env: + global: + - secure: NZHVmbkzMZGm9M71n5sitb47tyHJE/byA8l6u2zqdhfeEZsrdhZKpgTRYdQYa4btsBHoO/hImziRMz2SuaQgGyK3EiizzZfFqzzqfMvq1WXKeNNI46QtN9RKA60o+/TIptmJADIXfAq5KEjOBOVIyN93Wsf0+4LP13Ve+UDFG38= + - JAVA_6_HOME=/usr/lib/jvm/java-6-openjdk-amd64 + JAVA_7_HOME=/usr/lib/jvm/java-7-openjdk-amd64 + JAVA_8_HOME=/usr/lib/jvm/java-8-oracle + JAVA_9_HOME=/usr/lib/jvm/java-9-oracle install: - set -o pipefail - ls -al $JAVA_6_HOME - ls -al $JAVA_7_HOME - ls -al $JAVA_8_HOME + - ls -al $JAVA_9_HOME - $JAVA_6_HOME/bin/java -version - $JAVA_7_HOME/bin/java -version - $JAVA_8_HOME/bin/java -version - - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V | grep -Fv '[copy' + - $JAVA_9_HOME/bin/java -version + - ./mvnw install -DskipTests=true -Plocal -Dmaven.javadoc.skip=true -B -V | grep -Fv '[copy' -script: mvn clover2:setup test -Ptest clover2:aggregate clover2:clover -e | grep -Fv 'DEBUG' | grep -Fv '[copy' +script: + - jdk_switcher use oraclejdk8 + - ./mvnw clover:setup test -Plocal,test clover:aggregate clover:clover -e | grep -Fv 'DEBUG' | grep -Fv '[copy' after_success: - bash <(curl -s https://codecov.io/bash) + - bash ./doc/scripts/deployGitPage.sh dist: - trusty \ No newline at end of file diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 05e931023cba..60e9b3c8ee80 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,6 +1,7 @@ diff --git a/NOTICE b/NOTICE index e4bbf1c5992f..ed0c9c10a84e 100644 --- a/NOTICE +++ b/NOTICE @@ -282,20 +282,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -======================================================================= -jquery.autotype (https://github.com/mmonteleone/jquery.autotype) -======================================================================= - -Copyright (c) 2009 Michael Monteleone, http://michaelmonteleone.net - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - ======================================================================= Bootstrap (http://getbootstrap.com/) ======================================================================= @@ -871,3 +857,1054 @@ HBaseWD (https://github.com/sematext/HBaseWD) See the License for the specific language governing permissions and limitations under the License. + +======================================================================= +Open Sans (https://fonts.google.com/specimen/Open+Sans) +======================================================================= + +This software contains the following license and notice below: + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +======================================================================= +nanumfont (http://hangeul.naver.com/2016/nanum) +======================================================================= + +Copyright (c) 2010, NAVER Corporation (http://www.nhncorp.com), + +with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, +NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, +Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, +NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic, +Naver NanumBarunGothic, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +SIL OPEN FONT LICENSE +Version 1.1 - 26 February 2007 + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting - in part or in whole - any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +======================================================================= +FortAwesome/Font-Awesome (https://fontawesome.com/) +======================================================================= + +Font Awesome Free License +------------------------- + +Font Awesome Free is free, open source, and GPL friendly. You can use it for +commercial projects, open source projects, or really almost whatever you want. +Full Font Awesome Free license: https://fontawesome.com/license. + +# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) +In the Font Awesome Free download, the CC BY 4.0 license applies to all icons +packaged as SVG and JS file types. + +# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL) +In the Font Awesome Free download, the SIL OLF license applies to all icons +packaged as web and desktop font files. + +SIL OPEN FONT LICENSE +Version 1.1 - 26 February 2007 + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting - in part or in whole - any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +# Code: MIT License (https://opensource.org/licenses/MIT) +In the Font Awesome Free download, the MIT license applies to all non-font and +non-icon files. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +# Attribution +Attribution is required by MIT, SIL OLF, and CC BY licenses. Downloaded Font +Awesome Free files already contain embedded comments with sufficient +attribution, so you shouldn't need to do anything additional when using these +files normally. + +We've kept attribution comments terse, so we ask that you do not actively work +to remove them from files, especially code. They're a great way for folks to +learn about Font Awesome. + +# Brand Icons +All brand icons are trademarks of their respective owners. The use of these +trademarks does not indicate endorsement of the trademark holder by Font +Awesome, nor vice versa. **Please do not use brand logos for any purpose except +to represent the company, product, or service to which they refer.** + +======================================================================= +angular/angular (https://github.com/angular/angular) +======================================================================= + +The MIT License + +Copyright (c) 2014-2017 Google, Inc. http://angular.io + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +======================================================================= +angular/material2 (https://material.angular.io/) +======================================================================= + +The MIT License + +Copyright (c) 2018 Google LLC. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +======================================================================= +ngrx/platform (https://github.com/ngrx/platform) +======================================================================= + +The MIT License (MIT) + +Copyright (c) 2017 Brandon Roberts, Mike Ryan, Victor Savkin, Rob Wormald + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +======================================================================= +ng2-ui/datetime-picker (https://github.com/ng2-ui/datetime-picker) +======================================================================= + +Copyright (c) 2016 Allen Kim allenhwkim@gmail.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +======================================================================= +ngx-translate/core (https://github.com/ngx-translate/core) +======================================================================= + +Copyright (c) 2018 Olivier Combe + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +======================================================================= +ngx-translate/http-loader (https://github.com/ngx-translate/http-loader) +======================================================================= + +Copyright (c) 2018 Olivier Combe + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +======================================================================= +ag-grid/ag-grid (https://www.ag-grid.com/) +======================================================================= + +This project is made up of many packages. There are two license types: MIT and Commercial. + +Each package has it's own license file explaining the license for that package. + +The following packages are MIT licensed: ++ ag-grid-community ++ ag-grid-angular ++ ag-grid-angular-cli-example ++ ag-grid-aurelia ++ ag-grid-aurelia-example ++ ag-grid-docs ++ ag-grid-react ++ ag-grid-react-example ++ ag-grid-vue ++ ag-grid-vue-example + +The following packages are Commercial licensed: ++ ag-grid-enterprise + +To view the commercial license for ag-grid-enterprise, +see the file packages/ag-grid-enterprise/LICENSE.md + +=== + +The MIT License + +Copyright (c) 2015-2016 AG GRID LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +======================================================================= +ag-grid/ag-grid-angular (https://github.com/ag-grid/ag-grid-angular) +======================================================================= + +The MIT License + +Copyright (c) 2015-2016 AG GRID LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +======================================================================= +phenomnomnominal/angular-2-local-storage (https://github.com/phenomnomnominal/angular-2-local-storage) +======================================================================= + +MIT License + +Copyright (c) 2018 Craig Spence + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +======================================================================= +lancedikson/bowser (https://github.com/lancedikson/bowser) +======================================================================= + +Copyright 2015, Dustin Diaz (the "Original Author") +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +Distributions of all or part of the Software intended to be used +by the recipients as they would use the unmodified Software, +containing modifications that substantially alter, remove, or +disable functionality of the Software, outside of the documented +configuration mechanisms provided by the Software, shall be +modified such that the Original Author's bug reporting email +addresses and urls are either replaced with the contact information +of the parties responsible for the changes, or removed entirely. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + + +Except where noted, this license applies to any and all software +programs and associated documentation files created by the +Original Author, when distributed with the Software. + +======================================================================= +chartjs/Chart.js (https://www.chartjs.org/) +======================================================================= + +The MIT License (MIT) + +Copyright (c) 2018 Chart.js Contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +======================================================================= +nagix/chartjs-plugin-streaming (https://github.com/nagix/chartjs-plugin-streaming) +======================================================================= + +The MIT License (MIT) + +Copyright (c) 2018 Akihiko Kusanagi + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +======================================================================= +hammerjs/hammer.js (https://hammerjs.github.io/) +======================================================================= + +Copyright (C) 2011-2014 by Jorik Tangelder (Eight Media) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +======================================================================= +arkon/ng-click-outside (https://github.com/arkon/ng-click-outside) +======================================================================= + +The MIT License (MIT) + +Copyright (c) 2016 Eugene Cheung + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +======================================================================= +tb/ng2-nouislider (https://github.com/tb/ng2-nouislider) +======================================================================= + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +======================================================================= +maxisam/ngx-clipboard (https://github.com/maxisam/ngx-clipboard) +======================================================================= + +MIT License + +Copyright (c) 2018 Sam Lin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +======================================================================= +MurhafSousli/ngx-highlightjs (https://github.com/MurhafSousli/ngx-highlightjs) +======================================================================= + +MIT License + +Copyright (c) 2018 Murhaf Sousli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +======================================================================= +orizens/ngx-infinite-scroll (https://github.com/orizens/ngx-infinite-scroll) +======================================================================= + +MIT License + +Copyright (c) 2017 Roberto Simonetti + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +======================================================================= +leongersen/noUiSlider (https://github.com/leongersen/noUiSlider) +======================================================================= + +MIT License + +Copyright (c) 2018 Léon Gersen + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +======================================================================= +adobe-webplatform/Snap.svg (https://github.com/adobe-webplatform/Snap.svg) +======================================================================= + +// Copyright (c) 2013 - 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +----- + +Snap.svg is licensed under the Apache license version 2.0, January 2004 (see LICENSE file). + +Snap.svg uses the following third party libraries that may have licenses +differing from that of Snap.svg itself. You can find the libraries and their +respective licenses below. + + - eve ./node_modules/eve + + https://github.com/adobe-webplatform/eve/ + + Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + - Mocha ./node_modules/mocha + + https://github.com/visionmedia/mocha/ + + (The MIT License) + + Copyright (c) 2011-2013 TJ Holowaychuk + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + 'Software'), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + - Expect ./node_modules/expect.js + + https://github.com/LearnBoost/expect.js + + (The MIT License) + + Copyright (c) 2011 Guillermo Rauch + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + 'Software'), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + - Grunt ./node_modules/grunt + + http://gruntjs.com + + Copyright (c) 2013 "Cowboy" Ben Alman + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + + - Backbone ./demos/animated-game/js/backbone.js + + http://backbonejs.org/ + + (The MIT License) + + Copyright (c) 2010-2013 Jeremy Ashkenas, DocumentCloud + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + 'Software'), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + - Underscore ./demos/animated-game/js/underscore.js + + http://underscorejs.org + + (The MIT License) + + Copyright (c) 2010-2013 Jeremy Ashkenas, DocumentCloud + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + 'Software'), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + - jQuery ./demos/animated-game/js/jquery-1.9.0.min.js + + http://http://jquery.com/ + + (The MIT License) + + Copyright 2013 jQuery Foundation and other contributors + http://jquery.com/ + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + 'Software'), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +======================================================================= +almende/vis (http://visjs.org/) +======================================================================= + +Copyright (C) 2010-2017 Almende B.V. and Contributors + +Vis.js is dual licensed under both + +The Apache 2.0 License http://www.apache.org/licenses/LICENSE-2.0 +and + +The MIT License http://opensource.org/licenses/MIT +Vis.js may be distributed under either license. + +--- + +The MIT License (MIT) + +Copyright (c) 2014-2017 Almende B.V. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + diff --git a/README.md b/README.md index 00483cd10771..6d0786329008 100644 --- a/README.md +++ b/README.md @@ -1,156 +1,123 @@ + + ![Pinpoint](web/src/main/webapp/images/logo.png) [![Build Status](https://travis-ci.org/naver/pinpoint.svg?branch=master)](https://travis-ci.org/naver/pinpoint) [![codecov](https://codecov.io/gh/naver/pinpoint/branch/master/graph/badge.svg)](https://codecov.io/gh/naver/pinpoint) -**Pinpoint** is an APM (Application Performance Management) tool for large-scale distributed systems written in Java. Modelled after [Dapper](http://research.google.com/pubs/pub36356.html "Google Dapper"), Pinpoint provides a solution to help analyze the overall structure of the system and how components within them are interconnected by tracing transactions across distributed applications. +**Visit [our official web site](http://naver.github.io/pinpoint/) for more information and [Latest updates on Pinpoint](https://naver.github.io/pinpoint/news.html)** + +## Latest News (2018/08/30) + +Pinpoint has started to support application written in PHP. [Check-out our php-agent repository](https://github.com/naver/pinpoint-c-agent). -* Install agents without changing a single line of code -* Minimal impact on performance (approximately 3% increase in resource usage) +## Latest Release (2018/09/14) -## Latest Release (2018/01/04) -We're happy to announce the release of Pinpoint v1.7.1. -Please check the release note at (https://github.com/naver/pinpoint/releases/tag/1.7.1). +We're happy to announce the release of Pinpoint v1.8.0. +Please check the release note at (https://github.com/naver/pinpoint/releases/tag/1.8.0). -The current stable version is [**v1.7.1**](https://github.com/naver/pinpoint/releases/tag/1.7.1). +The current stable version is [v1.8.0](https://github.com/naver/pinpoint/releases/tag/1.8.0). -### Plugin Development Guide (2016/03/18) -We now have a [plugin development guide](https://github.com/naver/pinpoint/wiki/Pinpoint-Plugin-Developer-Guide "Pinpoint Plugin Development Guide"). Yay! +## About Pinpoint +**Pinpoint** is an APM (Application Performance Management) tool for large-scale distributed systems written in Java / [PHP](https://github.com/naver/pinpoint-c-agent). +Inspired by [Dapper](http://research.google.com/pubs/pub36356.html "Google Dapper"), +Pinpoint provides a solution to help analyze the overall structure of the system and how components within them are interconnected by tracing transactions across distributed applications. + +You should definitely check **Pinpoint** out If you want to + +* understand your *[application topology](https://naver.github.io/pinpoint/overview.html#overview)* at a glance +* monitor your application in *Real-Time* +* gain *code-level visibility* to every transaction +* install APM Agents *without changing a single line of code* +* have minimal impact on the performance (approximately 3% increase in resource usage) + +## Getting Started + * [Quick-start guide](https://naver.github.io/pinpoint/1.7.3/quickstart.html) for simple test run of Pinpoint + * [Installation guide](https://naver.github.io/pinpoint/1.7.3/installation.html) for further instructions. + ## Overview Services nowadays often consist of many different components, communicating amongst themselves as well as making API calls to external services. How each and every transaction gets executed is often left as a blackbox. Pinpoint traces transaction flows between these components and provides a clear view to identify problem areas and potential bottlenecks.
-For a more intimate guide, please check out our *[Introduction to Pinpoint](https://github.com/naver/pinpoint/wiki#video-clips)* video clip. +For a more intimate guide, please check out our *[Introduction to Pinpoint](http://naver.github.io/pinpoint/#want-a-quick-tour)* video clip. * **ServerMap** - Understand the topology of any distributed systems by visualizing how their components are interconnected. Clicking on a node reveals details about the component, such as its current status, and transaction count. * **Realtime Active Thread Chart** - Monitor active threads inside applications in real-time. * **Request/Response Scatter Chart** - Visualize request count and response patterns over time to identify potential problems. Transactions can be selected for additional detail by **dragging over the chart**. - ![Server Map](doc/img/ss_server-map.png) + ![Server Map](doc/images/ss_server-map.png) * **CallStack** - Gain code-level visibility to every transaction in a distributed environment, identifying bottlenecks and points of failure in a single view. - ![Call Stack](doc/img/ss_call-stack.png) + ![Call Stack](doc/images/ss_call-stack.png) * **Inspector** - View additional details on the application such as CPU usage, Memory/Garbage Collection, TPS, and JVM arguments. - ![Inspector](doc/img/ss_inspector.png) - -## Architecture -![Pinpoint Architecture](doc/img/pinpoint-architecture.png) + ![Inspector](doc/images/ss_inspector.png) ## Supported Modules * JDK 6+ -* Tomcat 6/7/8, [Jetty 8/9](https://github.com/naver/pinpoint/tree/master/plugins/jetty), [JBoss EAP 6](https://github.com/naver/pinpoint/tree/master/plugins/jboss), [Resin 4](https://github.com/naver/pinpoint/tree/master/plugins/resin), [Websphere 6/7/8](https://github.com/naver/pinpoint/tree/master/plugins/websphere) +* [Tomcat 6/7/8/9](https://github.com/naver/pinpoint/tree/master/plugins/tomcat), [Jetty 8/9](https://github.com/naver/pinpoint/tree/master/plugins/jetty), [JBoss EAP 6/7](https://github.com/naver/pinpoint/tree/master/plugins/jboss), [Resin 4](https://github.com/naver/pinpoint/tree/master/plugins/resin), [Websphere 6/7/8](https://github.com/naver/pinpoint/tree/master/plugins/websphere), [Vertx 3.3/3.4/3.5](https://github.com/naver/pinpoint/tree/master/plugins/vertx), [Weblogic 10/11g/12c](https://github.com/naver/pinpoint/tree/master/plugins/weblogic) * Spring, Spring Boot (Embedded Tomcat, Jetty) * Apache HTTP Client 3.x/4.x, JDK HttpConnector, GoogleHttpClient, OkHttpClient, NingAsyncHttpClient * Thrift Client, Thrift Service, DUBBO PROVIDER, DUBBO CONSUMER -* MySQL, Oracle, MSSQL, CUBRID,POSTGRESQL, MARIA +* ActiveMQ, RabbitMQ +* MySQL, Oracle, MSSQL(jtds), CUBRID,POSTGRESQL, MARIA * Arcus, Memcached, Redis, CASSANDRA * iBATIS, MyBatis * DBCP, DBCP2, HIKARICP * gson, Jackson, Json Lib * log4j, Logback -## Third Party Agents/Plugins -There may be agents, and plugins that are being developed and managed by other individuals/organizations. Please take a look [here](https://github.com/naver/pinpoint/wiki#third-party-agentsplugins) for the list and see if you would like to help out in their development. - -## Quick Start -You may run a sample Pinpoint instance in your own machine by running four simple scripts for each components: Collector, Web, Sample TestApp, HBase. - -Once the components are running, you should be able to visit http://localhost:28080 to view the Pinpoint Web UI, and http://localhost:28081 to generate transactions on the Sample TestApp. - -For details, please refer to the [quick-start guide](quickstart/README.md). - -## Installation -**Build Requirements** - -* JDK 6 installed ([jdk1.6.0_45](http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-419409.html#jdk-6u45-oth-JPR) recommended) -* JDK 7 installed ([jdk1.7.0_80](http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html#jdk-7u80-oth-JPR) recommended) -* JDK 8 installed -* JAVA_6_HOME environment variable set to JDK 6 home directory. -* JAVA_7_HOME environment variable set to JDK 7 home directory. -* JAVA_8_HOME environment variable set to JDK 8 home directory. - -**Prerequisites** +## Compatibility Java version required to run Pinpoint: Pinpoint Version | Agent | Collector | Web ---------------- | ----- | --------- | --- -1.0.x | 6-8 | 6+ | 6+ -1.1.x | 6-8 | 7+ | 7+ -1.5.x | 6-8 | 7+ | 7+ -1.6.x | 6-8 | 7+ | 7+ -1.7.x | 6-8 | 8+ | 8+ +1.0.x | 6-8 | 6-8 | 6-8 +1.1.x | 6-8 | 7-8 | 7-8 +1.5.x | 6-8 | 7-8 | 7-8 +1.6.x | 6-8 | 7-8 | 7-8 +1.7.x | 6-8 | 8 | 8 +1.8.x | 6-10 | 8 | 8 HBase compatibility table: -Pinpoint Version | HBase 0.94.x | HBase 0.98.x | HBase 1.0.x | HBase 1.1.x | HBase 1.2.x +Pinpoint Version | HBase 0.94.x | HBase 0.98.x | HBase 1.0.x | HBase 1.2.x | HBase 2.0.x ---------------- | ------------ | ------------ | ----------- | ----------- | ----------- 1.0.x | yes | no | no | no | no -1.1.x | no | not tested | yes | not tested | not tested -1.5.x | no | not tested | yes | not tested | not tested -1.6.x | no | not tested | not tested | not tested | yes -1.7.x | no | not tested | not tested | not tested | yes - -Agent compatibility table: +1.1.x | no | not tested | yes | not tested | no +1.5.x | no | not tested | yes | not tested | no +1.6.x | no | not tested | not tested | yes | no +1.7.x | no | not tested | not tested | yes | no +1.8.x | no | not tested | not tested | yes | no -Agent Version | Collector 1.0.x | Collector 1.1.x | Collector 1.5.x | Collector 1.6.x | Collector 1.7.x -------------- | --------------- | --------------- | --------------- | --------------- | --------------- -1.0.x | yes | yes | yes | yes | yes -1.1.x | not tested | yes | yes | yes | yes -1.5.x | no | no | yes | yes | yes -1.6.x | no | no | not tested | yes | yes -1.7.x | no | no | no | no | yes +Agent - Collector compatibility table: -Pinpoint Web Supported Browsers: +Agent Version | Collector 1.0.x | Collector 1.1.x | Collector 1.5.x | Collector 1.6.x | Collector 1.7.x | Collector 1.8.x +------------- | --------------- | --------------- | --------------- | --------------- | --------------- | --------------- +1.0.x | yes | yes | yes | yes | yes | yes +1.1.x | not tested | yes | yes | yes | yes | yes +1.5.x | no | no | yes | yes | yes | yes +1.6.x | no | no | not tested | yes | yes | yes +1.7.x | no | no | no | no | yes | yes +1.8.x | no | no | no | no | no | yes -* Chrome - -**Installation** - -To set up your very own Pinpoint instance you can either **download the build results** from our [**latest release**](https://github.com/naver/pinpoint/releases/latest), or manually build from your Git clone. -Take a look at our [installation guide](doc/installation.md) for further instructions. - -## Issues -For feature requests and bug reports, feel free to post them [here](https://github.com/naver/pinpoint/issues "Pinpoint Issues"). -Please take a look at [CONTRIBUTING.md#issues](CONTRIBUTING.md#issues) for some guidelines that'll help us understand your issues better. +Flink compatibility table: +Pinpoint Version | flink 1.3.X | flink 1.4.X +---------------- | ----------- | ----------- +1.7.x | yes | no | ## User Group -For Q/A and discussion [here](https://groups.google.com/forum/#!forum/pinpoint_user "Pinpoint Google Group"). - - -## Wiki -We have a [wiki](https://github.com/naver/pinpoint/wiki) page for roadmap, user guide, and some documentation. -We welcome any documentation contribution. - - -## Contribution -We welcome any and all suggestions. - -For plugin development, take a look at our [plugin development guide](https://github.com/naver/pinpoint/wiki/Pinpoint-Plugin-Developer-Guide "Pinpoint Plugin Development Guide"), along with [plugin samples](https://github.com/naver/pinpoint-plugin-sample "Pinpoint Plugin Samples project") project to get an idea of how we do instrumentation. The samples will provide you with example codes to help you get started. -**Please follow our [guideline](https://github.com/naver/pinpoint/wiki/Pinpoint-Plugin-Developer-Guide#iii-plugin-contribution-guideline "Plugin PR Guideline") when making pull-requests for new plugins.** - -For all pull-requests, make sure you've read through [CONTRIBUTING.md#pull-requests](CONTRIBUTING.md#pull-requests) and note that you will have to complete a [CLA](https://docs.google.com/forms/d/1oDX26pwmVZSoDfL9MwvwLsM23dHqc5pvgoZCp7jM940/viewform?c=0&w=1 "Contributor License Agreement") for your first pull-request. - -We would love to see additional tracing support for libraries such as [Storm](https://storm.apache.org "Apache Storm"), [HBase](http://hbase.apache.org "Apache HBase"), as well as profiler support for additional languages (.NET, C++). - -## Google Analytics -The web module has google analytics attached that tracks the number and the order of button clicks in the server map, transaction list, and the inspector view. - -This data is used to better understand how users interact with the Web UI which gives us valuable information in improving Pinpoint Web's user experience. -To disable this for any reason, set the following option to false in *pinpoint-web.properties* for your web instance. -``` -config.sendUsage=false -``` +For Q/A and discussion [here](https://groups.google.com/forum/#!forum/pinpoint_user). ## License Pinpoint is licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for full license text. ``` -Copyright 2017 NAVER Corp. +Copyright 2018 NAVER Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -164,3 +131,4 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` + diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 9da9a0291e15..000000000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-dinky \ No newline at end of file diff --git a/agent-it/.gitignore b/agent-it/.gitignore new file mode 100644 index 000000000000..17b25a5432b5 --- /dev/null +++ b/agent-it/.gitignore @@ -0,0 +1,6 @@ +/target/ +/*.iml +/build/ +/.settings/ +/.classpath +/.project diff --git a/agent-it/pom.xml b/agent-it/pom.xml new file mode 100644 index 000000000000..fb6ddac4bf71 --- /dev/null +++ b/agent-it/pom.xml @@ -0,0 +1,507 @@ + + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + 1.8.1-SNAPSHOT + + + pinpoint-agent-it + pinpoint-agent-it + + jar + + + 1.14.0 + 3.5.1-1 + + + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + + + + com.navercorp.pinpoint + pinpoint-annotations + + + com.navercorp.pinpoint + pinpoint-profiler-test + + + + com.navercorp.pinpoint + pinpoint-agent + ${project.version} + runtime + + + com.navercorp.pinpoint + pinpoint-bootstrap-java9 + + + com.navercorp.pinpoint + pinpoint-profiler-optional-jdk9 + + + + + + + + com.navercorp.pinpoint + pinpoint-plugins + pom + runtime + + + + + com.navercorp.pinpoint + pinpoint-test + test + + + + org.springframework + spring-test + test + + + org.springframework + spring-context + test + + + org.springframework + spring-webmvc + test + + + + javax.servlet + javax.servlet-api + test + + + + org.mariadb.jdbc + mariadb-java-client + test + + + ch.vorburger.mariaDB4j + mariaDB4j + 2.2.2 + test + + + + com.alibaba + fastjson + test + + + com.google.code.gson + gson + test + + + net.sf.json-lib + json-lib + jdk15 + test + + + com.google.http-client + google-http-client + test + + + org.apache.ibatis + ibatis-sqlmap + 2.3.4.726 + test + + + org.springframework + spring-ibatis + 2.0.8 + test + + + org.mybatis + mybatis + test + + + org.mybatis + mybatis-spring + test + + + + + org.apache.httpcomponents + httpcore + test + + + org.apache.httpcomponents + httpasyncclient + test + + + org.apache.httpcomponents + httpcore-nio + test + + + org.apache.httpcomponents + httpclient + test + + + commons-httpclient + commons-httpclient + test + + + + com.squareup.okhttp + okhttp + test + + + com.squareup.okhttp3 + okhttp + test + + + + com.alibaba + dubbo + test + + + + com.datastax.cassandra + cassandra-driver-core + test + + + org.scassandra + java-client + 1.1.2 + test + + + + org.apache.activemq + activemq-all + 5.13.2 + test + + + + com.netflix.hystrix + hystrix-core + 1.5.12 + test + + + + io.reactivex + rxjava + 1.2.0 + test + + + + org.codehaus.jackson + jackson-core-asl + 1.9.13 + test + + + org.codehaus.jackson + jackson-mapper-asl + 1.9.13 + test + + + + com.fasterxml.jackson.core + jackson-core + ${fastxml.jackson-jdk6.version} + test + + + com.fasterxml.jackson.core + jackson-annotations + ${fastxml.jackson-jdk6.version} + test + + + com.fasterxml.jackson.core + jackson-databind + ${fastxml.jackson-jdk6.version} + test + + + + org.nanohttpd + nanohttpd + 2.3.1 + test + + + + + com.alibaba + druid + test + + + + + com.zaxxer + HikariCP-java6 + 2.3.13 + test + + + + + org.springframework.amqp + spring-rabbit + 1.7.5.RELEASE + test + + + org.apache.qpid + qpid-broker + 6.1.1 + test + + + + com.ning + async-http-client + 1.8.3 + + + + org.asynchttpclient + async-http-client + 2.0.32 + + + + org.mongodb + bson + 3.7.0 + test + + + org.mongodb + mongodb-driver + 3.7.0 + test + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + 1.50.5 + test + + + + + org.apache.cxf + cxf-rt-frontend-jaxrs + test + + + org.apache.cxf + cxf-rt-frontend-jaxws + test + + + org.apache.cxf + cxf-rt-transports-http + test + + + org.apache.cxf + cxf-rt-rs-client + test + + + + org.apache.hbase + hbase-shaded-client + test + + + + org.eclipse.jetty + jetty-server + 9.2.11.v20150529 + test + + + + io.grpc + grpc-protobuf + ${grpc.version} + test + + + io.grpc + grpc-stub + ${grpc.version} + test + + + io.grpc + grpc-netty + ${grpc.version} + test + + + + io.netty + netty-all + + 4.1.28.Final + test + + + + + + + + ${basedir}/src/main/java + + **/*.java + + + + ${basedir}/src/main/resources + + + ${basedir}/src/main/resources-${env} + + + + + + kr.motd.maven + os-maven-plugin + 1.5.0.Final + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${plugin.surefire.version} + + true + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${plugin.failsafe.version} + + ${env.JAVA_8_HOME}/bin/java + + + + test-on-jvm6 + + integration-test + verify + + + + **/jdk7/**/ + **/jdk8/**/ + + + false + true + ${env.JAVA_6_HOME}/bin/java + + + + test-on-jvm7 + + integration-test + verify + + + + **/jdk7/**/ + + + false + true + ${env.JAVA_7_HOME}/bin/java + + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.5.1 + + com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + + + + + test-compile + test-compile-custom + + + + + + + diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/AgentPath.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/AgentPath.java new file mode 100644 index 000000000000..c7f2c549c7c3 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/AgentPath.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin; + +import com.navercorp.pinpoint.common.Version; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class AgentPath { + private AgentPath() { + } + + public static final String PATH = "../agent/target/pinpoint-agent-" + Version.VERSION; +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/PluginDisableIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/PluginDisableIT.java similarity index 95% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/PluginDisableIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/PluginDisableIT.java index a5ad622c7c32..eb8b51a42b47 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/PluginDisableIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/PluginDisableIT.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/SocketUtils.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/SocketUtils.java similarity index 99% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/SocketUtils.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/SocketUtils.java index 6309e016717d..fd3c09d3eb17 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/SocketUtils.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/SocketUtils.java @@ -1,11 +1,11 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/WebServer.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/WebServer.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/WebServer.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/WebServer.java index 1413c8235cbf..d185e664738a 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/WebServer.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/WebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/cxf/CxfClientIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/cxf/CxfClientIT.java new file mode 100644 index 000000000000..5d2f1c5f2cbd --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/cxf/CxfClientIT.java @@ -0,0 +1,116 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.cxf; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.apache.cxf.interceptor.LoggingInInterceptor; +import org.apache.cxf.interceptor.LoggingMessage; +import org.apache.cxf.interceptor.LoggingOutInterceptor; +import org.apache.cxf.interceptor.MessageSenderInterceptor; +import org.apache.cxf.jaxrs.client.ClientConfiguration; +import org.apache.cxf.jaxrs.client.WebClient; +import org.apache.cxf.message.Message; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.annotation; +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + + +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@JvmVersion(8) +@Dependency({"org.apache.cxf:cxf-rt-rs-client:[3.0.0][3.0.16][3.1.0][3.1.16],[3.2.1,)", "org.nanohttpd:nanohttpd:2.3.1"}) +@PinpointConfig("cxf/pinpoint-cxf-test.config") +public class CxfClientIT { + + private static WebServer webServer; + + @BeforeClass + public static void BeforeClass() throws Exception { + webServer = WebServer.newTestWebServer(); + + } + + @AfterClass + public static void AfterClass() throws Exception { + final WebServer copy = webServer; + if (copy != null) { + copy.stop(); + webServer = null; + } + } + + @Test + public void test() throws Exception { + + String address = webServer.getCallHttpUrl(); + + String json = "{\"id\" : 12345, \"name\" : \"victor\"}"; + + WebClient client = WebClient.create(address, true); + + ClientConfiguration configuration = WebClient.getConfig(client); + + // add logging interceptor + configuration.getInInterceptors().add(new LoggingInInterceptor()); + configuration.getOutInterceptors().add(new LoggingOutInterceptor()); + + client.path("/test1").accept("application/json").type("application/json; charset=UTF-8").post(json).close(); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + + verifier.printCache(); + + verifier.ignoreServiceType("JDK_HTTPURLCONNECTOR"); + + verifier.verifyTrace(event("CXF_MESSAGE_SENDER", MessageSenderInterceptor.class.getDeclaredMethod("handleMessage", Message.class))); + + verifier.verifyTrace(event("CXF_LOGGING_OUT", LoggingOutInterceptor.class.getDeclaredMethod("formatLoggingMessage", LoggingMessage.class), + annotation("cxf.address", address + "/test1"), + annotation("cxf.http.method", "POST"), + annotation("cxf.content.type", "application/json; charset=UTF-8"), + annotation("cxf.headers", "{Accept=[application/json], Content-Type=[application/json; charset=UTF-8]}"), + annotation("cxf.payload", "{\"id\" : 12345, \"name\" : \"victor\"}") + )); + +// verifier.verifyTrace(event("CXF_LOGGING_IN", LoggingInInterceptor.class.getDeclaredMethod("formatLoggingMessage", LoggingMessage.class), +// annotation("cxf.response.code", "200"), +// annotation("cxf.encoding", "ISO-8859-1"), +// annotation("cxf.content.type", "text/html"), +// annotation("cxf.headers", "{connection=[keep-alive], Content-Length=[2], content-type=[text/html], Date=[" + new Date() + "]}"), +// annotation("cxf.payload", "{}") +// )); + + verifier.verifyTraceCount(1); + + client.close(); + + } + + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidIT.java new file mode 100644 index 000000000000..ef705b27af79 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidIT.java @@ -0,0 +1,74 @@ +package com.navercorp.pinpoint.plugin.druid; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledConnection; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.SQLException; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({"com.alibaba:druid:[1.0.0][1.0.31],[1.1.0,)", "com.h2database:h2:1.4.191"}) +@PinpointConfig("druid/pinpoint-druid-test.config") +public class DruidIT { + private static final String serviceType = "DRUID"; + private static final String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; + + private static Method getConnectionMethod; + private static Method closeConnectionMethod; + + @BeforeClass + public static void setUp() throws NoSuchMethodException { + + getConnectionMethod = DruidDataSource.class.getDeclaredMethod("getConnection"); + closeConnectionMethod = DruidPooledConnection.class.getDeclaredMethod("close"); + } + + @Test + public void test() throws InterruptedException, SQLException { + + DruidDataSource dataSource = new DruidDataSource(); + + dataSource.setUrl(JDBC_URL); + dataSource.setValidationQuery("select 'x'"); + dataSource.setUsername("test"); + dataSource.setPassword("test"); + + dataSource.init(); + try { + Connection connection = dataSource.getConnection(); + Assert.assertNotNull(connection); + + Thread.sleep(500); + + connection.close(); + + Thread.sleep(500); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + verifier.verifyTrace(event(serviceType, getConnectionMethod)); + verifier.verifyTrace(event(serviceType, closeConnectionMethod)); + } finally { + if (dataSource != null) { + dataSource.close(); + } + } + } + +} \ No newline at end of file diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/dubbo/consumer/DubboConsumerIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/dubbo/consumer/DubboConsumerIT.java new file mode 100644 index 000000000000..39e340e87be0 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/dubbo/consumer/DubboConsumerIT.java @@ -0,0 +1,140 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.dubbo.consumer; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.monitor.MonitorService; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Result; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.protocol.AbstractInvoker; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author Jinkai.Ma + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({"com.alibaba:dubbo:2.5.3", "org.mockito:mockito-all:1.8.4"}) +public class DubboConsumerIT { + + @Mock + private RpcInvocation rpcInvocation; + private URL url; + + private AbstractInvoker abstractClusterInvoker; + + @Before + public void setUp() { + url = new URL("dubbo", "1.2.3.4", 5678); + MockitoAnnotations.initMocks(this); + } + + @Test + public void testConsumer() throws NoSuchMethodException { + abstractClusterInvoker = new MockInvoker(Demo.class, url); + try { + abstractClusterInvoker.invoke(rpcInvocation); + } catch (RpcException e) { + } + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + Method invoke = AbstractInvoker.class.getMethod("invoke", Invocation.class); + verifier.verifyTraceCount(1); + } + + @Test + public void testConsumerMonitor() { + abstractClusterInvoker = mock(AbstractInvoker.class); + when(abstractClusterInvoker.getInterface()).thenReturn(MonitorService.class); + try { + abstractClusterInvoker.invoke(rpcInvocation); + } catch (RpcException ignore) { + // ignore + } + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + verifier.verifyTraceCount(0); + } + + public static interface Demo { + } + + public static class MockInvoker extends AbstractInvoker { + URL url; + boolean available = true; + boolean destoryed = false; + Result result; + RpcException exception; + Callable callable; + + public MockInvoker(Class type, URL url) { + super(type, url); + } + + public void setResult(Result result) { + this.result = result; + } + + public void setException(RpcException exception) { + this.exception = exception; + } + + public void setCallable(Callable callable) { + this.callable = callable; + } + + @Override + protected Result doInvoke(Invocation invocation) throws Throwable { + if (callable != null) { + try { + callable.call(); + } catch (Exception e) { + throw new RpcException(e); + } + } + if (exception != null) { + throw exception; + } else { + return result; + } + } + } +} + + diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/dubbo/provider/DubboProviderIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/dubbo/provider/DubboProviderIT.java new file mode 100644 index 000000000000..de97b6c0f9c2 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/dubbo/provider/DubboProviderIT.java @@ -0,0 +1,125 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.dubbo.provider; + +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.RpcInvocation; +import com.alibaba.dubbo.rpc.cluster.Directory; +import com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.navercorp.pinpoint.test.plugin.TraceObjectManagable; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.lang.reflect.Method; + +import static org.mockito.Mockito.when; + +/** + * @author Jinkai.Ma + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({"com.alibaba:dubbo:2.5.3", "org.mockito:mockito-all:1.8.4"}) +@TraceObjectManagable +public class DubboProviderIT { + + public static final String META_DO_NOT_TRACE = "_DUBBO_DO_NOT_TRACE"; + public static final String META_TRANSACTION_ID = "_DUBBO_TRASACTION_ID"; + public static final String META_SPAN_ID = "_DUBBO_SPAN_ID"; + public static final String META_PARENT_SPAN_ID = "_DUBBO_PARENT_SPAN_ID"; + public static final String META_PARENT_APPLICATION_NAME = "_DUBBO_PARENT_APPLICATION_NAME"; + public static final String META_PARENT_APPLICATION_TYPE = "_DUBBO_PARENT_APPLICATION_TYPE"; + public static final String META_FLAGS = "_DUBBO_FLAGS"; + + @Mock + private RpcInvocation rpcInvocation; + private URL url; + @Mock + private Directory directory; + @Mock + private Invoker invoker; + + @Before + public void setUp() { + url = new URL("dubbo", "1.2.3.4", 5678); + MockitoAnnotations.initMocks(this); + when(directory.getUrl()).thenReturn(url); + when(rpcInvocation.getMethodName()).thenReturn("toString"); + when(rpcInvocation.getInvoker()).thenReturn(invoker); + when(invoker.getInterface()).thenReturn(String.class); + when(rpcInvocation.getAttachment(META_TRANSACTION_ID)).thenReturn("frontend.agent^1234567890^123321"); + when(rpcInvocation.getAttachment(META_SPAN_ID)).thenReturn("9876543210"); + when(rpcInvocation.getAttachment(META_PARENT_SPAN_ID)).thenReturn("1357913579"); + when(rpcInvocation.getAttachment(META_PARENT_APPLICATION_TYPE)).thenReturn("1000"); + when(rpcInvocation.getAttachment(META_PARENT_APPLICATION_NAME)).thenReturn("test.dubbo.consumer"); + when(rpcInvocation.getAttachment(META_FLAGS)).thenReturn("0"); + } + + @Test + public void testProvider() throws NoSuchMethodException { + AbstractProxyInvoker abstractProxyInvoker = new AbstractProxyInvoker(new String(), String.class, url) { + @Override + protected Object doInvoke(Object proxy, String methodName, Class[] parameterTypes, Object[] arguments) throws Throwable { + Method method = proxy.getClass().getMethod(methodName, parameterTypes); + return method.invoke(proxy, arguments); + } + }; + try { + abstractProxyInvoker.invoke(rpcInvocation); + } catch (RpcException ignore) { + ignore.printStackTrace(); + } + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + verifier.verifyTraceCount(2); + } + + @Test + public void testDoNotTrace() throws Exception { + when(rpcInvocation.getAttachment(META_DO_NOT_TRACE)).thenReturn("1"); + + AbstractProxyInvoker abstractProxyInvoker = new AbstractProxyInvoker(new String(), String.class, url) { + @Override + protected Object doInvoke(Object proxy, String methodName, Class[] parameterTypes, Object[] arguments) throws Throwable { + Method method = proxy.getClass().getMethod(methodName, parameterTypes); + return method.invoke(proxy, arguments); + } + }; + try { + abstractProxyInvoker.invoke(rpcInvocation); + } catch (RpcException ignore) { + ignore.printStackTrace(); + } + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + verifier.verifyTraceCount(0); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonIT.java new file mode 100644 index 000000000000..974499b18bcd --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonIT.java @@ -0,0 +1,128 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson; + +import com.alibaba.fastjson.JSON; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Method; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.annotation; +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +/** + * The type Fastjson it. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({"com.alibaba:fastjson:[1.2.10],[1.2.20],[1.2.30],[1.2.40,)"}) +@PinpointConfig("fastjson/pinpoint-fastjson-test.config") +public class FastjsonIT { + + private static final String serviceType = "FASTJSON"; + private static final String annotationKeyName = "fastjson.json.length"; + + /** + * Test. + * + * @throws Exception the exception + */ + @Test + public void test() throws Exception { + + TestBean testBean1 = new TestBean(); + testBean1.setId(123); + testBean1.setName("abc"); + + String json = JSON.toJSONString(testBean1); + + Method toJSONString = JSON.class.getDeclaredMethod("toJSONString", Object.class); + + TestBean testBean2 = JSON.parseObject(json, TestBean.class); + + Method parseObject = JSON.class.getDeclaredMethod("parseObject", String.class, Class.class); + + Assert.assertEquals(testBean1.getId(), testBean2.getId()); + Assert.assertEquals(testBean1.getName(), testBean2.getName()); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + verifier.verifyTrace(event(serviceType, toJSONString, annotation(annotationKeyName, json.length()))); + + verifier.verifyTrace(event(serviceType, parseObject, annotation(annotationKeyName, json.length()))); + + // No more traces + verifier.verifyTraceCount(0); + } + + /** + * The type Test bean. + */ + static class TestBean { + + private int id; + private String name; + + /** + * Gets id. + * + * @return the id + */ + public int getId() { + return id; + } + + /** + * Sets id. + * + * @param id the id + */ + public void setId(int id) { + this.id = id; + } + + /** + * Gets name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Sets name. + * + * @param name the name + */ + public void setName(String name) { + this.name = name; + } + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpRequestIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpRequestIT.java similarity index 88% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpRequestIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpRequestIT.java index 195d8dca923c..55f0d2f3b264 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpRequestIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/google/httpclient/HttpRequestIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,9 @@ import java.util.concurrent.Callable; import java.util.concurrent.Executor; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -43,7 +45,10 @@ * @author jaehong.kim */ @RunWith(PinpointPluginTestSuite.class) -@Dependency({ "com.google.http-client:google-http-client:[1.19.0],[1.20.0,)", "org.nanohttpd:nanohttpd:2.3.1"}) +@PinpointAgent(AgentPath.PATH) +// guava dependency issue +// google-http-client 1.26.0 does not include repackaged guava +@Dependency({ "com.google.http-client:google-http-client:[1.19.0],[1.20.0,)", "com.google.guava:guava:20.0", "org.nanohttpd:nanohttpd:2.3.1"}) public class HttpRequestIT { private static WebServer webServer; @@ -77,21 +82,24 @@ public void initialize(HttpRequest request) { try { request = requestFactory.buildGetRequest(url); response = request.execute(); - response.disconnect(); } catch (IOException ignored) { } finally { - if (response != null) { - response.disconnect(); - } + close(response); } - + Method executeMethod = HttpRequest.class.getDeclaredMethod("execute"); PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); verifier.printCache(); verifier.verifyTrace(Expectations.event("GOOGLE_HTTP_CLIENT_INTERNAL", executeMethod)); } - + + public void close(HttpResponse response) throws IOException { + if (response != null) { + response.disconnect(); + } + } + @Test public void executeAsync() throws Exception { HttpTransport NET_HTTP_TRANSPORT = new NetHttpTransport(); @@ -108,12 +116,10 @@ public void initialize(HttpRequest request) { try { request = requestFactory.buildGetRequest(url); response = request.executeAsync().get(); - response.disconnect(); } catch (IOException ignored) { + } finally { - if (response != null) { - response.disconnect(); - } + close(response); } Method executeAsyncMethod = HttpRequest.class.getDeclaredMethod("executeAsync", Executor.class); diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/Grpc_1_8_0_to_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/Grpc_1_8_0_to_IT.java new file mode 100644 index 000000000000..350ccb94989d --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/Grpc_1_8_0_to_IT.java @@ -0,0 +1,154 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTraceField; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Random; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.annotation; +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +/** + * @author Taejin Koo + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) + +@Dependency({"io.grpc:grpc-stub:[1.8.0,)", "io.grpc:grpc-netty:[1.8.0]", "io.grpc:grpc-protobuf:[1.8.0]"}) +@PinpointConfig("pinpoint-grpc-plugin-test.config") +public class Grpc_1_8_0_to_IT { + + private final Logger logger = Logger.getLogger(Grpc_1_8_0_to_IT.class.getName()); + + private final String REQUEST = "hello"; + + @Test + public void requestResponseTest() throws Exception { + HelloWorldSimpleServer server = null; + HelloWorldSimpleClient client = null; + try { + server = new HelloWorldSimpleServer(); + server.start(); + + client = new HelloWorldSimpleClient("127.0.0.1", server.getBindPort()); + String response = client.greet(REQUEST); + Assert.assertEquals(REQUEST.toUpperCase(), response); + + PluginTestVerifier verifier = getPluginTestVerifier(); + + assertTrace(server, verifier); + + verifier.verifyTraceCount(8); + } finally { + clearResources(client, server); + } + } + + @Test + public void streamingTest() throws Exception { + HelloWorldStreamServer server = null; + HelloWorldStreamClient client = null; + + Random random = new Random(System.currentTimeMillis()); + int requestCount = random.nextInt(5) + 1; + + try { + server = new HelloWorldStreamServer(); + server.start(); + + client = new HelloWorldStreamClient("127.0.0.1", server.getBindPort()); + client.greet(requestCount); + Assert.assertEquals(requestCount, server.getRequestCount()); + + PluginTestVerifier verifier = getPluginTestVerifier(); + + assertTrace(server, verifier); + verifier.verifyTraceCount(6 + (requestCount * 2)); + } finally { + clearResources(client, server); + } + } + + private PluginTestVerifier getPluginTestVerifier() { + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + if (logger.isLoggable(Level.FINE)) { + verifier.printCache(); + } + return verifier; + } + + + private void assertTrace(HelloWorldServer server, PluginTestVerifier verifier) { + verifier.verifyTrace(clientCallStartEvent(server)); + verifier.verifyTrace(event("GRPC_INTERNAL", "Grpc client listener Result Invocation")); + + verifier.verifyTrace(createServerRootTrace(server)); + + String streacmCreatedMethodDescritor = "io.grpc.internal.ServerImpl$ServerTransportListenerImpl.streamCreated(io.grpc.internal.ServerStream, java.lang.String, io.grpc.Metadata)"; + verifier.verifyTrace(event("GRPC_SERVER_INTERNAL", streacmCreatedMethodDescritor)); + } + + private ExpectedTrace clientCallStartEvent(HelloWorldServer server) { + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createEventBuilder("GRPC"); + eventBuilder.setMethodSignature("io.grpc.internal.ClientCallImpl.start(io.grpc.ClientCall$Listener, io.grpc.Metadata)"); + + String remoteAddress = "127.0.0.1:" + server.getBindPort(); + eventBuilder.setEndPoint(remoteAddress); + eventBuilder.setDestinationId(remoteAddress); + eventBuilder.setAnnotations(annotation("http.url", "http://" + remoteAddress + "/" + server.getMethodName())); + + return eventBuilder.build(); + } + + private ExpectedTrace createServerRootTrace(HelloWorldServer server) { + ExpectedTrace.Builder rootBuilder = ExpectedTrace.createRootBuilder("GRPC_SERVER"); + rootBuilder.setMethodSignature("Grpc HTTP Server"); + rootBuilder.setRpc("/" + server.getMethodName()); + rootBuilder.setRemoteAddr(ExpectedTraceField.createStartWith("127.0.0.1:")); + return rootBuilder.build(); + } + + private void clearResources(HelloWorldClient client, HelloWorldServer server) { + try { + if (client != null) { + client.shutdown(); + } + } catch (Exception e) { + } + try { + if (server != null) { + server.stop(); + } + } catch (Exception e) { + } + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldClient.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldClient.java new file mode 100644 index 000000000000..77325b06cfee --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldClient.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +/** + * @author Taejin Koo + */ +public interface HelloWorldClient { + + void shutdown() throws Exception; + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldServer.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldServer.java new file mode 100644 index 000000000000..f3c74ac24a1c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldServer.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import java.io.IOException; + +/** + * @author Taejin Koo + */ +public interface HelloWorldServer { + + void start() throws IOException; + + void stop(); + + int getBindPort(); + + String getMethodName(); + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldSimpleClient.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldSimpleClient.java new file mode 100644 index 000000000000..51dce5858f49 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldSimpleClient.java @@ -0,0 +1,78 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Metadata; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.stub.MetadataUtils; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Logger; + +/** + * copy grpc framework + * - https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java + * + * A simple client that requests a greeting from the {@link HelloWorldServer}. + */ +public class HelloWorldSimpleClient implements HelloWorldClient { + + private final Logger logger = Logger.getLogger(this.getClass().getName()); + + private final ManagedChannel channel; + private final GreeterGrpc.GreeterBlockingStub blockingStub; + + /** + * Construct client connecting to HelloWorld server at {@code host:port}. + */ + public HelloWorldSimpleClient(String host, int port) { + this(ManagedChannelBuilder.forAddress(host, port) + // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid + // needing certificates. +// .usePlaintext() + .usePlaintext(true) + .intercept(MetadataUtils.newCaptureMetadataInterceptor(new AtomicReference(), new AtomicReference())) + .build()); + } + + /** + * Construct client for accessing HelloWorld server using the existing channel. + */ + HelloWorldSimpleClient(ManagedChannel channel) { + this.channel = channel; + blockingStub = GreeterGrpc.newBlockingStub(channel); + } + + @Override + public void shutdown() throws InterruptedException { + channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + + public String greet(String name) { + HelloRequest request = HelloRequest.newBuilder().setName(name).build(); + HelloReply response = blockingStub.sayHello(request); + + logger.info("Greeting: {}" + response.getMessage()); + return response.getMessage(); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldSimpleServer.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldSimpleServer.java new file mode 100644 index 000000000000..689cd69293a8 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldSimpleServer.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import com.navercorp.pinpoint.plugin.SocketUtils; +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.stub.StreamObserver; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.io.IOException; +import java.util.logging.Logger; + +/** + * copy grpc framework + * - https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java + * + * Server that manages startup/shutdown of a {@code Greeter} server. + */ +public class HelloWorldSimpleServer implements HelloWorldServer { + + private final Logger logger = Logger.getLogger(this.getClass().getName()); + + private Server server; + + private int bindPort; + + @PostConstruct + public void start() throws IOException { + bindPort = SocketUtils.findAvailableTcpPort(27675); + + /* The port on which the server should run */ + server = ServerBuilder.forPort(bindPort) + .addService(new GreeterImpl()) + .build() + .start(); + + logger.info("Server started, listening on " + bindPort); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + System.err.println("*** shutting down gRPC server since JVM is shutting down"); + HelloWorldSimpleServer.this.stop(); + System.err.println("*** server shut down"); + } + }); + } + + @PreDestroy + public void stop() { + if (server != null) { + server.shutdown(); + } + } + + @Override + public int getBindPort() { + return bindPort; + } + + @Override + public String getMethodName() { + return GreeterGrpc.getSayHelloMethod().getFullMethodName(); + } + + static class GreeterImpl extends GreeterGrpc.GreeterImplBase { + + @Override + public void sayHello(HelloRequest req, StreamObserver responseObserver) { + HelloReply reply = HelloReply.newBuilder().setMessage(req.getName().toUpperCase()).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldStreamClient.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldStreamClient.java new file mode 100644 index 000000000000..74c545e6a173 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldStreamClient.java @@ -0,0 +1,256 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.examples.manualflowcontrol.StreamingGreeterGrpc; +import io.grpc.stub.ClientCallStreamObserver; +import io.grpc.stub.ClientResponseObserver; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +/** + * copy grpc framework + * - https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/manualflowcontrol/ManualFlowControlClient.java + */ +public class HelloWorldStreamClient implements HelloWorldClient { + + private final Logger logger = Logger.getLogger(this.getClass().getName()); + + private final ManagedChannel channel; + private final StreamingGreeterGrpc.StreamingGreeterStub stub; + + /** + * Construct client connecting to HelloWorld server at {@code host:port}. + */ + public HelloWorldStreamClient(String host, int port) { + this(ManagedChannelBuilder.forAddress(host, port) + // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid + // needing certificates. +// .usePlaintext() + .usePlaintext(true) + .build()); + } + + /** + * Construct client for accessing HelloWorld server using the existing channel. + */ + HelloWorldStreamClient(ManagedChannel channel) { + this.channel = channel; + this.stub = StreamingGreeterGrpc.newStub(channel); + } + + @Override + public void shutdown() throws InterruptedException { + channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + + /** + * Say hello to server. + */ + public void greet(final int callCount) throws InterruptedException { + + final CountDownLatch done = new CountDownLatch(1); + + ClientResponseObserver clientResponseObserver = + new ClientResponseObserver() { + + ClientCallStreamObserver requestStream; + + @Override + public void beforeStart(final ClientCallStreamObserver requestStream) { + this.requestStream = requestStream; + // Set up manual flow control for the response stream. It feels backwards to configure the response + // stream's flow control using the request stream's observer, but this is the way it is. + requestStream.disableAutoInboundFlowControl(); + + // Set up a back-pressure-aware producer for the request stream. The onReadyHandler will be invoked + // when the consuming side has enough buffer space to receive more messages. + // + // Messages are serialized into a transport-specific transmit buffer. Depending on the size of this buffer, + // MANY messages may be buffered, however, they haven't yet been sent to the server. The server must call + // request() to pull a buffered message from the client. + // + // Note: the onReadyHandler's invocation is serialized on the same thread pool as the incoming + // StreamObserver'sonNext(), onError(), and onComplete() handlers. Blocking the onReadyHandler will prevent + // additional messages from being processed by the incoming StreamObserver. The onReadyHandler must return + // in a timely manor or else message processing throughput will suffer. + requestStream.setOnReadyHandler(new Runnable() { + // An iterator is used so we can pause and resume iteration of the request data. + Iterator iterator = names().iterator(); + + @Override + public void run() { + int count = 0; + + // Start generating values from where we left off on a non-gRPC thread. + while (requestStream.isReady()) { + if (iterator.hasNext() && callCount > count) { + // Send more messages if there are more messages to send. + String name = iterator.next(); + logger.info("--> " + name); + io.grpc.examples.manualflowcontrol.HelloRequest request = io.grpc.examples.manualflowcontrol.HelloRequest.newBuilder().setName(name).build(); + requestStream.onNext(request); + count++; + } else { + // Signal completion if there is nothing left to send. + requestStream.onCompleted(); + } + } + } + }); + } + + @Override + public void onNext(io.grpc.examples.manualflowcontrol.HelloReply value) { + logger.info("<-- " + value.getMessage()); + // Signal the sender to send one message. + requestStream.request(1); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + done.countDown(); + } + + @Override + public void onCompleted() { + logger.info("All Done"); + done.countDown(); + } + }; + + // Note: clientResponseObserver is handling both request and response stream processing. + stub.sayHelloStreaming(clientResponseObserver); + + done.await(); + } + + private static List names() { + return Arrays.asList( + "Sophia", + "Jackson", + "Emma", + "Aiden", + "Olivia", + "Lucas", + "Ava", + "Liam", + "Mia", + "Noah", + "Isabella", + "Ethan", + "Riley", + "Mason", + "Aria", + "Caden", + "Zoe", + "Oliver", + "Charlotte", + "Elijah", + "Lily", + "Grayson", + "Layla", + "Jacob", + "Amelia", + "Michael", + "Emily", + "Benjamin", + "Madelyn", + "Carter", + "Aubrey", + "James", + "Adalyn", + "Jayden", + "Madison", + "Logan", + "Chloe", + "Alexander", + "Harper", + "Caleb", + "Abigail", + "Ryan", + "Aaliyah", + "Luke", + "Avery", + "Daniel", + "Evelyn", + "Jack", + "Kaylee", + "William", + "Ella", + "Owen", + "Ellie", + "Gabriel", + "Scarlett", + "Matthew", + "Arianna", + "Connor", + "Hailey", + "Jayce", + "Nora", + "Isaac", + "Addison", + "Sebastian", + "Brooklyn", + "Henry", + "Hannah", + "Muhammad", + "Mila", + "Cameron", + "Leah", + "Wyatt", + "Elizabeth", + "Dylan", + "Sarah", + "Nathan", + "Eliana", + "Nicholas", + "Mackenzie", + "Julian", + "Peyton", + "Eli", + "Maria", + "Levi", + "Grace", + "Isaiah", + "Adeline", + "Landon", + "Elena", + "David", + "Anna", + "Christian", + "Victoria", + "Andrew", + "Camilla", + "Brayden", + "Lillian", + "John", + "Natalie", + "Lincoln" + ); + } + + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldStreamServer.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldStreamServer.java new file mode 100644 index 000000000000..1cd929596a1b --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/grpc/HelloWorldStreamServer.java @@ -0,0 +1,175 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.Status; +import io.grpc.examples.manualflowcontrol.HelloReply; +import io.grpc.examples.manualflowcontrol.HelloRequest; +import io.grpc.examples.manualflowcontrol.StreamingGreeterGrpc; +import io.grpc.stub.ServerCallStreamObserver; +import io.grpc.stub.StreamObserver; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Logger; + +/** + * copy grpc framework + * - https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/manualflowcontrol/ManualFlowControlServer.java + */ +public class HelloWorldStreamServer implements HelloWorldServer { + + private final Logger logger = Logger.getLogger(this.getClass().getName()); + + private int requestCount; + + private Server server; + + private int bindPort; + + @PostConstruct + public void start() throws IOException { + StreamingGreeterGrpc.StreamingGreeterImplBase svc = new StreamingGreeterGrpc.StreamingGreeterImplBase() { + @Override + public StreamObserver sayHelloStreaming(final StreamObserver responseObserver) { + // Set up manual flow control for the request stream. It feels backwards to configure the request + // stream's flow control using the response stream's observer, but this is the way it is. + final ServerCallStreamObserver serverCallStreamObserver = + (ServerCallStreamObserver) responseObserver; + serverCallStreamObserver.disableAutoInboundFlowControl(); + + // Guard against spurious onReady() calls caused by a race between onNext() and onReady(). If the transport + // toggles isReady() from false to true while onNext() is executing, but before onNext() checks isReady(), + // request(1) would be called twice - once by onNext() and once by the onReady() scheduled during onNext()'s + // execution. + final AtomicBoolean wasReady = new AtomicBoolean(false); + + // Set up a back-pressure-aware consumer for the request stream. The onReadyHandler will be invoked + // when the consuming side has enough buffer space to receive more messages. + // + // Note: the onReadyHandler's invocation is serialized on the same thread pool as the incoming StreamObserver's + // onNext(), onError(), and onComplete() handlers. Blocking the onReadyHandler will prevent additional messages + // from being processed by the incoming StreamObserver. The onReadyHandler must return in a timely manor or else + // message processing throughput will suffer. + serverCallStreamObserver.setOnReadyHandler(new Runnable() { + public void run() { + if (serverCallStreamObserver.isReady() && wasReady.compareAndSet(false, true)) { + logger.info("READY"); + // Signal the request sender to send one message. This happens when isReady() turns true, signaling that + // the receive buffer has enough free space to receive more messages. Calling request() serves to prime + // the message pump. + serverCallStreamObserver.request(1); + } + } + }); + + // Give gRPC a StreamObserver that can observe and process incoming requests. + return new StreamObserver() { + @Override + public void onNext(HelloRequest request) { + requestCount++; + + // Process the request and send a response or an error. + try { + // Accept and enqueue the request. + String name = request.getName(); + logger.info("--> " + name); + + // Simulate server "work" + Thread.sleep(100); + + // Send a response. + String message = "Hello " + name; + logger.info("<-- " + message); + HelloReply reply = HelloReply.newBuilder().setMessage(message).build(); + responseObserver.onNext(reply); + + // Check the provided ServerCallStreamObserver to see if it is still ready to accept more messages. + if (serverCallStreamObserver.isReady()) { + // Signal the sender to send another request. As long as isReady() stays true, the server will keep + // cycling through the loop of onNext() -> request()...onNext() -> request()... until either the client + // runs out of messages and ends the loop or the server runs out of receive buffer space. + // + // If the server runs out of buffer space, isReady() will turn false. When the receive buffer has + // sufficiently drained, isReady() will turn true, and the serverCallStreamObserver's onReadyHandler + // will be called to restart the message pump. + serverCallStreamObserver.request(1); + } else { + // If not, note that back-pressure has begun. + wasReady.set(false); + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + responseObserver.onError( + Status.UNKNOWN.withDescription("Error handling request").withCause(throwable).asException()); + } + } + + @Override + public void onError(Throwable t) { + // End the response stream if the client presents an error. + t.printStackTrace(); + responseObserver.onCompleted(); + } + + @Override + public void onCompleted() { + // Signal the end of work when the client ends the request stream. + logger.info("COMPLETED"); + responseObserver.onCompleted(); + } + }; + } + }; + + bindPort = com.navercorp.pinpoint.plugin.SocketUtils.findAvailableTcpPort(27675); + + final Server server = ServerBuilder + .forPort(bindPort) + .addService(svc) + .build() + .start(); + this.server = server; + } + + @Override + public int getBindPort() { + return bindPort; + } + + @Override + public String getMethodName() { + return StreamingGreeterGrpc.getSayHelloStreamingMethod().getFullMethodName(); + } + + public int getRequestCount() { + return requestCount; + } + + @PreDestroy + public void stop() { + if (server != null) { + server.shutdown(); + } + } + + +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/gson/GsonIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/gson/GsonIT.java similarity index 97% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/gson/GsonIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/gson/GsonIT.java index a7f22863bfd0..6c66ef28fdc6 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/gson/GsonIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/gson/GsonIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -23,6 +23,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Type; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,6 +43,7 @@ * @author ChaYoung You */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({"com.google.code.gson:gson:[1.1],[1.4],[1.5],[1.6],[1.7.2],[2.0],[2.1],[2.2.4],[2.3.1,)"}) public class GsonIT { private static final boolean v1_2; diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbaseClientIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbaseClientIT.java new file mode 100644 index 000000000000..d437fc16f414 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbaseClientIT.java @@ -0,0 +1,80 @@ +package com.navercorp.pinpoint.plugin.hbase; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.*; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.annotation; +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; +import static org.mockito.Mockito.doReturn; + +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@JvmVersion(8) +@Dependency({"org.apache.hbase:hbase-shaded-client:[1.2.6.1]", "org.mockito:mockito-core:2.7.22"}) +@PinpointConfig("hbase/pinpoint-hbase-test.config") +public class HbaseClientIT { + + @Mock + private ClusterConnection connection; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testAdmin() throws Exception { + + doReturn(new Configuration()).when(connection).getConfiguration(); + + Admin admin = new HBaseAdmin(connection); + + try { + admin.tableExists(TableName.valueOf("test")); + } catch (Exception e) { + } + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + + verifier.printCache(); + + verifier.verifyTrace(event("HBASE_CLIENT_ADMIN", HBaseAdmin.class.getDeclaredMethod("tableExists", TableName.class), + annotation("hbase.client.params", "[test]"))); + + verifier.verifyTraceCount(0); + } + + @Test + public void testTable() throws Exception { + + doReturn(new Configuration()).when(connection).getConfiguration(); + + Table table = new HTable(TableName.valueOf("test"), connection); + + Put put = new Put("row".getBytes()); + + try { + table.put(put); + } catch (Exception e) { + } + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + + verifier.printCache(); + + verifier.verifyTrace(event("HBASE_CLIENT_TABLE", HTable.class.getDeclaredMethod("put", Put.class), + annotation("hbase.client.params", "rowKey: row"))); + + verifier.verifyTraceCount(0); + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpIT.java similarity index 96% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpIT.java index 7472008b2bea..caf1e95dd2b9 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,7 +19,9 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; @@ -41,6 +43,7 @@ * @author Taejin Koo */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({"com.zaxxer:HikariCP-java6:[2.3.13]", "com.h2database:h2:1.4.191"}) public class HikariCpIT { diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClientIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClientIT.java new file mode 100644 index 000000000000..67ba71ed1251 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClientIT.java @@ -0,0 +1,113 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.httpclient3; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; +import org.apache.commons.httpclient.HostConfiguration; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + * @author jaehong.kim + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "commons-httpclient:commons-httpclient:[3.0],[3.0.1],[3.1]", "org.nanohttpd:nanohttpd:2.3.1"}) +public class HttpClientIT { + + private static WebServer webServer; + + @BeforeClass + public static void BeforeClass() throws Exception { + webServer = WebServer.newTestWebServer(); + } + + @AfterClass + public static void AfterClass() throws Exception { + final WebServer copy = webServer; + if (copy != null) { + copy.stop(); + webServer = null; + } + } + + private static final long CONNECTION_TIMEOUT = 10000; + private static final int SO_TIMEOUT = 10000; + + @Test + public void test() throws Exception { + HttpClient client = new HttpClient(); + client.getParams().setConnectionManagerTimeout(CONNECTION_TIMEOUT); + client.getParams().setSoTimeout(SO_TIMEOUT); + + GetMethod method = new GetMethod(webServer.getCallHttpUrl()); + + // Provide custom retry handler is necessary + method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false)); + method.setQueryString(new NameValuePair[] { new NameValuePair("key2", "value2") }); + + try { + // Execute the method. + client.executeMethod(method); + } catch (Exception ignored) { + } finally { + method.releaseConnection(); + } + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + } + + @Test + public void hostConfig() throws Exception { + HttpClient client = new HttpClient(); + client.getParams().setConnectionManagerTimeout(CONNECTION_TIMEOUT); + client.getParams().setSoTimeout(SO_TIMEOUT); + + HostConfiguration config = new HostConfiguration(); + config.setHost("weather.naver.com", 80, "http"); + GetMethod method = new GetMethod("/rgn/cityWetrMain.nhn"); + + // Provide custom retry handler is necessary + method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false)); + method.setQueryString(new NameValuePair[] { new NameValuePair("key2", "value2") }); + + try { + // Execute the method. + client.executeMethod(config, method); + } catch (Exception ignored) { + } finally { + method.releaseConnection(); + } + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + } +} \ No newline at end of file diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/CloaeableHttpClientIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/CloaeableHttpClientIT.java similarity index 92% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/CloaeableHttpClientIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/CloaeableHttpClientIT.java index c54c2b5ba85e..92c1b03f2021 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/CloaeableHttpClientIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/CloaeableHttpClientIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,9 @@ import java.io.IOException; import java.io.InputStream; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.apache.http.HttpClientConnection; import org.apache.http.HttpEntity; import org.apache.http.HttpRequest; @@ -47,7 +49,8 @@ * @author jaehong.kim */ @RunWith(PinpointPluginTestSuite.class) -@Dependency({ "org.apache.httpcomponents:httpclient:[4.3],[4.3.1],[4.3.2],[4.3.3],[4.3.4],[4.4],[4.4.1],[4.5]", "org.nanohttpd:nanohttpd:2.3.1"}) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.httpcomponents:httpclient:[4.3],[4.3.1],[4.3.2],[4.3.3],[4.3.4],[4.3.6],[4.4],[4.4.1],[4.5],[4.5.1],[4.5.2],[4.5.3],[4.5.4],[4.3.5]", "org.nanohttpd:nanohttpd:2.3.1"}) public class CloaeableHttpClientIT { private static WebServer webServer; diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/ClosableAsyncHttpClientIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/ClosableAsyncHttpClientIT.java similarity index 80% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/ClosableAsyncHttpClientIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/ClosableAsyncHttpClientIT.java index 3a165929c78f..3875371ed36b 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/ClosableAsyncHttpClientIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/ClosableAsyncHttpClientIT.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.plugin.httpclient4; import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; @@ -6,7 +22,9 @@ import java.util.List; import java.util.concurrent.Future; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.apache.http.Consts; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; @@ -33,7 +51,8 @@ * @author netspider */ @RunWith(PinpointPluginTestSuite.class) -@Dependency({ "org.apache.httpcomponents:httpasyncclient:[4.0,)", "org.nanohttpd:nanohttpd:2.3.1"}) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.httpcomponents:httpasyncclient:[4.0],[4.0.1],[4.0.2],[4.1],[4.1.1],[4.1.2],[4.1.3]", "org.nanohttpd:nanohttpd:2.3.1"}) public class ClosableAsyncHttpClientIT { private static WebServer webServer; diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/DefaultHttpRequestRetryHandlerModifierIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/DefaultHttpRequestRetryHandlerModifierIT.java similarity index 86% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/DefaultHttpRequestRetryHandlerModifierIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/DefaultHttpRequestRetryHandlerModifierIT.java index 3338c0f60837..f0c13563aedd 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/DefaultHttpRequestRetryHandlerModifierIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/DefaultHttpRequestRetryHandlerModifierIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,6 +21,8 @@ import java.io.IOException; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; @@ -33,7 +35,8 @@ import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; @RunWith(PinpointPluginTestSuite.class) -@Dependency({ "org.apache.httpcomponents:httpclient:[4.3],[4.3.1],[4.3.2],[4.3.3],[4.3.4],[4.4],[4.4.1],[4.5]" }) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.httpcomponents:httpclient:[4.0],[4.0.1],[4.0.2],[4.0.3],[4.1],[4.1.1],[4.1.2],[4.1.3],[4.2],[4.2.1],[4.2.2],[4.2.3],[4.2.4],[4.2.4],[4.2.6],[4.3.3]" }) public class DefaultHttpRequestRetryHandlerModifierIT { @Test diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClientIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClientIT.java new file mode 100644 index 000000000000..0fcd030b7db9 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClientIT.java @@ -0,0 +1,104 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.httpclient4; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import org.apache.http.HttpClientConnection; +import org.apache.http.HttpRequest; +import org.apache.http.client.HttpClient; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.impl.client.AbstractHttpClient; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestExecutor; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + * @author jaehong.kim + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.httpcomponents:httpclient:[4.0],[4.0.1],[4.0.2],[4.0.3],[4.1],[4.1.1],[4.1.2],[4.1.3],[4.2],[4.2.1],[4.2.2],[4.2.3],[4.2.4],[4.2.4],[4.2.6],[4.3.3]", + "org.nanohttpd:nanohttpd:2.3.1"}) +public class HttpClientIT { + + private static WebServer webServer; + + @BeforeClass + public static void BeforeClass() throws Exception { + webServer = WebServer.newTestWebServer(); + } + + @AfterClass + public static void AfterClass() throws Exception { + final WebServer copy = webServer; + if (copy != null) { + copy.stop(); + webServer = null; + } + } + + @Test + public void test() throws Exception { + HttpClient httpClient = new DefaultHttpClient(); + try { + HttpPost post = new HttpPost(webServer.getCallHttpUrl()); + post.addHeader("Content-Type", "application/json;charset=UTF-8"); + + ResponseHandler responseHandler = new BasicResponseHandler(); + httpClient.execute(post, responseHandler); + } catch (Exception ignored) { + } finally { + if (null != httpClient && null != httpClient.getConnectionManager()) { + httpClient.getConnectionManager().shutdown(); + } + } + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + Class connectorClass; + + try { + connectorClass = Class.forName("org.apache.http.impl.conn.ManagedClientConnectionImpl"); + } catch (ClassNotFoundException e) { + connectorClass = Class.forName("org.apache.http.impl.conn.AbstractPooledConnAdapter"); + } + + verifier.verifyTrace(event("HTTP_CLIENT_4_INTERNAL", AbstractHttpClient.class.getMethod("execute", HttpUriRequest.class, ResponseHandler.class))); + final String hostname = webServer.getHostAndPort(); + verifier.verifyTrace(event("HTTP_CLIENT_4_INTERNAL", connectorClass.getMethod("open", HttpRoute.class, HttpContext.class, HttpParams.class), annotation("http.internal.display", hostname))); + verifier.verifyTrace(event("HTTP_CLIENT_4", HttpRequestExecutor.class.getMethod("execute", HttpRequest.class, HttpClientConnection.class, HttpContext.class), null, null, hostname, annotation("http.url", "/"), annotation("http.status.code", 200), annotation("http.io", anyAnnotationValue()))); + verifier.verifyTraceCount(0); + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_4_0_to_1_5_2_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_4_0_to_1_5_2_IT.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_4_0_to_1_5_2_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_4_0_to_1_5_2_IT.java index 0e958cc86802..6ca5c2c52af9 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_4_0_to_1_5_2_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_4_0_to_1_5_2_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,10 +20,12 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.hystrix.commands.SayHelloCommand; import com.navercorp.pinpoint.plugin.hystrix.runners.HystrixCommandTestRunner; import com.navercorp.pinpoint.test.plugin.Dependency; import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import com.navercorp.test.pinpoint.plugin.hystrix.repository.HelloRepository; @@ -51,6 +53,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) // Hystrix 1.4.0 - 1.4.2 requires Java 7 @JvmVersion(7) // rxjava, hystrix plugin enabled + custom trace method config diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_5_3_to_1_5_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_5_3_to_1_5_x_IT.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_5_3_to_1_5_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_5_3_to_1_5_x_IT.java index e16d4669c361..3f4c59596172 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_5_3_to_1_5_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixCommand_1_5_3_to_1_5_x_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,9 +20,11 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.hystrix.commands.SayHelloCommand; import com.navercorp.pinpoint.plugin.hystrix.runners.HystrixCommandTestRunner; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import com.navercorp.test.pinpoint.plugin.hystrix.repository.HelloRepository; @@ -50,6 +52,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) // rxjava, hystrix plugin enabled + custom trace method config @PinpointConfig("hystrix/pinpoint-hystrix.config") @Dependency({"com.netflix.hystrix:hystrix-core:[1.5.3,)","com.netflix.hystrix:hystrix-metrics-event-stream:1.1.2"}) diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_4_0_to_1_5_2_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_4_0_to_1_5_2_IT.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_4_0_to_1_5_2_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_4_0_to_1_5_2_IT.java index d9b5b10eaae2..4e6bb471f0e9 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_4_0_to_1_5_2_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_4_0_to_1_5_2_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,10 +20,12 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.hystrix.commands.SayHelloObservableCommand; import com.navercorp.pinpoint.plugin.hystrix.runners.HystrixObservableCommandTestRunner; import com.navercorp.pinpoint.test.plugin.Dependency; import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import com.navercorp.test.pinpoint.plugin.hystrix.repository.HelloRepository; @@ -49,6 +51,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) // Hystrix 1.4.0 - 1.4.2 requires Java 7 @JvmVersion(7) // rxjava, hystrix plugin enabled + custom trace method config diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_5_3_to_1_5_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_5_3_to_1_5_x_IT.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_5_3_to_1_5_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_5_3_to_1_5_x_IT.java index efb29d1c12b4..8452d96c9641 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_5_3_to_1_5_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixObservableCommand_1_5_3_to_1_5_x_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,9 +20,11 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.hystrix.commands.SayHelloObservableCommand; import com.navercorp.pinpoint.plugin.hystrix.runners.HystrixObservableCommandTestRunner; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import com.navercorp.test.pinpoint.plugin.hystrix.repository.HelloRepository; @@ -48,6 +50,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) // rxjava, hystrix plugin enabled + custom trace method config @PinpointConfig("hystrix/pinpoint-hystrix.config") @Dependency({"com.netflix.hystrix:hystrix-core:[1.5.3,)","com.netflix.hystrix:hystrix-metrics-event-stream:1.1.2"}) diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixTestHelper.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixTestHelper.java similarity index 97% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixTestHelper.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixTestHelper.java index 463c7f288773..9e38b057080a 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixTestHelper.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/HystrixTestHelper.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloCommand.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloCommand.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloCommand.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloCommand.java index 0e5327f08d75..a528b4aa9c9c 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloCommand.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloCommand.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloObservableCommand.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloObservableCommand.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloObservableCommand.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloObservableCommand.java index e77b0d06d8cd..b83559070ce1 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloObservableCommand.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/commands/SayHelloObservableCommand.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixCommandTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixCommandTestRunner.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixCommandTestRunner.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixCommandTestRunner.java index 98f1af1cbb06..0fd5b783c162 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixCommandTestRunner.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixCommandTestRunner.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixObservableCommandTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixObservableCommandTestRunner.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixObservableCommandTestRunner.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixObservableCommandTestRunner.java index 6330b8945b8b..aff8321d8cea 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixObservableCommandTestRunner.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/hystrix/runners/HystrixObservableCommandTestRunner.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientIT.java similarity index 91% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientIT.java index 4638877bdc00..b14e676b7b59 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientIT.java @@ -1,84 +1,84 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.ibatis; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.ibatis.sqlmap.client.SqlMapClient; -import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl; -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.ibatis:ibatis-sqlmap:[2.3.4.726]", "org.mockito:mockito-all:1.8.4" }) -public class SqlMapClientIT extends SqlMapExecutorTestBase { - - @Test - public void methodCallWithNullSqlIdShouldOnlyTraceMethodName() throws Exception { - SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); - super.testAndVerifyInsertWithNullSqlId(sqlMapClient); - } - - @Test - public void insertShouldBeTraced() throws Exception { - SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); - super.testAndVerifyInsert(sqlMapClient); - } - - @Test - public void deleteShouldBeTraced() throws Exception { - SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); - super.testAndVerifyDelete(sqlMapClient); - } - - @Test - public void updateShouldBeTraced() throws Exception { - SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); - super.testAndVerifyUpdate(sqlMapClient); - } - - @Test - public void queryForListShouldBeTraced() throws Exception { - SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); - super.testAndVerifyQueryForList(sqlMapClient); - } - - @Test - public void queryForMapShouldBeTraced() throws Exception { - SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); - super.testAndVerifyQueryForMap(sqlMapClient); - } - - @Test - public void queryForObjectShouldBeTraced() throws Exception { - SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); - super.testAndVerifyQueryForObject(sqlMapClient); - } - - @Test - public void queryForPaginagedListShouldBeTraced() throws Exception { - SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); - super.testAndVerifyQueryForPaginatedList(sqlMapClient); - } -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ibatis; + +import com.navercorp.pinpoint.plugin.AgentPath; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.ibatis.sqlmap.client.SqlMapClient; +import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.ibatis:ibatis-sqlmap:[2.3.4.726]", "org.mockito:mockito-all:1.8.4" }) +public class SqlMapClientIT extends SqlMapExecutorTestBase { + + @Test + public void methodCallWithNullSqlIdShouldOnlyTraceMethodName() throws Exception { + SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); + super.testAndVerifyInsertWithNullSqlId(sqlMapClient); + } + + @Test + public void insertShouldBeTraced() throws Exception { + SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); + super.testAndVerifyInsert(sqlMapClient); + } + + @Test + public void deleteShouldBeTraced() throws Exception { + SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); + super.testAndVerifyDelete(sqlMapClient); + } + + @Test + public void updateShouldBeTraced() throws Exception { + SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); + super.testAndVerifyUpdate(sqlMapClient); + } + + @Test + public void queryForListShouldBeTraced() throws Exception { + SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); + super.testAndVerifyQueryForList(sqlMapClient); + } + + @Test + public void queryForMapShouldBeTraced() throws Exception { + SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); + super.testAndVerifyQueryForMap(sqlMapClient); + } + + @Test + public void queryForObjectShouldBeTraced() throws Exception { + SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); + super.testAndVerifyQueryForObject(sqlMapClient); + } + + @Test + public void queryForPaginagedListShouldBeTraced() throws Exception { + SqlMapClient sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); + super.testAndVerifyQueryForPaginatedList(sqlMapClient); + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientTemplateIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientTemplateIT.java similarity index 96% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientTemplateIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientTemplateIT.java index 9f76590251d4..d5270351915e 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientTemplateIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapClientTemplateIT.java @@ -1,236 +1,236 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.ibatis; - -import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.mock; - -import java.lang.reflect.Method; - -import javax.sql.DataSource; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.orm.ibatis.SqlMapClientTemplate; - -import com.ibatis.sqlmap.client.SqlMapClient; -import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl; -import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate; -import com.ibatis.sqlmap.engine.scope.SessionScope; -import com.ibatis.sqlmap.engine.transaction.TransactionManager; -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - * Tests against spring-ibatis 2.0.7+. Prior versions require com.ibatis:ibatis2 dependency, which is not available in the repository. - * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.springframework:spring-ibatis:[2.0.7,)", "org.apache.ibatis:ibatis-sqlmap:[2.3.4.726]", - "org.mockito:mockito-all:1.8.4" }) -public class SqlMapClientTemplateIT { - - public class MockSqlMapExecutorDelegate extends SqlMapExecutorDelegate { - @Override - public SessionScope beginSessionScope() { - return mockSessionScope; - } - } - - @Mock - private MockSqlMapExecutorDelegate mockSqlMapExecutorDelegate; - - @Mock - private SessionScope mockSessionScope; - - @Mock - private DataSource mockDataSource; - - private SqlMapClient sqlMapClient; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(this.mockSqlMapExecutorDelegate.beginSessionScope()).thenReturn(this.mockSessionScope); - this.sqlMapClient = new SqlMapClientImpl(this.mockSqlMapExecutorDelegate); - } - - @Test - public void methodCallWithNullSqlIdShouldOnlyTraceMethodName() throws Exception { - // Given - SqlMapClientTemplate template = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); - // When - template.insert(null); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method insert = SqlMapClientTemplate.class.getDeclaredMethod("insert", String.class); - verifier.verifyTrace(event("IBATIS_SPRING", insert)); - } - - @Test - public void insertShouldBeTraced() throws Exception { - // Given - final String insertId = "insertId"; - SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); - // When - clientTemplate.insert(insertId); - clientTemplate.insert(insertId, new Object()); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method insert = SqlMapClientTemplate.class.getDeclaredMethod("insert", String.class); - Method insertWithParameter = SqlMapClientTemplate.class.getDeclaredMethod("insert", String.class, Object.class); - verifier.verifyTrace(event("IBATIS_SPRING", insert, Expectations.cachedArgs(insertId))); - verifier.verifyTrace(event("IBATIS_SPRING", insertWithParameter, Expectations.cachedArgs(insertId))); - } - - @Test - public void deleteShouldBeTraced() throws Exception { - // Given - final String deleteId = "deleteId"; - SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); - // When - clientTemplate.delete(deleteId); - clientTemplate.delete(deleteId, new Object()); - clientTemplate.delete(deleteId, new Object(), 0); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method delete1 = SqlMapClientTemplate.class.getDeclaredMethod("delete", String.class); - Method delete2 = SqlMapClientTemplate.class.getDeclaredMethod("delete", String.class, Object.class); - Method delete3 = SqlMapClientTemplate.class.getDeclaredMethod("delete", String.class, Object.class, int.class); - verifier.verifyTrace(event("IBATIS_SPRING", delete1, Expectations.cachedArgs(deleteId))); - verifier.verifyTrace(event("IBATIS_SPRING", delete2, Expectations.cachedArgs(deleteId))); - verifier.verifyTrace(event("IBATIS_SPRING", delete3, Expectations.cachedArgs(deleteId))); - } - - @Test - public void updateShouldBeTraced() throws Exception { - // Given - final String updateId = "updateId"; - SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); - // When - clientTemplate.update(updateId); - clientTemplate.update(updateId, new Object()); - clientTemplate.update(updateId, new Object(), 0); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method update1 = SqlMapClientTemplate.class.getDeclaredMethod("update", String.class); - Method update2 = SqlMapClientTemplate.class.getDeclaredMethod("update", String.class, Object.class); - Method update3 = SqlMapClientTemplate.class.getDeclaredMethod("update", String.class, Object.class, int.class); - verifier.verifyTrace(event("IBATIS_SPRING", update1, Expectations.cachedArgs(updateId))); - verifier.verifyTrace(event("IBATIS_SPRING", update2, Expectations.cachedArgs(updateId))); - verifier.verifyTrace(event("IBATIS_SPRING", update3, Expectations.cachedArgs(updateId))); - } - - @Test - public void queryForListShouldBeTraced() throws Exception { - // Given - final String queryForListId = "queryForListId"; - SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); - // When - clientTemplate.queryForList(queryForListId); - clientTemplate.queryForList(queryForListId, new Object()); - clientTemplate.queryForList(queryForListId, 0, 1); - clientTemplate.queryForList(queryForListId, new Object(), 0, 1); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method queryForList1 = SqlMapClientTemplate.class.getDeclaredMethod("queryForList", String.class); - Method queryForList2 = SqlMapClientTemplate.class.getDeclaredMethod("queryForList", String.class, Object.class); - Method queryForList3 = SqlMapClientTemplate.class.getDeclaredMethod("queryForList", String.class, int.class, - int.class); - Method queryForList4 = SqlMapClientTemplate.class.getDeclaredMethod("queryForList", String.class, Object.class, - int.class, int.class); - verifier.verifyTrace(event("IBATIS_SPRING", queryForList1, Expectations.cachedArgs(queryForListId))); - verifier.verifyTrace(event("IBATIS_SPRING", queryForList2, Expectations.cachedArgs(queryForListId))); - verifier.verifyTrace(event("IBATIS_SPRING", queryForList3, Expectations.cachedArgs(queryForListId))); - verifier.verifyTrace(event("IBATIS_SPRING", queryForList4, Expectations.cachedArgs(queryForListId))); - } - - @Test - public void queryForMapShouldBeTraced() throws Exception { - // Given - final String queryForMapId = "queryForMapId"; - SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); - // When - clientTemplate.queryForMap(queryForMapId, new Object(), "key"); - clientTemplate.queryForMap(queryForMapId, new Object(), "key", "value"); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method queryForMap1 = SqlMapClientTemplate.class.getDeclaredMethod("queryForMap", String.class, Object.class, - String.class); - Method queryForMap2 = SqlMapClientTemplate.class.getDeclaredMethod("queryForMap", String.class, Object.class, - String.class, String.class); - verifier.verifyTrace(event("IBATIS_SPRING", queryForMap1, Expectations.cachedArgs(queryForMapId))); - verifier.verifyTrace(event("IBATIS_SPRING", queryForMap2, Expectations.cachedArgs(queryForMapId))); - } - - @Test - public void queryForObjectShouldBeTraced() throws Exception { - // Given - final String queryForObjectId = "queryForObjectId"; - SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); - // When - clientTemplate.queryForObject(queryForObjectId); - clientTemplate.queryForObject(queryForObjectId, new Object()); - clientTemplate.queryForObject(queryForObjectId, new Object(), new Object()); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method queryForObject1 = SqlMapClientTemplate.class.getDeclaredMethod("queryForObject", String.class); - Method queryForObject2 = SqlMapClientTemplate.class.getDeclaredMethod("queryForObject", String.class, - Object.class); - Method queryForObject3 = SqlMapClientTemplate.class.getDeclaredMethod("queryForObject", String.class, - Object.class, Object.class); - verifier.verifyTrace(event("IBATIS_SPRING", queryForObject1, Expectations.cachedArgs(queryForObjectId))); - verifier.verifyTrace(event("IBATIS_SPRING", queryForObject2, Expectations.cachedArgs(queryForObjectId))); - verifier.verifyTrace(event("IBATIS_SPRING", queryForObject3, Expectations.cachedArgs(queryForObjectId))); - } - - @Test - @SuppressWarnings("deprecation") - public void queryForPaginagedListShouldBeTraced() throws Exception { - // Given - final String queryForPaginatedListId = "queryForPaginatedListId"; - // to emulate lazy-loading, otherwise exception is thrown - TransactionManager mockTxManager = mock(TransactionManager.class); - when(this.mockSqlMapExecutorDelegate.getTxManager()).thenReturn(mockTxManager); - SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); - // When - clientTemplate.queryForPaginatedList(queryForPaginatedListId, 1); - clientTemplate.queryForPaginatedList(queryForPaginatedListId, new Object(), 1); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method queryForPaginatedList1 = SqlMapClientTemplate.class.getDeclaredMethod("queryForPaginatedList", - String.class, int.class); - Method queryForPaginatedList2 = SqlMapClientTemplate.class.getDeclaredMethod("queryForPaginatedList", - String.class, Object.class, int.class); - verifier.verifyTrace(event("IBATIS_SPRING", queryForPaginatedList1, - Expectations.cachedArgs(queryForPaginatedListId))); - verifier.verifyTrace(event("IBATIS_SPRING", queryForPaginatedList2, - Expectations.cachedArgs(queryForPaginatedListId))); - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ibatis; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.mock; + +import java.lang.reflect.Method; + +import javax.sql.DataSource; + +import com.navercorp.pinpoint.plugin.AgentPath; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.orm.ibatis.SqlMapClientTemplate; + +import com.ibatis.sqlmap.client.SqlMapClient; +import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl; +import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate; +import com.ibatis.sqlmap.engine.scope.SessionScope; +import com.ibatis.sqlmap.engine.transaction.TransactionManager; +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + * Tests against spring-ibatis 2.0.7+. Prior versions require com.ibatis:ibatis2 dependency, which is not available in the repository. + * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.springframework:spring-ibatis:[2.0.7,)", "org.apache.ibatis:ibatis-sqlmap:[2.3.4.726]", + "org.mockito:mockito-all:1.8.4" }) +public class SqlMapClientTemplateIT { + + public class MockSqlMapExecutorDelegate extends SqlMapExecutorDelegate { + @Override + public SessionScope beginSessionScope() { + return mockSessionScope; + } + } + + @Mock + private MockSqlMapExecutorDelegate mockSqlMapExecutorDelegate; + + @Mock + private SessionScope mockSessionScope; + + @Mock + private DataSource mockDataSource; + + private SqlMapClient sqlMapClient; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(this.mockSqlMapExecutorDelegate.beginSessionScope()).thenReturn(this.mockSessionScope); + this.sqlMapClient = new SqlMapClientImpl(this.mockSqlMapExecutorDelegate); + } + + @Test + public void methodCallWithNullSqlIdShouldOnlyTraceMethodName() throws Exception { + // Given + SqlMapClientTemplate template = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); + // When + template.insert(null); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method insert = SqlMapClientTemplate.class.getDeclaredMethod("insert", String.class); + verifier.verifyTrace(event("IBATIS_SPRING", insert)); + } + + @Test + public void insertShouldBeTraced() throws Exception { + // Given + final String insertId = "insertId"; + SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); + // When + clientTemplate.insert(insertId); + clientTemplate.insert(insertId, new Object()); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method insert = SqlMapClientTemplate.class.getDeclaredMethod("insert", String.class); + Method insertWithParameter = SqlMapClientTemplate.class.getDeclaredMethod("insert", String.class, Object.class); + verifier.verifyTrace(event("IBATIS_SPRING", insert, Expectations.cachedArgs(insertId))); + verifier.verifyTrace(event("IBATIS_SPRING", insertWithParameter, Expectations.cachedArgs(insertId))); + } + + @Test + public void deleteShouldBeTraced() throws Exception { + // Given + final String deleteId = "deleteId"; + SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); + // When + clientTemplate.delete(deleteId); + clientTemplate.delete(deleteId, new Object()); + clientTemplate.delete(deleteId, new Object(), 0); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method delete1 = SqlMapClientTemplate.class.getDeclaredMethod("delete", String.class); + Method delete2 = SqlMapClientTemplate.class.getDeclaredMethod("delete", String.class, Object.class); + Method delete3 = SqlMapClientTemplate.class.getDeclaredMethod("delete", String.class, Object.class, int.class); + verifier.verifyTrace(event("IBATIS_SPRING", delete1, Expectations.cachedArgs(deleteId))); + verifier.verifyTrace(event("IBATIS_SPRING", delete2, Expectations.cachedArgs(deleteId))); + verifier.verifyTrace(event("IBATIS_SPRING", delete3, Expectations.cachedArgs(deleteId))); + } + + @Test + public void updateShouldBeTraced() throws Exception { + // Given + final String updateId = "updateId"; + SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); + // When + clientTemplate.update(updateId); + clientTemplate.update(updateId, new Object()); + clientTemplate.update(updateId, new Object(), 0); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method update1 = SqlMapClientTemplate.class.getDeclaredMethod("update", String.class); + Method update2 = SqlMapClientTemplate.class.getDeclaredMethod("update", String.class, Object.class); + Method update3 = SqlMapClientTemplate.class.getDeclaredMethod("update", String.class, Object.class, int.class); + verifier.verifyTrace(event("IBATIS_SPRING", update1, Expectations.cachedArgs(updateId))); + verifier.verifyTrace(event("IBATIS_SPRING", update2, Expectations.cachedArgs(updateId))); + verifier.verifyTrace(event("IBATIS_SPRING", update3, Expectations.cachedArgs(updateId))); + } + + @Test + public void queryForListShouldBeTraced() throws Exception { + // Given + final String queryForListId = "queryForListId"; + SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); + // When + clientTemplate.queryForList(queryForListId); + clientTemplate.queryForList(queryForListId, new Object()); + clientTemplate.queryForList(queryForListId, 0, 1); + clientTemplate.queryForList(queryForListId, new Object(), 0, 1); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method queryForList1 = SqlMapClientTemplate.class.getDeclaredMethod("queryForList", String.class); + Method queryForList2 = SqlMapClientTemplate.class.getDeclaredMethod("queryForList", String.class, Object.class); + Method queryForList3 = SqlMapClientTemplate.class.getDeclaredMethod("queryForList", String.class, int.class, + int.class); + Method queryForList4 = SqlMapClientTemplate.class.getDeclaredMethod("queryForList", String.class, Object.class, + int.class, int.class); + verifier.verifyTrace(event("IBATIS_SPRING", queryForList1, Expectations.cachedArgs(queryForListId))); + verifier.verifyTrace(event("IBATIS_SPRING", queryForList2, Expectations.cachedArgs(queryForListId))); + verifier.verifyTrace(event("IBATIS_SPRING", queryForList3, Expectations.cachedArgs(queryForListId))); + verifier.verifyTrace(event("IBATIS_SPRING", queryForList4, Expectations.cachedArgs(queryForListId))); + } + + @Test + public void queryForMapShouldBeTraced() throws Exception { + // Given + final String queryForMapId = "queryForMapId"; + SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); + // When + clientTemplate.queryForMap(queryForMapId, new Object(), "key"); + clientTemplate.queryForMap(queryForMapId, new Object(), "key", "value"); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method queryForMap1 = SqlMapClientTemplate.class.getDeclaredMethod("queryForMap", String.class, Object.class, + String.class); + Method queryForMap2 = SqlMapClientTemplate.class.getDeclaredMethod("queryForMap", String.class, Object.class, + String.class, String.class); + verifier.verifyTrace(event("IBATIS_SPRING", queryForMap1, Expectations.cachedArgs(queryForMapId))); + verifier.verifyTrace(event("IBATIS_SPRING", queryForMap2, Expectations.cachedArgs(queryForMapId))); + } + + @Test + public void queryForObjectShouldBeTraced() throws Exception { + // Given + final String queryForObjectId = "queryForObjectId"; + SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); + // When + clientTemplate.queryForObject(queryForObjectId); + clientTemplate.queryForObject(queryForObjectId, new Object()); + clientTemplate.queryForObject(queryForObjectId, new Object(), new Object()); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method queryForObject1 = SqlMapClientTemplate.class.getDeclaredMethod("queryForObject", String.class); + Method queryForObject2 = SqlMapClientTemplate.class.getDeclaredMethod("queryForObject", String.class, + Object.class); + Method queryForObject3 = SqlMapClientTemplate.class.getDeclaredMethod("queryForObject", String.class, + Object.class, Object.class); + verifier.verifyTrace(event("IBATIS_SPRING", queryForObject1, Expectations.cachedArgs(queryForObjectId))); + verifier.verifyTrace(event("IBATIS_SPRING", queryForObject2, Expectations.cachedArgs(queryForObjectId))); + verifier.verifyTrace(event("IBATIS_SPRING", queryForObject3, Expectations.cachedArgs(queryForObjectId))); + } + + @Test + @SuppressWarnings("deprecation") + public void queryForPaginagedListShouldBeTraced() throws Exception { + // Given + final String queryForPaginatedListId = "queryForPaginatedListId"; + // to emulate lazy-loading, otherwise exception is thrown + TransactionManager mockTxManager = mock(TransactionManager.class); + when(this.mockSqlMapExecutorDelegate.getTxManager()).thenReturn(mockTxManager); + SqlMapClientTemplate clientTemplate = new SqlMapClientTemplate(this.mockDataSource, this.sqlMapClient); + // When + clientTemplate.queryForPaginatedList(queryForPaginatedListId, 1); + clientTemplate.queryForPaginatedList(queryForPaginatedListId, new Object(), 1); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method queryForPaginatedList1 = SqlMapClientTemplate.class.getDeclaredMethod("queryForPaginatedList", + String.class, int.class); + Method queryForPaginatedList2 = SqlMapClientTemplate.class.getDeclaredMethod("queryForPaginatedList", + String.class, Object.class, int.class); + verifier.verifyTrace(event("IBATIS_SPRING", queryForPaginatedList1, + Expectations.cachedArgs(queryForPaginatedListId))); + verifier.verifyTrace(event("IBATIS_SPRING", queryForPaginatedList2, + Expectations.cachedArgs(queryForPaginatedListId))); + } + +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapExecutorTestBase.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapExecutorTestBase.java similarity index 97% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapExecutorTestBase.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapExecutorTestBase.java index 5d70991c0efb..e74ce22f6809 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapExecutorTestBase.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapExecutorTestBase.java @@ -1,169 +1,169 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.ibatis; - -import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; -import static org.mockito.Mockito.when; - -import java.lang.reflect.Method; - -import org.junit.Before; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import com.ibatis.sqlmap.client.SqlMapExecutor; -import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate; -import com.ibatis.sqlmap.engine.scope.SessionScope; -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; - -/** - * @author HyunGil Jeong - */ -public abstract class SqlMapExecutorTestBase { - - public class MockSqlMapExecutorDelegate extends SqlMapExecutorDelegate { - @Override - public SessionScope beginSessionScope() { - return mockSessionScope; - } - } - - @Mock - protected MockSqlMapExecutorDelegate mockSqlMapExecutorDelegate; - - @Mock - private SessionScope mockSessionScope; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(this.mockSqlMapExecutorDelegate.beginSessionScope()).thenReturn(this.mockSessionScope); - } - - protected final void testAndVerifyInsertWithNullSqlId(SqlMapExecutor executor) throws Exception { - executor.insert(null); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method insert = executor.getClass().getDeclaredMethod("insert", String.class); - verifier.verifyTrace(event("IBATIS", insert)); - } - - protected final void testAndVerifyInsert(SqlMapExecutor executor) throws Exception { - final String insertId = "insertId"; - executor.insert(insertId); - executor.insert(insertId, new Object()); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method insert = executor.getClass().getDeclaredMethod("insert", String.class); - Method insertWithParameter = executor.getClass().getDeclaredMethod("insert", String.class, Object.class); - verifier.verifyTrace(event("IBATIS", insert, Expectations.cachedArgs(insertId))); - verifier.verifyTrace(event("IBATIS", insertWithParameter, Expectations.cachedArgs(insertId))); - } - - protected final void testAndVerifyDelete(SqlMapExecutor executor) throws Exception { - final String deleteId = "deleteId"; - executor.delete(deleteId); - executor.delete(deleteId, new Object()); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - Method delete = executor.getClass().getDeclaredMethod("delete", String.class); - Method deleteWithParameter = executor.getClass().getDeclaredMethod("delete", String.class, Object.class); - verifier.verifyTrace(event("IBATIS", delete, Expectations.cachedArgs(deleteId))); - verifier.verifyTrace(event("IBATIS", deleteWithParameter, Expectations.cachedArgs(deleteId))); - } - - protected final void testAndVerifyUpdate(SqlMapExecutor executor) throws Exception { - final String updateId = "updateId"; - executor.update(updateId); - executor.update(updateId, new Object()); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method update = executor.getClass().getDeclaredMethod("update", String.class); - Method updateWithParameter = executor.getClass().getDeclaredMethod("update", String.class, Object.class); - verifier.verifyTrace(event("IBATIS", update, Expectations.cachedArgs(updateId))); - verifier.verifyTrace(event("IBATIS", updateWithParameter, Expectations.cachedArgs(updateId))); - } - - protected final void testAndVerifyQueryForList(SqlMapExecutor executor) throws Exception { - final String queryForListId = "queryForListId"; - executor.queryForList(queryForListId); - executor.queryForList(queryForListId, new Object()); - executor.queryForList(queryForListId, 0, 1); - executor.queryForList(queryForListId, new Object(), 0, 1); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method queryForList1 = executor.getClass().getDeclaredMethod("queryForList", String.class); - Method queryForList2 = executor.getClass().getDeclaredMethod("queryForList", String.class, Object.class); - Method queryForList3 = executor.getClass() - .getDeclaredMethod("queryForList", String.class, int.class, int.class); - Method queryForList4 = executor.getClass().getDeclaredMethod("queryForList", String.class, Object.class, - int.class, int.class); - verifier.verifyTrace(event("IBATIS", queryForList1, Expectations.cachedArgs(queryForListId))); - verifier.verifyTrace(event("IBATIS", queryForList2, Expectations.cachedArgs(queryForListId))); - verifier.verifyTrace(event("IBATIS", queryForList3, Expectations.cachedArgs(queryForListId))); - verifier.verifyTrace(event("IBATIS", queryForList4, Expectations.cachedArgs(queryForListId))); - } - - protected final void testAndVerifyQueryForMap(SqlMapExecutor executor) throws Exception { - final String queryForMapId = "queryForMapId"; - executor.queryForMap(queryForMapId, new Object(), "key"); - executor.queryForMap(queryForMapId, new Object(), "key", "value"); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method queryForMap1 = executor.getClass().getDeclaredMethod("queryForMap", String.class, Object.class, - String.class); - Method queryForMap2 = executor.getClass().getDeclaredMethod("queryForMap", String.class, Object.class, - String.class, String.class); - verifier.verifyTrace(event("IBATIS", queryForMap1, Expectations.cachedArgs(queryForMapId))); - verifier.verifyTrace(event("IBATIS", queryForMap2, Expectations.cachedArgs(queryForMapId))); - } - - protected final void testAndVerifyQueryForObject(SqlMapExecutor executor) throws Exception { - final String queryForObjectId = "queryForObjectId"; - executor.queryForObject(queryForObjectId); - executor.queryForObject(queryForObjectId, new Object()); - executor.queryForObject(queryForObjectId, new Object(), new Object()); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method queryForObject1 = executor.getClass().getDeclaredMethod("queryForObject", String.class); - Method queryForObject2 = executor.getClass().getDeclaredMethod("queryForObject", String.class, Object.class); - Method queryForObject3 = executor.getClass().getDeclaredMethod("queryForObject", String.class, Object.class, - Object.class); - verifier.verifyTrace(event("IBATIS", queryForObject1, Expectations.cachedArgs(queryForObjectId))); - verifier.verifyTrace(event("IBATIS", queryForObject2, Expectations.cachedArgs(queryForObjectId))); - verifier.verifyTrace(event("IBATIS", queryForObject3, Expectations.cachedArgs(queryForObjectId))); - } - - @SuppressWarnings("deprecation") - protected final void testAndVerifyQueryForPaginatedList(SqlMapExecutor executor) throws Exception { - final String queryForPaginatedListId = "queryForPaginatedListId"; - executor.queryForPaginatedList(queryForPaginatedListId, 1); - executor.queryForPaginatedList(queryForPaginatedListId, new Object(), 1); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method queryForPaginatedList1 = executor.getClass().getDeclaredMethod("queryForPaginatedList", String.class, - int.class); - Method queryForPaginatedList2 = executor.getClass().getDeclaredMethod("queryForPaginatedList", String.class, - Object.class, int.class); - verifier.verifyTrace(event("IBATIS", queryForPaginatedList1, Expectations.cachedArgs(queryForPaginatedListId))); - verifier.verifyTrace(event("IBATIS", queryForPaginatedList2, Expectations.cachedArgs(queryForPaginatedListId))); - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ibatis; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Method; + +import org.junit.Before; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.ibatis.sqlmap.client.SqlMapExecutor; +import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate; +import com.ibatis.sqlmap.engine.scope.SessionScope; +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; + +/** + * @author HyunGil Jeong + */ +public abstract class SqlMapExecutorTestBase { + + public class MockSqlMapExecutorDelegate extends SqlMapExecutorDelegate { + @Override + public SessionScope beginSessionScope() { + return mockSessionScope; + } + } + + @Mock + protected MockSqlMapExecutorDelegate mockSqlMapExecutorDelegate; + + @Mock + private SessionScope mockSessionScope; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(this.mockSqlMapExecutorDelegate.beginSessionScope()).thenReturn(this.mockSessionScope); + } + + protected final void testAndVerifyInsertWithNullSqlId(SqlMapExecutor executor) throws Exception { + executor.insert(null); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method insert = executor.getClass().getDeclaredMethod("insert", String.class); + verifier.verifyTrace(event("IBATIS", insert)); + } + + protected final void testAndVerifyInsert(SqlMapExecutor executor) throws Exception { + final String insertId = "insertId"; + executor.insert(insertId); + executor.insert(insertId, new Object()); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method insert = executor.getClass().getDeclaredMethod("insert", String.class); + Method insertWithParameter = executor.getClass().getDeclaredMethod("insert", String.class, Object.class); + verifier.verifyTrace(event("IBATIS", insert, Expectations.cachedArgs(insertId))); + verifier.verifyTrace(event("IBATIS", insertWithParameter, Expectations.cachedArgs(insertId))); + } + + protected final void testAndVerifyDelete(SqlMapExecutor executor) throws Exception { + final String deleteId = "deleteId"; + executor.delete(deleteId); + executor.delete(deleteId, new Object()); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + Method delete = executor.getClass().getDeclaredMethod("delete", String.class); + Method deleteWithParameter = executor.getClass().getDeclaredMethod("delete", String.class, Object.class); + verifier.verifyTrace(event("IBATIS", delete, Expectations.cachedArgs(deleteId))); + verifier.verifyTrace(event("IBATIS", deleteWithParameter, Expectations.cachedArgs(deleteId))); + } + + protected final void testAndVerifyUpdate(SqlMapExecutor executor) throws Exception { + final String updateId = "updateId"; + executor.update(updateId); + executor.update(updateId, new Object()); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method update = executor.getClass().getDeclaredMethod("update", String.class); + Method updateWithParameter = executor.getClass().getDeclaredMethod("update", String.class, Object.class); + verifier.verifyTrace(event("IBATIS", update, Expectations.cachedArgs(updateId))); + verifier.verifyTrace(event("IBATIS", updateWithParameter, Expectations.cachedArgs(updateId))); + } + + protected final void testAndVerifyQueryForList(SqlMapExecutor executor) throws Exception { + final String queryForListId = "queryForListId"; + executor.queryForList(queryForListId); + executor.queryForList(queryForListId, new Object()); + executor.queryForList(queryForListId, 0, 1); + executor.queryForList(queryForListId, new Object(), 0, 1); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method queryForList1 = executor.getClass().getDeclaredMethod("queryForList", String.class); + Method queryForList2 = executor.getClass().getDeclaredMethod("queryForList", String.class, Object.class); + Method queryForList3 = executor.getClass() + .getDeclaredMethod("queryForList", String.class, int.class, int.class); + Method queryForList4 = executor.getClass().getDeclaredMethod("queryForList", String.class, Object.class, + int.class, int.class); + verifier.verifyTrace(event("IBATIS", queryForList1, Expectations.cachedArgs(queryForListId))); + verifier.verifyTrace(event("IBATIS", queryForList2, Expectations.cachedArgs(queryForListId))); + verifier.verifyTrace(event("IBATIS", queryForList3, Expectations.cachedArgs(queryForListId))); + verifier.verifyTrace(event("IBATIS", queryForList4, Expectations.cachedArgs(queryForListId))); + } + + protected final void testAndVerifyQueryForMap(SqlMapExecutor executor) throws Exception { + final String queryForMapId = "queryForMapId"; + executor.queryForMap(queryForMapId, new Object(), "key"); + executor.queryForMap(queryForMapId, new Object(), "key", "value"); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method queryForMap1 = executor.getClass().getDeclaredMethod("queryForMap", String.class, Object.class, + String.class); + Method queryForMap2 = executor.getClass().getDeclaredMethod("queryForMap", String.class, Object.class, + String.class, String.class); + verifier.verifyTrace(event("IBATIS", queryForMap1, Expectations.cachedArgs(queryForMapId))); + verifier.verifyTrace(event("IBATIS", queryForMap2, Expectations.cachedArgs(queryForMapId))); + } + + protected final void testAndVerifyQueryForObject(SqlMapExecutor executor) throws Exception { + final String queryForObjectId = "queryForObjectId"; + executor.queryForObject(queryForObjectId); + executor.queryForObject(queryForObjectId, new Object()); + executor.queryForObject(queryForObjectId, new Object(), new Object()); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method queryForObject1 = executor.getClass().getDeclaredMethod("queryForObject", String.class); + Method queryForObject2 = executor.getClass().getDeclaredMethod("queryForObject", String.class, Object.class); + Method queryForObject3 = executor.getClass().getDeclaredMethod("queryForObject", String.class, Object.class, + Object.class); + verifier.verifyTrace(event("IBATIS", queryForObject1, Expectations.cachedArgs(queryForObjectId))); + verifier.verifyTrace(event("IBATIS", queryForObject2, Expectations.cachedArgs(queryForObjectId))); + verifier.verifyTrace(event("IBATIS", queryForObject3, Expectations.cachedArgs(queryForObjectId))); + } + + @SuppressWarnings("deprecation") + protected final void testAndVerifyQueryForPaginatedList(SqlMapExecutor executor) throws Exception { + final String queryForPaginatedListId = "queryForPaginatedListId"; + executor.queryForPaginatedList(queryForPaginatedListId, 1); + executor.queryForPaginatedList(queryForPaginatedListId, new Object(), 1); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method queryForPaginatedList1 = executor.getClass().getDeclaredMethod("queryForPaginatedList", String.class, + int.class); + Method queryForPaginatedList2 = executor.getClass().getDeclaredMethod("queryForPaginatedList", String.class, + Object.class, int.class); + verifier.verifyTrace(event("IBATIS", queryForPaginatedList1, Expectations.cachedArgs(queryForPaginatedListId))); + verifier.verifyTrace(event("IBATIS", queryForPaginatedList2, Expectations.cachedArgs(queryForPaginatedListId))); + } + +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapSessionIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapSessionIT.java similarity index 91% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapSessionIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapSessionIT.java index e307b932326a..a206358d0951 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapSessionIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ibatis/SqlMapSessionIT.java @@ -1,101 +1,101 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.ibatis; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.ibatis.sqlmap.client.SqlMapSession; -import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl; -import com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl; -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.ibatis:ibatis-sqlmap:[2.3.4.726]", "org.mockito:mockito-all:1.8.4" }) -public class SqlMapSessionIT extends SqlMapExecutorTestBase { - - private SqlMapClientImpl sqlMapClient; - - @Before - public void setUp() throws Exception { - super.setUp(); - this.sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); - } - - @After - public void cleanUp() throws Exception { - this.sqlMapClient = null; - } - - @Test - public void methodCallWithNullSqlIdShouldOnlyTraceMethodName() throws Exception { - SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); - super.testAndVerifyInsertWithNullSqlId(sqlMapSession); - } - - @Test - public void insertShouldBeTraced() throws Exception { - SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); - super.testAndVerifyInsert(sqlMapSession); - } - - @Test - public void deleteShouldBeTraced() throws Exception { - SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); - super.testAndVerifyDelete(sqlMapSession); - } - - @Test - public void updateShouldBeTraced() throws Exception { - SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); - super.testAndVerifyUpdate(sqlMapSession); - } - - @Test - public void queryForListShouldBeTraced() throws Exception { - SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); - super.testAndVerifyQueryForList(sqlMapSession); - } - - @Test - public void queryForMapShouldBeTraced() throws Exception { - SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); - super.testAndVerifyQueryForMap(sqlMapSession); - } - - @Test - public void queryForObjectShouldBeTraced() throws Exception { - SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); - super.testAndVerifyQueryForObject(sqlMapSession); - } - - @Test - public void queryForPaginagedListShouldBeTraced() throws Exception { - SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); - super.testAndVerifyQueryForPaginatedList(sqlMapSession); - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ibatis; + +import com.navercorp.pinpoint.plugin.AgentPath; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.ibatis.sqlmap.client.SqlMapSession; +import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl; +import com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.ibatis:ibatis-sqlmap:[2.3.4.726]", "org.mockito:mockito-all:1.8.4" }) +public class SqlMapSessionIT extends SqlMapExecutorTestBase { + + private SqlMapClientImpl sqlMapClient; + + @Before + public void setUp() throws Exception { + super.setUp(); + this.sqlMapClient = new SqlMapClientImpl(super.mockSqlMapExecutorDelegate); + } + + @After + public void cleanUp() throws Exception { + this.sqlMapClient = null; + } + + @Test + public void methodCallWithNullSqlIdShouldOnlyTraceMethodName() throws Exception { + SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); + super.testAndVerifyInsertWithNullSqlId(sqlMapSession); + } + + @Test + public void insertShouldBeTraced() throws Exception { + SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); + super.testAndVerifyInsert(sqlMapSession); + } + + @Test + public void deleteShouldBeTraced() throws Exception { + SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); + super.testAndVerifyDelete(sqlMapSession); + } + + @Test + public void updateShouldBeTraced() throws Exception { + SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); + super.testAndVerifyUpdate(sqlMapSession); + } + + @Test + public void queryForListShouldBeTraced() throws Exception { + SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); + super.testAndVerifyQueryForList(sqlMapSession); + } + + @Test + public void queryForMapShouldBeTraced() throws Exception { + SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); + super.testAndVerifyQueryForMap(sqlMapSession); + } + + @Test + public void queryForObjectShouldBeTraced() throws Exception { + SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); + super.testAndVerifyQueryForObject(sqlMapSession); + } + + @Test + public void queryForPaginagedListShouldBeTraced() throws Exception { + SqlMapSession sqlMapSession = new SqlMapSessionImpl(this.sqlMapClient); + super.testAndVerifyQueryForPaginatedList(sqlMapSession); + } + +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapperIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapperIT.java similarity index 96% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapperIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapperIT.java index 09c263cbc028..c9f33401bde6 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapperIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapperIT.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,6 +21,8 @@ import java.lang.reflect.Method; import java.nio.charset.Charset; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,6 +42,7 @@ * @author Sungkook Kim */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) // 2.7.0, 2.7.1 has JDK6 compatibility issue - https://github.com/FasterXML/jackson-databind/issues/1134 @Dependency({"com.fasterxml.jackson.core:jackson-databind:[2.0.6],[2.1.5],[2.2.4],[2.3.4],[2.4.6],[2.5.4,2.6.max],[2.7.2,)"}) public class ObjectMapperIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapper_1_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapper_1_x_IT.java similarity index 97% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapper_1_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapper_1_x_IT.java index e9336778222b..0fcfa6c621e0 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapper_1_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectMapper_1_x_IT.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,6 +24,8 @@ import java.lang.reflect.Method; import java.nio.charset.Charset; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.map.DeserializerProvider; import org.codehaus.jackson.map.ObjectMapper; @@ -41,6 +44,7 @@ * @author Sungkook Kim */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({"org.codehaus.jackson:jackson-mapper-asl:[1.0.1],[1.1.2],[1.2.1],[1.3.5],[1.4.5],[1.5.8],[1.6.9],[1.7.9],[1.8.11],[1.9.13]"}) public class ObjectMapper_1_x_IT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectReaderIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectReaderIT.java similarity index 94% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectReaderIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectReaderIT.java index 3398072a4f1f..9444defc57ca 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectReaderIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jackson/ObjectReaderIT.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,6 +20,8 @@ import java.lang.reflect.Method; import java.nio.charset.Charset; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,6 +39,7 @@ * @author Sungkook Kim */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) // 2.7.0, 2.7.1 has JDK6 compatibility issue - https://github.com/FasterXML/jackson-databind/issues/1134 @Dependency({"com.fasterxml.jackson.core:jackson-databind:[2.0.6],[2.1.5],[2.2.4],[2.3.4],[2.4.6],[2.5.4,2.6.max],[2.7.2,)"}) public class ObjectReaderIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java similarity index 96% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java index a95a6bf301ea..31f1427f883a 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_3_x_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,6 +21,8 @@ import java.lang.reflect.Method; import java.util.Properties; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,6 +36,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @JvmVersion(7) @Dependency({"org.mariadb.jdbc:mariadb-java-client:[1.3.0,1.3.max]", "ch.vorburger.mariaDB4j:mariaDB4j:2.2.2"}) public class MariaDB_1_3_x_IT extends MariaDB_IT_Base { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java similarity index 96% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java index 3c8fcfea2270..661cdf9e91e5 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_4_x_to_1_6_0_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,8 +18,10 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.test.plugin.Dependency; import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,6 +35,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @JvmVersion(7) @Dependency({ "org.mariadb.jdbc:mariadb-java-client:[1.4.min,1.6.min)", "ch.vorburger.mariaDB4j:mariaDB4j:2.2.2" }) public class MariaDB_1_4_x_to_1_6_0_IT extends MariaDB_IT_Base { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_6_x_to_2_0_0_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_6_x_to_2_0_0_IT.java similarity index 97% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_6_x_to_2_0_0_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_6_x_to_2_0_0_IT.java index 47394fb9af38..12445950ffb4 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_6_x_to_2_0_0_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_1_6_x_to_2_0_0_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,8 +18,10 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.test.plugin.Dependency; import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.Test; import org.junit.runner.RunWith; @@ -48,6 +50,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @JvmVersion(7) // 1.6.2+ works with Java 6, but since the IT includes 1.6.0 and 1.6.1 just run on Java 7 @Dependency({ "org.mariadb.jdbc:mariadb-java-client:[1.6.0,2.0.min)", "ch.vorburger.mariaDB4j:mariaDB4j:2.2.2" }) public class MariaDB_1_6_x_to_2_0_0_IT extends MariaDB_IT_Base { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_2_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_2_x_IT.java similarity index 96% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_2_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_2_x_IT.java index 679a8440e552..f0aeffcd4b0a 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_2_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_2_x_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,8 +18,10 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.test.plugin.Dependency; import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,6 +38,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @JvmVersion(8) // 2.x+ requires Java 8 @Dependency({ "org.mariadb.jdbc:mariadb-java-client:[2.0.1,)", "ch.vorburger.mariaDB4j:mariaDB4j:2.2.2" }) public class MariaDB_2_x_IT extends MariaDB_IT_Base { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_IT_Base.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_IT_Base.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_IT_Base.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_IT_Base.java index a3ff48ea7d0b..cef91fdce10f 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_IT_Base.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDB_IT_Base.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionIT.java similarity index 95% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionIT.java index d0560e231222..ae3fa446dd20 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionIT.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,8 +23,10 @@ import java.net.URL; import java.net.UnknownHostException; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.WebServer; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -39,6 +42,7 @@ * */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @JvmVersion({6, 7, 8}) @Dependency({ "org.nanohttpd:nanohttpd:2.3.1"}) public class HttpURLConnectionIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientITBase.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientITBase.java similarity index 99% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientITBase.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientITBase.java index 78cc50844003..9f9591652131 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientITBase.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientITBase.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientMultipleBrokersIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientMultipleBrokersIT.java similarity index 93% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientMultipleBrokersIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientMultipleBrokersIT.java index 5377c34ea611..397e237b57bf 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientMultipleBrokersIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientMultipleBrokersIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,9 +16,11 @@ package com.navercorp.pinpoint.plugin.jdk7.activemq.client; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.jdk7.activemq.client.util.ActiveMQClientITHelper; import com.navercorp.pinpoint.plugin.jdk7.activemq.client.util.TestBroker; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.AfterClass; @@ -31,6 +33,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @PinpointConfig("activemq/client/pinpoint-activemq-client.config") // 5.4.1 bug creates activemq-data directory even if persistence is set to false - skip it // 5.5.x activemq-all missing slf4j binder - just skip instead of supplying one diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientSingleBrokerIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientSingleBrokerIT.java similarity index 92% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientSingleBrokerIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientSingleBrokerIT.java index c8ea2684acab..b01b7393eda8 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientSingleBrokerIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/ActiveMQClientSingleBrokerIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,9 +16,11 @@ package com.navercorp.pinpoint.plugin.jdk7.activemq.client; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.jdk7.activemq.client.util.ActiveMQClientITHelper; import com.navercorp.pinpoint.plugin.jdk7.activemq.client.util.TestBroker; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.AfterClass; @@ -31,6 +33,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @PinpointConfig("activemq/client/pinpoint-activemq-client.config") // 5.4.1 bug creates activemq-data directory even if persistence is set to false - skip it // 5.5.x activemq-all missing slf4j binder - just skip instead of supplying one diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/ActiveMQClientITHelper.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/ActiveMQClientITHelper.java similarity index 95% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/ActiveMQClientITHelper.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/ActiveMQClientITHelper.java index 9c119b544974..edb8c272d2b5 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/ActiveMQClientITHelper.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/ActiveMQClientITHelper.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageConsumerBuilder.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageConsumerBuilder.java similarity index 97% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageConsumerBuilder.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageConsumerBuilder.java index 26ab5888f438..20b1c00dc176 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageConsumerBuilder.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageConsumerBuilder.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageProducerBuilder.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageProducerBuilder.java similarity index 96% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageProducerBuilder.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageProducerBuilder.java index 6327278d3d87..4729f03c83bd 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageProducerBuilder.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/MessageProducerBuilder.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBroker.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBroker.java new file mode 100644 index 000000000000..8593ad74f4c2 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBroker.java @@ -0,0 +1,126 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.activemq.client.util; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; + +import javax.jms.JMSException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author HyunGil Jeong + */ +public class TestBroker { + + public static final String DEFAULT_BROKER_URL = "tcp://127.0.0.1:61616"; + + private final String brokerName; + private final BrokerService brokerService; + private final Map connectionFactories; + private final Map connections = new HashMap(); + + private TestBroker(String brokerName, BrokerService brokerService, Map connectionFactories) throws Exception { + this.brokerName = brokerName; + this.brokerService = brokerService; + this.connectionFactories = Collections.unmodifiableMap(connectionFactories); + } + + String getBrokerName() { + return this.brokerName; + } + + ActiveMQConnection getConnection(String connectUri) throws JMSException { + if (!this.connections.containsKey(connectUri)) { + throw new IllegalArgumentException("Connection for connectUri [" + connectUri + "] does not exist"); + } + return this.connections.get(connectUri); + } + + boolean start() throws Exception { + this.brokerService.start(); + // it might be better to wait until the broker has fully started using BrokerService#waitUntilStarted + // but this method was only introduced in 5.3.0 + for (Map.Entry e : this.connectionFactories.entrySet()) { + String connectUri = e.getKey(); + ActiveMQConnectionFactory connectionFactory = e.getValue(); + ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); + connection.setClientID("client_" + connectUri); + connection.start(); + this.connections.put(connectUri, connection); + } + return true; + } + + void stop() throws Exception { + for (Map.Entry e : this.connections.entrySet()) { + ActiveMQConnection connection = e.getValue(); + connection.close(); + } + this.brokerService.stop(); + this.brokerService.waitUntilStopped(); + } + + public static class TestBrokerBuilder { + + private final String brokerName; + private final Set connectors = new HashSet(); + private final Set networkConnectors = new HashSet(); + + public TestBrokerBuilder(String brokerName) { + if (brokerName == null) { + throw new NullPointerException("brokerName must not be empty"); + } + this.brokerName = brokerName; + } + + public TestBrokerBuilder addConnector(String bindAddress) { + this.connectors.add(bindAddress); + return this; + } + + public TestBrokerBuilder addNetworkConnector(String discoveryAddress) { + this.networkConnectors.add(discoveryAddress); + return this; + } + + public TestBroker build() throws Exception { + if (this.connectors.isEmpty()) { + this.connectors.add(DEFAULT_BROKER_URL); + } + BrokerService brokerService = new BrokerService(); + brokerService.setBrokerName(this.brokerName); + brokerService.setPersistent(false); + brokerService.setUseJmx(false); + Map connectionFactories = new HashMap(); + for (String bindAddress : this.connectors) { + TransportConnector connector = brokerService.addConnector(bindAddress); + connectionFactories.put(bindAddress, new ActiveMQConnectionFactory(connector.getConnectUri())); + } + for (String discoveryAddress : this.networkConnectors) { + brokerService.addNetworkConnector(discoveryAddress); + } + return new TestBroker(this.brokerName, brokerService, connectionFactories); + } + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBrokerService.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBrokerService.java similarity index 96% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBrokerService.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBrokerService.java index 6de9d560d59c..6c55b564c5a5 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBrokerService.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBrokerService.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastaxITBase.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastaxITBase.java similarity index 75% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastaxITBase.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastaxITBase.java index c6f7550adf8a..00b88ce46739 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastaxITBase.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastaxITBase.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,8 +20,6 @@ import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Row; import com.datastax.driver.core.Session; import com.datastax.driver.core.Statement; import com.datastax.driver.core.StatementWrapper; @@ -29,11 +27,18 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; import com.navercorp.pinpoint.common.util.DefaultSqlParser; import com.navercorp.pinpoint.common.util.SqlParser; -import org.junit.Assert; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; +import org.scassandra.Scassandra; +import org.scassandra.ScassandraFactory; +import org.scassandra.http.client.ActivityClient; +import org.scassandra.http.client.CurrentClient; +import org.scassandra.http.client.PrimingClient; import java.lang.reflect.Method; -import java.util.Iterator; import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.sql; @@ -44,60 +49,70 @@ public abstract class CassandraDatastaxITBase { // com.navercorp.pinpoint.plugin.cassandra.CassandraConstants - protected static final String CASSANDRA = "CASSANDRA"; - protected static final String CASSANDRA_EXECUTE_QUERY = "CASSANDRA_EXECUTE_QUERY"; - - protected static final String TEST_KEYSPACE = "mykeyspace"; - protected static final String TEST_TABLE = "mytable"; - protected static final String TEST_COL_ID = "id"; - protected static final String TEST_COL_VALUE = "value"; - - protected static final String CQL_CREATE_KEYSPACE = String.format( - "CREATE KEYSPACE %s WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };", - TEST_KEYSPACE); - protected static final String CQL_CREATE_TABLE = String.format( - "CREATE TABLE %s ( %s int PRIMARY KEY, %s text );", - TEST_TABLE, TEST_COL_ID, TEST_COL_VALUE); - protected static final String CQL_INSERT = String.format( + private static final String CASSANDRA = "CASSANDRA"; + private static final String CASSANDRA_EXECUTE_QUERY = "CASSANDRA_EXECUTE_QUERY"; + + private static final String TEST_KEYSPACE = "mykeyspace"; + private static final String TEST_TABLE = "mytable"; + private static final String TEST_COL_ID = "id"; + private static final String TEST_COL_VALUE = "value"; + + private static final String CQL_INSERT = String.format( "INSERT INTO %s (%s, %s) VALUES (?, ?);", TEST_TABLE, TEST_COL_ID, TEST_COL_VALUE); // for normalized sql used for sql cache - protected static final SqlParser SQL_PARSER = new DefaultSqlParser(); + private static final SqlParser SQL_PARSER = new DefaultSqlParser(); + + private static String HOST = "127.0.0.1"; + private static final int DEFAULT_PORT = 9042; + private static final int DEFAULT_ADMIN_PORT = 9043; + private static final int PORT = CassandraTestHelper.findAvailablePortOrDefault(DEFAULT_PORT); + private static final int ADMIN_PORT = CassandraTestHelper.findAvailablePortOrDefault(DEFAULT_ADMIN_PORT); + private static final String CASSANDRA_ADDRESS = HOST + ":" + PORT; + + private static final Scassandra SERVER = ScassandraFactory.createServer(HOST, PORT, HOST, ADMIN_PORT); - protected static Cluster cluster; + private Cluster cluster; - // see cassandra/cassandra_${cassandraVersion}.yaml - protected static String HOST; - protected static int PORT; - protected static String CASSANDRA_ADDRESS; + private final PrimingClient primingClient = SERVER.primingClient(); + private final ActivityClient activityClient = SERVER.activityClient(); + private final CurrentClient currentClient = SERVER.currentClient(); - public static void initializeCluster(String cassandraVersion) throws Exception { - CassandraTestHelper.init(cassandraVersion); - HOST = CassandraTestHelper.getHost(); - PORT = CassandraTestHelper.getNativeTransportPort(); - CASSANDRA_ADDRESS = HOST + ":" + PORT; + @BeforeClass + public static void startUpBeforeClass() { + SERVER.start(); + } + + @Before + public void setUp() { cluster = Cluster.builder().addContactPoint(HOST).withPort(PORT).withoutMetrics().build(); - // Create KeySpace - Session emptySession = null; - try { - emptySession = cluster.connect(); - emptySession.execute(CQL_CREATE_KEYSPACE); - } finally { - closeSession(emptySession); + + // scassandra uses http client 4 for stub calls + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.ignoreServiceType("HTTP_CLIENT_4", "HTTP_CLIENT_4_INTERNAL"); + } + + @After + public void tearDown() { + if (primingClient != null) { + primingClient.clearAllPrimes(); } - // Create Table - Session myKeyspaceSession = null; - try { - myKeyspaceSession = cluster.connect(TEST_KEYSPACE); - myKeyspaceSession.execute(CQL_CREATE_TABLE); - } finally { - closeSession(myKeyspaceSession); + if (activityClient != null) { + activityClient.clearAllRecordedActivity(); + } + if (cluster != null) { + cluster.close(); } } + @AfterClass + public static void tearDownAfterClass() { + SERVER.stop(); + } + @Test public void testBoundStatement() throws Exception { - final int testId = 99; + final String testId ="99"; final String testValue = "testValue"; PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); @@ -134,11 +149,9 @@ public void testBoundStatement() throws Exception { // ==================== // Select Data (String) - final String cqlSelect = String.format("SELECT %s, %s FROM %s WHERE %s = %d", + final String cqlSelect = String.format("SELECT %s, %s FROM %s WHERE %s = %s", TEST_COL_ID, TEST_COL_VALUE, TEST_TABLE, TEST_COL_ID, testId); - verifySelect(myKeyspaceSession.execute(cqlSelect), testId, testValue); - - verifier.printCache(); + myKeyspaceSession.execute(cqlSelect); // SessionManager#execute(String) OR AbstractSession#execute(String) execute = sessionClass.getDeclaredMethod("execute", String.class); String normalizedSelectSql = SQL_PARSER.normalizedSql(cqlSelect).getNormalizedSql(); @@ -161,9 +174,9 @@ public void testBoundStatement() throws Exception { @Test public void testBatchStatement_and_StatementWrapper() throws Exception { - final int testId1 = 998; + final String testId1 = "998"; final String testValue1 = "testValue998"; - final int testId2 = 999; + final String testId2 = "999"; final String testValue2 = "testValue999"; PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); @@ -217,34 +230,16 @@ public void testBatchStatement_and_StatementWrapper() throws Exception { // SessionManager#prepare(String) OR AbstractSession#prepare(String) verifier.verifyTrace(event(CASSANDRA, prepare, null, CASSANDRA_ADDRESS, TEST_KEYSPACE, sql(cqlDelete, null))); // SessionManager#execute(String, Object[]) OR AbstractSession#execute(String, Object[]) - verifier.verifyTrace(event(CASSANDRA_EXECUTE_QUERY, execute, null, CASSANDRA_ADDRESS, TEST_KEYSPACE)); + verifier.verifyTrace(event(CASSANDRA_EXECUTE_QUERY, execute, null, CASSANDRA_ADDRESS, TEST_KEYSPACE, sql(cqlDelete, null))); } finally { closeSession(myKeyspaceSession); } } - private void verifySelect(ResultSet rs, int expectedTestId, String expectedTestValue) { - int resultCount = 0; - Iterator iter = rs.iterator(); - while (iter.hasNext()) { - Row row = iter.next(); - Assert.assertEquals(expectedTestId, row.getInt(0)); - Assert.assertEquals(expectedTestValue, row.getString(1)); - ++resultCount; - } - Assert.assertEquals(1, resultCount); - } - private static void closeSession(Session session) { if (session != null) { session.close(); } } - public static void cleanUpCluster() { - if (cluster != null) { - cluster.close(); - } - } - } diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_0_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_0_x_IT.java new file mode 100644 index 000000000000..a221f6ff4904 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_0_x_IT.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.cassandra; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.junit.runner.RunWith; + +/** + * Integration tests require {@link com.datastax.driver.core.StatementWrapper StatementWrapper}, so we + * limit datastax driver version to 2.0.10+. + * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ + "com.datastax.cassandra:cassandra-driver-core:[2.0.10,2.0.max]", + "org.scassandra:java-client:1.1.2"}) +public class CassandraDatastax_2_0_x_IT extends CassandraDatastaxITBase { +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_1_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_1_x_IT.java new file mode 100644 index 000000000000..81aef4b9ac64 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_1_x_IT.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.cassandra; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.junit.runner.RunWith; + +/** + * Integration tests require {@link com.datastax.driver.core.StatementWrapper StatementWrapper}, so we + * limit datastax driver version to 2.1.6+. + * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ + "com.datastax.cassandra:cassandra-driver-core:[2.1.6,2.1.max]", + "org.scassandra:java-client:1.1.2"}) +public class CassandraDatastax_2_1_x_IT extends CassandraDatastaxITBase { +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_2_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_2_x_IT.java new file mode 100644 index 000000000000..6daf92c3cc1d --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_2_x_IT.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.cassandra; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.junit.runner.RunWith; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ + "com.datastax.cassandra:cassandra-driver-core:[2.2.min,2.2.max]", + "org.scassandra:java-client:1.1.2"}) +public class CassandraDatastax_2_2_x_IT extends CassandraDatastaxITBase { +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_3_0_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_3_0_x_IT.java new file mode 100644 index 000000000000..fb7a58f22a4c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_3_0_x_IT.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.cassandra; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.junit.runner.RunWith; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ + "com.datastax.cassandra:cassandra-driver-core:[3.0.0,)", + "org.scassandra:java-client:1.1.2"}) +public class CassandraDatastax_3_0_x_IT extends CassandraDatastaxITBase { +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraTestHelper.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraTestHelper.java new file mode 100644 index 000000000000..e87290abc89a --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraTestHelper.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.cassandra; + +import java.net.ServerSocket; + +/** + * @author HyunGil Jeong + */ +public class CassandraTestHelper { + + private CassandraTestHelper() { + } + + public static int findAvailablePortOrDefault(int defaultPort) { + try { + ServerSocket ss = null; + try { + ss = new ServerSocket(0); + ss.setReuseAddress(true); + return ss.getLocalPort(); + } finally { + if (ss != null) { + ss.close(); + } + } + } catch (Exception e) { + // just ignore and return default + return defaultPort; + } + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClient_2_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClient_2_x_IT.java new file mode 100644 index 000000000000..e5067b8702c9 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClient_2_x_IT.java @@ -0,0 +1,175 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.jdk7.okhttp; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.plugin.okhttp.EndPointUtils; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.squareup.okhttp.*; +import com.squareup.okhttp.internal.http.HttpEngine; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.annotation; +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; +import static com.navercorp.pinpoint.common.trace.ServiceType.ASYNC; +import static com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants.OK_HTTP_CLIENT; +import static com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants.OK_HTTP_CLIENT_INTERNAL; + +/** + * @author jaehong.kim + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({"com.squareup.okhttp:okhttp:[2.0.0,3.0.0)", "org.nanohttpd:nanohttpd:2.3.1"}) +public class OkHttpClient_2_x_IT { + + private static WebServer webServer; + + + @BeforeClass + public static void BeforeClass() throws Exception { + webServer = WebServer.newTestWebServer(); + } + + + @AfterClass + public static void AfterClass() throws Exception { + final WebServer copy = webServer; + if (copy != null) { + copy.stop(); + webServer = null; + } + } + + @Test + public void execute() throws Exception { + Request request = new Request.Builder().url(webServer.getCallHttpUrl()).build(); + OkHttpClient client = new OkHttpClient(); + Response response = client.newCall(request).execute(); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + Method executeMethod = Call.class.getDeclaredMethod("execute"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), executeMethod)); + + Method sendRequestMethod = HttpEngine.class.getDeclaredMethod("sendRequest"); + verifier.verifyTrace(event(OK_HTTP_CLIENT.getName(), sendRequestMethod, + null, null, webServer.getHostAndPort(), + annotation("http.url", request.urlString()))); + + URL url = request.url(); + int port = EndPointUtils.getPort(url.getPort(), url.getDefaultPort()); + String hostAndPort = HostAndPort.toHostAndPortString(url.getHost(), port); + Method connectMethod = getConnectMethod(); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), connectMethod, + annotation("http.internal.display", hostAndPort))); + + Method readResponseMethod = HttpEngine.class.getDeclaredMethod("readResponse"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), readResponseMethod, + annotation("http.status.code", response.code()))); + + verifier.verifyTraceCount(0); + } + + @Test + public void enqueue() throws Exception { + Request request = new Request.Builder().url(webServer.getCallHttpUrl()).build(); + OkHttpClient client = new OkHttpClient(); + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference responseRef = new AtomicReference(null); + client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Request request, IOException e) { + latch.countDown(); + } + + @Override + public void onResponse(Response response) throws IOException { + responseRef.set(response); + latch.countDown(); + } + }); + latch.await(3, TimeUnit.SECONDS); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + + Method callEnqueueMethod = Call.class.getDeclaredMethod("enqueue", com.squareup.okhttp.Callback.class); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), callEnqueueMethod)); + + Method dispatcherEnqueueMethod = Dispatcher.class.getDeclaredMethod("enqueue", Class.forName("com.squareup.okhttp.Call$AsyncCall")); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), dispatcherEnqueueMethod)); + + verifier.verifyTrace(event(ASYNC.getName(), "Asynchronous Invocation")); + + Method executeMethod = Class.forName("com.squareup.okhttp.Call$AsyncCall").getDeclaredMethod("execute"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), executeMethod)); + + Method sendRequestMethod = HttpEngine.class.getDeclaredMethod("sendRequest"); + verifier.verifyTrace(event(OK_HTTP_CLIENT.getName(), sendRequestMethod, + null, null, webServer.getHostAndPort(), + annotation("http.url", request.urlString()))); + + URL url = request.url(); + int port = EndPointUtils.getPort(url.getPort(), url.getDefaultPort()); + String hostAndPort = HostAndPort.toHostAndPortString(url.getHost(), port); + Method connectMethod = getConnectMethod(); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), connectMethod, + annotation("http.internal.display", hostAndPort))); + + Response response = responseRef.get(); + Assert.assertNotNull("response is null", response); + Method readResponseMethod = HttpEngine.class.getDeclaredMethod("readResponse"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), readResponseMethod, + annotation("http.status.code", response.code()))); + + verifier.verifyTraceCount(0); + } + + private Method getConnectMethod() { + try { + // [2.3.0,) + return HttpEngine.class.getDeclaredMethod("connect"); + } catch (NoSuchMethodException e) { + try { + // [2.0.0,2.2.max] + return HttpEngine.class.getDeclaredMethod("connect", Request.class); + } catch (NoSuchMethodException e1) { + throw new AssertionError("Expected methods connect() / connect(com.squareup.okhttp.Request) not found in HttpEngine class"); + } + } + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClient_3_0_0_to_3_3_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClient_3_0_0_to_3_3_x_IT.java new file mode 100644 index 000000000000..6b410faac961 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClient_3_0_0_to_3_3_x_IT.java @@ -0,0 +1,155 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.jdk7.okhttp; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.annotation; +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; +import static com.navercorp.pinpoint.common.trace.ServiceType.ASYNC; +import static com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants.OK_HTTP_CLIENT; +import static com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants.OK_HTTP_CLIENT_INTERNAL; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({"com.squareup.okhttp3:okhttp:[3.0.0,3.3.max]", "org.nanohttpd:nanohttpd:2.3.1"}) +public class OkHttpClient_3_0_0_to_3_3_x_IT { + + private static WebServer webServer; + + + @BeforeClass + public static void BeforeClass() throws Exception { + webServer = WebServer.newTestWebServer(); + } + + + @AfterClass + public static void AfterClass() throws Exception { + final WebServer copy = webServer; + if (copy != null) { + copy.stop(); + webServer = null; + } + } + + @Test + public void execute() throws Exception { + Request request = new Request.Builder().url(webServer.getCallHttpUrl()).build(); + OkHttpClient client = new OkHttpClient(); + Response response = client.newCall(request).execute(); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + Method executeMethod = Class.forName("okhttp3.RealCall").getDeclaredMethod("execute"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), executeMethod)); + + Method sendRequestMethod = Class.forName("okhttp3.internal.http.HttpEngine").getDeclaredMethod("sendRequest"); + verifier.verifyTrace(event(OK_HTTP_CLIENT.getName(), sendRequestMethod, + null, null, webServer.getHostAndPort(), + annotation("http.url", request.url().toString()))); + + String hostAndPort = HostAndPort.toHostAndPortString(request.url().host(), request.url().port()); + Method connectMethod = Class.forName("okhttp3.internal.http.HttpEngine").getDeclaredMethod("connect"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), connectMethod, + annotation("http.internal.display", hostAndPort))); + + Method readResponseMethod = Class.forName("okhttp3.internal.http.HttpEngine").getDeclaredMethod("readResponse"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), readResponseMethod, + annotation("http.status.code", response.code()))); + + verifier.verifyTraceCount(0); + } + + @Test + public void enqueue() throws Exception { + Request request = new Request.Builder().url(webServer.getCallHttpUrl()).build(); + OkHttpClient client = new OkHttpClient(); + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference responseRef = new AtomicReference(null); + client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + latch.countDown(); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + responseRef.set(response); + latch.countDown(); + } + }); + latch.await(3, TimeUnit.SECONDS); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + Method realCallEnqueueMethod = Class.forName("okhttp3.RealCall").getDeclaredMethod("enqueue", Class.forName("okhttp3.Callback")); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), realCallEnqueueMethod)); + + Method dispatcherEnqueueMethod = Class.forName("okhttp3.Dispatcher").getDeclaredMethod("enqueue", Class.forName("okhttp3.RealCall$AsyncCall")); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), dispatcherEnqueueMethod)); + + verifier.verifyTrace(event(ASYNC.getName(), "Asynchronous Invocation")); + + Method executeMethod = Class.forName("okhttp3.RealCall$AsyncCall").getDeclaredMethod("execute"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), executeMethod)); + + Method sendRequestMethod = Class.forName("okhttp3.internal.http.HttpEngine").getDeclaredMethod("sendRequest"); + verifier.verifyTrace(event(OK_HTTP_CLIENT.getName(), sendRequestMethod, + null, null, webServer.getHostAndPort(), + annotation("http.url", request.url().toString()))); + + String hostAndPort = HostAndPort.toHostAndPortString(request.url().host(), request.url().port()); + Method connectMethod = Class.forName("okhttp3.internal.http.HttpEngine").getDeclaredMethod("connect"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), connectMethod, + annotation("http.internal.display", hostAndPort))); + + Response response = responseRef.get(); + Method readResponseMethod = Class.forName("okhttp3.internal.http.HttpEngine").getDeclaredMethod("readResponse"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), readResponseMethod, + annotation("http.status.code", response.code()))); + + verifier.verifyTraceCount(0); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClient_3_4_0_to_3_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClient_3_4_0_to_3_x_IT.java new file mode 100644 index 000000000000..cf6fe90c35b2 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClient_3_4_0_to_3_x_IT.java @@ -0,0 +1,176 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.jdk7.okhttp; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.annotation; +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; +import static com.navercorp.pinpoint.common.trace.ServiceType.ASYNC; +import static com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants.OK_HTTP_CLIENT; +import static com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants.OK_HTTP_CLIENT_INTERNAL; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({"com.squareup.okhttp3:okhttp:[3.4.0,)", "org.nanohttpd:nanohttpd:2.3.1"}) +public class OkHttpClient_3_4_0_to_3_x_IT { + + private static WebServer webServer; + + + @BeforeClass + public static void BeforeClass() throws Exception { + webServer = WebServer.newTestWebServer(); + } + + + @AfterClass + public static void AfterClass() throws Exception { + final WebServer copy = webServer; + if (copy != null) { + copy.stop(); + webServer = null; + } + } + + @Test + public void execute() throws Exception { + Request request = new Request.Builder().url(webServer.getCallHttpUrl()).build(); + OkHttpClient client = new OkHttpClient(); + Response response = client.newCall(request).execute(); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + Method executeMethod = Class.forName("okhttp3.RealCall").getDeclaredMethod("execute"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), executeMethod)); + + Method interceptMethod = Class.forName("okhttp3.internal.http.BridgeInterceptor").getDeclaredMethod("intercept", Class.forName("okhttp3.Interceptor$Chain")); + verifier.verifyTrace(event(OK_HTTP_CLIENT.getName(), interceptMethod, + null, null, webServer.getHostAndPort(), + annotation("http.url", request.url().toString()), + annotation("http.status.code", response.code()))); + + String hostAndPort = HostAndPort.toHostAndPortString(request.url().host(), request.url().port()); + Method connectMethod = getConnectMethod(Class.forName("okhttp3.internal.connection.RealConnection")); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), connectMethod, + annotation("http.internal.display", hostAndPort))); + + verifier.verifyTraceCount(0); + } + + @Test + public void enqueue() throws Exception { + Request request = new Request.Builder().url(webServer.getCallHttpUrl()).build(); + OkHttpClient client = new OkHttpClient(); + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference responseRef = new AtomicReference(null); + client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + latch.countDown(); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + responseRef.set(response); + latch.countDown(); + } + }); + latch.await(3, TimeUnit.SECONDS); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + verifier.printCache(); + + Method realCallEnqueueMethod = Class.forName("okhttp3.RealCall").getDeclaredMethod("enqueue", Class.forName("okhttp3.Callback")); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), realCallEnqueueMethod)); + + Method dispatcherEnqueueMethod = Class.forName("okhttp3.Dispatcher").getDeclaredMethod("enqueue", Class.forName("okhttp3.RealCall$AsyncCall")); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), dispatcherEnqueueMethod)); + + verifier.verifyTrace(event(ASYNC.getName(), "Asynchronous Invocation")); + + Method executeMethod = Class.forName("okhttp3.RealCall$AsyncCall").getDeclaredMethod("execute"); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), executeMethod)); + + Response response = responseRef.get(); + Method interceptMethod = Class.forName("okhttp3.internal.http.BridgeInterceptor").getDeclaredMethod("intercept", Class.forName("okhttp3.Interceptor$Chain")); + verifier.verifyTrace(event(OK_HTTP_CLIENT.getName(), interceptMethod, + null, null, webServer.getHostAndPort(), + annotation("http.url", request.url().toString()), + annotation("http.status.code", response.code()))); + + String hostAndPort = HostAndPort.toHostAndPortString(request.url().host(), request.url().port()); + Method connectMethod = getConnectMethod(Class.forName("okhttp3.internal.connection.RealConnection")); + verifier.verifyTrace(event(OK_HTTP_CLIENT_INTERNAL.getName(), connectMethod, + annotation("http.internal.display", hostAndPort))); + + verifier.verifyTraceCount(0); + } + + private Method getConnectMethod(Class realConnectionClass) throws ClassNotFoundException { + // [3.4.0,3.5.max] + try { + return realConnectionClass.getDeclaredMethod("connect", int.class, int.class, int.class, List.class, boolean.class); + } catch (NoSuchMethodException e) { + try { + // [3.6.0,3.8.max] + return realConnectionClass.getDeclaredMethod("connect", int.class, int.class, int.class, boolean.class); + } catch (NoSuchMethodException e1) { + try { + // [3.9.0,3.9.max] + return realConnectionClass.getDeclaredMethod("connect", int.class, int.class, int.class, boolean.class, + Class.forName("okhttp3.Call"), Class.forName("okhttp3.EventListener")); + } catch (NoSuchMethodException e2) { + try { + // [3.10.0,) + return realConnectionClass.getDeclaredMethod("connect", int.class, int.class, int.class, int.class, boolean.class, + Class.forName("okhttp3.Call"), Class.forName("okhttp3.EventListener")); + } catch (NoSuchMethodException e3) { + throw new AssertionError("Expected methods connect(...) not found in RealConnection class"); + } + } + } + } + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClientITBase.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClientITBase.java new file mode 100644 index 000000000000..9f8ff0655096 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClientITBase.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; + +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.TestBroker; +import com.rabbitmq.client.ConnectionFactory; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; + +/** + * @author Jiaqi Feng + * @author HyunGil Jeong + */ + +public abstract class RabbitMQClientITBase { + + private static final TestBroker BROKER = new TestBroker(); + + private final ConnectionFactory connectionFactory = new ConnectionFactory(); + protected final RabbitMQTestRunner testRunner = new RabbitMQTestRunner(connectionFactory); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + BROKER.start(); + } + + @AfterClass + public static void tearDownAfterClass() { + BROKER.shutdown(); + } + + @Before + public void setUp() { + connectionFactory.setHost(RabbitMQTestConstants.BROKER_HOST); + connectionFactory.setPort(RabbitMQTestConstants.BROKER_PORT); + connectionFactory.setSaslConfig(RabbitMQTestConstants.SASL_CONFIG); + } + + final ConnectionFactory getConnectionFactory() { + return connectionFactory; + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_2_7_0_to_3_3_0_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_2_7_0_to_3_3_0_IT.java new file mode 100644 index 000000000000..7567a1493984 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_2_7_0_to_3_3_0_IT.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * @author Jiaqi Feng + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"com.rabbitmq:amqp-client:[2.7.0,3.0.0)", "org.apache.qpid:qpid-broker:6.1.1"}) +public class RabbitMQClient_2_7_0_to_3_3_0_IT extends RabbitMQClientITBase { + + @Test + public void testPush() throws Exception { + testRunner.runPushTest(); + } + + @Test + public void testPull() throws Exception { + testRunner.runPullTest(); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_3_3_0_to_4_0_0_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_3_3_0_to_4_0_0_IT.java new file mode 100644 index 000000000000..9673ea7cc63c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_3_3_0_to_4_0_0_IT.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.rabbitmq.client.ConnectionFactory; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * @author Jiaqi Feng + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"com.rabbitmq:amqp-client:[3.3.0,4.0.0)", "org.apache.qpid:qpid-broker:6.1.1"}) +public class RabbitMQClient_3_3_0_to_4_0_0_IT extends RabbitMQClientITBase { + + @Test + public void testPush() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + + testRunner.runPushTest(); + } + + @Test + public void testPush_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + + testRunner.runPushTest(); + } + + @Test + public void testPull() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + + testRunner.runPullTest(); + } + + @Test + public void testPull_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + + testRunner.runPullTest(); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_4_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_4_x_IT.java new file mode 100644 index 000000000000..b0797fe2b787 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_4_x_IT.java @@ -0,0 +1,105 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.rabbitmq.client.ConnectionFactory; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * @author Jiaqi Feng + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"com.rabbitmq:amqp-client:[4.0.0,4.max)", "org.apache.qpid:qpid-broker:6.1.1"}) +public class RabbitMQClient_4_x_IT extends RabbitMQClientITBase { + + @Test + public void testPush() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + + testRunner.runPushTest(); + } + + @Test + public void testPush_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + + testRunner.runPushTest(); + } + + @Test + public void testPush_nio() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + connectionFactory.useNio(); + + testRunner.runPushTest(); + } + + @Test + public void testPush_nio_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + connectionFactory.useNio(); + + testRunner.runPushTest(); + } + + @Test + public void testPull() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + + testRunner.runPullTest(); + } + + @Test + public void testPull_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + + testRunner.runPullTest(); + } + + @Test + public void testPull_nio() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + connectionFactory.useNio(); + + testRunner.runPullTest(); + } + + @Test + public void testPull_nio_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + connectionFactory.useNio(); + + testRunner.runPullTest(); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_5_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_5_x_IT.java new file mode 100644 index 000000000000..47400e7dc2c5 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQClient_5_x_IT.java @@ -0,0 +1,107 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.rabbitmq.client.ConnectionFactory; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * @author Jiaqi Feng + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"com.rabbitmq:amqp-client:[5.0.0,)", "org.apache.qpid:qpid-broker:6.1.1"}) +@JvmVersion(8) +public class RabbitMQClient_5_x_IT extends RabbitMQClientITBase { + + @Test + public void testPush() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + + testRunner.runPushTest(); + } + + @Test + public void testPush_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + + testRunner.runPushTest(); + } + + @Test + public void testPush_nio() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + connectionFactory.useNio(); + + testRunner.runPushTest(); + } + + @Test + public void testPush_nio_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + connectionFactory.useNio(); + + testRunner.runPushTest(); + } + + @Test + public void testPull() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + + testRunner.runPullTest(); + } + + @Test + public void testPull_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + + testRunner.runPullTest(); + } + + @Test + public void testPull_nio() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(false); + connectionFactory.useNio(); + + testRunner.runPullTest(); + } + + @Test + public void testPull_nio_autorecovery() throws Exception { + ConnectionFactory connectionFactory = getConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + connectionFactory.useNio(); + + testRunner.runPullTest(); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQTestRunner.java new file mode 100644 index 000000000000..3e25f0ccda3c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitMQTestRunner.java @@ -0,0 +1,262 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.test.pinpoint.plugin.rabbitmq.MessageConverter; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.navercorp.test.pinpoint.plugin.rabbitmq.TestConsumer; +import com.navercorp.test.pinpoint.plugin.rabbitmq.TestMessagePuller; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.AMQCommand; +import org.junit.Assert; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +/** + * @author Jiaqi Feng + * @author HyunGil Jeong + */ +class RabbitMQTestRunner { + + private static final Random RANDOM = new Random(); + + RabbitMQTestRunner(ConnectionFactory connectionFactory) { + if (connectionFactory == null) { + throw new NullPointerException("connectionFactory must not be null"); + } + this.connectionFactory = connectionFactory; + } + + private final ConnectionFactory connectionFactory; + + void runPushTest() throws Exception { + int numMessages = RANDOM.nextInt(10) + 1; + runPushTest(numMessages); + } + + void runPushTest(int numMessages) throws Exception { + + final String message = "hello rabbit mq"; + + // producer side + final Connection producerConnection = connectionFactory.newConnection(); + final Channel producerChannel = producerConnection.createChannel(); + + producerChannel.exchangeDeclare(RabbitMQTestConstants.EXCHANGE, "direct", false); + producerChannel.queueDeclare(RabbitMQTestConstants.QUEUE_PUSH, false, false, false, null); + producerChannel.queueBind(RabbitMQTestConstants.QUEUE_PUSH, RabbitMQTestConstants.EXCHANGE, RabbitMQTestConstants.ROUTING_KEY_PUSH); + + for (int i = 0; i < numMessages; i++) { + AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder(); + producerChannel.basicPublish(RabbitMQTestConstants.EXCHANGE, RabbitMQTestConstants.ROUTING_KEY_PUSH, false, false, builder.appId("test").build(), message.getBytes()); + } + + producerChannel.close(); + producerConnection.close(); + + // consumer side + final Connection consumerConnection = connectionFactory.newConnection(); + final Channel consumerChannel = consumerConnection.createChannel(); + final String remoteAddress = consumerConnection.getAddress().getHostAddress() + ":" + consumerConnection.getPort(); + + consumerChannel.queueDeclare(RabbitMQTestConstants.QUEUE_PUSH, false, false, false, null); + + TestConsumer consumer = new TestConsumer(consumerChannel, MessageConverter.FOR_TEST); + consumerChannel.basicConsume(RabbitMQTestConstants.QUEUE_PUSH, true, consumer); + + List actualMessages = new ArrayList(numMessages); + for (int i = 0; i < numMessages; i++) { + actualMessages.add(consumer.getMessage(10, TimeUnit.SECONDS)); + } + + Assert.assertEquals(numMessages, actualMessages.size()); + for (String actualMessage : actualMessages) { + Assert.assertEquals(message, actualMessage); + } + + consumerChannel.close(); + consumerConnection.close(); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + // Wait till all traces are recorded (consumer traces are recorded from another thread) + int expectedTraceCountPerMessage = 6; + awaitAndVerifyTraceCount(verifier, expectedTraceCountPerMessage * numMessages, 5000L); + + verifier.printCache(); + + Class producerChannelClass = producerChannel.getClass(); + Method channelBasicPublish = producerChannelClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + Class consumerDispatchClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatchHandleDelivery = consumerDispatchClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + consumerDispatchHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class consumerClass = consumer.getClass(); + Method consumerHandleDelivery = consumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + consumerHandleDelivery); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + for (int i = 0; i < numMessages; i++) { + verifier.verifyDiscreteTrace(channelBasicPublishTrace); + verifier.verifyDiscreteTrace( + rabbitMqConsumerInvocationTrace, + Expectations.async( + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + consumerHandleDeliveryTrace, + markTrace)); + } + verifier.verifyTraceCount(0); + } + + void runPullTest() throws Exception { + + final String message = "hello rabbit mq"; + + // producer side + final Connection producerConnection = connectionFactory.newConnection(); + final Channel producerChannel = producerConnection.createChannel(); + + producerChannel.exchangeDeclare(RabbitMQTestConstants.EXCHANGE, "direct", false); + producerChannel.queueDeclare(RabbitMQTestConstants.QUEUE_PULL, false, false, false, null); + producerChannel.queueBind(RabbitMQTestConstants.QUEUE_PULL, RabbitMQTestConstants.EXCHANGE, RabbitMQTestConstants.ROUTING_KEY_PULL); + + AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder(); + producerChannel.basicPublish(RabbitMQTestConstants.EXCHANGE, RabbitMQTestConstants.ROUTING_KEY_PULL, false, false, builder.appId("test").build(), message.getBytes()); + + producerChannel.close(); + producerConnection.close(); + + //comsumer side + final Connection consumerConnection = connectionFactory.newConnection(); + final Channel consumerChannel = consumerConnection.createChannel(); + final String remoteAddress = consumerConnection.getAddress().getHostAddress() + ":" + consumerConnection.getPort(); + + TestMessagePuller messagePuller = new TestMessagePuller(consumerChannel); + Assert.assertEquals(message, messagePuller.pullMessage(MessageConverter.FOR_TEST, RabbitMQTestConstants.QUEUE_PULL, true)); + + consumerChannel.close(); + consumerConnection.close(); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + // Wait till all traces are recorded (consumer traces are recorded from another thread) + awaitAndVerifyTraceCount(verifier, 5, 5000L); + + verifier.printCache(); + // verify producer traces + Class producerChannelClass = producerChannel.getClass(); + Method channelBasicPublish = producerChannelClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class amqChannelClass = Class.forName("com.rabbitmq.client.impl.AMQChannel"); + Method handleCompleteInboundCommand = amqChannelClass.getDeclaredMethod("handleCompleteInboundCommand", AMQCommand.class); + ExpectedTrace handleCompleteInboundCommandTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + handleCompleteInboundCommand); // method + verifier.verifyDiscreteTrace( + channelBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + handleCompleteInboundCommandTrace); + + // verify consumer traces + Class consumerChannelClass = consumerChannel.getClass(); + Method channelBasicGet = consumerChannelClass.getDeclaredMethod("basicGet", String.class, boolean.class); + ExpectedTrace channelBasicGetTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + channelBasicGet); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + verifier.verifyDiscreteTrace( + channelBasicGetTrace, + markTrace); + verifier.verifyTraceCount(0); + } + + private void awaitAndVerifyTraceCount(PluginTestVerifier verifier, int expectedTraceCount, long maxWaitMs) throws InterruptedException { + final long waitIntervalMs = 100L; + long maxWaitTime = maxWaitMs; + if (maxWaitMs < waitIntervalMs) { + maxWaitTime = waitIntervalMs; + } + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < maxWaitTime) { + try { + verifier.verifyTraceCount(expectedTraceCount); + return; + } catch (AssertionError e) { + // ignore and retry + Thread.sleep(waitIntervalMs); + } + } + verifier.verifyTraceCount(expectedTraceCount); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbitTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbitTestRunner.java new file mode 100644 index 000000000000..1d74e9e40017 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbitTestRunner.java @@ -0,0 +1,117 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.spring; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.test.pinpoint.plugin.rabbitmq.MessageConverter; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.TestMessageHolder; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.service.TestReceiverService; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.service.TestSenderService; +import org.junit.Assert; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; + +import java.util.concurrent.TimeUnit; + +/** + * @author HyunGil Jeong + */ +public class SpringAmqpRabbitTestRunner { + + private static final long TRACE_WAIT_TIME_MS = 3000L; + + private final TestSenderService testSenderService; + private final TestReceiverService testReceiverService; + private final TestMessageHolder testMessageHolder; + private final ConnectionFactory connectionFactory; + private final String remoteAddress; + + SpringAmqpRabbitTestRunner(TestApplicationContext context) { + if (context == null) { + throw new NullPointerException("context must not be null"); + } + this.testSenderService = context.getTestSenderService(); + this.testMessageHolder = context.getTestMessageHolder(); + this.testReceiverService = context.getTestReceiverService(); + this.connectionFactory = context.getConnectionFactory(); + this.remoteAddress = connectionFactory.getHost() + ":" + connectionFactory.getPort(); + } + + String getRemoteAddress() { + return remoteAddress; + } + + PluginTestVerifier runPush(int expectedTraceCount) throws InterruptedException { + final String message = "hello rabbit mq"; + + testSenderService.sendMessage(RabbitMQTestConstants.EXCHANGE, RabbitMQTestConstants.ROUTING_KEY_PUSH, message); + Assert.assertEquals(message, testMessageHolder.getMessage(10, TimeUnit.SECONDS)); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + // Wait till all traces are recorded (consumer traces are recorded from another thread) + awaitAndVerifyTraceCount(verifier, expectedTraceCount, TRACE_WAIT_TIME_MS); + return verifier; + } + + PluginTestVerifier runPull(int expectedTraceCount) throws InterruptedException { + final String message = "hello rabbit mq!"; + + testSenderService.sendMessage(RabbitMQTestConstants.EXCHANGE, RabbitMQTestConstants.ROUTING_KEY_PULL, message); + Assert.assertEquals(message, testReceiverService.receiveMessage(MessageConverter.FOR_TEST)); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + // Wait till all traces are recorded (consumer traces are recorded from another thread) + awaitAndVerifyTraceCount(verifier, expectedTraceCount, TRACE_WAIT_TIME_MS); + return verifier; + } + + PluginTestVerifier runPull(int expectedTraceCount, long timeoutMs) throws InterruptedException { + final String message = "hello rabbit mq!"; + + testSenderService.sendMessage(RabbitMQTestConstants.EXCHANGE, RabbitMQTestConstants.ROUTING_KEY_PULL, message); + Assert.assertEquals(message, testReceiverService.receiveMessage(MessageConverter.FOR_TEST, timeoutMs)); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + // Wait till all traces are recorded (consumer traces are recorded from another thread) + awaitAndVerifyTraceCount(verifier, expectedTraceCount, TRACE_WAIT_TIME_MS); + return verifier; + } + + private static void awaitAndVerifyTraceCount(PluginTestVerifier verifier, int expectedTraceCount, long maxWaitMs) throws InterruptedException { + final long waitIntervalMs = 100L; + long maxWaitTime = maxWaitMs; + if (maxWaitMs < waitIntervalMs) { + maxWaitTime = waitIntervalMs; + } + long startTime = System.currentTimeMillis(); + try { + while (System.currentTimeMillis() - startTime < maxWaitTime) { + try { + verifier.verifyTraceCount(expectedTraceCount); + return; + } catch (AssertionError e) { + // ignore and retry + Thread.sleep(waitIntervalMs); + } + } + verifier.verifyTraceCount(expectedTraceCount); + } finally { + verifier.printCache(); + } + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_3_3_to_1_4_2_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_3_3_to_1_4_2_IT.java new file mode 100644 index 000000000000..c451a7c8042b --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_3_3_to_1_4_2_IT.java @@ -0,0 +1,222 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.spring; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.CommonConfig; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.MessageListenerConfig_Pre_1_4_0; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.ReceiverConfig_Pre_1_6_0; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.TestBroker; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.AMQCommand; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.amqp.core.Message; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"org.springframework.amqp:spring-rabbit:[1.3.3.RELEASE,1.4.2.RELEASE)", "com.fasterxml.jackson.core:jackson-core:2.8.11", "org.apache.qpid:qpid-broker:6.1.1"}) +public class SpringAmqpRabbit_1_3_3_to_1_4_2_IT { + + private static final TestBroker BROKER = new TestBroker(); + private static final TestApplicationContext CONTEXT = new TestApplicationContext(); + + private final SpringAmqpRabbitTestRunner testRunner = new SpringAmqpRabbitTestRunner(CONTEXT); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + BROKER.start(); + CONTEXT.init( + CommonConfig.class, + MessageListenerConfig_Pre_1_4_0.class, + ReceiverConfig_Pre_1_6_0.class); + } + + @AfterClass + public static void tearDownAfterClass() { + CONTEXT.close(); + BROKER.shutdown(); + } + + @Test + public void testPush() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class blockingQueueConsumerInternalConsumerClass = Class.forName("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$InternalConsumer"); + Method blockingQueueConsumerInternalConsumerHandleDelivery = blockingQueueConsumerInternalConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace blockingQueueConsumerInternalConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + blockingQueueConsumerInternalConsumerHandleDelivery); + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + Class abstractMessageListenerContainerClass = Class.forName("org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer"); + Method abstractMessageListenerContainerExecuteListener = abstractMessageListenerContainerClass.getDeclaredMethod("executeListener", Channel.class, Message.class); + ExpectedTrace abstractMessageListenerContainerExecuteListenerTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + abstractMessageListenerContainerExecuteListener); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] expectedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + blockingQueueConsumerInternalConsumerHandleDeliveryTrace, + deliveryConstructorTrace, + asynchronousInvocationTrace, + abstractMessageListenerContainerExecuteListenerTrace, + markTrace + }; + + final PluginTestVerifier verifier = testRunner.runPush(expectedTraces.length); + + verifier.verifyTrace(expectedTraces); + verifier.verifyTraceCount(0); + } + + @Test + public void testPull() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class amqChannelClass = Class.forName("com.rabbitmq.client.impl.AMQChannel"); + Method amqChannelHandleCompleteInboundCommand = amqChannelClass.getDeclaredMethod("handleCompleteInboundCommand", AMQCommand.class); + ExpectedTrace amqChannelHandleCompleteInboundCommandTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // method + amqChannelHandleCompleteInboundCommand); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + amqChannelHandleCompleteInboundCommandTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Method channelNBasicGet = channelNClass.getDeclaredMethod("basicGet", String.class, boolean.class); + ExpectedTrace channelNBasicGetTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + channelNBasicGet); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + channelNBasicGetTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_4_2_to_1_7_0_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_4_2_to_1_7_0_IT.java new file mode 100644 index 000000000000..b1c3cd52bfca --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_4_2_to_1_7_0_IT.java @@ -0,0 +1,223 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.spring; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.CommonConfig; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.MessageListenerConfig_Post_1_4_0; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.ReceiverConfig_Pre_1_6_0; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.TestBroker; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.AMQCommand; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.amqp.core.Message; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +// 1.4.5, 1.4.6, 1.6.4.RELEASE has dependency issues +@Dependency({"org.springframework.amqp:spring-rabbit:[1.4.2.RELEASE,1.4.5.RELEASE),[1.5.0.RELEASE,1.6.4.RELEASE),[1.6.5.RELEASE,1.7.0.RELEASE)", "com.fasterxml.jackson.core:jackson-core:2.8.11", "org.apache.qpid:qpid-broker:6.1.1"}) +public class SpringAmqpRabbit_1_4_2_to_1_7_0_IT { + + private static final TestBroker BROKER = new TestBroker(); + private static final TestApplicationContext CONTEXT = new TestApplicationContext(); + + private final SpringAmqpRabbitTestRunner testRunner = new SpringAmqpRabbitTestRunner(CONTEXT); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + BROKER.start(); + CONTEXT.init( + CommonConfig.class, + MessageListenerConfig_Post_1_4_0.class, + ReceiverConfig_Pre_1_6_0.class); + } + + @AfterClass + public static void tearDownAfterClass() { + CONTEXT.close(); + BROKER.shutdown(); + } + + @Test + public void testPush() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class blockingQueueConsumerInternalConsumerClass = Class.forName("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$InternalConsumer"); + Method blockingQueueConsumerInternalConsumerHandleDelivery = blockingQueueConsumerInternalConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace blockingQueueConsumerInternalConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + blockingQueueConsumerInternalConsumerHandleDelivery); + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + Class abstractMessageListenerContainerClass = Class.forName("org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer"); + Method abstractMessageListenerContainerExecuteListener = abstractMessageListenerContainerClass.getDeclaredMethod("executeListener", Channel.class, Message.class); + ExpectedTrace abstractMessageListenerContainerExecuteListenerTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + abstractMessageListenerContainerExecuteListener); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] expectedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + blockingQueueConsumerInternalConsumerHandleDeliveryTrace, + deliveryConstructorTrace, + asynchronousInvocationTrace, + abstractMessageListenerContainerExecuteListenerTrace, + markTrace + }; + + final PluginTestVerifier verifier = testRunner.runPush(expectedTraces.length); + + verifier.verifyTrace(expectedTraces); + verifier.verifyTraceCount(0); + } + + @Test + public void testPull() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class amqChannelClass = Class.forName("com.rabbitmq.client.impl.AMQChannel"); + Method amqChannelHandleCompleteInboundCommand = amqChannelClass.getDeclaredMethod("handleCompleteInboundCommand", AMQCommand.class); + ExpectedTrace amqChannelHandleCompleteInboundCommandTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // method + amqChannelHandleCompleteInboundCommand); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + amqChannelHandleCompleteInboundCommandTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Method channelNBasicGet = channelNClass.getDeclaredMethod("basicGet", String.class, boolean.class); + ExpectedTrace channelNBasicGetTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + channelNBasicGet); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + channelNBasicGetTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_7_0_to_1_7_7_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_7_0_to_1_7_7_IT.java new file mode 100644 index 000000000000..c460bb1af4d9 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_7_0_to_1_7_7_IT.java @@ -0,0 +1,309 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.spring; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.CommonConfig; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.MessageListenerConfig_Post_1_4_0; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.ReceiverConfig_Post_1_6_0; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.TestBroker; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.AMQCommand; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.amqp.core.Message; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"org.springframework.amqp:spring-rabbit:[1.7.0.RELEASE,1.7.7.RELEASE)", "com.fasterxml.jackson.core:jackson-core:2.8.11", "org.apache.qpid:qpid-broker:6.1.1"}) +public class SpringAmqpRabbit_1_7_0_to_1_7_7_IT { + + private static final TestBroker BROKER = new TestBroker(); + private static final TestApplicationContext CONTEXT = new TestApplicationContext(); + + private final SpringAmqpRabbitTestRunner testRunner = new SpringAmqpRabbitTestRunner(CONTEXT); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + BROKER.start(); + CONTEXT.init( + CommonConfig.class, + MessageListenerConfig_Post_1_4_0.class, + ReceiverConfig_Post_1_6_0.class); + } + + @AfterClass + public static void tearDownAfterClass() { + CONTEXT.close(); + BROKER.shutdown(); + } + + @Test + public void testPush() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class blockingQueueConsumerInternalConsumerClass = Class.forName("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$InternalConsumer"); + Method blockingQueueConsumerInternalConsumerHandleDelivery = blockingQueueConsumerInternalConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace blockingQueueConsumerInternalConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + blockingQueueConsumerInternalConsumerHandleDelivery); + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.support.Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + Class abstractMessageListenerContainerClass = Class.forName("org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer"); + Method abstractMessageListenerContainerExecuteListener = abstractMessageListenerContainerClass.getDeclaredMethod("executeListener", Channel.class, Message.class); + ExpectedTrace abstractMessageListenerContainerExecuteListenerTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + abstractMessageListenerContainerExecuteListener); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] expectedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + blockingQueueConsumerInternalConsumerHandleDeliveryTrace, + deliveryConstructorTrace, + asynchronousInvocationTrace, + abstractMessageListenerContainerExecuteListenerTrace, + markTrace + }; + + final PluginTestVerifier verifier = testRunner.runPush(expectedTraces.length); + + verifier.verifyTrace(expectedTraces); + verifier.verifyTraceCount(0); + } + + @Test + public void testPull() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class amqChannelClass = Class.forName("com.rabbitmq.client.impl.AMQChannel"); + Method amqChannelHandleCompleteInboundCommand = amqChannelClass.getDeclaredMethod("handleCompleteInboundCommand", AMQCommand.class); + ExpectedTrace amqChannelHandleCompleteInboundCommandTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // method + amqChannelHandleCompleteInboundCommand); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + amqChannelHandleCompleteInboundCommandTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Method channelNBasicGet = channelNClass.getDeclaredMethod("basicGet", String.class, boolean.class); + ExpectedTrace channelNBasicGetTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + channelNBasicGet); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + channelNBasicGetTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } + + @Test + public void testPullWithTimeout() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class queueingConsumerClass = Class.forName("com.rabbitmq.client.QueueingConsumer"); + Method queueingConsumerHandleDelivery = queueingConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace queueingConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + queueingConsumerHandleDelivery); + Class queueingConsumerDeliveryClass = Class.forName("com.rabbitmq.client.QueueingConsumer$Delivery"); + Constructor queueingConsumerDeliveryConstructor = queueingConsumerDeliveryClass.getDeclaredConstructor(Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace queueingConsumerDeliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + queueingConsumerDeliveryConstructor); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + queueingConsumerHandleDeliveryTrace, + queueingConsumerDeliveryConstructorTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class, long.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Method queueingConsumerNextDelivery = queueingConsumerClass.getDeclaredMethod("nextDelivery", long.class); + ExpectedTrace queueingConsumerNextDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + queueingConsumerNextDelivery); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + queueingConsumerNextDeliveryTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount, 5000L); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_7_7_to_2_0_0_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_7_7_to_2_0_0_IT.java new file mode 100644 index 000000000000..e369b45d0f4c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_1_7_7_to_2_0_0_IT.java @@ -0,0 +1,312 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.spring; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.TestBroker; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.CommonConfig; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.MessageListenerConfig_Post_1_4_0; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.ReceiverConfig_Post_1_6_0; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.AMQCommand; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.amqp.core.Message; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * BlockingQueueConsumer$ConsumerDecorator added in 2.0.3 has been backported to 1.7.7 as well. + * + * @author HyunGil Jeong + * @see SpringAmqpRabbit_2_0_3_to_2_1_0_IT + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"org.springframework.amqp:spring-rabbit:[1.7.7.RELEASE,2.0.0.RELEASE)", "com.fasterxml.jackson.core:jackson-core:2.8.11", "org.apache.qpid:qpid-broker:6.1.1"}) +public class SpringAmqpRabbit_1_7_7_to_2_0_0_IT { + + private static final TestBroker BROKER = new TestBroker(); + private static final TestApplicationContext CONTEXT = new TestApplicationContext(); + + private final SpringAmqpRabbitTestRunner testRunner = new SpringAmqpRabbitTestRunner(CONTEXT); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + BROKER.start(); + CONTEXT.init( + CommonConfig.class, + MessageListenerConfig_Post_1_4_0.class, + ReceiverConfig_Post_1_6_0.class); + } + + @AfterClass + public static void tearDownAfterClass() { + CONTEXT.close(); + BROKER.shutdown(); + } + + @Test + public void testPush() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class blockingQueueConsumerConsumerDecoratorClass = Class.forName("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$ConsumerDecorator"); + Method blockingQueueConsumerConsumerDecoratorHandleDelivery = blockingQueueConsumerConsumerDecoratorClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace blockingQueueConsumerConsumerDecoratorHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + blockingQueueConsumerConsumerDecoratorHandleDelivery); + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.support.Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + Class abstractMessageListenerContainerClass = Class.forName("org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer"); + Method abstractMessageListenerContainerExecuteListener = abstractMessageListenerContainerClass.getDeclaredMethod("executeListener", Channel.class, Message.class); + ExpectedTrace abstractMessageListenerContainerExecuteListenerTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + abstractMessageListenerContainerExecuteListener); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] expectedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + blockingQueueConsumerConsumerDecoratorHandleDeliveryTrace, + deliveryConstructorTrace, + asynchronousInvocationTrace, + abstractMessageListenerContainerExecuteListenerTrace, + markTrace + }; + + final PluginTestVerifier verifier = testRunner.runPush(expectedTraces.length); + + verifier.verifyTrace(expectedTraces); + verifier.verifyTraceCount(0); + } + + @Test + public void testPull() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class amqChannelClass = Class.forName("com.rabbitmq.client.impl.AMQChannel"); + Method amqChannelHandleCompleteInboundCommand = amqChannelClass.getDeclaredMethod("handleCompleteInboundCommand", AMQCommand.class); + ExpectedTrace amqChannelHandleCompleteInboundCommandTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // method + amqChannelHandleCompleteInboundCommand); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + amqChannelHandleCompleteInboundCommandTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Method channelNBasicGet = channelNClass.getDeclaredMethod("basicGet", String.class, boolean.class); + ExpectedTrace channelNBasicGetTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + channelNBasicGet); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + channelNBasicGetTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } + + @Test + public void testPullWithTimeout() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class queueingConsumerClass = Class.forName("com.rabbitmq.client.QueueingConsumer"); + Method queueingConsumerHandleDelivery = queueingConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace queueingConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + queueingConsumerHandleDelivery); + Class queueingConsumerDeliveryClass = Class.forName("com.rabbitmq.client.QueueingConsumer$Delivery"); + Constructor queueingConsumerDeliveryConstructor = queueingConsumerDeliveryClass.getDeclaredConstructor(Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace queueingConsumerDeliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + queueingConsumerDeliveryConstructor); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + queueingConsumerHandleDeliveryTrace, + queueingConsumerDeliveryConstructorTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class, long.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Method queueingConsumerNextDelivery = queueingConsumerClass.getDeclaredMethod("nextDelivery", long.class); + ExpectedTrace queueingConsumerNextDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + queueingConsumerNextDelivery); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + queueingConsumerNextDeliveryTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount, 5000L); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_2_0_0_to_2_0_3_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_2_0_0_to_2_0_3_IT.java new file mode 100644 index 000000000000..a1994e031e9a --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_2_0_0_to_2_0_3_IT.java @@ -0,0 +1,316 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.spring; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.CommonConfig; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.MessageListenerConfig_Post_1_4_0; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.ReceiverConfig_Post_1_6_0; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.TestBroker; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.AMQCommand; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.amqp.core.Message; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + *

Spring-amqp rabbit 2.x uses rabbitmq 5.x, which removed QueueingConsumer. + * + *

This affects traces recorded inside RabbitTemplate.receive(String queueName, long timeoutMillis) as + * prior to 2.0.0, QueueingConsumer methods were recorded and verified for. + * + *

2.0.0 instead uses an anonymous class extending RabbitTemplate.TemplateConsumer and so verification must + * be done on the anonymous class. Affects {@link #testPullWithTimeout()}. + * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"org.springframework.amqp:spring-rabbit:[2.0.0.RELEASE,2.0.3.RELEASE)", "com.fasterxml.jackson.core:jackson-core:2.8.11", "org.apache.qpid:qpid-broker:6.1.1"}) +@JvmVersion(8) +public class SpringAmqpRabbit_2_0_0_to_2_0_3_IT { + + private static final TestBroker BROKER = new TestBroker(); + private static final TestApplicationContext CONTEXT = new TestApplicationContext(); + + private final SpringAmqpRabbitTestRunner testRunner = new SpringAmqpRabbitTestRunner(CONTEXT); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + BROKER.start(); + CONTEXT.init( + CommonConfig.class, + MessageListenerConfig_Post_1_4_0.class, + ReceiverConfig_Post_1_6_0.class); + } + + @AfterClass + public static void tearDownAfterClass() { + CONTEXT.close(); + BROKER.shutdown(); + } + + @Test + public void testPush() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class blockingQueueConsumerInternalConsumerClass = Class.forName("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$InternalConsumer"); + Method blockingQueueConsumerInternalConsumerHandleDelivery = blockingQueueConsumerInternalConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace blockingQueueConsumerInternalConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + blockingQueueConsumerInternalConsumerHandleDelivery); + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.support.Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + Class abstractMessageListenerContainerClass = Class.forName("org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer"); + Method abstractMessageListenerContainerExecuteListener = abstractMessageListenerContainerClass.getDeclaredMethod("executeListener", Channel.class, Message.class); + ExpectedTrace abstractMessageListenerContainerExecuteListenerTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + abstractMessageListenerContainerExecuteListener); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] expectedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + blockingQueueConsumerInternalConsumerHandleDeliveryTrace, + deliveryConstructorTrace, + asynchronousInvocationTrace, + abstractMessageListenerContainerExecuteListenerTrace, + markTrace + }; + + final PluginTestVerifier verifier = testRunner.runPush(expectedTraces.length); + + verifier.verifyTrace(expectedTraces); + verifier.verifyTraceCount(0); + } + + @Test + public void testPull() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class amqChannelClass = Class.forName("com.rabbitmq.client.impl.AMQChannel"); + Method amqChannelHandleCompleteInboundCommand = amqChannelClass.getDeclaredMethod("handleCompleteInboundCommand", AMQCommand.class); + ExpectedTrace amqChannelHandleCompleteInboundCommandTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // method + amqChannelHandleCompleteInboundCommand); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + amqChannelHandleCompleteInboundCommandTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Method channelNBasicGet = channelNClass.getDeclaredMethod("basicGet", String.class, boolean.class); + ExpectedTrace channelNBasicGetTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + channelNBasicGet); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + channelNBasicGetTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } + + @Test + public void testPullWithTimeout() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + // RabbitTemplate internal consumer implementation - may change in future versions which will cause tests to + // fail, in which case the integration test needs to be updated to match code changes + Class rabbitTemplateInternalConsumerClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate$2"); + Method rabbitTemplateInternalConsumerHandleDelivery = rabbitTemplateInternalConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace rabbitTemplateInternalConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateInternalConsumerHandleDelivery); // method + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.support.Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + rabbitTemplateInternalConsumerHandleDeliveryTrace, + deliveryConstructorTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class, long.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount, 5000L); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_2_0_3_to_2_1_0_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_2_0_3_to_2_1_0_IT.java new file mode 100644 index 000000000000..1c3e5d174ea1 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_2_0_3_to_2_1_0_IT.java @@ -0,0 +1,315 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.spring; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.TestBroker; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.CommonConfig; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.MessageListenerConfig_Post_1_4_0; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.ReceiverConfig_Post_1_6_0; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.AMQCommand; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.amqp.core.Message; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + *

Spring-amqp rabbit 2.0.3 introduced BlockingQueueConsumer$ConsumerDecorator, which wraps + * BlockingQueueConsumer$InternalConsumer. + * + *

This affects asynchronous trace propagation as async trace object now gets attached to + * BlockingQueueConsumer$ConsumerDecorator instead of the previous + * BlockingQueueConsumer$InternalConsumer. + * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"org.springframework.amqp:spring-rabbit:[2.0.3.RELEASE,2.1.0.RELEASE)", "com.fasterxml.jackson.core:jackson-core:2.8.11", "org.apache.qpid:qpid-broker:6.1.1"}) +@JvmVersion(8) +public class SpringAmqpRabbit_2_0_3_to_2_1_0_IT { + + private static final TestBroker BROKER = new TestBroker(); + private static final TestApplicationContext CONTEXT = new TestApplicationContext(); + + private final SpringAmqpRabbitTestRunner testRunner = new SpringAmqpRabbitTestRunner(CONTEXT); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + BROKER.start(); + CONTEXT.init( + CommonConfig.class, + MessageListenerConfig_Post_1_4_0.class, + ReceiverConfig_Post_1_6_0.class); + } + + @AfterClass + public static void tearDownAfterClass() { + CONTEXT.close(); + BROKER.shutdown(); + } + + @Test + public void testPush() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class blockingQueueConsumerConsumerDecoratorClass = Class.forName("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$ConsumerDecorator"); + Method blockingQueueConsumerConsumerDecoratorHandleDelivery = blockingQueueConsumerConsumerDecoratorClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace blockingQueueConsumerConsumerDecoratorHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + blockingQueueConsumerConsumerDecoratorHandleDelivery); + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.support.Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + Class abstractMessageListenerContainerClass = Class.forName("org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer"); + Method abstractMessageListenerContainerExecuteListener = abstractMessageListenerContainerClass.getDeclaredMethod("executeListener", Channel.class, Message.class); + ExpectedTrace abstractMessageListenerContainerExecuteListenerTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + abstractMessageListenerContainerExecuteListener); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] expectedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + blockingQueueConsumerConsumerDecoratorHandleDeliveryTrace, + deliveryConstructorTrace, + asynchronousInvocationTrace, + abstractMessageListenerContainerExecuteListenerTrace, + markTrace + }; + + final PluginTestVerifier verifier = testRunner.runPush(expectedTraces.length); + + verifier.verifyTrace(expectedTraces); + verifier.verifyTraceCount(0); + } + + @Test + public void testPull() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class amqChannelClass = Class.forName("com.rabbitmq.client.impl.AMQChannel"); + Method amqChannelHandleCompleteInboundCommand = amqChannelClass.getDeclaredMethod("handleCompleteInboundCommand", AMQCommand.class); + ExpectedTrace amqChannelHandleCompleteInboundCommandTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // method + amqChannelHandleCompleteInboundCommand); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + amqChannelHandleCompleteInboundCommandTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Method channelNBasicGet = channelNClass.getDeclaredMethod("basicGet", String.class, boolean.class); + ExpectedTrace channelNBasicGetTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + channelNBasicGet); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + channelNBasicGetTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } + + @Test + public void testPullWithTimeout() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + // RabbitTemplate internal consumer implementation - may change in future versions which will cause tests to + // fail, in which case the integration test needs to be updated to match code changes + Class rabbitTemplateInternalConsumerClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate$2"); + Method rabbitTemplateInternalConsumerHandleDelivery = rabbitTemplateInternalConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace rabbitTemplateInternalConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateInternalConsumerHandleDelivery); // method + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.support.Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + rabbitTemplateInternalConsumerHandleDeliveryTrace, + deliveryConstructorTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class, long.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount, 5000L); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_2_1_x_to_2_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_2_1_x_to_2_x_IT.java new file mode 100644 index 000000000000..61c6fd0d084c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/SpringAmqpRabbit_2_1_x_to_2_x_IT.java @@ -0,0 +1,312 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.spring; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.TestBroker; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointConfig; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.CommonConfig; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.MessageListenerConfig_Post_1_4_0; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config.ReceiverConfig_Post_1_6_0; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.AMQCommand; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.amqp.core.Message; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * Spring-amqp rabbit 2.1.0 removed previously added BlockingQueueConsumer$ConsumerDecorator. + *

+ * Skip 2.1.1.RELEASE as it has spring 5.1.2.BUILD-SNAPSHOT dependencies not in maven central. + * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@PinpointConfig("rabbitmq/client/pinpoint-rabbitmq.config") +@Dependency({"org.springframework.amqp:spring-rabbit:[2.1.0.RELEASE,2.1.1.RELEASE),(2.1.1.RELEASE,)", "com.fasterxml.jackson.core:jackson-core:2.8.11", "org.apache.qpid:qpid-broker:6.1.1"}) +@JvmVersion(8) +public class SpringAmqpRabbit_2_1_x_to_2_x_IT { + + private static final TestBroker BROKER = new TestBroker(); + private static final TestApplicationContext CONTEXT = new TestApplicationContext(); + + private final SpringAmqpRabbitTestRunner testRunner = new SpringAmqpRabbitTestRunner(CONTEXT); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + BROKER.start(); + CONTEXT.init( + CommonConfig.class, + MessageListenerConfig_Post_1_4_0.class, + ReceiverConfig_Post_1_6_0.class); + } + + @AfterClass + public static void tearDownAfterClass() { + CONTEXT.close(); + BROKER.shutdown(); + } + + @Test + public void testPush() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PUSH)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + Class blockingQueueConsumerInternalConsumerClass = Class.forName("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$InternalConsumer"); + Method blockingQueueConsumerInternalConsumerHandleDelivery = blockingQueueConsumerInternalConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace blockingQueueConsumerInternalConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + blockingQueueConsumerInternalConsumerHandleDelivery); + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.support.Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class, String.class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + Class abstractMessageListenerContainerClass = Class.forName("org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer"); + Method abstractMessageListenerContainerExecuteListener = abstractMessageListenerContainerClass.getDeclaredMethod("executeListener", Channel.class, Message.class); + ExpectedTrace abstractMessageListenerContainerExecuteListenerTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + abstractMessageListenerContainerExecuteListener); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] expectedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + blockingQueueConsumerInternalConsumerHandleDeliveryTrace, + deliveryConstructorTrace, + asynchronousInvocationTrace, + abstractMessageListenerContainerExecuteListenerTrace, + markTrace + }; + + final PluginTestVerifier verifier = testRunner.runPush(expectedTraces.length); + + verifier.verifyTrace(expectedTraces); + verifier.verifyTraceCount(0); + } + + @Test + public void testPull() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class amqChannelClass = Class.forName("com.rabbitmq.client.impl.AMQChannel"); + Method amqChannelHandleCompleteInboundCommand = amqChannelClass.getDeclaredMethod("handleCompleteInboundCommand", AMQCommand.class); + ExpectedTrace amqChannelHandleCompleteInboundCommandTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // method + amqChannelHandleCompleteInboundCommand); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + amqChannelHandleCompleteInboundCommandTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Method channelNBasicGet = channelNClass.getDeclaredMethod("basicGet", String.class, boolean.class); + ExpectedTrace channelNBasicGetTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, + channelNBasicGet); + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + channelNBasicGetTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } + + @Test + public void testPullWithTimeout() throws Exception { + final String remoteAddress = testRunner.getRemoteAddress(); + + Class rabbitTemplateClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate"); + // verify queue-initiated traces + Method rabbitTemplateConvertAndSend = rabbitTemplateClass.getDeclaredMethod("convertAndSend", String.class, String.class, Object.class); + ExpectedTrace rabbitTemplateConvertAndSendTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateConvertAndSend); // method + // automatic recovery deliberately disabled as Spring has it's own recovery mechanism + Class channelNClass = Class.forName("com.rabbitmq.client.impl.ChannelN"); + Method channelNBasicPublish = channelNClass.getDeclaredMethod("basicPublish", String.class, String.class, boolean.class, boolean.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace channelNBasicPublishTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + channelNBasicPublish, // method + null, // rpc + remoteAddress, // endPoint + "exchange-" + RabbitMQTestConstants.EXCHANGE, // destinationId + Expectations.annotation("rabbitmq.exchange", RabbitMQTestConstants.EXCHANGE), + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + ExpectedTrace rabbitMqConsumerInvocationTrace = Expectations.root( + RabbitMQTestConstants.RABBITMQ_CLIENT, // serviceType + "RabbitMQ Consumer Invocation", // method + "rabbitmq://exchange=" + RabbitMQTestConstants.EXCHANGE, // rpc + null, // endPoint (collected but API to retrieve local address is not available in all versions, so skip) + remoteAddress, // remoteAddress + Expectations.annotation("rabbitmq.routingkey", RabbitMQTestConstants.ROUTING_KEY_PULL)); + Class consumerDispatcherClass = Class.forName("com.rabbitmq.client.impl.ConsumerDispatcher"); + Method consumerDispatcherHandleDelivery = consumerDispatcherClass.getDeclaredMethod("handleDelivery", Consumer.class, String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace consumerDispatcherHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + consumerDispatcherHandleDelivery); // method + ExpectedTrace asynchronousInvocationTrace = Expectations.event( + ServiceType.ASYNC.getName(), + "Asynchronous Invocation"); + // RabbitTemplate internal consumer implementation - may change in future versions which will cause tests to + // fail, in which case the integration test needs to be updated to match code changes + Class rabbitTemplateInternalConsumerClass = Class.forName("org.springframework.amqp.rabbit.core.RabbitTemplate$2"); + Method rabbitTemplateInternalConsumerHandleDelivery = rabbitTemplateInternalConsumerClass.getDeclaredMethod("handleDelivery", String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class); + ExpectedTrace rabbitTemplateInternalConsumerHandleDeliveryTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateInternalConsumerHandleDelivery); // method + Class deliveryClass = Class.forName("org.springframework.amqp.rabbit.support.Delivery"); + Constructor deliveryConstructor = deliveryClass.getDeclaredConstructor(String.class, Envelope.class, AMQP.BasicProperties.class, byte[].class, String.class); + ExpectedTrace deliveryConstructorTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + deliveryConstructor); + + ExpectedTrace[] queueInitiatedTraces = { + rabbitTemplateConvertAndSendTrace, + channelNBasicPublishTrace, + rabbitMqConsumerInvocationTrace, + consumerDispatcherHandleDeliveryTrace, + asynchronousInvocationTrace, + rabbitTemplateInternalConsumerHandleDeliveryTrace, + deliveryConstructorTrace + }; + + // verify client-initiated traces + Method rabbitTemplateReceive = rabbitTemplateClass.getDeclaredMethod("receive", String.class, long.class); + ExpectedTrace rabbitTemplateReceiveTrace = Expectations.event( + RabbitMQTestConstants.RABBITMQ_CLIENT_INTERNAL, // serviceType + rabbitTemplateReceive); // method + Class propagationMarkerClass = PropagationMarker.class; + Method propagationMarkerMark = propagationMarkerClass.getDeclaredMethod("mark"); + ExpectedTrace markTrace = Expectations.event( + ServiceType.INTERNAL_METHOD.getName(), + propagationMarkerMark); + + ExpectedTrace[] clientInitiatedTraces = { + rabbitTemplateReceiveTrace, + markTrace + }; + + int expectedTraceCount = queueInitiatedTraces.length + clientInitiatedTraces.length; + final PluginTestVerifier verifier = testRunner.runPull(expectedTraceCount, 5000L); + + verifier.verifyDiscreteTrace(queueInitiatedTraces); + verifier.verifyDiscreteTrace(clientInitiatedTraces); + + verifier.verifyTraceCount(0); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/TestApplicationContext.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/TestApplicationContext.java new file mode 100644 index 000000000000..31edffc41167 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/spring/TestApplicationContext.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.spring; + +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.TestMessageHolder; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.service.TestReceiverService; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.service.TestSenderService; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * @author HyunGil Jeong + */ +class TestApplicationContext { + + private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + public void init(Class... annotatedClasses) { + context.register(annotatedClasses); + context.refresh(); + } + + public void close() { + context.close(); + } + + public ConnectionFactory getConnectionFactory() { + return (ConnectionFactory) context.getBean("connectionFactory"); + } + + public TestMessageHolder getTestMessageHolder() { + return (TestMessageHolder) context.getBean("testMessageHolder"); + } + + public TestSenderService getTestSenderService() { + return (TestSenderService) context.getBean("testSenderService"); + } + + public TestReceiverService getTestReceiverService() { + return (TestReceiverService) context.getBean("testReceiverService"); + } + + public RabbitTemplate getRabbitTemplate() { + return (RabbitTemplate) context.getBean("rabbitTemplate"); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/util/DerbyUtil.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/util/DerbyUtil.java new file mode 100644 index 000000000000..26b3656f572a --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/util/DerbyUtil.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util; + +import java.io.OutputStream; + +/** + * Suppress derby.log by setting derby.stream.error.field to "DerbyUtil.DEV_NULL". + * + * @author HyunGil Jeong + */ +public class DerbyUtil { + public static final OutputStream DEV_NULL = new OutputStream() { + public void write(int b) {} + }; +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/util/RabbitMQTestConstants.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/util/RabbitMQTestConstants.java new file mode 100644 index 000000000000..5ce07b580045 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/util/RabbitMQTestConstants.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util; + +import com.rabbitmq.client.LongString; +import com.rabbitmq.client.SaslConfig; +import com.rabbitmq.client.SaslMechanism; +import com.rabbitmq.client.impl.LongStringHelper; + +/** + * @author HyunGil Jeong + */ +public interface RabbitMQTestConstants { + + String BROKER_HOST = "127.0.0.1"; + int BROKER_PORT = 20179; + + String RABBITMQ_CLIENT = "RABBITMQ_CLIENT"; + String RABBITMQ_CLIENT_INTERNAL = "RABBITMQ_CLIENT_INTERNAL"; + + String EXCHANGE = "TestExchange"; + String QUEUE_PUSH = "TestPushQueue"; + String QUEUE_PULL = "TestPullQueue"; + String ROUTING_KEY_PUSH = "push"; + String ROUTING_KEY_PULL = "pull"; + + SaslConfig SASL_CONFIG = new SaslConfig() { + public SaslMechanism getSaslMechanism(String[] mechanisms) { + return new SaslMechanism() { + public String getName() { + return "ANONYMOUS"; + } + + public LongString handleChallenge(LongString challenge, String username, String password) { + return LongStringHelper.asLongString(""); + } + }; + } + }; +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/util/TestBroker.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/util/TestBroker.java new file mode 100644 index 000000000000..2a8b012d3ba5 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/util/TestBroker.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util; + +import org.apache.qpid.server.Broker; +import org.apache.qpid.server.BrokerOptions; + +import java.io.File; + +/** + * @author HyunGil Jeong + */ +public class TestBroker { + + static { + setSystemProperties(); + } + + private final Broker broker = new Broker(); + + private static void setSystemProperties() { + String qpidWorkDir = new File(System.getProperty("java.io.tmpdir"), "qpidworktmp").getAbsolutePath(); + System.setProperty("qpid.work_dir", qpidWorkDir); + System.setProperty("qpid.initialConfigurationLocation", "rabbitmq/qpid/qpid-config.json"); + // Suppress derby.log + System.setProperty("derby.stream.error.field", "DerbyUtil.DEV_NULL"); + } + + public void start() throws Exception { + BrokerOptions brokerOptions = new BrokerOptions(); + brokerOptions.setConfigProperty("qpid.amqp_port", String.valueOf(RabbitMQTestConstants.BROKER_PORT)); + brokerOptions.setConfigurationStoreType("Memory"); + brokerOptions.setStartupLoggedToSystemOut(false); + start(brokerOptions); + } + + public void start(BrokerOptions brokerOptions) throws Exception { + broker.startup(brokerOptions); + } + + public void shutdown() { + broker.shutdown(); + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONArrayIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONArrayIT.java similarity index 94% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONArrayIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONArrayIT.java index 18d49bb2b138..1ea13c0a959c 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONArrayIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONArrayIT.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,6 +19,8 @@ import java.lang.reflect.Method; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import net.sf.json.JSONArray; import org.junit.Test; @@ -33,6 +36,7 @@ * @author Sangyoon Lee */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({ "net.sf.json-lib:json-lib:jar:jdk15:(,)" }) public class JsonLibJSONArrayIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONObjectIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONObjectIT.java similarity index 92% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONObjectIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONObjectIT.java index 71ed0df24a86..0fc5905ed25f 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONObjectIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONObjectIT.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,6 +21,8 @@ import java.util.HashMap; import java.util.Map; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import net.sf.json.JSONObject; import org.junit.Test; @@ -34,6 +37,7 @@ *@author Sangyoon Lee */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({"net.sf.json-lib:json-lib:jar:jdk15:(,)"}) public class JsonLibJSONObjectIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONSerializerIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONSerializerIT.java similarity index 91% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONSerializerIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONSerializerIT.java index 539b05097da5..c60fb7b52612 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONSerializerIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/json_lib/JsonLibJSONSerializerIT.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,6 +20,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import net.sf.json.JSON; import net.sf.json.JSONSerializer; @@ -34,6 +37,7 @@ * @author Sangyoon Lee */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({ "net.sf.json-lib:json-lib:jar:jdk15:(,)" }) public class JsonLibJSONSerializerIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/log4j/Log4jIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/log4j/Log4jIT.java similarity index 85% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/log4j/Log4jIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/log4j/Log4jIT.java index fc8164cf1f3f..7852734c5a64 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/log4j/Log4jIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/log4j/Log4jIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,6 +15,8 @@ */ package com.navercorp.pinpoint.plugin.log4j; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.apache.log4j.Logger; import org.apache.log4j.MDC; import org.junit.Assert; @@ -26,6 +28,7 @@ import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({"log4j:log4j:[1.2.16,)"}) @PinpointConfig("pinpoint-spring-bean-test.config") public class Log4jIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/logback/LogbackIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/logback/LogbackIT.java similarity index 80% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/logback/LogbackIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/logback/LogbackIT.java index 91395f0a355b..60179901c270 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/logback/LogbackIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/logback/LogbackIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,6 +15,8 @@ */ package com.navercorp.pinpoint.plugin.logback; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -27,7 +29,8 @@ import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; @RunWith(PinpointPluginTestSuite.class) -@Dependency({"ch.qos.logback:logback-classic:[1.0.13],[1.1.3,)", "org.slf4j:slf4j-api:1.7.12"}) +@PinpointAgent(AgentPath.PATH) +@Dependency({"ch.qos.logback:logback-classic:[1.0.13],[1.1.3,1.2.3]", "org.slf4j:slf4j-api:1.7.12"}) @PinpointConfig("pinpoint-spring-bean-test.config") public class LogbackIT { diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDBBase.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDBBase.java new file mode 100644 index 000000000000..06930dcf2f11 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDBBase.java @@ -0,0 +1,181 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongodb; + +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.result.DeleteResult; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedAnnotation; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.common.util.StringStringValue; +import com.navercorp.pinpoint.plugin.mongo.MongoConstants; +import com.navercorp.pinpoint.plugin.mongo.MongoUtil; +import de.flapdoodle.embed.mongo.MongodExecutable; +import de.flapdoodle.embed.mongo.MongodProcess; +import de.flapdoodle.embed.mongo.MongodStarter; +import de.flapdoodle.embed.mongo.config.IMongodConfig; +import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; +import de.flapdoodle.embed.mongo.config.Net; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.runtime.Network; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.junit.Assert; + +import java.lang.reflect.Method; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +/** + * @author Roy Kim + */ +public abstract class MongoDBBase { + + protected static final String MONGO = "MONGO"; + protected static final String MONGO_EXECUTE_QUERY = "MONGO_EXECUTE_QUERY"; + protected static String MONGODB_ADDRESS = "localhost:" + 27018; + + MongoDatabase database; + MongodProcess mongod; + + + public void startDB() throws Exception { + MongodStarter starter = MongodStarter.getDefaultInstance(); + + String bindIp = "localhost"; + int port = 27018; + + IMongodConfig mongodConfig = new MongodConfigBuilder() + .version(Version.Main.PRODUCTION) + .net(new Net(bindIp, port, Network.localhostIsIPv6())) + .build(); + + MongodExecutable mongodExecutable = null; + + mongodExecutable = starter.prepare(mongodConfig); + mongod = mongodExecutable.start(); + } + + public void stopDB() throws Exception { + //give time for the test to finish" + Thread.sleep(500L); + mongod.stop(); + } + + public void insertData(PluginTestVerifier verifier, MongoCollection collection, Class mongoDatabaseImpl, String collectionInfo, String collectionOption) { + //insert Data + Document doc = new Document("name", "Roy").append("company", "Naver"); + collection.insertOne(doc); + + Object[] objects = new Object[1]; + objects[0] = doc; + + StringStringValue parsedBson = MongoUtil.parseBson(objects, true); + + Method insertOne; + try { + insertOne = mongoDatabaseImpl.getDeclaredMethod("insertOne", Object.class); + } catch (NoSuchMethodException e) { + insertOne = null; + } + + verifier.verifyTrace(event(MONGO_EXECUTE_QUERY, insertOne, null, MONGODB_ADDRESS, null + , new ExpectedAnnotation(MongoConstants.MONGO_COLLECTION_INFO.getName(), collectionInfo) + , new ExpectedAnnotation(MongoConstants.MONGO_COLLECTION_OPTION.getName(), collectionOption) + , new ExpectedAnnotation(MongoConstants.MONGO_JSON_DATA.getName(), parsedBson))); + } + + public void updateData(PluginTestVerifier verifier, MongoCollection collection, Class mongoDatabaseImpl) { + + //update Data + Document doc = new Document("name", "Roy").append("company", "Naver"); + Document doc2 = new Document("$set", new Document("name", "Roy3")); + collection.updateOne(doc, doc2); + + Object[] objects = new Object[2]; + objects[0] = doc; + objects[1] = doc2; + + StringStringValue parsedBson = MongoUtil.parseBson(objects, true); + + Method updateOne; + try { + updateOne = mongoDatabaseImpl.getDeclaredMethod("updateOne", Bson.class, Bson.class); + } catch (NoSuchMethodException e) { + updateOne = null; + } + + verifier.verifyTrace(event(MONGO_EXECUTE_QUERY, updateOne, null, MONGODB_ADDRESS, null + , new ExpectedAnnotation(MongoConstants.MONGO_COLLECTION_INFO.getName(), "customers") + , new ExpectedAnnotation(MongoConstants.MONGO_COLLECTION_OPTION.getName(), "MAJORITY") + , new ExpectedAnnotation(MongoConstants.MONGO_JSON_DATA.getName(), parsedBson))); + } + + + public void readData(PluginTestVerifier verifier, MongoCollection collection, Class mongoDatabaseImpl) { + //read data + MongoCursor cursor = collection.find().iterator(); + + Method find; + try { + find = mongoDatabaseImpl.getDeclaredMethod("find"); + } catch (NoSuchMethodException e) { + find = null; + } + + verifier.verifyTrace(event(MONGO_EXECUTE_QUERY, find, null, MONGODB_ADDRESS, null + , new ExpectedAnnotation(MongoConstants.MONGO_COLLECTION_INFO.getName(), "customers") + , new ExpectedAnnotation(MongoConstants.MONGO_COLLECTION_OPTION.getName(), "secondaryPreferred"))); + + int resultCount = 0; + try { + while (cursor.hasNext()) { + resultCount++; + cursor.next(); + } + } finally { + cursor.close(); + } + Assert.assertEquals(1, resultCount); + } + + public void deleteData(PluginTestVerifier verifier, MongoCollection collection, Class mongoDatabaseImpl) { + //delete data + Document doc = new Document("name", "Roy3"); + Object[] objects = new Object[1]; + objects[0] = doc; + + StringStringValue parsedBson = MongoUtil.parseBson(objects, true); + + DeleteResult deleteResult = collection.deleteMany(doc); + + Method deleteMany; + try { + deleteMany = mongoDatabaseImpl.getDeclaredMethod("deleteMany", Bson.class); + } catch (NoSuchMethodException e) { + deleteMany = null; + } + + verifier.verifyTrace(event(MONGO_EXECUTE_QUERY, deleteMany, null, MONGODB_ADDRESS, null + , new ExpectedAnnotation(MongoConstants.MONGO_COLLECTION_INFO.getName(), "customers") + , new ExpectedAnnotation(MongoConstants.MONGO_COLLECTION_OPTION.getName(), "MAJORITY") + , new ExpectedAnnotation(MongoConstants.MONGO_JSON_DATA.getName(), parsedBson))); + + Assert.assertEquals(1, deleteResult.getDeletedCount()); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDB_3_0_x.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDB_3_0_x.java new file mode 100644 index 000000000000..127431d9f3bd --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDB_3_0_x.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance,the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongodb; + +import com.mongodb.MongoClientOptions; +import com.mongodb.ReadPreference; +import com.mongodb.WriteConcern; +import com.mongodb.client.MongoCollection; +import com.mongodb.connection.Cluster; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.bson.Document; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Constructor; +import java.util.List; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +/** + * @author Roy Kim + */ +@RunWith(PinpointPluginTestSuite.class) +@Dependency({ + "org.mongodb:mongodb-driver:[3.0.0,3.1.max]", + "org.mongodb:bson:3.6.4", + "de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.50.5" +}) +public class MongoDB_3_0_x extends MongoDBBase { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + + } + + @AfterClass + public static void tearDownAfterClass() { + + } + + @Test + public void testConnection() throws Exception { + + startDB(); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + + //create DB + com.mongodb.MongoClient mongoClient = new com.mongodb.MongoClient("localhost", 27018); + verifier.printCache(); + Class clusterClass = Class.forName("com.mongodb.Mongo"); + + Constructor create = clusterClass.getDeclaredConstructor(Cluster.class, MongoClientOptions.class, List.class); + verifier.verifyTrace(event(MONGO, create, null, MONGODB_ADDRESS, null)); + + database = mongoClient.getDatabase("myMongoDbFake").withReadPreference(ReadPreference.secondaryPreferred()).withWriteConcern(WriteConcern.MAJORITY); + MongoCollection collection = database.getCollection("customers"); + MongoCollection collection2 = database.getCollection("customers2").withWriteConcern(WriteConcern.ACKNOWLEDGED); + Class mongoDatabaseImpl = Class.forName("com.mongodb.MongoCollectionImpl"); + + insertData(verifier, collection, mongoDatabaseImpl, "customers", "MAJORITY"); + insertData(verifier, collection2, mongoDatabaseImpl, "customers2", "SAFE"); + updateData(verifier, collection, mongoDatabaseImpl); + readData(verifier, collection, mongoDatabaseImpl); + deleteData(verifier, collection, mongoDatabaseImpl); + + //close connection + mongoClient.close(); + stopDB(); + } + + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDB_3_2_x.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDB_3_2_x.java new file mode 100644 index 000000000000..df91ce7d24af --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDB_3_2_x.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance,the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongodb; + +import com.mongodb.MongoClientOptions; +import com.mongodb.ReadPreference; +import com.mongodb.WriteConcern; +import com.mongodb.client.MongoCollection; +import com.mongodb.connection.Cluster; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.bson.Document; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Constructor; +import java.util.List; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +/** + * @author Roy Kim + */ +@RunWith(PinpointPluginTestSuite.class) +@Dependency({ + "org.mongodb:mongodb-driver:[3.2.0,3.6.max]", + "org.mongodb:bson:3.6.4", + "de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.50.5" +}) +public class MongoDB_3_2_x extends MongoDBBase { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + + } + + @AfterClass + public static void tearDownAfterClass() { + + } + + @Test + public void testConnection() throws Exception { + + startDB(); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + + com.mongodb.MongoClient mongoClient = new com.mongodb.MongoClient("localhost", 27018); + verifier.printCache(); + Class clusterClass = Class.forName("com.mongodb.Mongo"); + + Constructor create = clusterClass.getDeclaredConstructor(Cluster.class, MongoClientOptions.class, List.class); + verifier.verifyTrace(event(MONGO, create, null, MONGODB_ADDRESS, null)); + + database = mongoClient.getDatabase("myMongoDbFake").withReadPreference(ReadPreference.secondaryPreferred()).withWriteConcern(WriteConcern.MAJORITY); + MongoCollection collection = database.getCollection("customers"); + MongoCollection collection2 = database.getCollection("customers2").withWriteConcern(WriteConcern.ACKNOWLEDGED); + Class mongoDatabaseImpl = Class.forName("com.mongodb.MongoCollectionImpl"); + + insertData(verifier, collection, mongoDatabaseImpl, "customers", "MAJORITY"); + insertData(verifier, collection2, mongoDatabaseImpl, "customers2", "ACKNOWLEDGED"); + updateData(verifier, collection, mongoDatabaseImpl); + readData(verifier, collection, mongoDatabaseImpl); + deleteData(verifier, collection, mongoDatabaseImpl); + + mongoClient.close(); + stopDB(); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDB_3_7_x.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDB_3_7_x.java new file mode 100644 index 000000000000..88a4ace9443c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mongodb/MongoDB_3_7_x.java @@ -0,0 +1,91 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance,the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongodb; + +import com.mongodb.MongoClientSettings; +import com.mongodb.MongoDriverInformation; +import com.mongodb.ReadPreference; +import com.mongodb.WriteConcern; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.bson.Document; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Method; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +/** + * @author Roy Kim + */ +@RunWith(PinpointPluginTestSuite.class) +@Dependency({ + "org.mongodb:mongodb-driver:[3.7.0,3.8.max]", + "org.mongodb:bson:3.7.0", + "de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.50.5" +}) +public class MongoDB_3_7_x extends MongoDBBase { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + + } + + @AfterClass + public static void tearDownAfterClass() { + + } + + @Test + public void testConnection() throws Exception { + + startDB(); + + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + + //create DB + MongoClient mongoClient = MongoClients.create("mongodb://localhost:27018"); + verifier.printCache(); + Class CreateDBClass = Class.forName("com.mongodb.client.MongoClients"); + + Method create = CreateDBClass.getDeclaredMethod("create", MongoClientSettings.class, MongoDriverInformation.class); + verifier.verifyTrace(event(MONGO, create, null, MONGODB_ADDRESS, null)); + + database = mongoClient.getDatabase("myMongoDbFake").withReadPreference(ReadPreference.secondaryPreferred()).withWriteConcern(WriteConcern.MAJORITY); + MongoCollection collection = database.getCollection("customers"); + MongoCollection collection2 = database.getCollection("customers2").withWriteConcern(WriteConcern.ACKNOWLEDGED); + Class mongoDatabaseImpl = Class.forName("com.mongodb.client.internal.MongoCollectionImpl"); + + insertData(verifier, collection, mongoDatabaseImpl, "customers", "MAJORITY"); + insertData(verifier, collection2, mongoDatabaseImpl, "customers2", "ACKNOWLEDGED"); + updateData(verifier, collection, mongoDatabaseImpl); + readData(verifier, collection, mongoDatabaseImpl); + deleteData(verifier, collection, mongoDatabaseImpl); + + //close connection + mongoClient.close(); + stopDB(); + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/DefaultSqlSessionIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/DefaultSqlSessionIT.java similarity index 90% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/DefaultSqlSessionIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/DefaultSqlSessionIT.java index 4e71f2246ce2..e46410589846 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/DefaultSqlSessionIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/DefaultSqlSessionIT.java @@ -1,108 +1,108 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.mybatis; - -import static org.mockito.Mockito.*; - -import org.apache.ibatis.executor.Executor; -import org.apache.ibatis.reflection.factory.ObjectFactory; -import org.apache.ibatis.session.Configuration; -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.defaults.DefaultSqlSession; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - * Tests against mybatis 3.0.3+. Prior versions are missing some APIs that are called during the IT. (Most notably, - * SqlSession's select and selectMap methods) - * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.mybatis:mybatis:[3.0.3,)", "org.mockito:mockito-all:1.8.4" }) -public class DefaultSqlSessionIT extends SqlSessionTestBase { - - @Mock - private Configuration configuration; - - @Mock - private ObjectFactory objectFactory; - - @Mock - private Executor executor; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - when(this.configuration.getObjectFactory()).thenReturn(this.objectFactory); - } - - @Override - protected SqlSession getSqlSession() { - return new DefaultSqlSession(this.configuration, this.executor, false); - } - - @Test - public void methodCallWithNullSqlIdShouldOnlyTraceMethodName() throws Exception { - super.testAndVerifyInsertWithNullParameter(); - } - - @Test - public void selectShouldBeTraced() throws Exception { - super.testAndVerifySelect(); - } - - @Test - public void selectOneShouldBeTraced() throws Exception { - super.testAndVerifySelectOne(); - } - - @Test - public void selectListShouldBeTraced() throws Exception { - super.testAndVerifySelectList(); - } - - @Test - public void selectMapShouldBeTraced() throws Exception { - super.testAndVerifySelectMap(); - } - - @Test - public void insertShouldBeTraced() throws Exception { - super.testAndVerifyInsert(); - } - - @Test - public void updateShouldBeTraced() throws Exception { - super.testAndVerifyUpdate(); - } - - @Test - public void deleteShouldBeTraced() throws Exception { - super.testAndVerifyDelete(); - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mybatis; + +import static org.mockito.Mockito.*; + +import com.navercorp.pinpoint.plugin.AgentPath; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.reflection.factory.ObjectFactory; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.defaults.DefaultSqlSession; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + * Tests against mybatis 3.0.3+. Prior versions are missing some APIs that are called during the IT. (Most notably, + * SqlSession's select and selectMap methods) + * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.mybatis:mybatis:[3.0.3,)", "org.mockito:mockito-all:1.8.4" }) +public class DefaultSqlSessionIT extends SqlSessionTestBase { + + @Mock + private Configuration configuration; + + @Mock + private ObjectFactory objectFactory; + + @Mock + private Executor executor; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(this.configuration.getObjectFactory()).thenReturn(this.objectFactory); + } + + @Override + protected SqlSession getSqlSession() { + return new DefaultSqlSession(this.configuration, this.executor, false); + } + + @Test + public void methodCallWithNullSqlIdShouldOnlyTraceMethodName() throws Exception { + super.testAndVerifyInsertWithNullParameter(); + } + + @Test + public void selectShouldBeTraced() throws Exception { + super.testAndVerifySelect(); + } + + @Test + public void selectOneShouldBeTraced() throws Exception { + super.testAndVerifySelectOne(); + } + + @Test + public void selectListShouldBeTraced() throws Exception { + super.testAndVerifySelectList(); + } + + @Test + public void selectMapShouldBeTraced() throws Exception { + super.testAndVerifySelectMap(); + } + + @Test + public void insertShouldBeTraced() throws Exception { + super.testAndVerifyInsert(); + } + + @Test + public void updateShouldBeTraced() throws Exception { + super.testAndVerifyUpdate(); + } + + @Test + public void deleteShouldBeTraced() throws Exception { + super.testAndVerifyDelete(); + } + +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplateITBase.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplateITBase.java similarity index 97% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplateITBase.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplateITBase.java index c8928c0ec66e..f93198baef7c 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplateITBase.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplateITBase.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_1_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_1_x_IT.java similarity index 86% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_1_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_1_x_IT.java index b2bad61a3d54..0a8c1e323a6c 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_1_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_1_x_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2015 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.plugin.mybatis; -import com.navercorp.pinpoint.common.Version; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.test.plugin.Dependency; import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; @@ -29,7 +29,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) +@PinpointAgent(AgentPath.PATH) @Dependency({ "org.mybatis:mybatis-spring:[1.1.0,1.1.max)", "org.mybatis:mybatis:3.2.7", "org.springframework:spring-jdbc:[4.1.7.RELEASE]", "org.mockito:mockito-all:1.8.4" }) public class SqlSessionTemplate_1_1_x_IT extends SqlSessionTemplateITBase { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_2_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_2_x_IT.java similarity index 86% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_2_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_2_x_IT.java index 41c661795c45..44ff524ea551 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_2_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_2_x_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.plugin.mybatis; -import com.navercorp.pinpoint.common.Version; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.test.plugin.Dependency; import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; @@ -28,7 +28,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) +@PinpointAgent(AgentPath.PATH) @Dependency({ "org.mybatis:mybatis-spring:[1.2.0,1.2.max)", "org.mybatis:mybatis:3.2.7", "org.springframework:spring-jdbc:[4.1.7.RELEASE]", "org.mockito:mockito-all:1.8.4" }) public class SqlSessionTemplate_1_2_x_IT extends SqlSessionTemplateITBase { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_3_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_3_x_IT.java similarity index 86% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_3_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_3_x_IT.java index 119ca22c46e9..17590363095f 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_3_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTemplate_1_3_x_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.plugin.mybatis; -import com.navercorp.pinpoint.common.Version; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.test.plugin.Dependency; import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; @@ -28,7 +28,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) +@PinpointAgent(AgentPath.PATH) @Dependency({ "org.mybatis:mybatis-spring:[1.3.0,1.3.max)", "org.mybatis:mybatis:3.4.0", "org.springframework:spring-jdbc:[4.1.7.RELEASE]", "org.mockito:mockito-all:1.8.4" }) public class SqlSessionTemplate_1_3_x_IT extends SqlSessionTemplateITBase { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTestBase.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTestBase.java similarity index 97% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTestBase.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTestBase.java index c4f5bd4a4bda..0118b6090a84 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTestBase.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/mybatis/SqlSessionTestBase.java @@ -1,169 +1,169 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.mybatis; - -import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; - -import java.lang.reflect.Method; - -import org.apache.ibatis.executor.result.DefaultResultHandler; -import org.apache.ibatis.session.ResultHandler; -import org.apache.ibatis.session.RowBounds; -import org.apache.ibatis.session.SqlSession; - -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; - -/** - * @author HyunGil Jeong - */ -public abstract class SqlSessionTestBase { - - protected abstract SqlSession getSqlSession(); - - protected final void testAndVerifyInsertWithNullParameter() throws Exception { - // Given - SqlSession sqlSession = getSqlSession(); - // When - sqlSession.insert(null); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method insert = sqlSession.getClass().getDeclaredMethod("insert", String.class); - verifier.verifyTrace(event("MYBATIS", insert)); - } - - protected final void testAndVerifySelect() throws Exception { - // Given - final String selectId = "selectId"; - SqlSession sqlSession = getSqlSession(); - // When - sqlSession.select(selectId, new DefaultResultHandler()); - sqlSession.select(selectId, new Object(), new DefaultResultHandler()); - sqlSession.select(selectId, new Object(), RowBounds.DEFAULT, new DefaultResultHandler()); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method select1 = sqlSession.getClass().getDeclaredMethod("select", String.class, ResultHandler.class); - verifier.verifyTrace(event("MYBATIS", select1, Expectations.cachedArgs(selectId))); - Method select2 = sqlSession.getClass().getDeclaredMethod("select", String.class, Object.class, - ResultHandler.class); - verifier.verifyTrace(event("MYBATIS", select2, Expectations.cachedArgs(selectId))); - Method select3 = sqlSession.getClass().getDeclaredMethod("select", String.class, Object.class, RowBounds.class, - ResultHandler.class); - verifier.verifyTrace(event("MYBATIS", select3, Expectations.cachedArgs(selectId))); - } - - protected final void testAndVerifySelectOne() throws Exception { - // Given - final String selectOneId = "selectOneId"; - SqlSession sqlSession = getSqlSession(); - // When - sqlSession.selectOne(selectOneId); - sqlSession.selectOne(selectOneId, new Object()); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method selectOne1 = sqlSession.getClass().getDeclaredMethod("selectOne", String.class); - Method selectOne2 = sqlSession.getClass().getDeclaredMethod("selectOne", String.class, Object.class); - verifier.verifyTrace(event("MYBATIS", selectOne1, Expectations.cachedArgs(selectOneId))); - verifier.verifyTrace(event("MYBATIS", selectOne2, Expectations.cachedArgs(selectOneId))); - } - - protected final void testAndVerifySelectList() throws Exception { - // Given - final String selectListId = "selectListId"; - SqlSession sqlSession = getSqlSession(); - // When - sqlSession.selectList(selectListId); - sqlSession.selectList(selectListId, new Object()); - sqlSession.selectList(selectListId, new Object(), RowBounds.DEFAULT); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method selectList1 = sqlSession.getClass().getDeclaredMethod("selectList", String.class); - Method selectList2 = sqlSession.getClass().getDeclaredMethod("selectList", String.class, Object.class); - Method selectList3 = sqlSession.getClass().getDeclaredMethod("selectList", String.class, Object.class, - RowBounds.class); - verifier.verifyTrace(event("MYBATIS", selectList1, Expectations.cachedArgs(selectListId))); - verifier.verifyTrace(event("MYBATIS", selectList2, Expectations.cachedArgs(selectListId))); - verifier.verifyTrace(event("MYBATIS", selectList3, Expectations.cachedArgs(selectListId))); - } - - protected final void testAndVerifySelectMap() throws Exception { - // Given - final String selectMapId = "selectListId"; - SqlSession sqlSession = getSqlSession(); - // When - sqlSession.selectMap(selectMapId, "key"); - sqlSession.selectMap(selectMapId, new Object(), "key"); - sqlSession.selectMap(selectMapId, new Object(), "key", RowBounds.DEFAULT); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method selectMap1 = sqlSession.getClass().getDeclaredMethod("selectMap", String.class, String.class); - Method selectMap2 = sqlSession.getClass().getDeclaredMethod("selectMap", String.class, Object.class, - String.class); - Method selectMap3 = sqlSession.getClass().getDeclaredMethod("selectMap", String.class, Object.class, - String.class, RowBounds.class); - verifier.verifyTrace(event("MYBATIS", selectMap1, Expectations.cachedArgs(selectMapId))); - verifier.verifyTrace(event("MYBATIS", selectMap2, Expectations.cachedArgs(selectMapId))); - verifier.verifyTrace(event("MYBATIS", selectMap3, Expectations.cachedArgs(selectMapId))); - } - - protected final void testAndVerifyInsert() throws Exception { - // Given - final String insertId = "insertId"; - SqlSession sqlSession = getSqlSession(); - // When - sqlSession.insert(insertId); - sqlSession.insert(insertId, new Object()); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method insert1 = sqlSession.getClass().getDeclaredMethod("insert", String.class); - Method insert2 = sqlSession.getClass().getDeclaredMethod("insert", String.class, Object.class); - verifier.verifyTrace(event("MYBATIS", insert1, Expectations.cachedArgs(insertId))); - verifier.verifyTrace(event("MYBATIS", insert2, Expectations.cachedArgs(insertId))); - } - - protected final void testAndVerifyUpdate() throws Exception { - // Given - final String updateId = "updateId"; - SqlSession sqlSession = getSqlSession(); - // When - sqlSession.update(updateId); - sqlSession.update(updateId, new Object()); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method update1 = sqlSession.getClass().getDeclaredMethod("update", String.class); - Method update2 = sqlSession.getClass().getDeclaredMethod("update", String.class, Object.class); - verifier.verifyTrace(event("MYBATIS", update1, Expectations.cachedArgs(updateId))); - verifier.verifyTrace(event("MYBATIS", update2, Expectations.cachedArgs(updateId))); - } - - protected final void testAndVerifyDelete() throws Exception { - // Given - final String deleteId = "deleteId"; - SqlSession sqlSession = getSqlSession(); - // When - sqlSession.delete(deleteId); - sqlSession.delete(deleteId, new Object()); - // Then - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - Method delete1 = sqlSession.getClass().getDeclaredMethod("delete", String.class); - Method delete2 = sqlSession.getClass().getDeclaredMethod("delete", String.class, Object.class); - verifier.verifyTrace(event("MYBATIS", delete1, Expectations.cachedArgs(deleteId))); - verifier.verifyTrace(event("MYBATIS", delete2, Expectations.cachedArgs(deleteId))); - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mybatis; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +import java.lang.reflect.Method; + +import org.apache.ibatis.executor.result.DefaultResultHandler; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.apache.ibatis.session.SqlSession; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; + +/** + * @author HyunGil Jeong + */ +public abstract class SqlSessionTestBase { + + protected abstract SqlSession getSqlSession(); + + protected final void testAndVerifyInsertWithNullParameter() throws Exception { + // Given + SqlSession sqlSession = getSqlSession(); + // When + sqlSession.insert(null); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method insert = sqlSession.getClass().getDeclaredMethod("insert", String.class); + verifier.verifyTrace(event("MYBATIS", insert)); + } + + protected final void testAndVerifySelect() throws Exception { + // Given + final String selectId = "selectId"; + SqlSession sqlSession = getSqlSession(); + // When + sqlSession.select(selectId, new DefaultResultHandler()); + sqlSession.select(selectId, new Object(), new DefaultResultHandler()); + sqlSession.select(selectId, new Object(), RowBounds.DEFAULT, new DefaultResultHandler()); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method select1 = sqlSession.getClass().getDeclaredMethod("select", String.class, ResultHandler.class); + verifier.verifyTrace(event("MYBATIS", select1, Expectations.cachedArgs(selectId))); + Method select2 = sqlSession.getClass().getDeclaredMethod("select", String.class, Object.class, + ResultHandler.class); + verifier.verifyTrace(event("MYBATIS", select2, Expectations.cachedArgs(selectId))); + Method select3 = sqlSession.getClass().getDeclaredMethod("select", String.class, Object.class, RowBounds.class, + ResultHandler.class); + verifier.verifyTrace(event("MYBATIS", select3, Expectations.cachedArgs(selectId))); + } + + protected final void testAndVerifySelectOne() throws Exception { + // Given + final String selectOneId = "selectOneId"; + SqlSession sqlSession = getSqlSession(); + // When + sqlSession.selectOne(selectOneId); + sqlSession.selectOne(selectOneId, new Object()); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method selectOne1 = sqlSession.getClass().getDeclaredMethod("selectOne", String.class); + Method selectOne2 = sqlSession.getClass().getDeclaredMethod("selectOne", String.class, Object.class); + verifier.verifyTrace(event("MYBATIS", selectOne1, Expectations.cachedArgs(selectOneId))); + verifier.verifyTrace(event("MYBATIS", selectOne2, Expectations.cachedArgs(selectOneId))); + } + + protected final void testAndVerifySelectList() throws Exception { + // Given + final String selectListId = "selectListId"; + SqlSession sqlSession = getSqlSession(); + // When + sqlSession.selectList(selectListId); + sqlSession.selectList(selectListId, new Object()); + sqlSession.selectList(selectListId, new Object(), RowBounds.DEFAULT); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method selectList1 = sqlSession.getClass().getDeclaredMethod("selectList", String.class); + Method selectList2 = sqlSession.getClass().getDeclaredMethod("selectList", String.class, Object.class); + Method selectList3 = sqlSession.getClass().getDeclaredMethod("selectList", String.class, Object.class, + RowBounds.class); + verifier.verifyTrace(event("MYBATIS", selectList1, Expectations.cachedArgs(selectListId))); + verifier.verifyTrace(event("MYBATIS", selectList2, Expectations.cachedArgs(selectListId))); + verifier.verifyTrace(event("MYBATIS", selectList3, Expectations.cachedArgs(selectListId))); + } + + protected final void testAndVerifySelectMap() throws Exception { + // Given + final String selectMapId = "selectListId"; + SqlSession sqlSession = getSqlSession(); + // When + sqlSession.selectMap(selectMapId, "key"); + sqlSession.selectMap(selectMapId, new Object(), "key"); + sqlSession.selectMap(selectMapId, new Object(), "key", RowBounds.DEFAULT); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method selectMap1 = sqlSession.getClass().getDeclaredMethod("selectMap", String.class, String.class); + Method selectMap2 = sqlSession.getClass().getDeclaredMethod("selectMap", String.class, Object.class, + String.class); + Method selectMap3 = sqlSession.getClass().getDeclaredMethod("selectMap", String.class, Object.class, + String.class, RowBounds.class); + verifier.verifyTrace(event("MYBATIS", selectMap1, Expectations.cachedArgs(selectMapId))); + verifier.verifyTrace(event("MYBATIS", selectMap2, Expectations.cachedArgs(selectMapId))); + verifier.verifyTrace(event("MYBATIS", selectMap3, Expectations.cachedArgs(selectMapId))); + } + + protected final void testAndVerifyInsert() throws Exception { + // Given + final String insertId = "insertId"; + SqlSession sqlSession = getSqlSession(); + // When + sqlSession.insert(insertId); + sqlSession.insert(insertId, new Object()); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method insert1 = sqlSession.getClass().getDeclaredMethod("insert", String.class); + Method insert2 = sqlSession.getClass().getDeclaredMethod("insert", String.class, Object.class); + verifier.verifyTrace(event("MYBATIS", insert1, Expectations.cachedArgs(insertId))); + verifier.verifyTrace(event("MYBATIS", insert2, Expectations.cachedArgs(insertId))); + } + + protected final void testAndVerifyUpdate() throws Exception { + // Given + final String updateId = "updateId"; + SqlSession sqlSession = getSqlSession(); + // When + sqlSession.update(updateId); + sqlSession.update(updateId, new Object()); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method update1 = sqlSession.getClass().getDeclaredMethod("update", String.class); + Method update2 = sqlSession.getClass().getDeclaredMethod("update", String.class, Object.class); + verifier.verifyTrace(event("MYBATIS", update1, Expectations.cachedArgs(updateId))); + verifier.verifyTrace(event("MYBATIS", update2, Expectations.cachedArgs(updateId))); + } + + protected final void testAndVerifyDelete() throws Exception { + // Given + final String deleteId = "deleteId"; + SqlSession sqlSession = getSqlSession(); + // When + sqlSession.delete(deleteId); + sqlSession.delete(deleteId, new Object()); + // Then + PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); + Method delete1 = sqlSession.getClass().getDeclaredMethod("delete", String.class); + Method delete2 = sqlSession.getClass().getDeclaredMethod("delete", String.class, Object.class); + verifier.verifyTrace(event("MYBATIS", delete1, Expectations.cachedArgs(deleteId))); + verifier.verifyTrace(event("MYBATIS", delete2, Expectations.cachedArgs(deleteId))); + } + +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/netty/NettyIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/netty/NettyIT.java similarity index 96% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/netty/NettyIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/netty/NettyIT.java index 8176f30909f9..222c0816f0b0 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/netty/NettyIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/netty/NettyIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,8 +18,11 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.WebServer; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import io.netty.bootstrap.Bootstrap; @@ -57,6 +60,8 @@ * @author Taejin Koo */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@JvmVersion(7) @Dependency({"io.netty:netty-all:[4.1.0.Final,4.1.max]", "org.nanohttpd:nanohttpd:2.3.1"}) @PinpointConfig("pinpoint-netty-plugin-test.config") public class NettyIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientIT.java similarity index 75% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientIT.java index a62a9953ee6d..65cb76ea4cfc 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientIT.java @@ -1,10 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.plugin.ning.asynchttpclient; import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; import java.util.concurrent.Future; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.WebServer; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -24,6 +42,7 @@ * @author netspider */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({ "com.ning:async-http-client:[1.7.24],[1.8.16,1.8.999)", "org.nanohttpd:nanohttpd:2.3.1"}) @JvmVersion(7) public class NingAsyncHttpClientIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_0_0_to_1_1_0_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_0_0_to_1_1_0_IT.java similarity index 91% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_0_0_to_1_1_0_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_0_0_to_1_1_0_IT.java index 8e026924cbe1..2022d6f6ef1c 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_0_0_to_1_1_0_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_0_0_to_1_1_0_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,10 +16,12 @@ package com.navercorp.pinpoint.plugin.rxjava; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.rxjava.runners.ConnectableObservableTestRunner; import com.navercorp.pinpoint.plugin.rxjava.runners.GroupedObservableTestRunner; import com.navercorp.pinpoint.plugin.rxjava.runners.ObservableTestRunner; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.Test; @@ -29,6 +31,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) // rxjava plugin enabled + custom trace method config @PinpointConfig("rxjava/pinpoint-rxjava.config") @Dependency({"io.reactivex:rxjava:[1.0.0,1.1.0]"}) diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_1_to_1_1_5_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_1_to_1_1_5_IT.java similarity index 93% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_1_to_1_1_5_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_1_to_1_1_5_IT.java index b6da2b9a7853..b537403653c0 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_1_to_1_1_5_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_1_to_1_1_5_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,11 +16,13 @@ package com.navercorp.pinpoint.plugin.rxjava; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.rxjava.runners.ConnectableObservableTestRunner; import com.navercorp.pinpoint.plugin.rxjava.runners.GroupedObservableTestRunner; import com.navercorp.pinpoint.plugin.rxjava.runners.ObservableTestRunner; import com.navercorp.pinpoint.plugin.rxjava.runners.SingleTestRunner; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.Test; @@ -30,6 +32,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) // rxjava plugin enabled + custom trace method config @PinpointConfig("rxjava/pinpoint-rxjava.config") @Dependency({"io.reactivex:rxjava:[1.1.1,1.1.5]"}) diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_6_to_1_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_6_to_1_x_IT.java similarity index 93% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_6_to_1_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_6_to_1_x_IT.java index a5bf05962775..ae8d3b49c981 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_6_to_1_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/RxJava_1_1_6_to_1_x_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,12 +16,14 @@ package com.navercorp.pinpoint.plugin.rxjava; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.rxjava.runners.CompletableTestRunner; import com.navercorp.pinpoint.plugin.rxjava.runners.ConnectableObservableTestRunner; import com.navercorp.pinpoint.plugin.rxjava.runners.GroupedObservableTestRunner; import com.navercorp.pinpoint.plugin.rxjava.runners.ObservableTestRunner; import com.navercorp.pinpoint.plugin.rxjava.runners.SingleTestRunner; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.Test; @@ -31,6 +33,7 @@ * @author HyunGil Jeong */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) // rxjava plugin enabled + custom trace method config @PinpointConfig("rxjava/pinpoint-rxjava.config") @Dependency({"io.reactivex:rxjava:[1.1.6,)"}) diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/CompletableTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/CompletableTestRunner.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/CompletableTestRunner.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/CompletableTestRunner.java index c45c01561448..cadd00be13ac 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/CompletableTestRunner.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/CompletableTestRunner.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ConnectableObservableTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ConnectableObservableTestRunner.java similarity index 99% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ConnectableObservableTestRunner.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ConnectableObservableTestRunner.java index 18ab95cc97c4..aa4c87d6fb89 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ConnectableObservableTestRunner.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ConnectableObservableTestRunner.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/GroupedObservableTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/GroupedObservableTestRunner.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/GroupedObservableTestRunner.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/GroupedObservableTestRunner.java index 9b41e6f91d54..1f3573d4b1da 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/GroupedObservableTestRunner.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/GroupedObservableTestRunner.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ObservableTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ObservableTestRunner.java similarity index 99% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ObservableTestRunner.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ObservableTestRunner.java index 311b10e1df3f..8bef4040c9c5 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ObservableTestRunner.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/ObservableTestRunner.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/SingleTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/SingleTestRunner.java similarity index 98% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/SingleTestRunner.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/SingleTestRunner.java index 59f4252e5bbe..c56d5339e627 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/SingleTestRunner.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/SingleTestRunner.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/TestHelper.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/TestHelper.java similarity index 90% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/TestHelper.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/TestHelper.java index b6242290a577..e8e748cc9ca9 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/TestHelper.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/rxjava/runners/TestHelper.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/spring/web/RestTemplateIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/spring/web/RestTemplateIT.java similarity index 95% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/spring/web/RestTemplateIT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/spring/web/RestTemplateIT.java index 714b275cfeb9..81e8c57f4d35 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/spring/web/RestTemplateIT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/spring/web/RestTemplateIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,8 +18,10 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.plugin.WebServer; import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointConfig; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.AfterClass; @@ -38,6 +40,7 @@ * @author Taejin Koo */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({"org.springframework:spring-web:[4.1.2.RELEASE],[4.2.0.RELEASE,4.2.max],[4.3.0.RELEASE,4.3.max]", "org.apache.httpcomponents:httpclient:4.3", "io.netty:netty-all:4.1.9.Final", "org.nanohttpd:nanohttpd:2.3.1"}) @PinpointConfig("pinpoint-disabled-plugin-test.config") public class RestTemplateIT { diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_3_x_to_4_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_3_x_to_4_x_IT.java similarity index 92% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_3_x_to_4_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_3_x_to_4_x_IT.java index 74dbde33607f..0df0124db045 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_3_x_to_4_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_3_x_to_4_x_IT.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,6 +20,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.mock.web.MockHttpServletRequest; @@ -38,6 +41,7 @@ * */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({"org.springframework:spring-webmvc:[3.0.7.RELEASE],[3.1.4.RELEASE],[3.2.14.RELEASE],[4.0.9.RELEASE],[4.1.7.RELEASE],[4.2.0.RELEASE,4.max]", "org.springframework:spring-test", "javax.servlet:javax.servlet-api:3.0.1"}) public class SpringWebMvc_3_x_to_4_x_IT { private static final String SPRING_MVC = "SPRING_MVC"; diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_5_x_IT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_5_x_IT.java similarity index 92% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_5_x_IT.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_5_x_IT.java index 751d3c339150..c0ba4a7cd807 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_5_x_IT.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvc_5_x_IT.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,8 +18,10 @@ import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.AgentPath; import com.navercorp.pinpoint.test.plugin.Dependency; import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; import org.junit.Test; import org.junit.runner.RunWith; @@ -38,6 +40,7 @@ * */ @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @JvmVersion(8) @Dependency({"org.springframework:spring-webmvc:[5.0.0.RELEASE,)", "org.springframework:spring-test", "javax.servlet:javax.servlet-api:3.0.1"}) public class SpringWebMvc_5_x_IT { diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/TestEnvironment.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/TestEnvironment.java new file mode 100644 index 000000000000..80ec15f2ecdc --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/TestEnvironment.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common; + +import java.net.InetSocketAddress; + +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TProtocolFactory; + +/** + * @author HyunGil Jeong + */ +public class TestEnvironment { + + private static final int MIN_SERVER_PORT = 9091; + private static final int MAX_SERVER_PORT = 9099; + + private static final String SERVER_HOST = "localhost"; + private static final String SERVER_IP = "127.0.0.1"; + private static final TProtocolFactory PROTOCOL_FACTORY = new TBinaryProtocol.Factory(); + private static final String HTTP_PATH = "/thrift"; + + private final String serverHost = SERVER_HOST; + private final String serverIp = SERVER_IP; + private final int port = MIN_SERVER_PORT + (int)(Math.random() * (MAX_SERVER_PORT - MIN_SERVER_PORT) + 1); + private final String httpPath = HTTP_PATH; + private final String httpUrl = "http://" + serverHost + ":" + port + httpPath; + private final InetSocketAddress serverAddress = new InetSocketAddress(SERVER_IP, this.port); + private final TProtocolFactory protocolFactory = PROTOCOL_FACTORY; + + public String getServerHost() { + return this.serverHost; + } + + public String getServerIp() { + return this.serverIp; + } + + public int getPort() { + return this.port; + } + + public String getHttpPath() { + return this.httpPath; + } + + public String getHttpUrl() { + return this.httpUrl; + } + + public InetSocketAddress getServerAddress() { + return this.serverAddress; + } + + public TProtocolFactory getProtocolFactory() { + return this.protocolFactory; + } + +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/AsyncEchoTestClient.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/AsyncEchoTestClient.java similarity index 89% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/AsyncEchoTestClient.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/AsyncEchoTestClient.java index 0a952a5be2f6..90dcdf13370f 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/AsyncEchoTestClient.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/AsyncEchoTestClient.java @@ -1,171 +1,176 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.common.client; - -import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.InetSocketAddress; -import java.nio.channels.SelectionKey; -import java.util.concurrent.CountDownLatch; - -import org.apache.thrift.TBase; -import org.apache.thrift.TException; -import org.apache.thrift.TServiceClient; -import org.apache.thrift.async.AsyncMethodCallback; -import org.apache.thrift.async.TAsyncClientManager; -import org.apache.thrift.async.TAsyncMethodCall; -import org.apache.thrift.transport.TNonblockingSocket; -import org.apache.thrift.transport.TNonblockingTransport; - -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedAnnotation; -import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; - -/** - * @author HyunGil Jeong - */ -public class AsyncEchoTestClient implements EchoTestClient { - - private final TestEnvironment environment; - private final TNonblockingTransport transport; - private final EchoService.AsyncClient asyncClient; - private final TAsyncClientManager asyncClientManager = new TAsyncClientManager(); - - private AsyncEchoTestClient(TestEnvironment environment) throws IOException { - this.environment = environment; - this.transport = new TNonblockingSocket(this.environment.getServerIp(), this.environment.getPort()); - this.asyncClient = new EchoService.AsyncClient(this.environment.getProtocolFactory(), this.asyncClientManager, this.transport); - } - - @Override - public String echo(String message) throws TException { - final CountDownLatch latch = new CountDownLatch(1); - final AsyncEchoResultHolder resultHolder = new AsyncEchoResultHolder(); - final AsyncMethodCallback callback = new EchoMethodCallback(latch, resultHolder); - this.asyncClient.echo(message, callback); - boolean isInterrupted = false; - while (true) { - try { - latch.await(); - return resultHolder.getResult(); - } catch (InterruptedException e) { - isInterrupted = true; - } finally { - if (isInterrupted) { - Thread.currentThread().interrupt(); - } - } - } - } - - @Override - public void verifyTraces(PluginTestVerifier verifier, String expectedMessage) throws Exception { - final InetSocketAddress actualServerAddress = this.environment.getServerAddress(); - // ********** Asynchronous Traces - // SpanEvent - Asynchronous Invocation - ExpectedTrace asyncInvocationTrace = event("ASYNC", "Asynchronous Invocation"); - - // SpanEvent - TAsyncMethodCall.cleanUpAndFireCallback - Method cleanUpAndFireCallback = TAsyncMethodCall.class.getDeclaredMethod("cleanUpAndFireCallback", - SelectionKey.class); - ExpectedTrace cleanUpAndFireCallbackTrace = event("THRIFT_CLIENT_INTERNAL", cleanUpAndFireCallback); - - // SpanEvent - TServiceClient.receiveBase - Method receiveBase = TServiceClient.class.getDeclaredMethod("receiveBase", TBase.class, String.class); - ExpectedAnnotation thriftResult = Expectations.annotation("thrift.result", "echo_result(success:" - + expectedMessage + ")"); - ExpectedTrace receiveBaseTrace = event("THRIFT_CLIENT_INTERNAL", // ServiceType - receiveBase, // Method - thriftResult // Annotation("thrift.result") - ); - - // ********** Root trace for Asynchronous traces - // SpanEvent - TAsyncClientManager.call - Method call = TAsyncClientManager.class.getDeclaredMethod("call", TAsyncMethodCall.class); - ExpectedAnnotation thriftUrl = Expectations.annotation("thrift.url", actualServerAddress.getHostName() + ":" - + actualServerAddress.getPort() + "/com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo_call"); - ExpectedTrace callTrace = event("THRIFT_CLIENT", // ServiceType - call, // Method - null, // rpc - null, // endPoint - actualServerAddress.getHostName() + ":" + actualServerAddress.getPort(), // destinationId - thriftUrl // Annotation("thrift.url") - ); - verifier.verifyTrace(async(callTrace, asyncInvocationTrace, cleanUpAndFireCallbackTrace, receiveBaseTrace)); - } - - private static class AsyncEchoResultHolder { - private volatile String result; - - public void setResult(String result) { - this.result = result; - } - - public String getResult() { - return this.result; - } - } - - @Override - public void close() { - if (this.asyncClientManager.isRunning()) { - this.asyncClientManager.stop(); - } - if (this.transport.isOpen()) { - this.transport.close(); - } - } - - private static class EchoMethodCallback implements AsyncMethodCallback { - - private final CountDownLatch completeLatch; - private final AsyncEchoResultHolder resultHolder; - - private EchoMethodCallback(final CountDownLatch completeLatch, final AsyncEchoResultHolder resultHolder) { - this.completeLatch = completeLatch; - this.resultHolder = resultHolder; - } - - @Override - public void onComplete(String response) { - this.resultHolder.setResult(response); - this.completeLatch.countDown(); - } - - @Override - public void onError(Exception exception) { - try { - this.resultHolder.setResult(exception.toString()); - } finally { - this.completeLatch.countDown(); - } - } - - } - - public static class Client extends AsyncEchoTestClient { - public Client(TestEnvironment environment) throws IOException { - super(environment); - } - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common.client; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.nio.channels.SelectionKey; +import java.util.concurrent.CountDownLatch; + +import com.navercorp.pinpoint.bootstrap.plugin.util.SocketAddressUtils; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.apache.thrift.TServiceClient; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.async.TAsyncClientManager; +import org.apache.thrift.async.TAsyncMethodCall; +import org.apache.thrift.transport.TNonblockingSocket; +import org.apache.thrift.transport.TNonblockingTransport; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedAnnotation; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; + +/** + * @author HyunGil Jeong + */ +public class AsyncEchoTestClient implements EchoTestClient { + + private final TestEnvironment environment; + private final TNonblockingTransport transport; + private final EchoService.AsyncClient asyncClient; + private final TAsyncClientManager asyncClientManager = new TAsyncClientManager(); + + private AsyncEchoTestClient(TestEnvironment environment) throws IOException { + this.environment = environment; + this.transport = new TNonblockingSocket(this.environment.getServerIp(), this.environment.getPort()); + this.asyncClient = new EchoService.AsyncClient(this.environment.getProtocolFactory(), this.asyncClientManager, this.transport); + } + + @Override + public String echo(String message) throws TException { + final CountDownLatch latch = new CountDownLatch(1); + final AsyncEchoResultHolder resultHolder = new AsyncEchoResultHolder(); + final AsyncMethodCallback callback = new EchoMethodCallback(latch, resultHolder); + this.asyncClient.echo(message, callback); + boolean isInterrupted = false; + while (true) { + try { + latch.await(); + return resultHolder.getResult(); + } catch (InterruptedException e) { + isInterrupted = true; + } finally { + if (isInterrupted) { + Thread.currentThread().interrupt(); + } + } + } + } + + @Override + public void verifyTraces(PluginTestVerifier verifier, String expectedMessage) throws Exception { + final InetSocketAddress socketAddress = this.environment.getServerAddress(); + final String hostName = SocketAddressUtils.getHostNameFirst(socketAddress); + // refer to com.navercorp.pinpoint.plugin.thrift.ThriftUtils#getHostPort + final String remoteAddress = HostAndPort.toHostAndPortString(hostName, socketAddress.getPort()); + // ********** Asynchronous Traces + // SpanEvent - Asynchronous Invocation + ExpectedTrace asyncInvocationTrace = event("ASYNC", "Asynchronous Invocation"); + + // SpanEvent - TAsyncMethodCall.cleanUpAndFireCallback + Method cleanUpAndFireCallback = TAsyncMethodCall.class.getDeclaredMethod("cleanUpAndFireCallback", + SelectionKey.class); + ExpectedTrace cleanUpAndFireCallbackTrace = event("THRIFT_CLIENT_INTERNAL", cleanUpAndFireCallback); + + // SpanEvent - TServiceClient.receiveBase + Method receiveBase = TServiceClient.class.getDeclaredMethod("receiveBase", TBase.class, String.class); + ExpectedAnnotation thriftResult = Expectations.annotation("thrift.result", "echo_result(success:" + + expectedMessage + ")"); + ExpectedTrace receiveBaseTrace = event("THRIFT_CLIENT_INTERNAL", // ServiceType + receiveBase, // Method + thriftResult // Annotation("thrift.result") + ); + + // ********** Root trace for Asynchronous traces + // SpanEvent - TAsyncClientManager.call + Method call = TAsyncClientManager.class.getDeclaredMethod("call", TAsyncMethodCall.class); + ExpectedAnnotation thriftUrl = Expectations.annotation("thrift.url", + remoteAddress + "/com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo"); + ExpectedTrace callTrace = event("THRIFT_CLIENT", // ServiceType + call, // Method + null, // rpc + null, // endPoint + remoteAddress, // destinationId + thriftUrl // Annotation("thrift.url") + ); + verifier.verifyTrace(async(callTrace, asyncInvocationTrace, cleanUpAndFireCallbackTrace, receiveBaseTrace)); + } + + private static class AsyncEchoResultHolder { + private volatile String result; + + public void setResult(String result) { + this.result = result; + } + + public String getResult() { + return this.result; + } + } + + @Override + public void close() { + if (this.asyncClientManager.isRunning()) { + this.asyncClientManager.stop(); + } + if (this.transport.isOpen()) { + this.transport.close(); + } + } + + private static class EchoMethodCallback implements AsyncMethodCallback { + + private final CountDownLatch completeLatch; + private final AsyncEchoResultHolder resultHolder; + + private EchoMethodCallback(final CountDownLatch completeLatch, final AsyncEchoResultHolder resultHolder) { + this.completeLatch = completeLatch; + this.resultHolder = resultHolder; + } + + @Override + public void onComplete(String response) { + this.resultHolder.setResult(response); + this.completeLatch.countDown(); + } + + @Override + public void onError(Exception exception) { + try { + this.resultHolder.setResult(exception.toString()); + } finally { + this.completeLatch.countDown(); + } + } + + } + + public static class Client extends AsyncEchoTestClient { + public Client(TestEnvironment environment) throws IOException { + super(environment); + } + } + +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/EchoTestClient.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/EchoTestClient.java similarity index 89% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/EchoTestClient.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/EchoTestClient.java index 552c70e1ea49..fc332316471e 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/EchoTestClient.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/EchoTestClient.java @@ -1,34 +1,34 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.common.client; - -import org.apache.thrift.TException; - -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; - -/** - * @author HyunGil Jeong - */ -public interface EchoTestClient { - - public String echo(String message) throws TException; - - public void verifyTraces(PluginTestVerifier verifier, String expectedMessage) throws Exception; - - public void close(); - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common.client; + +import org.apache.thrift.TException; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; + +/** + * @author HyunGil Jeong + */ +public interface EchoTestClient { + + public String echo(String message) throws TException; + + public void verifyTraces(PluginTestVerifier verifier, String expectedMessage) throws Exception; + + public void close(); + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/HttpEchoTestClient.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/HttpEchoTestClient.java new file mode 100644 index 000000000000..18e9b62680bb --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/HttpEchoTestClient.java @@ -0,0 +1,102 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common.client; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedAnnotation; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.apache.thrift.TServiceClient; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.transport.THttpClient; +import org.apache.thrift.transport.TTransportException; + +import java.lang.reflect.Method; +import java.net.URL; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +/** + * @author HyunGil Jeong + */ +public class HttpEchoTestClient implements EchoTestClient { + + private final TestEnvironment environment; + private final THttpClient httpClient; + + private HttpEchoTestClient(TestEnvironment environment, THttpClient httpClient) throws TTransportException { + this.environment = environment; + this.httpClient = httpClient; + } + + @Override + public String echo(String message) throws TException { + TProtocol protocol = environment.getProtocolFactory().getProtocol(httpClient); + EchoService.Client client = new EchoService.Client(protocol); + return client.echo(message); + } + + @Override + public void verifyTraces(PluginTestVerifier verifier, String expectedMessage) throws Exception { + // ignore jdk http url connector traces + verifier.ignoreServiceType("JDK_HTTPURLCONNECTOR"); + + // refer to TServiceClientSendBaseInterceptor.getRemoteAddressForTHttpClient(...) + URL url = new URL(environment.getHttpUrl()); + String hostAndPort = HostAndPort.toHostAndPortString(url.getHost(), url.getPort()); + + // SpanEvent - TServiceClient.sendBase + Method sendBaseMethod = TServiceClient.class.getDeclaredMethod("sendBase", String.class, TBase.class); + ExpectedAnnotation thriftUrl = Expectations.annotation("thrift.url", + hostAndPort + "/com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo"); + ExpectedAnnotation thriftArgs = Expectations.annotation("thrift.args", + "echo_args(message:" + expectedMessage + ")"); + ExpectedTrace tServiceClientSendBaseTrace = event( + "THRIFT_CLIENT_INTERNAL", + sendBaseMethod, + thriftUrl, thriftArgs); + + // SpanEvent - HttpURLConnection.connect (ignore) + + // SpanEvent - TServiceClient.receiveBase + Method receiveBaseMethod = TServiceClient.class.getDeclaredMethod("receiveBase", TBase.class, String.class); + ExpectedAnnotation thriftResult = Expectations.annotation( + "thrift.result", "echo_result(success:" + expectedMessage + ")"); + ExpectedTrace tServiceClientReceiveBaseTrace = event( + "THRIFT_CLIENT_INTERNAL", + receiveBaseMethod, + thriftResult); + + verifier.verifyDiscreteTrace( + tServiceClientSendBaseTrace, + tServiceClientReceiveBaseTrace); + } + + @Override + public void close() { + httpClient.close(); + } + + public static HttpEchoTestClient create(TestEnvironment environment) throws TTransportException { + return new HttpEchoTestClient(environment, new THttpClient(environment.getHttpUrl())); + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/SyncEchoTestClient.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/SyncEchoTestClient.java similarity index 84% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/SyncEchoTestClient.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/SyncEchoTestClient.java index 0df82d87b6b4..8f9734da0dc1 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/SyncEchoTestClient.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/client/SyncEchoTestClient.java @@ -1,108 +1,113 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.common.client; - -import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; - -import java.lang.reflect.Method; -import java.net.InetSocketAddress; - -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; -import org.apache.thrift.TBase; -import org.apache.thrift.TException; -import org.apache.thrift.TServiceClient; -import org.apache.thrift.protocol.TProtocol; -import org.apache.thrift.transport.TFramedTransport; -import org.apache.thrift.transport.TSocket; -import org.apache.thrift.transport.TTransport; -import org.apache.thrift.transport.TTransportException; - -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedAnnotation; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; - -/** - * @author HyunGil Jeong - */ -public abstract class SyncEchoTestClient implements EchoTestClient { - - private final TestEnvironment environment; - private final TTransport transport; - - private SyncEchoTestClient(TestEnvironment environment, TTransport transport) throws TTransportException { - this.environment = environment; - this.transport = transport; - this.transport.open(); - } - - @Override - public final String echo(String message) throws TException { - TProtocol protocol = this.environment.getProtocolFactory().getProtocol(transport); - EchoService.Client client = new EchoService.Client(protocol); - return client.echo(message); - } - - @Override - public void verifyTraces(PluginTestVerifier verifier, String expectedMessage) throws Exception { - final InetSocketAddress actualServerAddress = this.environment.getServerAddress(); - // SpanEvent - TServiceClient.sendBase - Method sendBase = TServiceClient.class.getDeclaredMethod("sendBase", String.class, TBase.class); - // refer to com.navercorp.pinpoint.plugin.thrift.ThriftUtils#getClientServiceName - ExpectedAnnotation thriftUrl = Expectations.annotation("thrift.url", actualServerAddress.getHostName() + ":" - + actualServerAddress.getPort() + "/com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo"); - ExpectedAnnotation thriftArgs = Expectations.annotation("thrift.args", "echo_args(message:" + expectedMessage - + ")"); - - // SpanEvent - TServiceClient.receiveBase - Method receiveBase = TServiceClient.class.getDeclaredMethod("receiveBase", TBase.class, String.class); - ExpectedAnnotation thriftResult = Expectations.annotation("thrift.result", "echo_result(success:" - + expectedMessage + ")"); - - verifier.verifyDiscreteTrace(event("THRIFT_CLIENT", // ServiceType - sendBase, // Method - null, // rpc - null, // endPoint - HostAndPort.toHostAndPortString(actualServerAddress.getHostName(), actualServerAddress.getPort()), // destinationId - thriftUrl, // Annotation("thrift.url") - thriftArgs), // Annotation("thrift.args") - event("THRIFT_CLIENT_INTERNAL", // ServiceType - receiveBase, // Method - thriftResult // Annotation("thrift.result") - )); - } - - @Override - public void close() { - if (this.transport.isOpen()) { - this.transport.close(); - } - } - - public static class Client extends SyncEchoTestClient { - public Client(TestEnvironment environment) throws TTransportException { - super(environment, new TSocket(environment.getServerIp(), environment.getPort())); - } - } - - public static class ClientForNonblockingServer extends SyncEchoTestClient { - public ClientForNonblockingServer(TestEnvironment environment) throws TTransportException { - super(environment, new TFramedTransport(new TSocket(environment.getServerIp(), environment.getPort()))); - } - } -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common.client; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; + +import java.lang.reflect.Method; +import java.net.InetSocketAddress; + +import com.navercorp.pinpoint.bootstrap.plugin.util.SocketAddressUtils; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.apache.thrift.TServiceClient; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.transport.TFramedTransport; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.apache.thrift.transport.TTransportException; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedAnnotation; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; + +/** + * @author HyunGil Jeong + */ +public abstract class SyncEchoTestClient implements EchoTestClient { + + private final TestEnvironment environment; + private final TTransport transport; + + private SyncEchoTestClient(TestEnvironment environment, TTransport transport) throws TTransportException { + this.environment = environment; + this.transport = transport; + this.transport.open(); + } + + @Override + public final String echo(String message) throws TException { + TProtocol protocol = this.environment.getProtocolFactory().getProtocol(transport); + EchoService.Client client = new EchoService.Client(protocol); + return client.echo(message); + } + + @Override + public void verifyTraces(PluginTestVerifier verifier, String expectedMessage) throws Exception { + // refer to TServiceClientSendBaseInterceptor.getRemoteAddress(...) + final InetSocketAddress socketAddress = this.environment.getServerAddress(); + final String hostName = SocketAddressUtils.getHostNameFirst(socketAddress); + final String remoteAddress = HostAndPort.toHostAndPortString(hostName, socketAddress.getPort()); + + // SpanEvent - TServiceClient.sendBase + Method sendBase = TServiceClient.class.getDeclaredMethod("sendBase", String.class, TBase.class); + + ExpectedAnnotation thriftUrl = Expectations.annotation("thrift.url", + remoteAddress + "/com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo"); + ExpectedAnnotation thriftArgs = Expectations.annotation("thrift.args", + "echo_args(message:" + expectedMessage + ")"); + + // SpanEvent - TServiceClient.receiveBase + Method receiveBase = TServiceClient.class.getDeclaredMethod("receiveBase", TBase.class, String.class); + ExpectedAnnotation thriftResult = Expectations.annotation("thrift.result", "echo_result(success:" + + expectedMessage + ")"); + + verifier.verifyDiscreteTrace(event("THRIFT_CLIENT", // ServiceType + sendBase, // Method + null, // rpc + null, // endPoint + remoteAddress, // destinationId + thriftUrl, // Annotation("thrift.url") + thriftArgs), // Annotation("thrift.args") + event("THRIFT_CLIENT_INTERNAL", // ServiceType + receiveBase, // Method + thriftResult // Annotation("thrift.result") + )); + } + + @Override + public void close() { + if (this.transport.isOpen()) { + this.transport.close(); + } + } + + public static class Client extends SyncEchoTestClient { + public Client(TestEnvironment environment) throws TTransportException { + super(environment, new TSocket(environment.getServerIp(), environment.getPort())); + } + } + + public static class ClientForNonblockingServer extends SyncEchoTestClient { + public ClientForNonblockingServer(TestEnvironment environment) throws TTransportException { + super(environment, new TFramedTransport(new TSocket(environment.getServerIp(), environment.getPort()))); + } + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/AsyncEchoTestServer.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/AsyncEchoTestServer.java similarity index 86% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/AsyncEchoTestServer.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/AsyncEchoTestServer.java index ab901ae30f9c..25240f7e2fb0 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/AsyncEchoTestServer.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/AsyncEchoTestServer.java @@ -1,131 +1,140 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.common.server; - -import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.InetSocketAddress; - -import org.apache.thrift.TBaseAsyncProcessor; -import org.apache.thrift.TProcessor; -import org.apache.thrift.server.AbstractNonblockingServer; -import org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer; -import org.apache.thrift.server.THsHaServer; -import org.apache.thrift.server.TNonblockingServer; -import org.apache.thrift.server.TThreadedSelectorServer; -import org.apache.thrift.transport.TNonblockingServerSocket; -import org.apache.thrift.transport.TTransportException; - -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; -import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; -import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; - -/** - * @author HyunGil Jeong - */ -public abstract class AsyncEchoTestServer extends EchoTestServer { - - protected AsyncEchoTestServer(T server, TestEnvironment environment) throws TTransportException { - super(server, environment); - } - - @Override - public void verifyServerTraces(PluginTestVerifier verifier) throws Exception { - final InetSocketAddress actualServerAddress = super.environment.getServerAddress(); - verifier.verifyTraceCount(2); - Method process = TBaseAsyncProcessor.class.getDeclaredMethod("process", AsyncFrameBuffer.class); - // RootSpan - verifier.verifyTrace(root("THRIFT_SERVER", // ServiceType, - "Thrift Server Invocation", // Method - "com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo", // rpc - actualServerAddress.getHostName() + ":" + actualServerAddress.getPort(), // endPoint - actualServerAddress.getHostName() // remoteAddress - )); - // SpanEvent - TBaseAsyncProcessor.process - verifier.verifyTrace(event("THRIFT_SERVER_INTERNAL", process)); - verifier.verifyTraceCount(0); - } - - public static class AsyncEchoTestServerFactory { - - private static TProcessor getAsyncProcessor() { - return new EchoService.AsyncProcessor(new EchoServiceAsyncHandler()); - } - - public static AsyncEchoTestServer threadedSelectorServer( - final TestEnvironment environment) throws TTransportException { - TThreadedSelectorServer server = new TThreadedSelectorServer(new TThreadedSelectorServer.Args( - new TNonblockingServerSocket(environment.getPort())).processor(getAsyncProcessor()) - .inputProtocolFactory(environment.getProtocolFactory()) - .outputProtocolFactory(environment.getProtocolFactory())); - return new AsyncEchoTestServer(server, environment) { - @Override - public SyncEchoTestClient getSynchronousClient() throws TTransportException { - return new SyncEchoTestClient.ClientForNonblockingServer(environment); - } - - @Override - public AsyncEchoTestClient getAsynchronousClient() throws IOException { - return new AsyncEchoTestClient.Client(environment); - } - }; - } - - public static AsyncEchoTestServer nonblockingServer(final TestEnvironment environment) - throws TTransportException { - TNonblockingServer server = new TNonblockingServer(new TNonblockingServer.Args( - new TNonblockingServerSocket(environment.getPort())).processor(getAsyncProcessor()) - .inputProtocolFactory(environment.getProtocolFactory()) - .outputProtocolFactory(environment.getProtocolFactory())); - return new AsyncEchoTestServer(server, environment) { - @Override - public SyncEchoTestClient getSynchronousClient() throws TTransportException { - return new SyncEchoTestClient.ClientForNonblockingServer(environment); - } - - @Override - public AsyncEchoTestClient getAsynchronousClient() throws IOException { - return new AsyncEchoTestClient.Client(environment); - } - }; - } - - public static AsyncEchoTestServer halfSyncHalfAsyncServer(final TestEnvironment environment) - throws TTransportException { - THsHaServer server = new THsHaServer(new THsHaServer.Args(new TNonblockingServerSocket( - environment.getPort())).processor(getAsyncProcessor()) - .inputProtocolFactory(environment.getProtocolFactory()) - .outputProtocolFactory(environment.getProtocolFactory())); - return new AsyncEchoTestServer(server, environment) { - @Override - public SyncEchoTestClient getSynchronousClient() throws TTransportException { - return new SyncEchoTestClient.ClientForNonblockingServer(environment); - } - - @Override - public AsyncEchoTestClient getAsynchronousClient() throws IOException { - return new AsyncEchoTestClient.Client(environment); - } - }; - } - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common.server; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; + +import com.navercorp.pinpoint.bootstrap.plugin.util.SocketAddressUtils; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import org.apache.thrift.TBaseAsyncProcessor; +import org.apache.thrift.TException; +import org.apache.thrift.TProcessor; +import org.apache.thrift.async.AsyncMethodCallback; +import org.apache.thrift.server.AbstractNonblockingServer; +import org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer; +import org.apache.thrift.server.THsHaServer; +import org.apache.thrift.server.TNonblockingServer; +import org.apache.thrift.server.TThreadedSelectorServer; +import org.apache.thrift.transport.TNonblockingServerSocket; +import org.apache.thrift.transport.TTransportException; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; + +/** + * @author HyunGil Jeong + */ +public abstract class AsyncEchoTestServer extends ThriftEchoTestServer { + + protected AsyncEchoTestServer(T server, TestEnvironment environment) { + super(server, environment); + } + + @Override + public void verifyServerTraces(PluginTestVerifier verifier) throws Exception { + final InetSocketAddress socketAddress = super.environment.getServerAddress(); + final String address = SocketAddressUtils.getAddressFirst(socketAddress); + verifier.verifyTraceCount(2); + Method process = TBaseAsyncProcessor.class.getDeclaredMethod("process", AsyncFrameBuffer.class); + // RootSpan + verifier.verifyTrace(root("THRIFT_SERVER", // ServiceType, + "Thrift Server Invocation", // Method + "com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo", // rpc + HostAndPort.toHostAndPortString(address, socketAddress.getPort()), // endPoint + address // remoteAddress + )); + // SpanEvent - TBaseAsyncProcessor.process + verifier.verifyTrace(event("THRIFT_SERVER_INTERNAL", process)); + } + + public static class AsyncEchoTestServerFactory { + + private static TProcessor getAsyncProcessor() { + return new EchoService.AsyncProcessor(new EchoService.AsyncIface() { + @Override + public void echo(String message, AsyncMethodCallback resultHandler) throws TException { + resultHandler.onComplete(message); + } + }); + } + + public static AsyncEchoTestServer threadedSelectorServer( + final TestEnvironment environment) throws TTransportException { + TThreadedSelectorServer server = new TThreadedSelectorServer(new TThreadedSelectorServer.Args( + new TNonblockingServerSocket(environment.getPort())).processor(getAsyncProcessor()) + .inputProtocolFactory(environment.getProtocolFactory()) + .outputProtocolFactory(environment.getProtocolFactory())); + return new AsyncEchoTestServer(server, environment) { + @Override + public SyncEchoTestClient getSynchronousClient() throws TTransportException { + return new SyncEchoTestClient.ClientForNonblockingServer(environment); + } + + @Override + public AsyncEchoTestClient getAsynchronousClient() throws IOException { + return new AsyncEchoTestClient.Client(environment); + } + }; + } + + public static AsyncEchoTestServer nonblockingServer(final TestEnvironment environment) + throws TTransportException { + TNonblockingServer server = new TNonblockingServer(new TNonblockingServer.Args( + new TNonblockingServerSocket(environment.getPort())).processor(getAsyncProcessor()) + .inputProtocolFactory(environment.getProtocolFactory()) + .outputProtocolFactory(environment.getProtocolFactory())); + return new AsyncEchoTestServer(server, environment) { + @Override + public SyncEchoTestClient getSynchronousClient() throws TTransportException { + return new SyncEchoTestClient.ClientForNonblockingServer(environment); + } + + @Override + public AsyncEchoTestClient getAsynchronousClient() throws IOException { + return new AsyncEchoTestClient.Client(environment); + } + }; + } + + public static AsyncEchoTestServer halfSyncHalfAsyncServer(final TestEnvironment environment) + throws TTransportException { + THsHaServer server = new THsHaServer(new THsHaServer.Args(new TNonblockingServerSocket( + environment.getPort())).processor(getAsyncProcessor()) + .inputProtocolFactory(environment.getProtocolFactory()) + .outputProtocolFactory(environment.getProtocolFactory())); + return new AsyncEchoTestServer(server, environment) { + @Override + public SyncEchoTestClient getSynchronousClient() throws TTransportException { + return new SyncEchoTestClient.ClientForNonblockingServer(environment); + } + + @Override + public AsyncEchoTestClient getAsynchronousClient() throws IOException { + return new AsyncEchoTestClient.Client(environment); + } + }; + } + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/EchoTestServer.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/EchoTestServer.java new file mode 100644 index 000000000000..4bb87e17a8a9 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/EchoTestServer.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common.server; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; + +import java.util.concurrent.ExecutorService; + +/** + * @author HyunGil Jeong + */ +public interface EchoTestServer { + + void start(ExecutorService executorService); + + void stop(); + + void verifyTraces(PluginTestVerifier verifier) throws Exception; +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/HttpEchoTestServer.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/HttpEchoTestServer.java new file mode 100644 index 000000000000..a3b9f8fdd6c8 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/HttpEchoTestServer.java @@ -0,0 +1,147 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common.server; + +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedAnnotation; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.client.HttpEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; +import org.apache.thrift.TBaseProcessor; +import org.apache.thrift.TException; +import org.apache.thrift.TProcessor; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.server.TServlet; +import org.apache.thrift.transport.TTransportException; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.concurrent.ExecutorService; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.event; + +/** + * @author HyunGil Jeong + */ +public abstract class HttpEchoTestServer implements EchoTestServer { + + private final TestEnvironment environment; + private final Server server; + + protected HttpEchoTestServer(TestEnvironment environment, TProcessor processor) { + this.environment = environment; + int port = this.environment.getPort(); + String path = this.environment.getHttpPath(); + TProtocolFactory protocolFactory = this.environment.getProtocolFactory(); + this.server = new Server(port); + this.server.setHandler(new EchoHttpServerHandler(path, processor, protocolFactory)); + } + + public abstract HttpEchoTestClient getHttpClient() throws TTransportException; + + @Override + public void start(ExecutorService executorService) { + try { + server.start(); + } catch (Exception e) { + throw new IllegalStateException("Failed to start EchoHttpServer.", e); + } + } + + @Override + public void stop() { + if (server.isStarted()) { + try { + server.stop(); + } catch (Exception e) { + throw new IllegalStateException("Failed to stop EchoHttpServer.", e); + } + } + } + + @Override + public void verifyTraces(PluginTestVerifier verifier) throws Exception { + // ignore Jetty traces + verifier.ignoreServiceType("JETTY", "JETTY_METHOD"); + + // RootSpan - Jetty Servlet Process (ignore) + + // SpanEvent - (Jetty) Server.handle (ignore) + + // SpanEvent - TBaseProcessor.process + // refer to TBaseProcessorProcessInterceptor.finalizeSpanEvent(...) + Method processMethod = TBaseProcessor.class.getDeclaredMethod("process", TProtocol.class, TProtocol.class); + ExpectedAnnotation thriftUrl = Expectations.annotation( + "thrift.url", "com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo"); + ExpectedTrace tBaseProcessorProcessTrace = event( + "THRIFT_SERVER_INTERNAL", + processMethod, + thriftUrl); + + verifier.verifyDiscreteTrace(tBaseProcessorProcessTrace); + } + + public static HttpEchoTestServer createServer(final TestEnvironment environment) { + TProcessor processor = new EchoService.Processor(new EchoService.Iface() { + @Override + public String echo(String message) throws TException { + return message; + } + }); + return new HttpEchoTestServer(environment, processor) { + @Override + public HttpEchoTestClient getHttpClient() throws TTransportException { + return HttpEchoTestClient.create(environment); + } + }; + } + + private class EchoHttpServerHandler extends AbstractHandler { + + private final String path; + private final TServlet servlet; + + private EchoHttpServerHandler(String path, TProcessor processor, TProtocolFactory protocolFactory) { + this.path = path; + this.servlet = new TServlet(processor, protocolFactory) { + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + super.service(req, resp); + } + }; + } + + @Override + public void handle(String target, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException { + if (path.equals(target)) { + servlet.service(httpServletRequest, httpServletResponse); + } else { + httpServletResponse.sendError(HttpStatus.NOT_FOUND_404, target + " is not available."); + } + } + } +} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/SyncEchoTestServer.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/SyncEchoTestServer.java similarity index 89% rename from agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/SyncEchoTestServer.java rename to agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/SyncEchoTestServer.java index fa8361b9dc0f..224e6fb7ade3 100644 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/SyncEchoTestServer.java +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/SyncEchoTestServer.java @@ -1,171 +1,180 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.common.server; - -import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.InetSocketAddress; - -import org.apache.thrift.TBaseProcessor; -import org.apache.thrift.TProcessor; -import org.apache.thrift.protocol.TProtocol; -import org.apache.thrift.server.THsHaServer; -import org.apache.thrift.server.TNonblockingServer; -import org.apache.thrift.server.TServer; -import org.apache.thrift.server.TSimpleServer; -import org.apache.thrift.server.TThreadPoolServer; -import org.apache.thrift.server.TThreadedSelectorServer; -import org.apache.thrift.transport.TNonblockingServerSocket; -import org.apache.thrift.transport.TServerSocket; -import org.apache.thrift.transport.TTransportException; - -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; -import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; -import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; - -/** - * @author HyunGil Jeong - */ -public abstract class SyncEchoTestServer extends EchoTestServer { - - protected SyncEchoTestServer(T server, TestEnvironment environment) throws TTransportException { - super(server, environment); - } - - @Override - public void verifyServerTraces(PluginTestVerifier verifier) throws Exception { - final InetSocketAddress actualServerAddress = super.environment.getServerAddress(); - verifier.verifyTraceCount(2); - Method process = TBaseProcessor.class.getDeclaredMethod("process", TProtocol.class, TProtocol.class); - verifier.verifyDiscreteTrace( - // RootSpan - Thrift Server Invocation - root("THRIFT_SERVER", // ServiceType, - "Thrift Server Invocation", // Method - "com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo", // rpc - actualServerAddress.getHostName() + ":" + actualServerAddress.getPort(), // endPoint - actualServerAddress.getHostName()), // remoteAddress - // SpanEvent - TBaseProcessor.process - event("THRIFT_SERVER_INTERNAL", process)); - verifier.verifyTraceCount(0); - } - - public static class SyncEchoTestServerFactory { - - private static TProcessor getProcessor() { - return new EchoService.Processor(new EchoServiceHandler()); - } - - public static SyncEchoTestServer simpleServer(final TestEnvironment environment) - throws TTransportException { - TSimpleServer server = new TSimpleServer(new TSimpleServer.Args(new TServerSocket(environment.getPort())) - .processor(getProcessor()).inputProtocolFactory(environment.getProtocolFactory()) - .outputProtocolFactory(environment.getProtocolFactory())); - return new SyncEchoTestServer(server, environment) { - @Override - public SyncEchoTestClient getSynchronousClient() throws TTransportException { - return new SyncEchoTestClient.Client(environment); - } - - @Override - public AsyncEchoTestClient getAsynchronousClient() throws IOException { - return new AsyncEchoTestClient.Client(environment); - } - }; - } - - public static SyncEchoTestServer threadedPoolServer(final TestEnvironment environment) - throws TTransportException { - TThreadPoolServer server = new TThreadPoolServer(new TThreadPoolServer.Args(new TServerSocket( - environment.getPort())).processor(getProcessor()) - .inputProtocolFactory(environment.getProtocolFactory()) - .outputProtocolFactory(environment.getProtocolFactory())); - return new SyncEchoTestServer(server, environment) { - @Override - public SyncEchoTestClient getSynchronousClient() throws TTransportException { - return new SyncEchoTestClient.Client(environment); - } - - @Override - public AsyncEchoTestClient getAsynchronousClient() throws IOException { - return new AsyncEchoTestClient.Client(environment); - } - }; - } - - public static SyncEchoTestServer threadedSelectorServer( - final TestEnvironment environment) throws TTransportException { - TThreadedSelectorServer server = new TThreadedSelectorServer(new TThreadedSelectorServer.Args( - new TNonblockingServerSocket(environment.getPort())).processor(getProcessor()) - .inputProtocolFactory(environment.getProtocolFactory()) - .outputProtocolFactory(environment.getProtocolFactory())); - return new SyncEchoTestServer(server, environment) { - @Override - public SyncEchoTestClient getSynchronousClient() throws TTransportException { - return new SyncEchoTestClient.ClientForNonblockingServer(environment); - } - - @Override - public AsyncEchoTestClient getAsynchronousClient() throws IOException { - return new AsyncEchoTestClient.Client(environment); - } - }; - } - - public static SyncEchoTestServer nonblockingServer(final TestEnvironment environment) - throws TTransportException { - TNonblockingServer server = new TNonblockingServer(new TNonblockingServer.Args( - new TNonblockingServerSocket(environment.getPort())).processor(getProcessor()) - .inputProtocolFactory(environment.getProtocolFactory()) - .outputProtocolFactory(environment.getProtocolFactory())); - return new SyncEchoTestServer(server, environment) { - @Override - public SyncEchoTestClient getSynchronousClient() throws TTransportException { - return new SyncEchoTestClient.ClientForNonblockingServer(environment); - } - - @Override - public AsyncEchoTestClient getAsynchronousClient() throws IOException { - return new AsyncEchoTestClient.Client(environment); - } - }; - } - - public static SyncEchoTestServer halfSyncHalfAsyncServer(final TestEnvironment environment) - throws TTransportException { - THsHaServer server = new THsHaServer(new THsHaServer.Args(new TNonblockingServerSocket( - environment.getPort())).processor(getProcessor()) - .inputProtocolFactory(environment.getProtocolFactory()) - .outputProtocolFactory(environment.getProtocolFactory())); - return new SyncEchoTestServer(server, environment) { - @Override - public SyncEchoTestClient getSynchronousClient() throws TTransportException { - return new SyncEchoTestClient.ClientForNonblockingServer(environment); - } - - @Override - public AsyncEchoTestClient getAsynchronousClient() throws IOException { - return new AsyncEchoTestClient.Client(environment); - } - }; - } - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common.server; + +import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; + +import com.navercorp.pinpoint.bootstrap.plugin.util.SocketAddressUtils; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import org.apache.thrift.TBaseProcessor; +import org.apache.thrift.TException; +import org.apache.thrift.TProcessor; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.server.THsHaServer; +import org.apache.thrift.server.TNonblockingServer; +import org.apache.thrift.server.TServer; +import org.apache.thrift.server.TSimpleServer; +import org.apache.thrift.server.TThreadPoolServer; +import org.apache.thrift.server.TThreadedSelectorServer; +import org.apache.thrift.transport.TNonblockingServerSocket; +import org.apache.thrift.transport.TServerSocket; +import org.apache.thrift.transport.TTransportException; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; + +/** + * @author HyunGil Jeong + */ +public abstract class SyncEchoTestServer extends ThriftEchoTestServer { + + protected SyncEchoTestServer(T server, TestEnvironment environment) { + super(server, environment); + } + + @Override + public void verifyServerTraces(PluginTestVerifier verifier) throws Exception { + final InetSocketAddress socketAddress = super.environment.getServerAddress(); + final String address = SocketAddressUtils.getAddressFirst(socketAddress); + verifier.verifyTraceCount(2); + Method process = TBaseProcessor.class.getDeclaredMethod("process", TProtocol.class, TProtocol.class); + verifier.verifyDiscreteTrace( + // RootSpan - Thrift Server Invocation + // refer to TBaseProcessorProcessInterceptor.finalizeSpan(...) + root("THRIFT_SERVER", // ServiceType, + "Thrift Server Invocation", // Method + "com/navercorp/pinpoint/plugin/thrift/dto/EchoService/echo", // rpc + HostAndPort.toHostAndPortString(address, socketAddress.getPort()), // endPoint + address), // remoteAddress + // SpanEvent - TBaseProcessor.process + event("THRIFT_SERVER_INTERNAL", process)); + } + + public static class SyncEchoTestServerFactory { + + private static TProcessor getProcessor() { + return new EchoService.Processor(new EchoService.Iface() { + @Override + public String echo(String message) throws TException { + return message; + } + }); + } + + public static SyncEchoTestServer simpleServer(final TestEnvironment environment) + throws TTransportException { + TSimpleServer server = new TSimpleServer(new TSimpleServer.Args(new TServerSocket(environment.getPort())) + .processor(getProcessor()).inputProtocolFactory(environment.getProtocolFactory()) + .outputProtocolFactory(environment.getProtocolFactory())); + return new SyncEchoTestServer(server, environment) { + @Override + public SyncEchoTestClient getSynchronousClient() throws TTransportException { + return new SyncEchoTestClient.Client(environment); + } + + @Override + public AsyncEchoTestClient getAsynchronousClient() throws IOException { + return new AsyncEchoTestClient.Client(environment); + } + }; + } + + public static SyncEchoTestServer threadedPoolServer(final TestEnvironment environment) + throws TTransportException { + TThreadPoolServer server = new TThreadPoolServer(new TThreadPoolServer.Args(new TServerSocket( + environment.getPort())).processor(getProcessor()) + .inputProtocolFactory(environment.getProtocolFactory()) + .outputProtocolFactory(environment.getProtocolFactory())); + return new SyncEchoTestServer(server, environment) { + @Override + public SyncEchoTestClient getSynchronousClient() throws TTransportException { + return new SyncEchoTestClient.Client(environment); + } + + @Override + public AsyncEchoTestClient getAsynchronousClient() throws IOException { + return new AsyncEchoTestClient.Client(environment); + } + }; + } + + public static SyncEchoTestServer threadedSelectorServer( + final TestEnvironment environment) throws TTransportException { + TThreadedSelectorServer server = new TThreadedSelectorServer(new TThreadedSelectorServer.Args( + new TNonblockingServerSocket(environment.getPort())).processor(getProcessor()) + .inputProtocolFactory(environment.getProtocolFactory()) + .outputProtocolFactory(environment.getProtocolFactory())); + return new SyncEchoTestServer(server, environment) { + @Override + public SyncEchoTestClient getSynchronousClient() throws TTransportException { + return new SyncEchoTestClient.ClientForNonblockingServer(environment); + } + + @Override + public AsyncEchoTestClient getAsynchronousClient() throws IOException { + return new AsyncEchoTestClient.Client(environment); + } + }; + } + + public static SyncEchoTestServer nonblockingServer(final TestEnvironment environment) + throws TTransportException { + TNonblockingServer server = new TNonblockingServer(new TNonblockingServer.Args( + new TNonblockingServerSocket(environment.getPort())).processor(getProcessor()) + .inputProtocolFactory(environment.getProtocolFactory()) + .outputProtocolFactory(environment.getProtocolFactory())); + return new SyncEchoTestServer(server, environment) { + @Override + public SyncEchoTestClient getSynchronousClient() throws TTransportException { + return new SyncEchoTestClient.ClientForNonblockingServer(environment); + } + + @Override + public AsyncEchoTestClient getAsynchronousClient() throws IOException { + return new AsyncEchoTestClient.Client(environment); + } + }; + } + + public static SyncEchoTestServer halfSyncHalfAsyncServer(final TestEnvironment environment) + throws TTransportException { + THsHaServer server = new THsHaServer(new THsHaServer.Args(new TNonblockingServerSocket( + environment.getPort())).processor(getProcessor()) + .inputProtocolFactory(environment.getProtocolFactory()) + .outputProtocolFactory(environment.getProtocolFactory())); + return new SyncEchoTestServer(server, environment) { + @Override + public SyncEchoTestClient getSynchronousClient() throws TTransportException { + return new SyncEchoTestClient.ClientForNonblockingServer(environment); + } + + @Override + public AsyncEchoTestClient getAsynchronousClient() throws IOException { + return new AsyncEchoTestClient.Client(environment); + } + }; + } + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/ThriftEchoTestServer.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/ThriftEchoTestServer.java new file mode 100644 index 000000000000..d5d63bd8496f --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/ThriftEchoTestServer.java @@ -0,0 +1,125 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.common.server; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.server.ServerContext; +import org.apache.thrift.server.TServer; +import org.apache.thrift.server.TServerEventHandler; +import org.apache.thrift.transport.TTransport; +import org.apache.thrift.transport.TTransportException; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * @author HyunGil Jeong + */ +public abstract class ThriftEchoTestServer implements EchoTestServer { + + private final T server; + + protected final TestEnvironment environment; + + protected ThriftEchoTestServer(T server, TestEnvironment environment) { + if (server == null) { + throw new IllegalArgumentException("server cannot be null"); + } + this.server = server; + this.environment = environment; + } + + @Override + public void start(ExecutorService executor) { + if (this.server.isServing()) { + return; + } + + CountDownLatch waitToServeLatch = new CountDownLatch(1); + server.setServerEventHandler(new WaitToServeHandler(waitToServeLatch)); + + executor.execute(new Runnable() { + @Override + public void run() { + server.serve(); + } + }); + + boolean started = false; + try { + started = waitToServeLatch.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + if (!started) { + throw new IllegalStateException("Failed to start EchoThriftServer."); + } + } + + @Override + public void stop() { + this.server.stop(); + } + + @Override + public void verifyTraces(PluginTestVerifier verifier) throws Exception { + this.verifyServerTraces(verifier); + } + + protected abstract void verifyServerTraces(PluginTestVerifier verifier) throws Exception; + + public abstract SyncEchoTestClient getSynchronousClient() throws TTransportException; + + public abstract AsyncEchoTestClient getAsynchronousClient() throws IOException; + + + private class WaitToServeHandler implements TServerEventHandler { + + private final CountDownLatch waitToServeLatch; + + public WaitToServeHandler(CountDownLatch waitToServeLatch) { + this.waitToServeLatch = waitToServeLatch; + } + + @Override + public void preServe() { + waitToServeLatch.countDown(); + } + + @Override + public ServerContext createContext(TProtocol tProtocol, TProtocol tProtocol1) { + return null; + } + + @Override + public void deleteContext(ServerContext serverContext, TProtocol tProtocol, TProtocol tProtocol1) { + + } + + @Override + public void processContext(ServerContext serverContext, TTransport tTransport, TTransport tTransport1) { + + } + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/dto/EchoService.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/dto/EchoService.java new file mode 100644 index 000000000000..a86972671980 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/dto/EchoService.java @@ -0,0 +1,969 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Autogenerated by Thrift Compiler (0.10.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package com.navercorp.pinpoint.plugin.thrift.dto; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-01-25") +public class EchoService { + + public interface Iface { + + public String echo(String message) throws org.apache.thrift.TException; + + } + + public interface AsyncIface { + + public void echo(String message, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + + } + + public static class Client extends org.apache.thrift.TServiceClient implements Iface { + public static class Factory implements org.apache.thrift.TServiceClientFactory { + public Factory() {} + public Client getClient(org.apache.thrift.protocol.TProtocol prot) { + return new Client(prot); + } + public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) { + return new Client(iprot, oprot); + } + } + + public Client(org.apache.thrift.protocol.TProtocol prot) + { + super(prot, prot); + } + + public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) { + super(iprot, oprot); + } + + public String echo(String message) throws org.apache.thrift.TException + { + send_echo(message); + return recv_echo(); + } + + public void send_echo(String message) throws org.apache.thrift.TException + { + echo_args args = new echo_args(); + args.setMessage(message); + sendBase("echo", args); + } + + public String recv_echo() throws org.apache.thrift.TException + { + echo_result result = new echo_result(); + receiveBase(result, "echo"); + if (result.isSetSuccess()) { + return result.success; + } + throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "echo failed: unknown result"); + } + + } + public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface { + public static class Factory implements org.apache.thrift.async.TAsyncClientFactory { + private org.apache.thrift.async.TAsyncClientManager clientManager; + private org.apache.thrift.protocol.TProtocolFactory protocolFactory; + public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) { + this.clientManager = clientManager; + this.protocolFactory = protocolFactory; + } + public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) { + return new AsyncClient(protocolFactory, clientManager, transport); + } + } + + public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) { + super(protocolFactory, clientManager, transport); + } + + public void echo(String message, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + checkReady(); + echo_call method_call = new echo_call(message, resultHandler, this, ___protocolFactory, ___transport); + this.___currentMethod = method_call; + ___manager.call(method_call); + } + + public static class echo_call extends org.apache.thrift.async.TAsyncMethodCall { + private String message; + public echo_call(String message, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { + super(client, protocolFactory, transport, resultHandler, false); + this.message = message; + } + + public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { + prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("echo", org.apache.thrift.protocol.TMessageType.CALL, 0)); + echo_args args = new echo_args(); + args.setMessage(message); + args.write(prot); + prot.writeMessageEnd(); + } + + public String getResult() throws org.apache.thrift.TException { + if (getState() != State.RESPONSE_READ) { + throw new IllegalStateException("Method call not finished!"); + } + org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); + org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); + return (new Client(prot)).recv_echo(); + } + } + + } + + public static class Processor extends org.apache.thrift.TBaseProcessor implements org.apache.thrift.TProcessor { + private static final org.slf4j.Logger _LOGGER = org.slf4j.LoggerFactory.getLogger(Processor.class.getName()); + public Processor(I iface) { + super(iface, getProcessMap(new java.util.HashMap>())); + } + + protected Processor(I iface, java.util.Map> processMap) { + super(iface, getProcessMap(processMap)); + } + + private static java.util.Map> getProcessMap(java.util.Map> processMap) { + processMap.put("echo", new echo()); + return processMap; + } + + public static class echo extends org.apache.thrift.ProcessFunction { + public echo() { + super("echo"); + } + + public echo_args getEmptyArgsInstance() { + return new echo_args(); + } + + protected boolean isOneway() { + return false; + } + + public echo_result getResult(I iface, echo_args args) throws org.apache.thrift.TException { + echo_result result = new echo_result(); + result.success = iface.echo(args.message); + return result; + } + } + + } + + public static class AsyncProcessor extends org.apache.thrift.TBaseAsyncProcessor { + private static final org.slf4j.Logger _LOGGER = org.slf4j.LoggerFactory.getLogger(AsyncProcessor.class.getName()); + public AsyncProcessor(I iface) { + super(iface, getProcessMap(new java.util.HashMap>())); + } + + protected AsyncProcessor(I iface, java.util.Map> processMap) { + super(iface, getProcessMap(processMap)); + } + + private static java.util.Map> getProcessMap(java.util.Map> processMap) { + processMap.put("echo", new echo()); + return processMap; + } + + public static class echo extends org.apache.thrift.AsyncProcessFunction { + public echo() { + super("echo"); + } + + public echo_args getEmptyArgsInstance() { + return new echo_args(); + } + + public org.apache.thrift.async.AsyncMethodCallback getResultHandler(final org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final int seqid) { + final org.apache.thrift.AsyncProcessFunction fcall = this; + return new org.apache.thrift.async.AsyncMethodCallback() { + public void onComplete(String o) { + echo_result result = new echo_result(); + result.success = o; + try { + fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid); + } catch (org.apache.thrift.transport.TTransportException e) { + _LOGGER.error("TTransportException writing to internal frame buffer", e); + fb.close(); + } catch (Exception e) { + _LOGGER.error("Exception writing to internal frame buffer", e); + onError(e); + } + } + public void onError(Exception e) { + byte msgType = org.apache.thrift.protocol.TMessageType.REPLY; + org.apache.thrift.TSerializable msg; + echo_result result = new echo_result(); + if (e instanceof org.apache.thrift.transport.TTransportException) { + _LOGGER.error("TTransportException inside handler", e); + fb.close(); + return; + } else if (e instanceof org.apache.thrift.TApplicationException) { + _LOGGER.error("TApplicationException inside handler", e); + msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; + msg = (org.apache.thrift.TApplicationException)e; + } else { + _LOGGER.error("Exception inside handler", e); + msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; + msg = new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage()); + } + try { + fcall.sendResponse(fb,msg,msgType,seqid); + } catch (Exception ex) { + _LOGGER.error("Exception writing to internal frame buffer", ex); + fb.close(); + } + } + }; + } + + protected boolean isOneway() { + return false; + } + + public void start(I iface, echo_args args, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + iface.echo(args.message,resultHandler); + } + } + + } + + public static class echo_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("echo_args"); + + private static final org.apache.thrift.protocol.TField MESSAGE_FIELD_DESC = new org.apache.thrift.protocol.TField("message", org.apache.thrift.protocol.TType.STRING, (short)1); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new echo_argsStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new echo_argsTupleSchemeFactory(); + + private String message; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + MESSAGE((short)1, "message"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // MESSAGE + return MESSAGE; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(String name) { + return byName.get(name); + } + + private final short _thriftId; + private final String _fieldName; + + _Fields(short thriftId, String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.MESSAGE, new org.apache.thrift.meta_data.FieldMetaData("message", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(echo_args.class, metaDataMap); + } + + public echo_args() { + } + + public echo_args( + String message) + { + this(); + this.message = message; + } + + /** + * Performs a deep copy on other. + */ + public echo_args(echo_args other) { + if (other.isSetMessage()) { + this.message = other.message; + } + } + + public echo_args deepCopy() { + return new echo_args(this); + } + + @Override + public void clear() { + this.message = null; + } + + public String getMessage() { + return this.message; + } + + public void setMessage(String message) { + this.message = message; + } + + public void unsetMessage() { + this.message = null; + } + + /** Returns true if field message is set (has been assigned a value) and false otherwise */ + public boolean isSetMessage() { + return this.message != null; + } + + public void setMessageIsSet(boolean value) { + if (!value) { + this.message = null; + } + } + + public void setFieldValue(_Fields field, Object value) { + switch (field) { + case MESSAGE: + if (value == null) { + unsetMessage(); + } else { + setMessage((String)value); + } + break; + + } + } + + public Object getFieldValue(_Fields field) { + switch (field) { + case MESSAGE: + return getMessage(); + + } + throw new IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new IllegalArgumentException(); + } + + switch (field) { + case MESSAGE: + return isSetMessage(); + } + throw new IllegalStateException(); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + if (that instanceof echo_args) + return this.equals((echo_args)that); + return false; + } + + public boolean equals(echo_args that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_message = true && this.isSetMessage(); + boolean that_present_message = true && that.isSetMessage(); + if (this_present_message || that_present_message) { + if (!(this_present_message && that_present_message)) + return false; + if (!this.message.equals(that.message)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetMessage()) ? 131071 : 524287); + if (isSetMessage()) + hashCode = hashCode * 8191 + message.hashCode(); + + return hashCode; + } + + @Override + public int compareTo(echo_args other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = Boolean.valueOf(isSetMessage()).compareTo(other.isSetMessage()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetMessage()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.message, other.message); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("echo_args("); + boolean first = true; + + sb.append("message:"); + if (this.message == null) { + sb.append("null"); + } else { + sb.append(this.message); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class echo_argsStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public echo_argsStandardScheme getScheme() { + return new echo_argsStandardScheme(); + } + } + + private static class echo_argsStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, echo_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // MESSAGE + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.message = iprot.readString(); + struct.setMessageIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, echo_args struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.message != null) { + oprot.writeFieldBegin(MESSAGE_FIELD_DESC); + oprot.writeString(struct.message); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class echo_argsTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public echo_argsTupleScheme getScheme() { + return new echo_argsTupleScheme(); + } + } + + private static class echo_argsTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, echo_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetMessage()) { + optionals.set(0); + } + oprot.writeBitSet(optionals, 1); + if (struct.isSetMessage()) { + oprot.writeString(struct.message); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, echo_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(1); + if (incoming.get(0)) { + struct.message = iprot.readString(); + struct.setMessageIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } + } + + public static class echo_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("echo_result"); + + private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.STRING, (short)0); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new echo_resultStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new echo_resultTupleSchemeFactory(); + + private String success; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + SUCCESS((short)0, "success"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 0: // SUCCESS + return SUCCESS; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(String name) { + return byName.get(name); + } + + private final short _thriftId; + private final String _fieldName; + + _Fields(short thriftId, String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(echo_result.class, metaDataMap); + } + + public echo_result() { + } + + public echo_result( + String success) + { + this(); + this.success = success; + } + + /** + * Performs a deep copy on other. + */ + public echo_result(echo_result other) { + if (other.isSetSuccess()) { + this.success = other.success; + } + } + + public echo_result deepCopy() { + return new echo_result(this); + } + + @Override + public void clear() { + this.success = null; + } + + public String getSuccess() { + return this.success; + } + + public void setSuccess(String success) { + this.success = success; + } + + public void unsetSuccess() { + this.success = null; + } + + /** Returns true if field success is set (has been assigned a value) and false otherwise */ + public boolean isSetSuccess() { + return this.success != null; + } + + public void setSuccessIsSet(boolean value) { + if (!value) { + this.success = null; + } + } + + public void setFieldValue(_Fields field, Object value) { + switch (field) { + case SUCCESS: + if (value == null) { + unsetSuccess(); + } else { + setSuccess((String)value); + } + break; + + } + } + + public Object getFieldValue(_Fields field) { + switch (field) { + case SUCCESS: + return getSuccess(); + + } + throw new IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new IllegalArgumentException(); + } + + switch (field) { + case SUCCESS: + return isSetSuccess(); + } + throw new IllegalStateException(); + } + + @Override + public boolean equals(Object that) { + if (that == null) + return false; + if (that instanceof echo_result) + return this.equals((echo_result)that); + return false; + } + + public boolean equals(echo_result that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_success = true && this.isSetSuccess(); + boolean that_present_success = true && that.isSetSuccess(); + if (this_present_success || that_present_success) { + if (!(this_present_success && that_present_success)) + return false; + if (!this.success.equals(that.success)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetSuccess()) ? 131071 : 524287); + if (isSetSuccess()) + hashCode = hashCode * 8191 + success.hashCode(); + + return hashCode; + } + + @Override + public int compareTo(echo_result other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = Boolean.valueOf(isSetSuccess()).compareTo(other.isSetSuccess()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetSuccess()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, other.success); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("echo_result("); + boolean first = true; + + sb.append("success:"); + if (this.success == null) { + sb.append("null"); + } else { + sb.append(this.success); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class echo_resultStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public echo_resultStandardScheme getScheme() { + return new echo_resultStandardScheme(); + } + } + + private static class echo_resultStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, echo_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 0: // SUCCESS + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.success = iprot.readString(); + struct.setSuccessIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, echo_result struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.success != null) { + oprot.writeFieldBegin(SUCCESS_FIELD_DESC); + oprot.writeString(struct.success); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class echo_resultTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public echo_resultTupleScheme getScheme() { + return new echo_resultTupleScheme(); + } + } + + private static class echo_resultTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, echo_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetSuccess()) { + optionals.set(0); + } + oprot.writeBitSet(optionals, 1); + if (struct.isSetSuccess()) { + oprot.writeString(struct.success); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, echo_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(1); + if (incoming.get(0)) { + struct.success = iprot.readString(); + struct.setSuccessIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/EchoTestRunner.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/EchoTestRunner.java new file mode 100644 index 000000000000..0863134e5c4e --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/EchoTestRunner.java @@ -0,0 +1,93 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.apache.thrift.transport.TTransportException; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; + +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.client.EchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; + +/** + * @author HyunGil Jeong + */ +public abstract class EchoTestRunner { + + private static ExecutorService SERVER_EXECUTOR; + + private T echoServer; + + PluginTestVerifier verifier; + + @BeforeClass + public static void setUpBeforeClass() { + SERVER_EXECUTOR = Executors.newSingleThreadExecutor(); + } + + @Before + public void setUp() throws TTransportException { + this.echoServer = createEchoServer(new TestEnvironment()); + this.verifier = PluginTestVerifierHolder.getInstance(); + this.echoServer.start(SERVER_EXECUTOR); + } + + @After + public void tearDown() { + if (this.echoServer != null) { + this.echoServer.stop(); + } + } + + @AfterClass + public static void tearDownAfterClass() { + SERVER_EXECUTOR.shutdown(); + } + + protected T getServer() { + return echoServer; + } + + protected String invokeAndVerify(EchoTestClient echoClient, String message) throws Exception { + try { + return echoClient.echo(message); + } finally { + echoClient.close(); + // give a chance to flush out span data + Thread.sleep(500L); + this.verifyTraces(echoClient, message); + } + } + + protected abstract T createEchoServer(TestEnvironment environment) throws TTransportException; + + private void verifyTraces(EchoTestClient echoClient, String expectedMessage) throws Exception { + this.verifier.printCache(System.out); + echoClient.verifyTraces(this.verifier, expectedMessage); + this.echoServer.verifyTraces(this.verifier); + this.verifier.verifyTraceCount(0); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftHalfSyncHalfAsyncServerAsyncIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftHalfSyncHalfAsyncServerAsyncIT.java new file mode 100644 index 000000000000..b206fd80b5e4 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftHalfSyncHalfAsyncServerAsyncIT.java @@ -0,0 +1,78 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it.asynchronous; + +import static org.junit.Assert.assertEquals; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.ThriftEchoTestServer; +import org.apache.thrift.server.THsHaServer; +import org.apache.thrift.transport.TTransportException; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.server.AsyncEchoTestServer.AsyncEchoTestServerFactory; +import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + *

Integration test for THsHaServer with asynchronous processor.

+ * + *

Tests against libthrift 0.9.2+ due to THRIFT-2274
+ * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

+ * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", + "org.slf4j:slf4j-simple:1.6.6", "org.slf4j:log4j-over-slf4j:1.6.6", "org.slf4j:slf4j-api:1.6.6" }) +public class ThriftHalfSyncHalfAsyncServerAsyncIT extends EchoTestRunner> { + + @Override + protected ThriftEchoTestServer createEchoServer(TestEnvironment environment) throws TTransportException { + return AsyncEchoTestServerFactory.halfSyncHalfAsyncServer(environment); + } + + @Test + public void testSynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final SyncEchoTestClient client = getServer().getSynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + + @Test + public void testAsynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final AsyncEchoTestClient client = getServer().getAsynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftNonblockingServerAsyncIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftNonblockingServerAsyncIT.java new file mode 100644 index 000000000000..f7cb6165ed6c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftNonblockingServerAsyncIT.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it.asynchronous; + +import static org.junit.Assert.assertEquals; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.ThriftEchoTestServer; +import org.apache.thrift.server.TNonblockingServer; +import org.apache.thrift.transport.TTransportException; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.server.AsyncEchoTestServer.AsyncEchoTestServerFactory; +import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + *

Integration test for TNonblockingServer with asynchronous processor.

+ * + *

Tests against libthrift 0.9.2+ due to THRIFT-2274
+ * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

+ * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", + "org.slf4j:slf4j-simple:1.6.6", "org.slf4j:log4j-over-slf4j:1.6.6", "org.slf4j:slf4j-api:1.6.6" }) +public class ThriftNonblockingServerAsyncIT extends EchoTestRunner> { + + @Override + protected ThriftEchoTestServer createEchoServer(TestEnvironment environment) + throws TTransportException { + return AsyncEchoTestServerFactory.nonblockingServer(environment); + } + + @Test + public void testSynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final SyncEchoTestClient client = getServer().getSynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + + @Test + public void testAsynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final AsyncEchoTestClient client = getServer().getAsynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftThreadedSelectorServerAsyncIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftThreadedSelectorServerAsyncIT.java new file mode 100644 index 000000000000..188ac280845e --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftThreadedSelectorServerAsyncIT.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it.asynchronous; + +import static org.junit.Assert.assertEquals; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.ThriftEchoTestServer; +import org.apache.thrift.server.TThreadedSelectorServer; +import org.apache.thrift.transport.TTransportException; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.server.AsyncEchoTestServer.AsyncEchoTestServerFactory; +import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + *

Integration test for TThreadedSelectorServer with asynchronous processor.

+ * + *

Tests against libthrift 0.9.2+ due to THRIFT-2274
+ * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

+ * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", + "org.slf4j:slf4j-simple:1.6.6", "org.slf4j:log4j-over-slf4j:1.6.6", "org.slf4j:slf4j-api:1.6.6" }) +public class ThriftThreadedSelectorServerAsyncIT extends EchoTestRunner> { + + @Override + protected ThriftEchoTestServer createEchoServer(TestEnvironment environment) + throws TTransportException { + return AsyncEchoTestServerFactory.threadedSelectorServer(environment); + } + + @Test + public void testSynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final SyncEchoTestClient client = getServer().getSynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + + @Test + public void testAsynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final AsyncEchoTestClient client = getServer().getAsynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/http/ThriftHttpIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/http/ThriftHttpIT.java new file mode 100644 index 000000000000..df3b3b738eb9 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/http/ThriftHttpIT.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it.http; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.client.HttpEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.HttpEchoTestServer; +import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.JvmVersion; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; +import org.apache.thrift.transport.TTransportException; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; + +/** + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@JvmVersion(8) +@Dependency({ "org.apache.thrift:libthrift:[0.9.1,)", "org.eclipse.jetty:jetty-server:9.2.11.v20150529", + "org.slf4j:slf4j-simple:1.6.6", "org.slf4j:log4j-over-slf4j:1.6.6", "org.slf4j:slf4j-api:1.6.6" }) +public class ThriftHttpIT extends EchoTestRunner { + + @Override + protected HttpEchoTestServer createEchoServer(TestEnvironment environment) throws TTransportException { + return HttpEchoTestServer.createServer(environment); + } + + @Test + public void testThriftHttpCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final HttpEchoTestClient client = getServer().getHttpClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftHalfSyncHalfAsyncServerIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftHalfSyncHalfAsyncServerIT.java new file mode 100644 index 000000000000..56016c3ed036 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftHalfSyncHalfAsyncServerIT.java @@ -0,0 +1,78 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it.synchronous; + +import static org.junit.Assert.assertEquals; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.ThriftEchoTestServer; +import org.apache.thrift.server.THsHaServer; +import org.apache.thrift.transport.TTransportException; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; +import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + *

Integration test for THsHaServer with synchronous processor.

+ * + *

Tests against libthrift 0.9.2+ due to THRIFT-2274
+ * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

+ * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", + "org.slf4j:slf4j-simple:1.6.6", "org.slf4j:log4j-over-slf4j:1.6.6", "org.slf4j:slf4j-api:1.6.6" }) +public class ThriftHalfSyncHalfAsyncServerIT extends EchoTestRunner> { + + @Override + protected ThriftEchoTestServer createEchoServer(TestEnvironment environment) throws TTransportException { + return SyncEchoTestServerFactory.halfSyncHalfAsyncServer(environment); + } + + @Test + public void testSynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final SyncEchoTestClient client = getServer().getSynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + + @Test + public void testAsynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final AsyncEchoTestClient client = getServer().getAsynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftNonblockingServerIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftNonblockingServerIT.java new file mode 100644 index 000000000000..4cdd9a152167 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftNonblockingServerIT.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it.synchronous; + +import static org.junit.Assert.assertEquals; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.ThriftEchoTestServer; +import org.apache.thrift.server.TNonblockingServer; +import org.apache.thrift.transport.TTransportException; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; +import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + *

Integration test for TNonblockingServer with synchronous processor.

+ * + *

Tests against libthrift 0.9.2+ due to THRIFT-2274 + * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

+ * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", + "org.slf4j:slf4j-simple:1.6.6", "org.slf4j:log4j-over-slf4j:1.6.6", "org.slf4j:slf4j-api:1.6.6" }) +public class ThriftNonblockingServerIT extends EchoTestRunner> { + + @Override + protected ThriftEchoTestServer createEchoServer(TestEnvironment environment) + throws TTransportException { + return SyncEchoTestServerFactory.nonblockingServer(environment); + } + + @Test + public void testSynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final SyncEchoTestClient client = getServer().getSynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + + @Test + public void testAsynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final AsyncEchoTestClient client = getServer().getAsynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftSimpleServerIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftSimpleServerIT.java new file mode 100644 index 000000000000..a71aef4ed0d6 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftSimpleServerIT.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it.synchronous; + +import static org.junit.Assert.*; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.ThriftEchoTestServer; +import org.apache.thrift.server.TSimpleServer; +import org.apache.thrift.transport.TTransportException; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; +import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + * Integration test for TSimpleServer with synchronous processor. + * + * Tests against libthrift 0.9.1+ + * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.thrift:libthrift:[0.9.1,)", + "org.slf4j:slf4j-simple:1.6.6", "org.slf4j:log4j-over-slf4j:1.6.6", "org.slf4j:slf4j-api:1.6.6" }) +public class ThriftSimpleServerIT extends EchoTestRunner> { + + @Override + protected ThriftEchoTestServer createEchoServer(TestEnvironment environment) throws TTransportException { + return SyncEchoTestServerFactory.simpleServer(environment); + } + + @Test + public void testSynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final SyncEchoTestClient client = getServer().getSynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadPoolServerIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadPoolServerIT.java new file mode 100644 index 000000000000..7216ea4073d8 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadPoolServerIT.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it.synchronous; + +import static org.junit.Assert.assertEquals; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.ThriftEchoTestServer; +import org.apache.thrift.server.TThreadPoolServer; +import org.apache.thrift.transport.TTransportException; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; +import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + * Integration test for TThreadPoolServer with synchronous processor. + * + * Tests against libthrift 0.9.1+ + * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.thrift:libthrift:[0.9.1,)", + "org.slf4j:slf4j-simple:1.6.6", "org.slf4j:log4j-over-slf4j:1.6.6", "org.slf4j:slf4j-api:1.6.6" }) +public class ThriftThreadPoolServerIT extends EchoTestRunner> { + + @Override + protected ThriftEchoTestServer createEchoServer(TestEnvironment environment) + throws TTransportException { + return SyncEchoTestServerFactory.threadedPoolServer(environment); + } + + @Test + public void testSynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final SyncEchoTestClient client = getServer().getSynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + +} diff --git a/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadedSelectorServerIT.java b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadedSelectorServerIT.java new file mode 100644 index 000000000000..c08c3dae00b7 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadedSelectorServerIT.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.it.synchronous; + +import static org.junit.Assert.assertEquals; + +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; +import com.navercorp.pinpoint.plugin.thrift.common.server.ThriftEchoTestServer; +import org.apache.thrift.server.TThreadedSelectorServer; +import org.apache.thrift.transport.TTransportException; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; +import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; +import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; +import com.navercorp.pinpoint.test.plugin.Dependency; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; +import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; + +/** + *

Integration test for TThreadedSelectorServer with synchronous processor.

+ * + *

Tests against libthrift 0.9.2+ due to THRIFT-2274 + * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

+ * + * @author HyunGil Jeong + */ +@RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) +@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", + "org.slf4j:slf4j-simple:1.6.6", "org.slf4j:log4j-over-slf4j:1.6.6", "org.slf4j:slf4j-api:1.6.6" }) +public class ThriftThreadedSelectorServerIT extends EchoTestRunner> { + + @Override + protected ThriftEchoTestServer createEchoServer(TestEnvironment environment) + throws TTransportException { + return SyncEchoTestServerFactory.threadedSelectorServer(environment); + } + + @Test + public void testSynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final SyncEchoTestClient client = getServer().getSynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + + @Test + public void testAsynchronousRpcCall() throws Exception { + // Given + final String expectedMessage = "TEST_MESSAGE"; + // When + final AsyncEchoTestClient client = getServer().getAsynchronousClient(); + final String result = invokeAndVerify(client, expectedMessage); + // Then + assertEquals(expectedMessage, result); + } + +} diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessagePrinter.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessagePrinter.java similarity index 91% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessagePrinter.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessagePrinter.java index 965a700aa083..0b67f7d46f34 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessagePrinter.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessagePrinter.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiveHandler.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiveHandler.java similarity index 93% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiveHandler.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiveHandler.java index e7b52aa551df..43bdae1754d3 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiveHandler.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiveHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiver.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiver.java similarity index 94% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiver.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiver.java index de4407a6e6b8..8faec43ecd05 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiver.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/MessageReceiver.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/PollingMessageReceiver.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/PollingMessageReceiver.java similarity index 97% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/PollingMessageReceiver.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/PollingMessageReceiver.java index 7bae41babcb5..c4dc4606b6ee 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/PollingMessageReceiver.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/activemq/PollingMessageReceiver.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloObservableRepository.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloObservableRepository.java similarity index 97% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloObservableRepository.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloObservableRepository.java index 4f1d833d670d..719c6ad2ffd3 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloObservableRepository.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloObservableRepository.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloRepository.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloRepository.java similarity index 95% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloRepository.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloRepository.java index 637ef77a67da..46c2bd1ebceb 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloRepository.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/hystrix/repository/HelloRepository.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/MessageConverter.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/MessageConverter.java new file mode 100644 index 000000000000..2e23e4056893 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/MessageConverter.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq; + +import java.io.UnsupportedEncodingException; + +/** + * @author HyunGil Jeong + */ +public interface MessageConverter { + T convertMessage(byte[] messageBody); + + MessageConverter FOR_TEST = new MessageConverter() { + @Override + public String convertMessage(byte[] messageBody) { + try { + return new String(messageBody, "UTF-8"); + } catch (UnsupportedEncodingException e) { + return null; + } + } + }; +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/PropagationMarker.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/PropagationMarker.java new file mode 100644 index 000000000000..411a01ba6956 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/PropagationMarker.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq; + +/** + * @author HyunGil Jeong + */ +public class PropagationMarker { + + public void mark() { + // do nothing - this method is solely for checking trace propagation + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/TestConsumer.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/TestConsumer.java new file mode 100644 index 000000000000..3f94faedfeae --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/TestConsumer.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq; + +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.Envelope; + +import java.io.IOException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * @author HyunGil Jeong + */ +public class TestConsumer extends DefaultConsumer { + + private final PropagationMarker marker = new PropagationMarker(); + + private final MessageConverter messageConverter; + + private final BlockingQueue messages = new LinkedBlockingQueue(); + + public TestConsumer(Channel channel, MessageConverter messageConverter) { + super(channel); + if (messageConverter == null) { + throw new NullPointerException("messageConverter must not be null"); + } + this.messageConverter = messageConverter; + } + + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + if (body == null) { + return; + } + marker.mark(); + messages.add(messageConverter.convertMessage(body)); + } + + public T getMessage(long timeoutMs, TimeUnit unit) throws InterruptedException { + return messages.poll(timeoutMs, unit); + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/TestMessagePuller.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/TestMessagePuller.java new file mode 100644 index 000000000000..d37064727b00 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/TestMessagePuller.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.GetResponse; + +import java.io.IOException; + +/** + * @author HyunGil Jeong + */ +public class TestMessagePuller { + + private final Channel channel; + private final PropagationMarker propagationMarker = new PropagationMarker(); + + public TestMessagePuller(Channel channel) { + if (channel == null) { + throw new NullPointerException("channel must not be null"); + } + this.channel = channel; + } + + public T pullMessage(MessageConverter messageConverter, String queueName, boolean autoAck) throws IOException { + GetResponse response = channel.basicGet(queueName, autoAck); + if (response == null) { + return null; + } + propagationMarker.mark(); + byte[] body = response.getBody(); + T message = messageConverter.convertMessage(body); + if (!autoAck) { + channel.basicAck(response.getEnvelope().getDeliveryTag(), false); + } + return message; + } + +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/TestMessageHolder.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/TestMessageHolder.java new file mode 100644 index 000000000000..0b6e44bbbf6e --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/TestMessageHolder.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * @author HyunGil Jeong + */ +public class TestMessageHolder { + + private final BlockingQueue messages = new LinkedBlockingQueue(); + + public void addMessage(String message) { + messages.add(message); + } + + public String getMessage(long timeoutMs, TimeUnit unit) throws InterruptedException { + return messages.poll(timeoutMs, unit); + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/CommonConfig.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/CommonConfig.java new file mode 100644 index 000000000000..a058ff53ec95 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/CommonConfig.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config; + +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.TestMessageHolder; +import org.springframework.amqp.core.AmqpAdmin; +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.DirectExchange; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.rabbit.annotation.EnableRabbit; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitAdmin; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * @author HyunGil Jeong + */ +@Configuration +@EnableRabbit +@ComponentScan("com.navercorp.test.pinpoint.plugin.rabbitmq.spring.service") +public class CommonConfig { + + @Bean(name = "connectionFactory") + public ConnectionFactory connectionFactory() { + com.rabbitmq.client.ConnectionFactory connectionFactory = new com.rabbitmq.client.ConnectionFactory(); + connectionFactory.setHost(RabbitMQTestConstants.BROKER_HOST); + connectionFactory.setPort(RabbitMQTestConstants.BROKER_PORT); + connectionFactory.setSaslConfig(RabbitMQTestConstants.SASL_CONFIG); + connectionFactory.setAutomaticRecoveryEnabled(false); + return new CachingConnectionFactory(connectionFactory); + } + + @Bean + public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) { + return new RabbitAdmin(connectionFactory); + } + + @Bean(name = "testExchange") + public DirectExchange testExchange() { + return new DirectExchange(RabbitMQTestConstants.EXCHANGE, false, false); + } + + @Bean(name = "testPushQueue") + public Queue testPushQueue() { + return new Queue(RabbitMQTestConstants.QUEUE_PUSH, false, false, false); + } + + @Bean(name = "testPullQueue") + public Queue testPullQueue() { + return new Queue(RabbitMQTestConstants.QUEUE_PULL, false, false, false); + } + + @Bean(name = "pushBinding") + public Binding pushBinding() { + return BindingBuilder.bind(testPushQueue()).to(testExchange()).with(RabbitMQTestConstants.ROUTING_KEY_PUSH); + } + + @Bean(name = "pullBinding") + public Binding pullBinding() { + return BindingBuilder.bind(testPullQueue()).to(testExchange()).with(RabbitMQTestConstants.ROUTING_KEY_PULL); + } + + @Bean(name = "rabbitTemplate") + public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { + return new RabbitTemplate(connectionFactory); + } + + @Bean(name = "testMessageHolder") + public TestMessageHolder testMessageHolder() { + return new TestMessageHolder(); + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/MessageListenerConfig_Post_1_4_0.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/MessageListenerConfig_Post_1_4_0.java new file mode 100644 index 000000000000..09b537877116 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/MessageListenerConfig_Post_1_4_0.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config; + +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * @author HyunGil Jeong + */ +@Configuration +@ComponentScan("com.navercorp.test.pinpoint.plugin.rabbitmq.spring.listener") +public class MessageListenerConfig_Post_1_4_0 { + + @Bean(name = "rabbitListenerContainerFactory") + public RabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) { + SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory(); + containerFactory.setConnectionFactory(connectionFactory); + return containerFactory; + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/MessageListenerConfig_Pre_1_4_0.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/MessageListenerConfig_Pre_1_4_0.java new file mode 100644 index 000000000000..c64f92ba04bd --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/MessageListenerConfig_Pre_1_4_0.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config; + +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.handler.TestMessageHandler; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * @author HyunGil Jeong + */ +@Configuration +@ComponentScan("com.navercorp.test.pinpoint.plugin.rabbitmq.spring.handler") +public class MessageListenerConfig_Pre_1_4_0 { + + @Bean + public SimpleMessageListenerContainer listenerContainer(ConnectionFactory connectionFactory, TestMessageHandler testMessageHandler) { + SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); + container.setConnectionFactory(connectionFactory); + container.setQueueNames(RabbitMQTestConstants.QUEUE_PUSH); + container.setMessageListener(new MessageListenerAdapter(testMessageHandler)); + return container; + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/ReceiverConfig_Post_1_6_0.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/ReceiverConfig_Post_1_6_0.java new file mode 100644 index 000000000000..9e7009ad75ee --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/ReceiverConfig_Post_1_6_0.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config; + +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.receiver.TestReceiver; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.receiver.TestReceiver_Post_1_6_0; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author HyunGil Jeong + */ +@Configuration +public class ReceiverConfig_Post_1_6_0 { + + @Bean + public TestReceiver testReceiver(RabbitTemplate rabbitTemplate) { + return new TestReceiver_Post_1_6_0(rabbitTemplate); + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/ReceiverConfig_Pre_1_6_0.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/ReceiverConfig_Pre_1_6_0.java new file mode 100644 index 000000000000..b5299df0dc0c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/config/ReceiverConfig_Pre_1_6_0.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.config; + +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.receiver.TestReceiver; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.receiver.TestReceiver_Pre_1_6_0; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author HyunGil Jeong + */ +@Configuration +public class ReceiverConfig_Pre_1_6_0 { + + @Bean + public TestReceiver testReceiver(RabbitTemplate rabbitTemplate) { + return new TestReceiver_Pre_1_6_0(rabbitTemplate); + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/handler/TestMessageHandler.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/handler/TestMessageHandler.java new file mode 100644 index 000000000000..87ab8bdedefd --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/handler/TestMessageHandler.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.handler; + +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.TestMessageHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author HyunGil Jeong + */ +@Component +public class TestMessageHandler { + + private final PropagationMarker marker = new PropagationMarker(); + private final TestMessageHolder testMessageHolder; + + @Autowired + public TestMessageHandler(TestMessageHolder testMessageHolder) { + if (testMessageHolder == null) { + throw new NullPointerException("testMessageHolder must not be null"); + } + this.testMessageHolder = testMessageHolder; + } + + public void handleMessage(String message) { + marker.mark(); + testMessageHolder.addMessage(message); + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/listener/TestMessageListener.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/listener/TestMessageListener.java new file mode 100644 index 000000000000..fe8889ba83ed --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/listener/TestMessageListener.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.listener; + +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.TestMessageHolder; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author HyunGil Jeong + */ +@Component +public class TestMessageListener { + + private final PropagationMarker marker = new PropagationMarker(); + private final TestMessageHolder testMessageHolder; + + @Autowired + public TestMessageListener(TestMessageHolder testMessageHolder) { + if (testMessageHolder == null) { + throw new NullPointerException("testMessageHolder must not be null"); + } + this.testMessageHolder = testMessageHolder; + } + + @RabbitListener(queues = RabbitMQTestConstants.QUEUE_PUSH) + public void receiveMessage(String message) { + marker.mark(); + testMessageHolder.addMessage(message); + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/receiver/TestReceiver.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/receiver/TestReceiver.java new file mode 100644 index 000000000000..af1bb703bf93 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/receiver/TestReceiver.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.receiver; + +import com.navercorp.test.pinpoint.plugin.rabbitmq.MessageConverter; + +/** + * @author HyunGil Jeong + */ +public interface TestReceiver { + + T receiveMessage(String queueName, MessageConverter messageConverter); + + T receiveMessage(String queueName, MessageConverter messageConverter, long timeoutMs) throws InterruptedException; +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/receiver/TestReceiver_Post_1_6_0.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/receiver/TestReceiver_Post_1_6_0.java new file mode 100644 index 000000000000..0dacbc311e83 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/receiver/TestReceiver_Post_1_6_0.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.receiver; + +import com.navercorp.test.pinpoint.plugin.rabbitmq.MessageConverter; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.core.RabbitTemplate; + +/** + * @author HyunGil Jeong + */ +public class TestReceiver_Post_1_6_0 implements TestReceiver { + + private final RabbitTemplate rabbitTemplate; + + public TestReceiver_Post_1_6_0(RabbitTemplate rabbitTemplate) { + if (rabbitTemplate == null) { + throw new NullPointerException("rabbitTemplate must not be null"); + } + this.rabbitTemplate = rabbitTemplate; + } + + @Override + public T receiveMessage(String queueName, MessageConverter messageConverter) { + Message message = rabbitTemplate.receive(queueName); + return convertMessage(messageConverter, message); + } + + @Override + public T receiveMessage(String queueName, MessageConverter messageConverter, long timeoutMs) throws InterruptedException { + Message message = rabbitTemplate.receive(queueName, timeoutMs); + return convertMessage(messageConverter, message); + } + + private T convertMessage(MessageConverter messageConverter, Message message) { + if (message == null) { + return null; + } + byte[] body = message.getBody(); + return messageConverter.convertMessage(body); + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/receiver/TestReceiver_Pre_1_6_0.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/receiver/TestReceiver_Pre_1_6_0.java new file mode 100644 index 000000000000..ac499be576fd --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/receiver/TestReceiver_Pre_1_6_0.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.receiver; + +import com.navercorp.test.pinpoint.plugin.rabbitmq.MessageConverter; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.core.RabbitTemplate; + +/** + * @author HyunGil Jeong + */ +public class TestReceiver_Pre_1_6_0 implements TestReceiver { + + private final RabbitTemplate rabbitTemplate; + + public TestReceiver_Pre_1_6_0(RabbitTemplate rabbitTemplate) { + if (rabbitTemplate == null) { + throw new NullPointerException("rabbitTemplate must not be null"); + } + this.rabbitTemplate = rabbitTemplate; + } + + @Override + public T receiveMessage(String queueName, MessageConverter messageConverter) { + Message message = rabbitTemplate.receive(queueName); + if (message == null) { + return null; + } + byte[] body = message.getBody(); + return messageConverter.convertMessage(body); + } + + @Override + public T receiveMessage(String queueName, MessageConverter messageConverter, long timeoutMs) throws InterruptedException { + // RabbitTemplate.receive with timeout is only available from 1.6.0+ + // We could instead utilize RabbitTemplate.setReceiveTimeout, but it's just the same thing as above for + // trace verification purposes. + throw new UnsupportedOperationException("receive with timeout not available"); + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/service/TestReceiverService.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/service/TestReceiverService.java new file mode 100644 index 000000000000..ad15b5cc46e9 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/service/TestReceiverService.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.service; + +import com.navercorp.pinpoint.plugin.jdk7.rabbitmq.util.RabbitMQTestConstants; +import com.navercorp.test.pinpoint.plugin.rabbitmq.MessageConverter; +import com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker; +import com.navercorp.test.pinpoint.plugin.rabbitmq.spring.receiver.TestReceiver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author HyunGil Jeong + */ +@Service +public class TestReceiverService { + + private final TestReceiver testReceiver; + private final PropagationMarker propagationMarker; + + @Autowired + public TestReceiverService(TestReceiver testReceiver) { + if (testReceiver == null) { + throw new NullPointerException("testReceiver must not be null"); + } + this.testReceiver = testReceiver; + this.propagationMarker = new PropagationMarker(); + } + + public T receiveMessage(MessageConverter messageConverter) { + T message = testReceiver.receiveMessage(RabbitMQTestConstants.QUEUE_PULL, messageConverter); + if (message == null) { + return null; + } + propagationMarker.mark(); + return message; + } + + public T receiveMessage(MessageConverter messageConverter, long timeoutMs) throws InterruptedException { + T message = testReceiver.receiveMessage(RabbitMQTestConstants.QUEUE_PULL, messageConverter, timeoutMs); + if (message == null) { + return null; + } + propagationMarker.mark(); + return message; + } +} diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/service/TestSenderService.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/service/TestSenderService.java new file mode 100644 index 000000000000..46a4801365a1 --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rabbitmq/spring/service/TestSenderService.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rabbitmq.spring.service; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +/** + * @author HyunGil Jeong + */ +@Service +@Qualifier("testSenderService") +public class TestSenderService { + + @Autowired + private RabbitTemplate rabbitTemplate; + + public void sendMessage(String exchange, String routingKey, String message) { + rabbitTemplate.convertAndSend(exchange, routingKey, message); + } +} diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/repository/EchoRepository.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/repository/EchoRepository.java similarity index 94% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/repository/EchoRepository.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/repository/EchoRepository.java index ace3980ffbff..c860aa23613d 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/repository/EchoRepository.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/repository/EchoRepository.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoService.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoService.java new file mode 100644 index 000000000000..5a67c027dd2c --- /dev/null +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoService.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.plugin.rxjava.service; + +import com.navercorp.test.pinpoint.plugin.rxjava.repository.EchoRepository; +import rx.Single; +import rx.SingleSubscriber; + +/** + * @author HyunGil Jeong + */ +public class EchoService { + + private final EchoRepository echoRepository = new EchoRepository(); + + public Single echo(final String message) { + return Single.create(new Single.OnSubscribe() { + @Override + public void call(SingleSubscriber singleSubscriber) { + if (!singleSubscriber.isUnsubscribed()) { + String echo = echoRepository.echo(message); + singleSubscriber.onSuccess(echo); + } + } + }); + } + + public Single echo(final String message, final Exception expected) { + return Single.create(new Single.OnSubscribe() { + @Override + public void call(SingleSubscriber singleSubscriber) { + try { + if (!singleSubscriber.isUnsubscribed()) { + String echo = echoRepository.echo(message, expected); + singleSubscriber.onSuccess(echo); + } + } catch (Exception e) { + singleSubscriber.onError(e); + } + } + }); + } + +} diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoesService.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoesService.java similarity index 96% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoesService.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoesService.java index 8f9fdd2dcaa2..cde68761e745 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoesService.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoesService.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/ShoutService.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/ShoutService.java similarity index 94% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/ShoutService.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/ShoutService.java index 6c3215149960..51e34c980d8d 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/ShoutService.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/ShoutService.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/AbstractAutowireCapableBeanFactoryModifierIT.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/AbstractAutowireCapableBeanFactoryModifierIT.java similarity index 94% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/AbstractAutowireCapableBeanFactoryModifierIT.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/AbstractAutowireCapableBeanFactoryModifierIT.java index dcd8d1d05546..bf47a0d6632c 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/AbstractAutowireCapableBeanFactoryModifierIT.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/AbstractAutowireCapableBeanFactoryModifierIT.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,8 @@ package com.navercorp.test.pinpoint.plugin.spring.beans; +import com.navercorp.pinpoint.plugin.AgentPath; +import com.navercorp.pinpoint.test.plugin.PinpointAgent; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.context.ApplicationContext; @@ -29,6 +31,7 @@ import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; @RunWith(PinpointPluginTestSuite.class) +@PinpointAgent(AgentPath.PATH) @Dependency({"org.springframework:spring-context:[3.0.7.RELEASE],[3.1.4.RELEASE],[3.2.14.RELEASE],[4.0.9.RELEASE],[4.1.7.RELEASE],[4.2.0.RELEASE,)", "cglib:cglib-nodep:3.1"}) @PinpointConfig("pinpoint-spring-bean-test.config") public class AbstractAutowireCapableBeanFactoryModifierIT { diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Excluded.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Excluded.java similarity index 89% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Excluded.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Excluded.java index 8b7b61e07ce9..47f7421f8449 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Excluded.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Excluded.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Inner.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Inner.java similarity index 89% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Inner.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Inner.java index 56f6ca42cf16..055da9fa4337 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Inner.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Inner.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Maru.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Maru.java similarity index 94% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Maru.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Maru.java index 279446cd9004..0877cd64a9b7 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Maru.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Maru.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Morae.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Morae.java similarity index 88% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Morae.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Morae.java index 8af5f38e7e18..fa50128db7d2 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Morae.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Morae.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Mozzi.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Mozzi.java similarity index 89% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Mozzi.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Mozzi.java index 8f7c0d532f03..7da109b2dd85 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Mozzi.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Mozzi.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Outer.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Outer.java similarity index 91% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Outer.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Outer.java index aad725167a9b..ee1be3b4908e 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Outer.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/Outer.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/ProxyTarget.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/ProxyTarget.java similarity index 89% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/ProxyTarget.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/ProxyTarget.java index 8329dc8b81b3..504f7f2371d8 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/ProxyTarget.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/ProxyTarget.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/TestAdvisor.java b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/TestAdvisor.java similarity index 96% rename from agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/TestAdvisor.java rename to agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/TestAdvisor.java index 7a3004ee2f34..9d8928e9284d 100644 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/TestAdvisor.java +++ b/agent-it/src/test/java/com/navercorp/test/pinpoint/plugin/spring/beans/TestAdvisor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/agent-it/src/test/proto/hello_streaming.proto b/agent-it/src/test/proto/hello_streaming.proto new file mode 100644 index 000000000000..325b9093b0c4 --- /dev/null +++ b/agent-it/src/test/proto/hello_streaming.proto @@ -0,0 +1,37 @@ +// Copyright 2015 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.manualflowcontrol"; +option java_outer_classname = "HelloStreamingProto"; +option objc_class_prefix = "HLWS"; + +package manualflowcontrol; + +// The greeting service definition. +service StreamingGreeter { + // Streams a many greetings + rpc SayHelloStreaming (stream HelloRequest) returns (stream HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/agent-it/src/test/proto/helloworld.proto b/agent-it/src/test/proto/helloworld.proto new file mode 100644 index 000000000000..c60d9416f1fc --- /dev/null +++ b/agent-it/src/test/proto/helloworld.proto @@ -0,0 +1,37 @@ +// Copyright 2015 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.helloworld"; +option java_outer_classname = "HelloWorldProto"; +option objc_class_prefix = "HLW"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/agent/src/test/resources/activemq/client/pinpoint-activemq-client.config b/agent-it/src/test/resources/activemq/client/pinpoint-activemq-client.config similarity index 100% rename from agent/src/test/resources/activemq/client/pinpoint-activemq-client.config rename to agent-it/src/test/resources/activemq/client/pinpoint-activemq-client.config diff --git a/agent/src/test/resources/cassandra/cassandra_2_0_x.yaml b/agent-it/src/test/resources/cassandra/cassandra_2_0_x.yaml similarity index 100% rename from agent/src/test/resources/cassandra/cassandra_2_0_x.yaml rename to agent-it/src/test/resources/cassandra/cassandra_2_0_x.yaml diff --git a/agent/src/test/resources/cassandra/cassandra_2_1_x.yaml b/agent-it/src/test/resources/cassandra/cassandra_2_1_x.yaml similarity index 100% rename from agent/src/test/resources/cassandra/cassandra_2_1_x.yaml rename to agent-it/src/test/resources/cassandra/cassandra_2_1_x.yaml diff --git a/agent/src/test/resources/cassandra/cassandra_2_2_x.yaml b/agent-it/src/test/resources/cassandra/cassandra_2_2_x.yaml similarity index 100% rename from agent/src/test/resources/cassandra/cassandra_2_2_x.yaml rename to agent-it/src/test/resources/cassandra/cassandra_2_2_x.yaml diff --git a/agent/src/test/resources/cassandra/cassandra_3_0_x.yaml b/agent-it/src/test/resources/cassandra/cassandra_3_0_x.yaml similarity index 100% rename from agent/src/test/resources/cassandra/cassandra_3_0_x.yaml rename to agent-it/src/test/resources/cassandra/cassandra_3_0_x.yaml diff --git a/agent-it/src/test/resources/cxf/pinpoint-cxf-test.config b/agent-it/src/test/resources/cxf/pinpoint-cxf-test.config new file mode 100644 index 000000000000..9e9931209753 --- /dev/null +++ b/agent-it/src/test/resources/cxf/pinpoint-cxf-test.config @@ -0,0 +1,864 @@ +# +# Pinpoint agent configuration +# + +########################################################### +# Collector server # +########################################################### +profiler.collector.ip=127.0.0.1 + +# placeHolder support "${key}" +profiler.collector.span.ip=${profiler.collector.ip} +profiler.collector.span.port=9996 + +# placeHolder support "${key}" +profiler.collector.stat.ip=${profiler.collector.ip} +profiler.collector.stat.port=9995 + +# placeHolder support "${key}" +profiler.collector.tcp.ip=${profiler.collector.ip} +profiler.collector.tcp.port=9994 + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +# Application namespace +# Differentiate from external pinpoint agents. (e.g., com.pinpoint) +profiler.application.namespace= + +profiler.interceptorregistry.size=8192 + +# Manually override jvm vendor name (Oracle, IBM, OpenJDK, etc) +# You probably won't ever need to set this value. +profiler.jvm.vendor.name= + +# Manually override agent's OS name (MAC, Window, Linus, AIX, HP_UX, BSD) +# You probably won't ever need to set this value.(to collect file descriptor) +profiler.os.name= + +# Interval (in milliseconds) at which agent stat data is collected. (default : 5000, min : 1000, max : 5000) +profiler.jvm.stat.collect.interval=5000 +# Number of agent stat data sent to the collector in a single batch. (default : 6) +profiler.jvm.stat.batch.send.count=6 + +# Allow to add detailed collector's metrics +profiler.jvm.stat.collect.detailed.metrics=true + +# Allow sampling. +profiler.sampling.enable=true + +# 1 out of n transactions will be sampled where n is the rate. (1: 100%) +profiler.sampling.rate=1 + +# Allow buffering when flushing span to IO. +profiler.io.buffering.enable=true + +# How many spans to store if buffering enabled. +profiler.io.buffering.buffersize=20 + +# Capacity of the SpanDataSender write queue. +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 +profiler.spandatasender.chunk.size=16384 +profiler.spandatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.spandatasender.transport.type=UDP + +# Capacity of the StatDataSender write queue. +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 +profiler.statdatasender.chunk.size=16384 +profiler.statdatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.statdatasender.transport.type=UDP + +# Interval to retry sending agent info. Unit is milliseconds. +profiler.agentInfo.send.retry.interval=300000 + +# Allow TCP data command. +profiler.tcpdatasender.command.accept.enable=true +profiler.tcpdatasender.command.activethread.enable=true +profiler.tcpdatasender.command.activethread.count.enable=true +profiler.tcpdatasender.command.activethread.threaddump.enable=true +profiler.tcpdatasender.command.activethread.threadlightdump.enable=true + +profiler.tcpdatasender.client.write.timeout=3000 +profiler.tcpdatasender.client.request.timeout=3000 +profiler.tcpdatasender.client.reconnect.interval=3000 +profiler.tcpdatasender.client.ping.interval=300000 +profiler.tcpdatasender.client.handshake.interval=60000 + +# Trace Agent active thread info. +profiler.pinpoint.activethread=true + +# Trace DataSource +profiler.pinpoint.datasource=true + +# Deadlock Monitor +profiler.monitor.deadlock.enable=true +profiler.monitor.deadlock.interval=60000 + +## Call Stack +# Set max depth, if -1 is unlimited and min is 2. +profiler.callstack.max.depth=64 + +# weather or not to propagate exceptions occurred at interceptor +profiler.interceptor.exception.propagate=false + +# Allow bytecode framework (JAVASSIST or ASM) +profiler.instrument.engine=ASM + +# bytecode dump option +# java bytecode debug option +bytecode.dump.enable=false +#bytecode.dump.classlist=com.naver.user.UserService,com.pinpoint.debug.TestClass +bytecode.dump.classlist= +bytecode.dump.bytecode=false +bytecode.dump.verify=false +bytecode.dump.asm=false + +# Matcher +profiler.instrument.matcher.enable=true +# Matcher cache. max size is 64. +profiler.instrument.matcher.interface.cache.size=4 +profiler.instrument.matcher.interface.cache.entry.size=16 +profiler.instrument.matcher.annotation.cache.size=4 +profiler.instrument.matcher.annotation.cache.entry.size=4 +profiler.instrument.matcher.super.cache.size=4 +profiler.instrument.matcher.super.cache.entry.size=4 + +# Lambda expressions. +profiler.lambda.expressions.support=true + +# Proxy HTTP headers. +# Please see (https://github.com/naver/pinpoint/blob/master/doc/proxy-http-header.md) for more information. +profiler.proxy.http.header.enable=true + +# HTTP status code with request failure. +# 1xx, 2xx, 3xx, 4xx, 5xx, 100, 101, 200, 201, ... 501, 502, 503, 504, 505 +# e.g. profiler.http.status.code.errors=5xx, 401, 403 +profiler.http.status.code.errors=5xx + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + +########################################################### +# application type detect order # +########################################################### +profiler.type.detect.order= + +profiler.plugin.disable= + +########################################################### +# user defined classes # +########################################################### +# Specify classes and methods you want to profile here. + +# Needs to be a comma separated list of fully qualified class names, or fully qualified package names with wild card class. +profiler.include= +# Ex: foo.bar.MyClass, foo.baz.* + +# Needs to be a comma separated list of fully qualified method names. Wild card not supported. +profiler.entrypoint= +# Ex: foo.bar.MyClass.myMethod, foo.bar.MyClass.anotherMethod + +# Message queue listener invoker methods. +# This is usually for when a separate implementation or a framework provides a separate handler for invoking callbacks +# when consuming messages. +# Comma-separated list of fully qualified method names with a Message argument. +profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener,org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener + +########################################################### +# TOMCAT # +########################################################### +profiler.tomcat.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap +# Check pre-conditions when registering class file transformers mainly due to JBoss plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.apache.catalina.startup.Bootstrap, +# or SpringBoot's launchers. +# Set this to false to bypass this check entirely (such as when launching standalone applications running embedded Tomcat). +profiler.tomcat.conditional.transform=true +# Hide pinpoint headers. +profiler.tomcat.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html +# HTTP Request methods to exclude from tracing +#profiler.tomcat.excludemethod= +profiler.tomcat.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.tomcat.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.tomcat.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.tomcat.realipemptyvalue}, Ignore header value. +#profiler.tomcat.realipemptyvalue=unknown + + +########################################################### +# JETTY # +########################################################### +profiler.jetty.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.jetty.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jetty.excludemethod= +# Hide pinpoint headers. +profiler.jetty.hide-pinpoint-header=true +profiler.jetty.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jetty.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jetty.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jetty.realipemptyvalue}, Ignore header value. +#profiler.jetty.realipemptyvalue=unknown + +########################################################### +# DUBBO # +########################################################### +profiler.dubbo.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.dubbo.bootstrap.main=com.alibaba.dubbo.container.Main + + +########################################################### +# JBOSS # +########################################################### +profiler.jboss.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jboss.bootstrap.main=org.jboss.modules.Main +# Check pre-conditions when registering class file transformers mainly due to Tomcat plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.jboss.modules.Main. +# Set this to false to bypass this check entirely. +profiler.jboss.conditional.transform=true +# Hide pinpoint headers. +profiler.jboss.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.jboss.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jboss.excludemethod= +profiler.jboss.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jboss.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jboss.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. +#profiler.jboss.realipemptyvalue=unknown + +########################################################### +# Resin +########################################################### +# default enable resin plugin +profiler.resin.enable=true +# if empty , default value is : com.caucho.server.resin.Resin +profiler.resin.bootstrap.main= +# trace param in request ,default value is true +profiler.resin.tracerequestparam=true +# excudeurl eg: filter static resources : /**/*.jpg,/**/*.png,/**/*.css,/**/*.js +profiler.resin.excludeurl= +# Hide pinpoint headers. +profiler.resin.hidepinpointheader=true +# HTTP Request methods to exclude from tracing +#profiler.resin.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.resin.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.resin.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.resin.realipemptyvalue}, Ignore header value. +#profiler.resin.realipemptyvalue=unknown + +########################################################### +# Weblogic +########################################################### +profiler.weblogic.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.weblogic.bootstrap.main=weblogic.Server +# trace param in request ,default value is true +profiler.weblogic.tracerequestparam=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.weblogic.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.weblogic.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.weblogic.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.weblogic.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.weblogic.realipemptyvalue}, Ignore header value. +#profiler.weblogic.realipemptyvalue=unknown + + +########################################################### +# Vert.x(Reliability and stability can not be guaranteed) # +########################################################### +profiler.vertx.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.vertx.bootstrap.main=io.vertx.core.Starter +# Track Vertx.runOnContext() & Vertx.executeBlocking(). +# Sets the base packages that implements io.vertx.core.Handler. +# Improvement is in progress. +profiler.vertx.handler.base-packages= +# e.g. com.service.handler, com.server.http.handler + +# HTTP server +profiler.vertx.http.server.enable=true +# Set HttpServerRequestHandler method name. The argument is io.vertx.core.http.HttpServerRequest. +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept +profiler.vertx.http.server.tracerequestparam=true +profiler.vertx.http.server.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.vertx.http.server.excludeurl= +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.vertx.http.server.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.vertx.http.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.vertx.http.server.realipemptyvalue}, Ignore header value. +#profiler.vertx.http.server.realipemptyvalue=unknown +# HTTP Request methods to exclude from tracing +#profiler.vertx.http.server.excludemethod= + +# HTTP client +profiler.vertx.http.client.enable=true +profiler.vertx.http.client.param=true +profiler.vertx.http.client.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.vertx.http.client.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.vertx.http.client.cookie.sampling.rate=1 +profiler.vertx.http.client.entity.statuscode=true + +########################################################### +# Undertow +########################################################### +profiler.undertow.enable=true +# trace param in request ,default value is true +profiler.undertow.tracerequestparam=true +# Hide pinpoint headers. +profiler.undertow.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.undertow.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.undertow.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.undertow.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.undertow.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.undertow.realipemptyvalue}, Ignore header value. +#profiler.undertow.realipemptyvalue=unknown + +########################################################### +# SPRING BOOT # +########################################################### +profiler.springboot.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.springboot.bootstrap.main=org.springframework.boot.loader.JarLauncher, org.springframework.boot.loader.WarLauncher, org.springframework.boot.loader.PropertiesLauncher + +########################################################### +# JSP # +########################################################### +profiler.jsp.enable=true + +########################################################### +# JDBC # +########################################################### +# Profile JDBC drivers. +profiler.jdbc=true +# Size of cache. Fixed maximum. +profiler.jdbc.sqlcachesize=1024 +# trace bindvalues for PreparedStatements +profiler.jdbc.tracesqlbindvalue=true +# Maximum bindvalue size. +profiler.jdbc.maxsqlbindvaluesize=1024 + +# +# MYSQL +# +# Profile MySQL. +profiler.jdbc.mysql=true +# Allow profiling of setautocommit. +profiler.jdbc.mysql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mysql.commit=true +# Allow profiling of rollback. +profiler.jdbc.mysql.rollback=true +# Trace bindvalues for MySQL PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mysql.tracesqlbindvalue=true + +# +# MARIADB +# +# Profile MariaDB +profiler.jdbc.mariadb=true +# Allow profiling of setautocommit. +profiler.jdbc.mariadb.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mariadb.commit=true +# Allow profiling of rollback. +profiler.jdbc.mariadb.rollback=true +# Trace bindvalues for MariaDB PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mariadb.tracesqlbindvalue=true + +# +# MSSQL Jtds +# +# Profile jTDS. +profiler.jdbc.jtds=true +# Allow profiling of setautocommit. +profiler.jdbc.jtds.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.jtds.commit=true +# Allow profiling of rollback. +profiler.jdbc.jtds.rollback=true +# Trace bindvalues for jTDS PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.jtds.tracesqlbindvalue=true + +# +# Oracle +# +# Profile Oracle DB. +profiler.jdbc.oracle=true +# Allow profiling of setautocommit. +profiler.jdbc.oracle.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.oracle.commit=true +# Allow profiling of rollback. +profiler.jdbc.oracle.rollback=true +# Trace bindvalues for Oracle PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.oracle.tracesqlbindvalue=true + +# +# CUBRID +# +# Profile CUBRID. +profiler.jdbc.cubrid=true +# Allow profiling of setautocommit. +profiler.jdbc.cubrid.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.cubrid.commit=true +# Allow profiling of rollback. +profiler.jdbc.cubrid.rollback=true +# Trace bindvalues for CUBRID PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.cubrid.tracesqlbindvalue=true + +# +# DBCP +# +# Profile DBCP. +profiler.jdbc.dbcp=true +profiler.jdbc.dbcp.connectionclose=true + +# +# DBCP2 +# +# Profile DBCP2. +profiler.jdbc.dbcp2=true +profiler.jdbc.dbcp2.connectionclose=true + +# +# HIKARICP +# +profiler.jdbc.hikaricp=true +profiler.jdbc.hikaricp.connectionclose=true + +# +# CASSANDRA +# +# Profile CASSANDRA. +profiler.cassandra=true +# Trace bindvalues for CASSANDRA PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.cassandra.tracecqlbindvalue=true + +# +# PostgreSQL +# +# Profile PostgreSQL. +profiler.jdbc.postgresql=true +# Allow profiling of setautocommit. +profiler.jdbc.postgresql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.postgresql.commit=true +# Allow profiling of rollback. +profiler.jdbc.postgresql.rollback=true + +########################################################### +# MONGODB +########################################################### +profiler.mongo=true +profiler.mongo.collectJson=true + +########################################################### +# Apache HTTP Client 3.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient3.param=true + +# Record Cookies. +profiler.apache.httpclient3.cookie=true + +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient3.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient3.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.entity.dumptype=ALWAYS +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient3.entity.sampling.rate=1 + +# Record IO time. +profiler.apache.httpclient3.io=true + +########################################################### +# Apache HTTP Client 4.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient4.param=true + +# Record cookies. +profiler.apache.httpclient4.cookie=true + +# When cookies should be dumped. It could be ALWAYS or EXCEPTION. +profiler.apache.httpclient4.cookie.dumptype=ALWAYS + +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient4.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient4.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient4.entity.dumptype=ALWAYS + +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient4.entity.sampling.rate=1 + +# Allow profiling status code value. +profiler.apache.httpclient4.entity.statuscode=true + +# Record IO time. +profiler.apache.httpclient4.io=true + +# Not supported yet. +#profiler.apache.nio.httpclient4=true + +########################################################### +# JDK HTTPURLConnection # +########################################################### +# Profile parameter. +profiler.jdk.http.param=true + +########################################################### +# Ning Async HTTP Client # +########################################################### +# Profile Ning Async HTTP Client. +profiler.ning.asynchttpclient=true +# Record cookies. +profiler.ning.asynchttpclient.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS +# Cookie dump size. +profiler.ning.asynchttpclient.cookie.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.cookie.sampling.rate=1 +# Record Entities. +profiler.ning.asynchttpclient.entity=true +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.entity.dumptype=ALWAYS +# Entity dump size. +profiler.ning.asynchttpclient.entity.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.entity.sampling.rate=1 +# Record parameters. (unsupported in 1.8.x, 1.9.x versions) +profiler.ning.asynchttpclient.param=true +# When to dump parameters. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.param.dumptype=ALWAYS +# Parameter dump size. +profiler.ning.asynchttpclient.param.dumpsize=1024 +# 1 out of n parameters will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.param.sampling.rate=1 + + +########################################################### +# Arcus # +########################################################### +# Profile Arcus. +profiler.arcus=true +profiler.arcus.async=true +# Record keytrace. +profiler.arcus.keytrace=true + +########################################################### +# Memcached # +########################################################### +# Profile Memecached. +profiler.memcached=true +profiler.memcached.async=true +# Record keytrace +profiler.memcached.keytrace=true + +########################################################### +# Thrift # +########################################################### +# Profile Thrift +profiler.thrift.client=true +profiler.thrift.client.async=true +# Profile processor. +profiler.thrift.processor=true +profiler.thrift.processor.async=true +# Allow recording arguments. +profiler.thrift.service.args=true +# Allow recording result. +profiler.thrift.service.result=true + + +########################################################### +# ibatis # +########################################################### +# Profile ibatis. +profiler.orm.ibatis=true + +########################################################### +# mybatis # +########################################################### +# Profile mybatis +profiler.orm.mybatis=true + +########################################################### +# spring-beans +########################################################### +# Profile spring-beans +profiler.spring.beans=true + +# filters +# filter +# filter OR filters +# filter +# value +# value AND filter +# value +# token +# token OR token +# token +# profiler.spring.beans.n.scope= [component-scan | post-processor] default is component-scan. +# profiler.spring.beans.n.base-packages= [package name, ...] +# profiler.spring.beans.n.name.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.class.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.annotation= [annotation name, ...] +# +# Scope: +# component-scan: or @ComponentScan +# post-processor: BeanPostProcessor - Slow!!! +# +# ANT Style pattern rules: +# ? - matches on character +# * - matches zero or more characters +# ** - matches zero or more 'directories' in a path + +# Examples +# profiler.spring.beans.1.scope=component-scan +# profiler.spring.beans.1.base-packages=com.foo, com.bar +# profiler.spring.beans.1.name.pattern=.*Foo, regex:.*Bar, antstyle:*Controller +# profiler.spring.beans.1.class.pattern= +# profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository +# +# profiler.spring.beans.2.scope=post-processor +# profiler.spring.beans.2.base-packages=com.foo +# profiler.spring.beans.2.name.pattern= +# profiler.spring.beans.2.class.pattern=antstyle:com.foo.repository.*Repository, antstyle:com.foo.Service.Main* +# profiler.spring.beans.2.annotation= + +profiler.spring.beans.1.scope=component-scan +profiler.spring.beans.1.base-packages= +profiler.spring.beans.1.name.pattern= +profiler.spring.beans.1.class.pattern= +profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository + +profiler.spring.beans.mark.error=false + +########################################################### +# spring @Async +########################################################### +profiler.spring.async.enable=true +# Add custom AsyncTaskExecutor classes. Comma separated list of fully qualified class names. Wildcard not supported. +# Default values +# org.springframework.scheduling.concurrent.ConcurrentTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.core.task.SimpleAsyncTaskExecutor +# org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor +# org.springframework.core.task.support.TaskExecutorAdapter +# org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.jca.work.WorkManagerTaskExecutor +# org.springframework.scheduling.commonj.WorkManagerTaskExecutor +profiler.spring.async.executor.class.names= + +########################################################### +# log4j (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.log4j.logging.transactioninfo=false + +########################################################### +# logback (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.logback.logging.transactioninfo=false + +########################################################### +# google httpclient +########################################################### +# Profile async. +profiler.google.httpclient.async=true + +########################################################### +# redis +########################################################### +profiler.redis.pipeline +profiler.redis=true +profiler.redis.io=true + +########################################################### +# OkHttp +########################################################### +profiler.okhttp.enable=true +# Record param. +profiler.okhttp.param=true + +# Record Cookies. +profiler.okhttp.cookie=false +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.okhttp.cookie.dumptype=EXCEPTION +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.okhttp.cookie.sampling.rate=1 +# enqueue operation +profiler.okhttp.async=true + +########################################################### +# Apache CXF +########################################################### +profiler.cxf.service.enable=true +profiler.cxf.logging.enable=true +#profiler.cxf.client=true +#profiler.cxf.client.hiddenParams= + +########################################################### +# gson +########################################################### +profiler.json.gson=true + +########################################################### +# jackson +########################################################### +profiler.json.jackson=true + +########################################################### +# json-lib +########################################################### +profiler.json.jsonlib=true + +########################################################### +# ActiveMQ Client +########################################################### +profiler.activemq.client.enable=true +profiler.activemq.client.producer.enable=true +profiler.activemq.client.consumer.enable=true +profiler.activemq.client.trace.message=false + +# ActiveMQ destination path separator (default is ".") +profiler.activemq.client.destination.separator= + +# ActiveMQ destinations to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.activemq.client.destination.exclude= + +########################################################### +# RxJava +########################################################### +profiler.rxjava=true + +########################################################### +# Hystrix +########################################################### +# profiler.rxjava must also be enabled to properly trace hystrix commands +profiler.hystrix=true + +########################################################### +# RestTemplate +########################################################### +profiler.resttemplate=false + +########################################################### +# Netty +########################################################### +# recommend netty plugin disable, when using VERTX. +profiler.netty=false +profiler.netty.http=false + +########################################################### +# RabbitMQ Client +########################################################### +profiler.rabbitmq.client.enable=true +profiler.rabbitmq.client.producer.enable=true +profiler.rabbitmq.client.consumer.enable=true +# Custom consumer classes to be traced (comma separated list of fully qualified class names) +# If a consumer class is an inner class, specify the outer class +profiler.rabbitmq.client.consumer.classes= +# RabbitMQ exchange to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.rabbitmq.client.exchange.exclude= + +########################################################### +# Akka HTTP (Reliability and stability can not be guaranteed) +########################################################### +# HTTP server +profiler.akka.http.enable=false +# original IP address header +profiler.akka.http.realipheader=Remote-Address +# URLs to exclude from tracing +profiler.akka.http.excludeurl= +# HTTP Request methods to exclude from tracing +profiler.akka.http.excludemethod= +# Set transform target +# If you are using another directive, change below config +profiler.akka.http.transform.targetname=akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRequestContext$2 +profiler.akka.http.transform.targetparameter=scala.Function1,scala.Function1,akka.http.scaladsl.server.RequestContext + +########################################################### +# Kafka (Reliability and stability can not be guaranteed) +# Version 0.11+ is supported. +# Note: RemoteTrace will not occur if the method specified in the profiler.kafka.consumer.entryPoint is not the first trace point. +########################################################### +profiler.kafka.producer.enable=false +profiler.kafka.consumer.enable=false +// you must set target that handles ConsumerRecord as a argument for remote trace +// ex) profiler.kafka.entryPoint=clazzName.methodName +profiler.kafka.consumer.entryPoint= \ No newline at end of file diff --git a/agent-it/src/test/resources/druid/pinpoint-druid-test.config b/agent-it/src/test/resources/druid/pinpoint-druid-test.config new file mode 100644 index 000000000000..9e2a916456f3 --- /dev/null +++ b/agent-it/src/test/resources/druid/pinpoint-druid-test.config @@ -0,0 +1,862 @@ +# +# Pinpoint agent configuration +# + +########################################################### +# Collector server # +########################################################### +profiler.collector.ip=127.0.0.1 + +# placeHolder support "${key}" +profiler.collector.span.ip=${profiler.collector.ip} +profiler.collector.span.port=9996 + +# placeHolder support "${key}" +profiler.collector.stat.ip=${profiler.collector.ip} +profiler.collector.stat.port=9995 + +# placeHolder support "${key}" +profiler.collector.tcp.ip=${profiler.collector.ip} +profiler.collector.tcp.port=9994 + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +# Application namespace +# Differentiate from external pinpoint agents. (e.g., com.pinpoint) +profiler.application.namespace= + +profiler.interceptorregistry.size=8192 + +# Manually override jvm vendor name (Oracle, IBM, OpenJDK, etc) +# You probably won't ever need to set this value. +profiler.jvm.vendor.name= + +# Manually override agent's OS name (MAC, Window, Linus, AIX, HP_UX, BSD) +# You probably won't ever need to set this value.(to collect file descriptor) +profiler.os.name= + +# Interval (in milliseconds) at which agent stat data is collected. (default : 5000, min : 1000, max : 5000) +profiler.jvm.stat.collect.interval=5000 +# Number of agent stat data sent to the collector in a single batch. (default : 6) +profiler.jvm.stat.batch.send.count=6 + +# Allow to add detailed collector's metrics +profiler.jvm.stat.collect.detailed.metrics=true + +# Allow sampling. +profiler.sampling.enable=true + +# 1 out of n transactions will be sampled where n is the rate. (1: 100%) +profiler.sampling.rate=1 + +# Allow buffering when flushing span to IO. +profiler.io.buffering.enable=true + +# How many spans to store if buffering enabled. +profiler.io.buffering.buffersize=20 + +# Capacity of the SpanDataSender write queue. +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 +profiler.spandatasender.chunk.size=16384 +profiler.spandatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.spandatasender.transport.type=UDP + +# Capacity of the StatDataSender write queue. +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 +profiler.statdatasender.chunk.size=16384 +profiler.statdatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.statdatasender.transport.type=UDP + +# Interval to retry sending agent info. Unit is milliseconds. +profiler.agentInfo.send.retry.interval=300000 + +# Allow TCP data command. +profiler.tcpdatasender.command.accept.enable=true +profiler.tcpdatasender.command.activethread.enable=true +profiler.tcpdatasender.command.activethread.count.enable=true +profiler.tcpdatasender.command.activethread.threaddump.enable=true +profiler.tcpdatasender.command.activethread.threadlightdump.enable=true + +profiler.tcpdatasender.client.write.timeout=3000 +profiler.tcpdatasender.client.request.timeout=3000 +profiler.tcpdatasender.client.reconnect.interval=3000 +profiler.tcpdatasender.client.ping.interval=300000 +profiler.tcpdatasender.client.handshake.interval=60000 + +# Trace Agent active thread info. +profiler.pinpoint.activethread=true + +# Trace DataSource +profiler.pinpoint.datasource=true + +# Deadlock Monitor +profiler.monitor.deadlock.enable=true +profiler.monitor.deadlock.interval=60000 + +## Call Stack +# Set max depth, if -1 is unlimited and min is 2. +profiler.callstack.max.depth=64 + +# weather or not to propagate exceptions occurred at interceptor +profiler.interceptor.exception.propagate=false + +# Allow bytecode framework (JAVASSIST or ASM) +profiler.instrument.engine=ASM + +# bytecode dump option +# java bytecode debug option +bytecode.dump.enable=false +#bytecode.dump.classlist=com.naver.user.UserService,com.pinpoint.debug.TestClass +bytecode.dump.classlist= +bytecode.dump.bytecode=false +bytecode.dump.verify=false +bytecode.dump.asm=false + +# Matcher +profiler.instrument.matcher.enable=true +# Matcher cache. max size is 64. +profiler.instrument.matcher.interface.cache.size=4 +profiler.instrument.matcher.interface.cache.entry.size=16 +profiler.instrument.matcher.annotation.cache.size=4 +profiler.instrument.matcher.annotation.cache.entry.size=4 +profiler.instrument.matcher.super.cache.size=4 +profiler.instrument.matcher.super.cache.entry.size=4 + +# Lambda expressions. +profiler.lambda.expressions.support=true + +# Proxy HTTP headers. +# Please see (https://github.com/naver/pinpoint/blob/master/doc/proxy-http-header.md) for more information. +profiler.proxy.http.header.enable=true + +# HTTP status code with request failure. +# 1xx, 2xx, 3xx, 4xx, 5xx, 100, 101, 200, 201, ... 501, 502, 503, 504, 505 +# e.g. profiler.http.status.code.errors=5xx, 401, 403 +profiler.http.status.code.errors=5xx + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + +########################################################### +# application type detect order # +########################################################### +profiler.type.detect.order= + +profiler.plugin.disable= + +########################################################### +# user defined classes # +########################################################### +# Specify classes and methods you want to profile here. + +# Needs to be a comma separated list of fully qualified class names, or fully qualified package names with wild card class. +profiler.include= +# Ex: foo.bar.MyClass, foo.baz.* + +# Needs to be a comma separated list of fully qualified method names. Wild card not supported. +profiler.entrypoint= +# Ex: foo.bar.MyClass.myMethod, foo.bar.MyClass.anotherMethod + +# Message queue listener invoker methods. +# This is usually for when a separate implementation or a framework provides a separate handler for invoking callbacks +# when consuming messages. +# Comma-separated list of fully qualified method names with a Message argument. +profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener,org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener + +########################################################### +# TOMCAT # +########################################################### +profiler.tomcat.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap +# Check pre-conditions when registering class file transformers mainly due to JBoss plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.apache.catalina.startup.Bootstrap, +# or SpringBoot's launchers. +# Set this to false to bypass this check entirely (such as when launching standalone applications running embedded Tomcat). +profiler.tomcat.conditional.transform=true +# Hide pinpoint headers. +profiler.tomcat.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html +# HTTP Request methods to exclude from tracing +#profiler.tomcat.excludemethod= +profiler.tomcat.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.tomcat.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.tomcat.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.tomcat.realipemptyvalue}, Ignore header value. +#profiler.tomcat.realipemptyvalue=unknown + + +########################################################### +# JETTY # +########################################################### +profiler.jetty.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.jetty.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jetty.excludemethod= +# Hide pinpoint headers. +profiler.jetty.hide-pinpoint-header=true +profiler.jetty.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jetty.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jetty.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jetty.realipemptyvalue}, Ignore header value. +#profiler.jetty.realipemptyvalue=unknown + +########################################################### +# DUBBO # +########################################################### +profiler.dubbo.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.dubbo.bootstrap.main=com.alibaba.dubbo.container.Main + + +########################################################### +# JBOSS # +########################################################### +profiler.jboss.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jboss.bootstrap.main=org.jboss.modules.Main +# Check pre-conditions when registering class file transformers mainly due to Tomcat plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.jboss.modules.Main. +# Set this to false to bypass this check entirely. +profiler.jboss.conditional.transform=true +# Hide pinpoint headers. +profiler.jboss.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.jboss.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jboss.excludemethod= +profiler.jboss.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jboss.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jboss.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. +#profiler.jboss.realipemptyvalue=unknown + +########################################################### +# Resin +########################################################### +# default enable resin plugin +profiler.resin.enable=true +# if empty , default value is : com.caucho.server.resin.Resin +profiler.resin.bootstrap.main= +# trace param in request ,default value is true +profiler.resin.tracerequestparam=true +# excudeurl eg: filter static resources : /**/*.jpg,/**/*.png,/**/*.css,/**/*.js +profiler.resin.excludeurl= +# Hide pinpoint headers. +profiler.resin.hidepinpointheader=true +# HTTP Request methods to exclude from tracing +#profiler.resin.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.resin.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.resin.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.resin.realipemptyvalue}, Ignore header value. +#profiler.resin.realipemptyvalue=unknown + +########################################################### +# Weblogic +########################################################### +profiler.weblogic.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.weblogic.bootstrap.main=weblogic.Server +# trace param in request ,default value is true +profiler.weblogic.tracerequestparam=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.weblogic.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.weblogic.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.weblogic.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.weblogic.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.weblogic.realipemptyvalue}, Ignore header value. +#profiler.weblogic.realipemptyvalue=unknown + + +########################################################### +# Vert.x(Reliability and stability can not be guaranteed) # +########################################################### +profiler.vertx.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.vertx.bootstrap.main=io.vertx.core.Starter +# Track Vertx.runOnContext() & Vertx.executeBlocking(). +# Sets the base packages that implements io.vertx.core.Handler. +# Improvement is in progress. +profiler.vertx.handler.base-packages= +# e.g. com.service.handler, com.server.http.handler + +# HTTP server +profiler.vertx.http.server.enable=true +# Set HttpServerRequestHandler method name. The argument is io.vertx.core.http.HttpServerRequest. +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept +profiler.vertx.http.server.tracerequestparam=true +profiler.vertx.http.server.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.vertx.http.server.excludeurl= +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.vertx.http.server.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.vertx.http.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.vertx.http.server.realipemptyvalue}, Ignore header value. +#profiler.vertx.http.server.realipemptyvalue=unknown +# HTTP Request methods to exclude from tracing +#profiler.vertx.http.server.excludemethod= + +# HTTP client +profiler.vertx.http.client.enable=true +profiler.vertx.http.client.param=true +profiler.vertx.http.client.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.vertx.http.client.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.vertx.http.client.cookie.sampling.rate=1 +profiler.vertx.http.client.entity.statuscode=true + +########################################################### +# Undertow +########################################################### +profiler.undertow.enable=true +# trace param in request ,default value is true +profiler.undertow.tracerequestparam=true +# Hide pinpoint headers. +profiler.undertow.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.undertow.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.undertow.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.undertow.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.undertow.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.undertow.realipemptyvalue}, Ignore header value. +#profiler.undertow.realipemptyvalue=unknown + +########################################################### +# SPRING BOOT # +########################################################### +profiler.springboot.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.springboot.bootstrap.main=org.springframework.boot.loader.JarLauncher, org.springframework.boot.loader.WarLauncher, org.springframework.boot.loader.PropertiesLauncher + +########################################################### +# JSP # +########################################################### +profiler.jsp.enable=true + +########################################################### +# JDBC # +########################################################### +# Profile JDBC drivers. +profiler.jdbc=true +# Size of cache. Fixed maximum. +profiler.jdbc.sqlcachesize=1024 +# trace bindvalues for PreparedStatements +profiler.jdbc.tracesqlbindvalue=true +# Maximum bindvalue size. +profiler.jdbc.maxsqlbindvaluesize=1024 + +# +# MYSQL +# +# Profile MySQL. +profiler.jdbc.mysql=true +# Allow profiling of setautocommit. +profiler.jdbc.mysql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mysql.commit=true +# Allow profiling of rollback. +profiler.jdbc.mysql.rollback=true +# Trace bindvalues for MySQL PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mysql.tracesqlbindvalue=true + +# +# MARIADB +# +# Profile MariaDB +profiler.jdbc.mariadb=true +# Allow profiling of setautocommit. +profiler.jdbc.mariadb.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mariadb.commit=true +# Allow profiling of rollback. +profiler.jdbc.mariadb.rollback=true +# Trace bindvalues for MariaDB PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mariadb.tracesqlbindvalue=true + +# +# MSSQL Jtds +# +# Profile jTDS. +profiler.jdbc.jtds=true +# Allow profiling of setautocommit. +profiler.jdbc.jtds.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.jtds.commit=true +# Allow profiling of rollback. +profiler.jdbc.jtds.rollback=true +# Trace bindvalues for jTDS PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.jtds.tracesqlbindvalue=true + +# +# Oracle +# +# Profile Oracle DB. +profiler.jdbc.oracle=true +# Allow profiling of setautocommit. +profiler.jdbc.oracle.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.oracle.commit=true +# Allow profiling of rollback. +profiler.jdbc.oracle.rollback=true +# Trace bindvalues for Oracle PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.oracle.tracesqlbindvalue=true + +# +# CUBRID +# +# Profile CUBRID. +profiler.jdbc.cubrid=true +# Allow profiling of setautocommit. +profiler.jdbc.cubrid.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.cubrid.commit=true +# Allow profiling of rollback. +profiler.jdbc.cubrid.rollback=true +# Trace bindvalues for CUBRID PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.cubrid.tracesqlbindvalue=true + +# +# DBCP +# +# Profile DBCP. +profiler.jdbc.dbcp=true +profiler.jdbc.dbcp.connectionclose=true + +# +# DBCP2 +# +# Profile DBCP2. +profiler.jdbc.dbcp2=true +profiler.jdbc.dbcp2.connectionclose=true + +# +# HIKARICP +# +profiler.jdbc.hikaricp=true +profiler.jdbc.hikaricp.connectionclose=true + +# +# DRUID +# +profiler.jdbc.druid=true +profiler.jdbc.druid.connectionclose=true + +# +# CASSANDRA +# +# Profile CASSANDRA. +profiler.cassandra=true +# Trace bindvalues for CASSANDRA PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.cassandra.tracecqlbindvalue=true + +# +# PostgreSQL +# +# Profile PostgreSQL. +profiler.jdbc.postgresql=true +# Allow profiling of setautocommit. +profiler.jdbc.postgresql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.postgresql.commit=true +# Allow profiling of rollback. +profiler.jdbc.postgresql.rollback=true + +########################################################### +# MONGODB +########################################################### +profiler.mongo=true +profiler.mongo.collectJson=true + +########################################################### +# Apache HTTP Client 3.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient3.param=true + +# Record Cookies. +profiler.apache.httpclient3.cookie=true + +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient3.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient3.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.entity.dumptype=ALWAYS +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient3.entity.sampling.rate=1 + +# Record IO time. +profiler.apache.httpclient3.io=true + +########################################################### +# Apache HTTP Client 4.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient4.param=true + +# Record cookies. +profiler.apache.httpclient4.cookie=true + +# When cookies should be dumped. It could be ALWAYS or EXCEPTION. +profiler.apache.httpclient4.cookie.dumptype=ALWAYS + +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient4.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient4.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient4.entity.dumptype=ALWAYS + +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient4.entity.sampling.rate=1 + +# Allow profiling status code value. +profiler.apache.httpclient4.entity.statuscode=true + +# Record IO time. +profiler.apache.httpclient4.io=true + +# Not supported yet. +#profiler.apache.nio.httpclient4=true + +########################################################### +# JDK HTTPURLConnection # +########################################################### +# Profile parameter. +profiler.jdk.http.param=true + +########################################################### +# Ning Async HTTP Client # +########################################################### +# Profile Ning Async HTTP Client. +profiler.ning.asynchttpclient=true +# Record cookies. +profiler.ning.asynchttpclient.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS +# Cookie dump size. +profiler.ning.asynchttpclient.cookie.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.cookie.sampling.rate=1 +# Record Entities. +profiler.ning.asynchttpclient.entity=true +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.entity.dumptype=ALWAYS +# Entity dump size. +profiler.ning.asynchttpclient.entity.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.entity.sampling.rate=1 +# Record parameters. (unsupported in 1.8.x, 1.9.x versions) +profiler.ning.asynchttpclient.param=true +# When to dump parameters. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.param.dumptype=ALWAYS +# Parameter dump size. +profiler.ning.asynchttpclient.param.dumpsize=1024 +# 1 out of n parameters will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.param.sampling.rate=1 + + +########################################################### +# Arcus # +########################################################### +# Profile Arcus. +profiler.arcus=true +profiler.arcus.async=true +# Record keytrace. +profiler.arcus.keytrace=true + +########################################################### +# Memcached # +########################################################### +# Profile Memecached. +profiler.memcached=true +profiler.memcached.async=true +# Record keytrace +profiler.memcached.keytrace=true + +########################################################### +# Thrift # +########################################################### +# Profile Thrift +profiler.thrift.client=true +profiler.thrift.client.async=true +# Profile processor. +profiler.thrift.processor=true +profiler.thrift.processor.async=true +# Allow recording arguments. +profiler.thrift.service.args=true +# Allow recording result. +profiler.thrift.service.result=true + + +########################################################### +# ibatis # +########################################################### +# Profile ibatis. +profiler.orm.ibatis=true + +########################################################### +# mybatis # +########################################################### +# Profile mybatis +profiler.orm.mybatis=true + +########################################################### +# spring-beans +########################################################### +# Profile spring-beans +profiler.spring.beans=true + +# filters +# filter +# filter OR filters +# filter +# value +# value AND filter +# value +# token +# token OR token +# token +# profiler.spring.beans.n.scope= [component-scan | post-processor] default is component-scan. +# profiler.spring.beans.n.base-packages= [package name, ...] +# profiler.spring.beans.n.name.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.class.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.annotation= [annotation name, ...] +# +# Scope: +# component-scan: or @ComponentScan +# post-processor: BeanPostProcessor - Slow!!! +# +# ANT Style pattern rules: +# ? - matches on character +# * - matches zero or more characters +# ** - matches zero or more 'directories' in a path + +# Examples +# profiler.spring.beans.1.scope=component-scan +# profiler.spring.beans.1.base-packages=com.foo, com.bar +# profiler.spring.beans.1.name.pattern=.*Foo, regex:.*Bar, antstyle:*Controller +# profiler.spring.beans.1.class.pattern= +# profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository +# +# profiler.spring.beans.2.scope=post-processor +# profiler.spring.beans.2.base-packages=com.foo +# profiler.spring.beans.2.name.pattern= +# profiler.spring.beans.2.class.pattern=antstyle:com.foo.repository.*Repository, antstyle:com.foo.Service.Main* +# profiler.spring.beans.2.annotation= + +profiler.spring.beans.1.scope=component-scan +profiler.spring.beans.1.base-packages= +profiler.spring.beans.1.name.pattern= +profiler.spring.beans.1.class.pattern= +profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository + +profiler.spring.beans.mark.error=false + +########################################################### +# spring @Async +########################################################### +profiler.spring.async.enable=true +# Add custom AsyncTaskExecutor classes. Comma separated list of fully qualified class names. Wildcard not supported. +# Default values +# org.springframework.scheduling.concurrent.ConcurrentTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.core.task.SimpleAsyncTaskExecutor +# org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor +# org.springframework.core.task.support.TaskExecutorAdapter +# org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.jca.work.WorkManagerTaskExecutor +# org.springframework.scheduling.commonj.WorkManagerTaskExecutor +profiler.spring.async.executor.class.names= + +########################################################### +# log4j (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.log4j.logging.transactioninfo=false + +########################################################### +# logback (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.logback.logging.transactioninfo=false + +########################################################### +# google httpclient +########################################################### +# Profile async. +profiler.google.httpclient.async=true + +########################################################### +# redis +########################################################### +profiler.redis.pipeline +profiler.redis=true +profiler.redis.io=true + +########################################################### +# OkHttp +########################################################### +profiler.okhttp.enable=true +# Record param. +profiler.okhttp.param=true + +# Record Cookies. +profiler.okhttp.cookie=false +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.okhttp.cookie.dumptype=EXCEPTION +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.okhttp.cookie.sampling.rate=1 +# enqueue operation +profiler.okhttp.async=true + +########################################################### +# gson +########################################################### +profiler.json.gson=true + +########################################################### +# jackson +########################################################### +profiler.json.jackson=true + +########################################################### +# json-lib +########################################################### +profiler.json.jsonlib=true + +########################################################### +# ActiveMQ Client +########################################################### +profiler.activemq.client.enable=true +profiler.activemq.client.producer.enable=true +profiler.activemq.client.consumer.enable=true +profiler.activemq.client.trace.message=false + +# ActiveMQ destination path separator (default is ".") +profiler.activemq.client.destination.separator= + +# ActiveMQ destinations to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.activemq.client.destination.exclude= + +########################################################### +# RxJava +########################################################### +profiler.rxjava=true + +########################################################### +# Hystrix +########################################################### +# profiler.rxjava must also be enabled to properly trace hystrix commands +profiler.hystrix=true + +########################################################### +# RestTemplate +########################################################### +profiler.resttemplate=false + +########################################################### +# Netty +########################################################### +# recommend netty plugin disable, when using VERTX. +profiler.netty=false +profiler.netty.http=false + +########################################################### +# RabbitMQ Client +########################################################### +profiler.rabbitmq.client.enable=true +profiler.rabbitmq.client.producer.enable=true +profiler.rabbitmq.client.consumer.enable=true +# Custom consumer classes to be traced (comma separated list of fully qualified class names) +# If a consumer class is an inner class, specify the outer class +profiler.rabbitmq.client.consumer.classes= +# RabbitMQ exchange to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.rabbitmq.client.exchange.exclude= + +########################################################### +# Akka HTTP (Reliability and stability can not be guaranteed) +########################################################### +# HTTP server +profiler.akka.http.enable=false +# original IP address header +profiler.akka.http.realipheader=Remote-Address +# URLs to exclude from tracing +profiler.akka.http.excludeurl= +# HTTP Request methods to exclude from tracing +profiler.akka.http.excludemethod= +# Set transform target +# If you are using another directive, change below config +profiler.akka.http.transform.targetname=akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRequestContext$2 +profiler.akka.http.transform.targetparameter=scala.Function1,scala.Function1,akka.http.scaladsl.server.RequestContext + +########################################################### +# Kafka (Reliability and stability can not be guaranteed) +# Version 0.11+ is supported. +# Note: RemoteTrace will not occur if the method specified in the profiler.kafka.consumer.entryPoint is not the first trace point. +########################################################### +profiler.kafka.producer.enable=false +profiler.kafka.consumer.enable=false +// you must set target that handles ConsumerRecord as a argument for remote trace +// ex) profiler.kafka.entryPoint=clazzName.methodName +profiler.kafka.consumer.entryPoint= \ No newline at end of file diff --git a/agent-it/src/test/resources/fastjson/pinpoint-fastjson-test.config b/agent-it/src/test/resources/fastjson/pinpoint-fastjson-test.config new file mode 100644 index 000000000000..62fb65555571 --- /dev/null +++ b/agent-it/src/test/resources/fastjson/pinpoint-fastjson-test.config @@ -0,0 +1,861 @@ +# +# Pinpoint agent configuration +# + +########################################################### +# Collector server # +########################################################### +profiler.collector.ip=127.0.0.1 + +# placeHolder support "${key}" +profiler.collector.span.ip=${profiler.collector.ip} +profiler.collector.span.port=9996 + +# placeHolder support "${key}" +profiler.collector.stat.ip=${profiler.collector.ip} +profiler.collector.stat.port=9995 + +# placeHolder support "${key}" +profiler.collector.tcp.ip=${profiler.collector.ip} +profiler.collector.tcp.port=9994 + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +# Application namespace +# Differentiate from external pinpoint agents. (e.g., com.pinpoint) +profiler.application.namespace= + +profiler.interceptorregistry.size=8192 + +# Manually override jvm vendor name (Oracle, IBM, OpenJDK, etc) +# You probably won't ever need to set this value. +profiler.jvm.vendor.name= + +# Manually override agent's OS name (MAC, Window, Linus, AIX, HP_UX, BSD) +# You probably won't ever need to set this value.(to collect file descriptor) +profiler.os.name= + +# Interval (in milliseconds) at which agent stat data is collected. (default : 5000, min : 1000, max : 5000) +profiler.jvm.stat.collect.interval=5000 +# Number of agent stat data sent to the collector in a single batch. (default : 6) +profiler.jvm.stat.batch.send.count=6 + +# Allow to add detailed collector's metrics +profiler.jvm.stat.collect.detailed.metrics=true + +# Allow sampling. +profiler.sampling.enable=true + +# 1 out of n transactions will be sampled where n is the rate. (1: 100%) +profiler.sampling.rate=1 + +# Allow buffering when flushing span to IO. +profiler.io.buffering.enable=true + +# How many spans to store if buffering enabled. +profiler.io.buffering.buffersize=20 + +# Capacity of the SpanDataSender write queue. +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 +profiler.spandatasender.chunk.size=16384 +profiler.spandatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.spandatasender.transport.type=UDP + +# Capacity of the StatDataSender write queue. +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 +profiler.statdatasender.chunk.size=16384 +profiler.statdatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.statdatasender.transport.type=UDP + +# Interval to retry sending agent info. Unit is milliseconds. +profiler.agentInfo.send.retry.interval=300000 + +# Allow TCP data command. +profiler.tcpdatasender.command.accept.enable=true +profiler.tcpdatasender.command.activethread.enable=true +profiler.tcpdatasender.command.activethread.count.enable=true +profiler.tcpdatasender.command.activethread.threaddump.enable=true +profiler.tcpdatasender.command.activethread.threadlightdump.enable=true + +profiler.tcpdatasender.client.write.timeout=3000 +profiler.tcpdatasender.client.request.timeout=3000 +profiler.tcpdatasender.client.reconnect.interval=3000 +profiler.tcpdatasender.client.ping.interval=300000 +profiler.tcpdatasender.client.handshake.interval=60000 + +# Trace Agent active thread info. +profiler.pinpoint.activethread=true + +# Trace DataSource +profiler.pinpoint.datasource=true + +# Deadlock Monitor +profiler.monitor.deadlock.enable=true +profiler.monitor.deadlock.interval=60000 + +## Call Stack +# Set max depth, if -1 is unlimited and min is 2. +profiler.callstack.max.depth=64 + +# weather or not to propagate exceptions occurred at interceptor +profiler.interceptor.exception.propagate=false + +# Allow bytecode framework (JAVASSIST or ASM) +profiler.instrument.engine=ASM + +# bytecode dump option +# java bytecode debug option +bytecode.dump.enable=false +#bytecode.dump.classlist=com.naver.user.UserService,com.pinpoint.debug.TestClass +bytecode.dump.classlist= +bytecode.dump.bytecode=false +bytecode.dump.verify=false +bytecode.dump.asm=false + +# Matcher +profiler.instrument.matcher.enable=true +# Matcher cache. max size is 64. +profiler.instrument.matcher.interface.cache.size=4 +profiler.instrument.matcher.interface.cache.entry.size=16 +profiler.instrument.matcher.annotation.cache.size=4 +profiler.instrument.matcher.annotation.cache.entry.size=4 +profiler.instrument.matcher.super.cache.size=4 +profiler.instrument.matcher.super.cache.entry.size=4 + +# Lambda expressions. +profiler.lambda.expressions.support=true + +# Proxy HTTP headers. +# Please see (https://github.com/naver/pinpoint/blob/master/doc/proxy-http-header.md) for more information. +profiler.proxy.http.header.enable=true + +# HTTP status code with request failure. +# 1xx, 2xx, 3xx, 4xx, 5xx, 100, 101, 200, 201, ... 501, 502, 503, 504, 505 +# e.g. profiler.http.status.code.errors=5xx, 401, 403 +profiler.http.status.code.errors=5xx + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + +########################################################### +# application type detect order # +########################################################### +profiler.type.detect.order= + +profiler.plugin.disable= + +########################################################### +# user defined classes # +########################################################### +# Specify classes and methods you want to profile here. + +# Needs to be a comma separated list of fully qualified class names, or fully qualified package names with wild card class. +profiler.include= +# Ex: foo.bar.MyClass, foo.baz.* + +# Needs to be a comma separated list of fully qualified method names. Wild card not supported. +profiler.entrypoint= +# Ex: foo.bar.MyClass.myMethod, foo.bar.MyClass.anotherMethod + +# Message queue listener invoker methods. +# This is usually for when a separate implementation or a framework provides a separate handler for invoking callbacks +# when consuming messages. +# Comma-separated list of fully qualified method names with a Message argument. +profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener,org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener + +########################################################### +# TOMCAT # +########################################################### +profiler.tomcat.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap +# Check pre-conditions when registering class file transformers mainly due to JBoss plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.apache.catalina.startup.Bootstrap, +# or SpringBoot's launchers. +# Set this to false to bypass this check entirely (such as when launching standalone applications running embedded Tomcat). +profiler.tomcat.conditional.transform=true +# Hide pinpoint headers. +profiler.tomcat.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html +# HTTP Request methods to exclude from tracing +#profiler.tomcat.excludemethod= +profiler.tomcat.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.tomcat.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.tomcat.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.tomcat.realipemptyvalue}, Ignore header value. +#profiler.tomcat.realipemptyvalue=unknown + + +########################################################### +# JETTY # +########################################################### +profiler.jetty.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.jetty.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jetty.excludemethod= +# Hide pinpoint headers. +profiler.jetty.hide-pinpoint-header=true +profiler.jetty.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jetty.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jetty.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jetty.realipemptyvalue}, Ignore header value. +#profiler.jetty.realipemptyvalue=unknown + +########################################################### +# DUBBO # +########################################################### +profiler.dubbo.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.dubbo.bootstrap.main=com.alibaba.dubbo.container.Main + + +########################################################### +# JBOSS # +########################################################### +profiler.jboss.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jboss.bootstrap.main=org.jboss.modules.Main +# Check pre-conditions when registering class file transformers mainly due to Tomcat plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.jboss.modules.Main. +# Set this to false to bypass this check entirely. +profiler.jboss.conditional.transform=true +# Hide pinpoint headers. +profiler.jboss.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.jboss.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jboss.excludemethod= +profiler.jboss.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jboss.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jboss.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. +#profiler.jboss.realipemptyvalue=unknown + +########################################################### +# Resin +########################################################### +# default enable resin plugin +profiler.resin.enable=true +# if empty , default value is : com.caucho.server.resin.Resin +profiler.resin.bootstrap.main= +# trace param in request ,default value is true +profiler.resin.tracerequestparam=true +# excudeurl eg: filter static resources : /**/*.jpg,/**/*.png,/**/*.css,/**/*.js +profiler.resin.excludeurl= +# Hide pinpoint headers. +profiler.resin.hidepinpointheader=true +# HTTP Request methods to exclude from tracing +#profiler.resin.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.resin.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.resin.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.resin.realipemptyvalue}, Ignore header value. +#profiler.resin.realipemptyvalue=unknown + +########################################################### +# Weblogic +########################################################### +profiler.weblogic.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.weblogic.bootstrap.main=weblogic.Server +# trace param in request ,default value is true +profiler.weblogic.tracerequestparam=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.weblogic.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.weblogic.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.weblogic.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.weblogic.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.weblogic.realipemptyvalue}, Ignore header value. +#profiler.weblogic.realipemptyvalue=unknown + + +########################################################### +# Vert.x(Reliability and stability can not be guaranteed) # +########################################################### +profiler.vertx.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.vertx.bootstrap.main=io.vertx.core.Starter +# Track Vertx.runOnContext() & Vertx.executeBlocking(). +# Sets the base packages that implements io.vertx.core.Handler. +# Improvement is in progress. +profiler.vertx.handler.base-packages= +# e.g. com.service.handler, com.server.http.handler + +# HTTP server +profiler.vertx.http.server.enable=true +# Set HttpServerRequestHandler method name. The argument is io.vertx.core.http.HttpServerRequest. +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept +profiler.vertx.http.server.tracerequestparam=true +profiler.vertx.http.server.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.vertx.http.server.excludeurl= +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.vertx.http.server.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.vertx.http.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.vertx.http.server.realipemptyvalue}, Ignore header value. +#profiler.vertx.http.server.realipemptyvalue=unknown +# HTTP Request methods to exclude from tracing +#profiler.vertx.http.server.excludemethod= + +# HTTP client +profiler.vertx.http.client.enable=true +profiler.vertx.http.client.param=true +profiler.vertx.http.client.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.vertx.http.client.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.vertx.http.client.cookie.sampling.rate=1 +profiler.vertx.http.client.entity.statuscode=true + +########################################################### +# Undertow +########################################################### +profiler.undertow.enable=true +# trace param in request ,default value is true +profiler.undertow.tracerequestparam=true +# Hide pinpoint headers. +profiler.undertow.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.undertow.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.undertow.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.undertow.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.undertow.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.undertow.realipemptyvalue}, Ignore header value. +#profiler.undertow.realipemptyvalue=unknown + +########################################################### +# SPRING BOOT # +########################################################### +profiler.springboot.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.springboot.bootstrap.main=org.springframework.boot.loader.JarLauncher, org.springframework.boot.loader.WarLauncher, org.springframework.boot.loader.PropertiesLauncher + +########################################################### +# JSP # +########################################################### +profiler.jsp.enable=true + +########################################################### +# JDBC # +########################################################### +# Profile JDBC drivers. +profiler.jdbc=true +# Size of cache. Fixed maximum. +profiler.jdbc.sqlcachesize=1024 +# trace bindvalues for PreparedStatements +profiler.jdbc.tracesqlbindvalue=true +# Maximum bindvalue size. +profiler.jdbc.maxsqlbindvaluesize=1024 + +# +# MYSQL +# +# Profile MySQL. +profiler.jdbc.mysql=true +# Allow profiling of setautocommit. +profiler.jdbc.mysql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mysql.commit=true +# Allow profiling of rollback. +profiler.jdbc.mysql.rollback=true +# Trace bindvalues for MySQL PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mysql.tracesqlbindvalue=true + +# +# MARIADB +# +# Profile MariaDB +profiler.jdbc.mariadb=true +# Allow profiling of setautocommit. +profiler.jdbc.mariadb.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mariadb.commit=true +# Allow profiling of rollback. +profiler.jdbc.mariadb.rollback=true +# Trace bindvalues for MariaDB PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mariadb.tracesqlbindvalue=true + +# +# MSSQL Jtds +# +# Profile jTDS. +profiler.jdbc.jtds=true +# Allow profiling of setautocommit. +profiler.jdbc.jtds.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.jtds.commit=true +# Allow profiling of rollback. +profiler.jdbc.jtds.rollback=true +# Trace bindvalues for jTDS PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.jtds.tracesqlbindvalue=true + +# +# Oracle +# +# Profile Oracle DB. +profiler.jdbc.oracle=true +# Allow profiling of setautocommit. +profiler.jdbc.oracle.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.oracle.commit=true +# Allow profiling of rollback. +profiler.jdbc.oracle.rollback=true +# Trace bindvalues for Oracle PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.oracle.tracesqlbindvalue=true + +# +# CUBRID +# +# Profile CUBRID. +profiler.jdbc.cubrid=true +# Allow profiling of setautocommit. +profiler.jdbc.cubrid.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.cubrid.commit=true +# Allow profiling of rollback. +profiler.jdbc.cubrid.rollback=true +# Trace bindvalues for CUBRID PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.cubrid.tracesqlbindvalue=true + +# +# DBCP +# +# Profile DBCP. +profiler.jdbc.dbcp=true +profiler.jdbc.dbcp.connectionclose=true + +# +# DBCP2 +# +# Profile DBCP2. +profiler.jdbc.dbcp2=true +profiler.jdbc.dbcp2.connectionclose=true + +# +# HIKARICP +# +profiler.jdbc.hikaricp=true +profiler.jdbc.hikaricp.connectionclose=true + +# +# CASSANDRA +# +# Profile CASSANDRA. +profiler.cassandra=true +# Trace bindvalues for CASSANDRA PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.cassandra.tracecqlbindvalue=true + +# +# PostgreSQL +# +# Profile PostgreSQL. +profiler.jdbc.postgresql=true +# Allow profiling of setautocommit. +profiler.jdbc.postgresql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.postgresql.commit=true +# Allow profiling of rollback. +profiler.jdbc.postgresql.rollback=true + +########################################################### +# MONGODB +########################################################### +profiler.mongo=true +profiler.mongo.collectJson=true + +########################################################### +# Apache HTTP Client 3.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient3.param=true + +# Record Cookies. +profiler.apache.httpclient3.cookie=true + +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient3.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient3.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.entity.dumptype=ALWAYS +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient3.entity.sampling.rate=1 + +# Record IO time. +profiler.apache.httpclient3.io=true + +########################################################### +# Apache HTTP Client 4.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient4.param=true + +# Record cookies. +profiler.apache.httpclient4.cookie=true + +# When cookies should be dumped. It could be ALWAYS or EXCEPTION. +profiler.apache.httpclient4.cookie.dumptype=ALWAYS + +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient4.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient4.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient4.entity.dumptype=ALWAYS + +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient4.entity.sampling.rate=1 + +# Allow profiling status code value. +profiler.apache.httpclient4.entity.statuscode=true + +# Record IO time. +profiler.apache.httpclient4.io=true + +# Not supported yet. +#profiler.apache.nio.httpclient4=true + +########################################################### +# JDK HTTPURLConnection # +########################################################### +# Profile parameter. +profiler.jdk.http.param=true + +########################################################### +# Ning Async HTTP Client # +########################################################### +# Profile Ning Async HTTP Client. +profiler.ning.asynchttpclient=true +# Record cookies. +profiler.ning.asynchttpclient.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS +# Cookie dump size. +profiler.ning.asynchttpclient.cookie.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.cookie.sampling.rate=1 +# Record Entities. +profiler.ning.asynchttpclient.entity=true +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.entity.dumptype=ALWAYS +# Entity dump size. +profiler.ning.asynchttpclient.entity.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.entity.sampling.rate=1 +# Record parameters. (unsupported in 1.8.x, 1.9.x versions) +profiler.ning.asynchttpclient.param=true +# When to dump parameters. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.param.dumptype=ALWAYS +# Parameter dump size. +profiler.ning.asynchttpclient.param.dumpsize=1024 +# 1 out of n parameters will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.param.sampling.rate=1 + + +########################################################### +# Arcus # +########################################################### +# Profile Arcus. +profiler.arcus=true +profiler.arcus.async=true +# Record keytrace. +profiler.arcus.keytrace=true + +########################################################### +# Memcached # +########################################################### +# Profile Memecached. +profiler.memcached=true +profiler.memcached.async=true +# Record keytrace +profiler.memcached.keytrace=true + +########################################################### +# Thrift # +########################################################### +# Profile Thrift +profiler.thrift.client=true +profiler.thrift.client.async=true +# Profile processor. +profiler.thrift.processor=true +profiler.thrift.processor.async=true +# Allow recording arguments. +profiler.thrift.service.args=true +# Allow recording result. +profiler.thrift.service.result=true + + +########################################################### +# ibatis # +########################################################### +# Profile ibatis. +profiler.orm.ibatis=true + +########################################################### +# mybatis # +########################################################### +# Profile mybatis +profiler.orm.mybatis=true + +########################################################### +# spring-beans +########################################################### +# Profile spring-beans +profiler.spring.beans=true + +# filters +# filter +# filter OR filters +# filter +# value +# value AND filter +# value +# token +# token OR token +# token +# profiler.spring.beans.n.scope= [component-scan | post-processor] default is component-scan. +# profiler.spring.beans.n.base-packages= [package name, ...] +# profiler.spring.beans.n.name.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.class.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.annotation= [annotation name, ...] +# +# Scope: +# component-scan: or @ComponentScan +# post-processor: BeanPostProcessor - Slow!!! +# +# ANT Style pattern rules: +# ? - matches on character +# * - matches zero or more characters +# ** - matches zero or more 'directories' in a path + +# Examples +# profiler.spring.beans.1.scope=component-scan +# profiler.spring.beans.1.base-packages=com.foo, com.bar +# profiler.spring.beans.1.name.pattern=.*Foo, regex:.*Bar, antstyle:*Controller +# profiler.spring.beans.1.class.pattern= +# profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository +# +# profiler.spring.beans.2.scope=post-processor +# profiler.spring.beans.2.base-packages=com.foo +# profiler.spring.beans.2.name.pattern= +# profiler.spring.beans.2.class.pattern=antstyle:com.foo.repository.*Repository, antstyle:com.foo.Service.Main* +# profiler.spring.beans.2.annotation= + +profiler.spring.beans.1.scope=component-scan +profiler.spring.beans.1.base-packages= +profiler.spring.beans.1.name.pattern= +profiler.spring.beans.1.class.pattern= +profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository + +profiler.spring.beans.mark.error=false + +########################################################### +# spring @Async +########################################################### +profiler.spring.async.enable=true +# Add custom AsyncTaskExecutor classes. Comma separated list of fully qualified class names. Wildcard not supported. +# Default values +# org.springframework.scheduling.concurrent.ConcurrentTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.core.task.SimpleAsyncTaskExecutor +# org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor +# org.springframework.core.task.support.TaskExecutorAdapter +# org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.jca.work.WorkManagerTaskExecutor +# org.springframework.scheduling.commonj.WorkManagerTaskExecutor +profiler.spring.async.executor.class.names= + +########################################################### +# log4j (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.log4j.logging.transactioninfo=false + +########################################################### +# logback (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.logback.logging.transactioninfo=false + +########################################################### +# google httpclient +########################################################### +# Profile async. +profiler.google.httpclient.async=true + +########################################################### +# redis +########################################################### +profiler.redis.pipeline +profiler.redis=true +profiler.redis.io=true + +########################################################### +# OkHttp +########################################################### +profiler.okhttp.enable=true +# Record param. +profiler.okhttp.param=true + +# Record Cookies. +profiler.okhttp.cookie=false +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.okhttp.cookie.dumptype=EXCEPTION +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.okhttp.cookie.sampling.rate=1 +# enqueue operation +profiler.okhttp.async=true + +########################################################### +# fastjson +########################################################### +profiler.json.fastjson=true + +########################################################### +# gson +########################################################### +profiler.json.gson=true + +########################################################### +# jackson +########################################################### +profiler.json.jackson=true + +########################################################### +# json-lib +########################################################### +profiler.json.jsonlib=true + +########################################################### +# ActiveMQ Client +########################################################### +profiler.activemq.client.enable=true +profiler.activemq.client.producer.enable=true +profiler.activemq.client.consumer.enable=true +profiler.activemq.client.trace.message=false + +# ActiveMQ destination path separator (default is ".") +profiler.activemq.client.destination.separator= + +# ActiveMQ destinations to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.activemq.client.destination.exclude= + +########################################################### +# RxJava +########################################################### +profiler.rxjava=true + +########################################################### +# Hystrix +########################################################### +# profiler.rxjava must also be enabled to properly trace hystrix commands +profiler.hystrix=true + +########################################################### +# RestTemplate +########################################################### +profiler.resttemplate=false + +########################################################### +# Netty +########################################################### +# recommend netty plugin disable, when using VERTX. +profiler.netty=false +profiler.netty.http=false + +########################################################### +# RabbitMQ Client +########################################################### +profiler.rabbitmq.client.enable=true +profiler.rabbitmq.client.producer.enable=true +profiler.rabbitmq.client.consumer.enable=true +# Custom consumer classes to be traced (comma separated list of fully qualified class names) +# If a consumer class is an inner class, specify the outer class +profiler.rabbitmq.client.consumer.classes= +# RabbitMQ exchange to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.rabbitmq.client.exchange.exclude= + +########################################################### +# Akka HTTP (Reliability and stability can not be guaranteed) +########################################################### +# HTTP server +profiler.akka.http.enable=false +# original IP address header +profiler.akka.http.realipheader=Remote-Address +# URLs to exclude from tracing +profiler.akka.http.excludeurl= +# HTTP Request methods to exclude from tracing +profiler.akka.http.excludemethod= +# Set transform target +# If you are using another directive, change below config +profiler.akka.http.transform.targetname=akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRequestContext$2 +profiler.akka.http.transform.targetparameter=scala.Function1,scala.Function1,akka.http.scaladsl.server.RequestContext + +########################################################### +# Kafka (Reliability and stability can not be guaranteed) +# Version 0.11+ is supported. +# Note: RemoteTrace will not occur if the method specified in the profiler.kafka.consumer.entryPoint is not the first trace point. +########################################################### +profiler.kafka.producer.enable=false +profiler.kafka.consumer.enable=false +// you must set target that handles ConsumerRecord as a argument for remote trace +// ex) profiler.kafka.entryPoint=clazzName.methodName +profiler.kafka.consumer.entryPoint= \ No newline at end of file diff --git a/agent-it/src/test/resources/hbase/pinpoint-hbase-test.config b/agent-it/src/test/resources/hbase/pinpoint-hbase-test.config new file mode 100644 index 000000000000..9dfb75813de4 --- /dev/null +++ b/agent-it/src/test/resources/hbase/pinpoint-hbase-test.config @@ -0,0 +1,884 @@ +# +# Pinpoint agent configuration +# + +########################################################### +# Collector server # +########################################################### +profiler.collector.ip=127.0.0.1 + +# placeHolder support "${key}" +profiler.collector.span.ip=${profiler.collector.ip} +profiler.collector.span.port=9996 + +# placeHolder support "${key}" +profiler.collector.stat.ip=${profiler.collector.ip} +profiler.collector.stat.port=9995 + +# placeHolder support "${key}" +profiler.collector.tcp.ip=${profiler.collector.ip} +profiler.collector.tcp.port=9994 + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +# Application namespace +# Differentiate from external pinpoint agents. (e.g., com.pinpoint) +profiler.application.namespace= + +profiler.interceptorregistry.size=8192 + +# Manually override jvm vendor name (Oracle, IBM, OpenJDK, etc) +# You probably won't ever need to set this value. +profiler.jvm.vendor.name= + +# Manually override agent's OS name (MAC, Window, Linus, AIX, HP_UX, BSD) +# You probably won't ever need to set this value.(to collect file descriptor) +profiler.os.name= + +# Interval (in milliseconds) at which agent stat data is collected. (default : 5000, min : 1000, max : 5000) +profiler.jvm.stat.collect.interval=5000 +# Number of agent stat data sent to the collector in a single batch. (default : 6) +profiler.jvm.stat.batch.send.count=6 + +# Allow to add detailed collector's metrics +profiler.jvm.stat.collect.detailed.metrics=true + +# Allow sampling. +profiler.sampling.enable=true + +# 1 out of n transactions will be sampled where n is the rate. (1: 100%) +profiler.sampling.rate=1 + +# Allow buffering when flushing span to IO. +profiler.io.buffering.enable=true + +# How many spans to store if buffering enabled. +profiler.io.buffering.buffersize=20 + +# Capacity of the SpanDataSender write queue. +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 +profiler.spandatasender.chunk.size=16384 +profiler.spandatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.spandatasender.transport.type=UDP + +# Capacity of the StatDataSender write queue. +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 +profiler.statdatasender.chunk.size=16384 +profiler.statdatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.statdatasender.transport.type=UDP + +# Interval to retry sending agent info. Unit is milliseconds. +profiler.agentInfo.send.retry.interval=300000 + +# Allow TCP data command. +profiler.tcpdatasender.command.accept.enable=true +profiler.tcpdatasender.command.activethread.enable=true +profiler.tcpdatasender.command.activethread.count.enable=true +profiler.tcpdatasender.command.activethread.threaddump.enable=true +profiler.tcpdatasender.command.activethread.threadlightdump.enable=true + +profiler.tcpdatasender.client.write.timeout=3000 +profiler.tcpdatasender.client.request.timeout=3000 +profiler.tcpdatasender.client.reconnect.interval=3000 +profiler.tcpdatasender.client.ping.interval=300000 +profiler.tcpdatasender.client.handshake.interval=60000 + +# Trace Agent active thread info. +profiler.pinpoint.activethread=true + +# Trace DataSource +profiler.pinpoint.datasource=true + +# Deadlock Monitor +profiler.monitor.deadlock.enable=true +profiler.monitor.deadlock.interval=60000 + +## Call Stack +# Set max depth, if -1 is unlimited and min is 2. +profiler.callstack.max.depth=64 + +# weather or not to propagate exceptions occurred at interceptor +profiler.interceptor.exception.propagate=false + +# Allow bytecode framework (JAVASSIST or ASM) +profiler.instrument.engine=ASM + +# bytecode dump option +# java bytecode debug option +bytecode.dump.enable=false +#bytecode.dump.classlist=com.naver.user.UserService,com.pinpoint.debug.TestClass +bytecode.dump.classlist= +bytecode.dump.bytecode=false +bytecode.dump.verify=false +bytecode.dump.asm=false + +# Matcher +profiler.instrument.matcher.enable=true +# Matcher cache. max size is 64. +profiler.instrument.matcher.interface.cache.size=4 +profiler.instrument.matcher.interface.cache.entry.size=16 +profiler.instrument.matcher.annotation.cache.size=4 +profiler.instrument.matcher.annotation.cache.entry.size=4 +profiler.instrument.matcher.super.cache.size=4 +profiler.instrument.matcher.super.cache.entry.size=4 + +# Lambda expressions. +profiler.lambda.expressions.support=true + +# Proxy HTTP headers. +# Please see (https://github.com/naver/pinpoint/blob/master/doc/proxy-http-header.md) for more information. +profiler.proxy.http.header.enable=true + +# HTTP status code with request failure. +# 1xx, 2xx, 3xx, 4xx, 5xx, 100, 101, 200, 201, ... 501, 502, 503, 504, 505 +# e.g. profiler.http.status.code.errors=5xx, 401, 403 +profiler.http.status.code.errors=5xx + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + +########################################################### +# application type detect order # +########################################################### +profiler.type.detect.order= + +profiler.plugin.disable= + +########################################################### +# user defined classes # +########################################################### +# Specify classes and methods you want to profile here. + +# Needs to be a comma separated list of fully qualified class names, or fully qualified package names with wild card class. +profiler.include= +# Ex: foo.bar.MyClass, foo.baz.* + +# Needs to be a comma separated list of fully qualified method names. Wild card not supported. +profiler.entrypoint= +# Ex: foo.bar.MyClass.myMethod, foo.bar.MyClass.anotherMethod + +# Message queue listener invoker methods. +# This is usually for when a separate implementation or a framework provides a separate handler for invoking callbacks +# when consuming messages. +# Comma-separated list of fully qualified method names with a Message argument. +profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener,org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener + +########################################################### +# TOMCAT # +########################################################### +profiler.tomcat.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap +# Check pre-conditions when registering class file transformers mainly due to JBoss plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.apache.catalina.startup.Bootstrap, +# or SpringBoot's launchers. +# Set this to false to bypass this check entirely (such as when launching standalone applications running embedded Tomcat). +profiler.tomcat.conditional.transform=true +# Hide pinpoint headers. +profiler.tomcat.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html +# HTTP Request methods to exclude from tracing +#profiler.tomcat.excludemethod= +profiler.tomcat.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.tomcat.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.tomcat.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.tomcat.realipemptyvalue}, Ignore header value. +#profiler.tomcat.realipemptyvalue=unknown + + +########################################################### +# JETTY # +########################################################### +profiler.jetty.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.jetty.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jetty.excludemethod= +# Hide pinpoint headers. +profiler.jetty.hide-pinpoint-header=true +profiler.jetty.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jetty.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jetty.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jetty.realipemptyvalue}, Ignore header value. +#profiler.jetty.realipemptyvalue=unknown + +########################################################### +# DUBBO # +########################################################### +profiler.dubbo.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.dubbo.bootstrap.main=com.alibaba.dubbo.container.Main + + +########################################################### +# JBOSS # +########################################################### +profiler.jboss.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jboss.bootstrap.main=org.jboss.modules.Main +# Check pre-conditions when registering class file transformers mainly due to Tomcat plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.jboss.modules.Main. +# Set this to false to bypass this check entirely. +profiler.jboss.conditional.transform=true +# Hide pinpoint headers. +profiler.jboss.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.jboss.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jboss.excludemethod= +profiler.jboss.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jboss.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jboss.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. +#profiler.jboss.realipemptyvalue=unknown + +########################################################### +# Resin +########################################################### +# default enable resin plugin +profiler.resin.enable=true +# if empty , default value is : com.caucho.server.resin.Resin +profiler.resin.bootstrap.main= +# trace param in request ,default value is true +profiler.resin.tracerequestparam=true +# excudeurl eg: filter static resources : /**/*.jpg,/**/*.png,/**/*.css,/**/*.js +profiler.resin.excludeurl= +# Hide pinpoint headers. +profiler.resin.hidepinpointheader=true +# HTTP Request methods to exclude from tracing +#profiler.resin.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.resin.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.resin.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.resin.realipemptyvalue}, Ignore header value. +#profiler.resin.realipemptyvalue=unknown + +########################################################### +# Weblogic +########################################################### +profiler.weblogic.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.weblogic.bootstrap.main=weblogic.Server +# trace param in request ,default value is true +profiler.weblogic.tracerequestparam=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.weblogic.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.weblogic.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.weblogic.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.weblogic.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.weblogic.realipemptyvalue}, Ignore header value. +#profiler.weblogic.realipemptyvalue=unknown + + +########################################################### +# Vert.x(Reliability and stability can not be guaranteed) # +########################################################### +profiler.vertx.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.vertx.bootstrap.main=io.vertx.core.Starter +# Track Vertx.runOnContext() & Vertx.executeBlocking(). +# Sets the base packages that implements io.vertx.core.Handler. +# Improvement is in progress. +profiler.vertx.handler.base-packages= +# e.g. com.service.handler, com.server.http.handler + +# HTTP server +profiler.vertx.http.server.enable=true +# Set HttpServerRequestHandler method name. The argument is io.vertx.core.http.HttpServerRequest. +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept +profiler.vertx.http.server.tracerequestparam=true +profiler.vertx.http.server.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.vertx.http.server.excludeurl= +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.vertx.http.server.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.vertx.http.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.vertx.http.server.realipemptyvalue}, Ignore header value. +#profiler.vertx.http.server.realipemptyvalue=unknown +# HTTP Request methods to exclude from tracing +#profiler.vertx.http.server.excludemethod= + +# HTTP client +profiler.vertx.http.client.enable=true +profiler.vertx.http.client.param=true +profiler.vertx.http.client.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.vertx.http.client.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.vertx.http.client.cookie.sampling.rate=1 +profiler.vertx.http.client.entity.statuscode=true + +########################################################### +# Undertow +########################################################### +profiler.undertow.enable=true +# trace param in request ,default value is true +profiler.undertow.tracerequestparam=true +# Hide pinpoint headers. +profiler.undertow.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.undertow.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.undertow.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.undertow.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.undertow.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.undertow.realipemptyvalue}, Ignore header value. +#profiler.undertow.realipemptyvalue=unknown + +########################################################### +# SPRING BOOT # +########################################################### +profiler.springboot.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.springboot.bootstrap.main=org.springframework.boot.loader.JarLauncher, org.springframework.boot.loader.WarLauncher, org.springframework.boot.loader.PropertiesLauncher + +########################################################### +# JSP # +########################################################### +profiler.jsp.enable=true + +########################################################### +# JDBC # +########################################################### +# Profile JDBC drivers. +profiler.jdbc=true +# Size of cache. Fixed maximum. +profiler.jdbc.sqlcachesize=1024 +# trace bindvalues for PreparedStatements +profiler.jdbc.tracesqlbindvalue=true +# Maximum bindvalue size. +profiler.jdbc.maxsqlbindvaluesize=1024 + +# +# MYSQL +# +# Profile MySQL. +profiler.jdbc.mysql=true +# Allow profiling of setautocommit. +profiler.jdbc.mysql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mysql.commit=true +# Allow profiling of rollback. +profiler.jdbc.mysql.rollback=true +# Trace bindvalues for MySQL PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mysql.tracesqlbindvalue=true + +# +# MARIADB +# +# Profile MariaDB +profiler.jdbc.mariadb=true +# Allow profiling of setautocommit. +profiler.jdbc.mariadb.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mariadb.commit=true +# Allow profiling of rollback. +profiler.jdbc.mariadb.rollback=true +# Trace bindvalues for MariaDB PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mariadb.tracesqlbindvalue=true + +# +# MSSQL Jtds +# +# Profile jTDS. +profiler.jdbc.jtds=true +# Allow profiling of setautocommit. +profiler.jdbc.jtds.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.jtds.commit=true +# Allow profiling of rollback. +profiler.jdbc.jtds.rollback=true +# Trace bindvalues for jTDS PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.jtds.tracesqlbindvalue=true + +# +# Oracle +# +# Profile Oracle DB. +profiler.jdbc.oracle=true +# Allow profiling of setautocommit. +profiler.jdbc.oracle.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.oracle.commit=true +# Allow profiling of rollback. +profiler.jdbc.oracle.rollback=true +# Trace bindvalues for Oracle PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.oracle.tracesqlbindvalue=true + +# +# CUBRID +# +# Profile CUBRID. +profiler.jdbc.cubrid=true +# Allow profiling of setautocommit. +profiler.jdbc.cubrid.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.cubrid.commit=true +# Allow profiling of rollback. +profiler.jdbc.cubrid.rollback=true +# Trace bindvalues for CUBRID PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.cubrid.tracesqlbindvalue=true + +# +# DBCP +# +# Profile DBCP. +profiler.jdbc.dbcp=true +profiler.jdbc.dbcp.connectionclose=true + +# +# DBCP2 +# +# Profile DBCP2. +profiler.jdbc.dbcp2=true +profiler.jdbc.dbcp2.connectionclose=true + +# +# HIKARICP +# +profiler.jdbc.hikaricp=true +profiler.jdbc.hikaricp.connectionclose=true + +# +# DRUID +# +profiler.jdbc.druid=true +profiler.jdbc.druid.connectionclose=true + +# +# CASSANDRA +# +# Profile CASSANDRA. +profiler.cassandra=true +# Trace bindvalues for CASSANDRA PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.cassandra.tracecqlbindvalue=true + +# +# PostgreSQL +# +# Profile PostgreSQL. +profiler.jdbc.postgresql=true +# Allow profiling of setautocommit. +profiler.jdbc.postgresql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.postgresql.commit=true +# Allow profiling of rollback. +profiler.jdbc.postgresql.rollback=true + +########################################################### +# MONGODB +########################################################### +profiler.mongo=true +profiler.mongo.collectJson=true + +########################################################### +# Apache HTTP Client 3.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient3.param=true + +# Record Cookies. +profiler.apache.httpclient3.cookie=true + +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient3.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient3.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.entity.dumptype=ALWAYS +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient3.entity.sampling.rate=1 + +# Record IO time. +profiler.apache.httpclient3.io=true + +########################################################### +# Apache HTTP Client 4.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient4.param=true + +# Record cookies. +profiler.apache.httpclient4.cookie=true + +# When cookies should be dumped. It could be ALWAYS or EXCEPTION. +profiler.apache.httpclient4.cookie.dumptype=ALWAYS + +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient4.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient4.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient4.entity.dumptype=ALWAYS + +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient4.entity.sampling.rate=1 + +# Allow profiling status code value. +profiler.apache.httpclient4.entity.statuscode=true + +# Record IO time. +profiler.apache.httpclient4.io=true + +# Not supported yet. +#profiler.apache.nio.httpclient4=true + +########################################################### +# JDK HTTPURLConnection # +########################################################### +# Profile parameter. +profiler.jdk.http.param=true + +########################################################### +# Ning Async HTTP Client # +########################################################### +# Profile Ning Async HTTP Client. +profiler.ning.asynchttpclient=true +# Record cookies. +profiler.ning.asynchttpclient.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS +# Cookie dump size. +profiler.ning.asynchttpclient.cookie.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.cookie.sampling.rate=1 +# Record Entities. +profiler.ning.asynchttpclient.entity=true +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.entity.dumptype=ALWAYS +# Entity dump size. +profiler.ning.asynchttpclient.entity.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.entity.sampling.rate=1 +# Record parameters. (unsupported in 1.8.x, 1.9.x versions) +profiler.ning.asynchttpclient.param=true +# When to dump parameters. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.param.dumptype=ALWAYS +# Parameter dump size. +profiler.ning.asynchttpclient.param.dumpsize=1024 +# 1 out of n parameters will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.param.sampling.rate=1 + + +########################################################### +# Arcus # +########################################################### +# Profile Arcus. +profiler.arcus=true +profiler.arcus.async=true +# Record keytrace. +profiler.arcus.keytrace=true + +########################################################### +# Memcached # +########################################################### +# Profile Memecached. +profiler.memcached=true +profiler.memcached.async=true +# Record keytrace +profiler.memcached.keytrace=true + +########################################################### +# Thrift # +########################################################### +# Profile Thrift +profiler.thrift.client=true +profiler.thrift.client.async=true +# Profile processor. +profiler.thrift.processor=true +profiler.thrift.processor.async=true +# Allow recording arguments. +profiler.thrift.service.args=true +# Allow recording result. +profiler.thrift.service.result=true + + +########################################################### +# ibatis # +########################################################### +# Profile ibatis. +profiler.orm.ibatis=true + +########################################################### +# mybatis # +########################################################### +# Profile mybatis +profiler.orm.mybatis=true + +########################################################### +# spring-beans +########################################################### +# Profile spring-beans +profiler.spring.beans=true + +# filters +# filter +# filter OR filters +# filter +# value +# value AND filter +# value +# token +# token OR token +# token +# profiler.spring.beans.n.scope= [component-scan | post-processor] default is component-scan. +# profiler.spring.beans.n.base-packages= [package name, ...] +# profiler.spring.beans.n.name.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.class.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.annotation= [annotation name, ...] +# +# Scope: +# component-scan: or @ComponentScan +# post-processor: BeanPostProcessor - Slow!!! +# +# ANT Style pattern rules: +# ? - matches on character +# * - matches zero or more characters +# ** - matches zero or more 'directories' in a path + +# Examples +# profiler.spring.beans.1.scope=component-scan +# profiler.spring.beans.1.base-packages=com.foo, com.bar +# profiler.spring.beans.1.name.pattern=.*Foo, regex:.*Bar, antstyle:*Controller +# profiler.spring.beans.1.class.pattern= +# profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository +# +# profiler.spring.beans.2.scope=post-processor +# profiler.spring.beans.2.base-packages=com.foo +# profiler.spring.beans.2.name.pattern= +# profiler.spring.beans.2.class.pattern=antstyle:com.foo.repository.*Repository, antstyle:com.foo.Service.Main* +# profiler.spring.beans.2.annotation= + +profiler.spring.beans.1.scope=component-scan +profiler.spring.beans.1.base-packages= +profiler.spring.beans.1.name.pattern= +profiler.spring.beans.1.class.pattern= +profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository + +profiler.spring.beans.mark.error=false + +########################################################### +# spring @Async +########################################################### +profiler.spring.async.enable=true +# Add custom AsyncTaskExecutor classes. Comma separated list of fully qualified class names. Wildcard not supported. +# Default values +# org.springframework.scheduling.concurrent.ConcurrentTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.core.task.SimpleAsyncTaskExecutor +# org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor +# org.springframework.core.task.support.TaskExecutorAdapter +# org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.jca.work.WorkManagerTaskExecutor +# org.springframework.scheduling.commonj.WorkManagerTaskExecutor +profiler.spring.async.executor.class.names= + +########################################################### +# log4j (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.log4j.logging.transactioninfo=false + +########################################################### +# logback (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.logback.logging.transactioninfo=false + +########################################################### +# google httpclient +########################################################### +# Profile async. +profiler.google.httpclient.async=true + +########################################################### +# redis +########################################################### +profiler.redis.pipeline +profiler.redis=true +profiler.redis.io=true + +########################################################### +# OkHttp +########################################################### +profiler.okhttp.enable=true +# Record param. +profiler.okhttp.param=true + +# Record Cookies. +profiler.okhttp.cookie=false +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.okhttp.cookie.dumptype=EXCEPTION +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.okhttp.cookie.sampling.rate=1 +# enqueue operation +profiler.okhttp.async=true + +########################################################### +# Apache CXF +# +# Note: logging.enable must use cxf logging +# see http://cxf.apache.org/docs/message-logging.html +########################################################### +profiler.cxf.service.enable=true +profiler.cxf.logging.enable=true + +########################################################### +# fastjson +########################################################### +profiler.json.fastjson=true + +########################################################### +# gson +########################################################### +profiler.json.gson=true + +########################################################### +# jackson +########################################################### +profiler.json.jackson=true + +########################################################### +# json-lib +########################################################### +profiler.json.jsonlib=true + +########################################################### +# ActiveMQ Client +########################################################### +profiler.activemq.client.enable=true +profiler.activemq.client.producer.enable=true +profiler.activemq.client.consumer.enable=true +profiler.activemq.client.trace.message=false + +# ActiveMQ destination path separator (default is ".") +profiler.activemq.client.destination.separator= + +# ActiveMQ destinations to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.activemq.client.destination.exclude= + +########################################################### +# RxJava +########################################################### +profiler.rxjava=true + +########################################################### +# Hystrix +########################################################### +# profiler.rxjava must also be enabled to properly trace hystrix commands +profiler.hystrix=true + +########################################################### +# RestTemplate +########################################################### +profiler.resttemplate=false + +########################################################### +# Netty +########################################################### +# recommend netty plugin disable, when using VERTX. +profiler.netty=false +profiler.netty.http=false + +########################################################### +# RabbitMQ Client +########################################################### +profiler.rabbitmq.client.enable=true +profiler.rabbitmq.client.producer.enable=true +profiler.rabbitmq.client.consumer.enable=true +# Custom consumer classes to be traced (comma separated list of fully qualified class names) +# If a consumer class is an inner class, specify the outer class +profiler.rabbitmq.client.consumer.classes= +# RabbitMQ exchange to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.rabbitmq.client.exchange.exclude= + +########################################################### +# Akka HTTP (Reliability and stability can not be guaranteed) +########################################################### +# HTTP server +profiler.akka.http.enable=false +# original IP address header +profiler.akka.http.realipheader=Remote-Address +# URLs to exclude from tracing +profiler.akka.http.excludeurl= +# HTTP Request methods to exclude from tracing +profiler.akka.http.excludemethod= +# Set transform target +# If you are using another directive, change below config +profiler.akka.http.transform.targetname=akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRequestContext$2 +profiler.akka.http.transform.targetparameter=scala.Function1,scala.Function1,akka.http.scaladsl.server.RequestContext + +########################################################### +# Kafka (Reliability and stability can not be guaranteed) +# Version 0.11+ is supported. +# Note: RemoteTrace will not occur if the method specified in the profiler.kafka.consumer.entryPoint is not the first trace point. +########################################################### +profiler.kafka.producer.enable=false +profiler.kafka.consumer.enable=false +// you must set target that handles ConsumerRecord as a argument for remote trace +// ex) profiler.kafka.entryPoint=clazzName.methodName +profiler.kafka.consumer.entryPoint= + +########################################################### +# Hbase (Reliability and stability can not be guaranteed) +########################################################### +profiler.hbase.client.enable=true +profiler.hbase.client.admin.enable=true +profiler.hbase.client.table.enable=true +profiler.hbase.client.params.enable=true \ No newline at end of file diff --git a/agent/src/test/resources/hystrix/pinpoint-hystrix.config b/agent-it/src/test/resources/hystrix/pinpoint-hystrix.config similarity index 100% rename from agent/src/test/resources/hystrix/pinpoint-hystrix.config rename to agent-it/src/test/resources/hystrix/pinpoint-hystrix.config diff --git a/agent/src/test/resources/jdbc/mariadb/init.sql b/agent-it/src/test/resources/jdbc/mariadb/init.sql similarity index 100% rename from agent/src/test/resources/jdbc/mariadb/init.sql rename to agent-it/src/test/resources/jdbc/mariadb/init.sql diff --git a/agent/src/test/resources/pinpoint-disabled-plugin-test.config b/agent-it/src/test/resources/pinpoint-disabled-plugin-test.config similarity index 100% rename from agent/src/test/resources/pinpoint-disabled-plugin-test.config rename to agent-it/src/test/resources/pinpoint-disabled-plugin-test.config diff --git a/agent-it/src/test/resources/pinpoint-grpc-plugin-test.config b/agent-it/src/test/resources/pinpoint-grpc-plugin-test.config new file mode 100644 index 000000000000..80bcb65fae20 --- /dev/null +++ b/agent-it/src/test/resources/pinpoint-grpc-plugin-test.config @@ -0,0 +1,380 @@ +# +# Pinpoint agent configuration +# + +########################################################### +# Collector server # +########################################################### +profiler.collector.ip=127.0.0.1 + +# placeHolder support "${key}" +profiler.collector.span.ip=${profiler.collector.ip} +profiler.collector.span.port=9996 + +# placeHolder support "${key}" +profiler.collector.stat.ip=${profiler.collector.ip} +profiler.collector.stat.port=9995 + +# placeHolder support "${key}" +profiler.collector.tcp.ip=${profiler.collector.ip} +profiler.collector.tcp.port=9994 + + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +profiler.jvm.collect.interval=1000 + +profiler.sampling.enable=true + +# Set sampling rate. If you set it to 10, 1 out of 10 transaction will be sampled. +profiler.sampling.rate=1 + +profiler.io.buffering.enable=true +profiler.io.buffering.buffersize=20 + +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 +profiler.spandatasender.chunk.size=16384 +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.spandatasender.transport.type=UDP + +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 +profiler.statdatasender.chunk.size=16384 +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.statdatasender.transport.type=UDP + +profiler.agentInfo.send.retry.interval=300000 + +# Allows TCP data command +profiler.tcpdatasender.command.accept.enable=true + +# Allow bytecode framework (JAVASSIST or ASM) +profiler.instrument.engine=ASM + + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + +########################################################### +# application type detect order # +########################################################### +profiler.type.detect.order= + +profiler.plugin.disable=com.navercorp.pinpoint.plugin.jackson.JacksonPlugin + +########################################################### +# user defined classes # +########################################################### +profiler.include= + +########################################################### +# TOMCAT # +########################################################### +profiler.tomcat.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap +# Check pre-conditions when registering class file transformers mainly due to JBoss plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.apache.catalina.startup.Bootstrap, +# or SpringBoot's launchers. +# Set this to false to bypass this check entirely (such as when launching standalone applications running embedded Tomcat). +profiler.tomcat.conditional.transform=true +# Hide pinpoint headers. +profiler.tomcat.hidepinpointheader=true +# URLs to exclude from tracing +profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html +profiler.tomcat.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.tomcat.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.tomcat.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.tomcat.realipemptyvalue}, Ignore header value. +#profiler.tomcat.realipemptyvalue=unknown + + +########################################################### +# JETTY # +########################################################### +profiler.jetty.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main +# URLs to exclude from tracing +profiler.jetty.excludeurl= + + +########################################################### +# DUBBO # +########################################################### +profiler.dubbo.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.dubbo.bootstrap.main=com.alibaba.dubbo.container.Main + + +########################################################### +# JBOSS # +########################################################### +profiler.jboss.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jboss.bootstrap.main=org.jboss.modules.Main +# Check pre-conditions when registering class file transformers mainly due to Tomcat plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.jboss.modules.Main. +# Set this to false to bypass this check entirely. +profiler.jboss.conditional.transform=true +# Hide pinpoint headers. +profiler.jboss.hidepinpointheader=true +# URLs to exclude from tracing +profiler.jboss.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jboss.excludemethod= +profiler.jboss.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jboss.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jboss.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. +#profiler.jboss.realipemptyvalue=unknown + + +########################################################### +# SPRING BOOT # +########################################################### +profiler.springboot.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.springboot.bootstrap.main=org.springframework.boot.loader.JarLauncher, org.springframework.boot.loader.WarLauncher, org.springframework.boot.loader.PropertiesLauncher + +########################################################### +# JDBC # +########################################################### +profiler.jdbc=true +profiler.jdbc.sqlcachesize=1024 +profiler.jdbc.maxsqlbindvaluesize=1024 + +# +# MYSQL +# +profiler.jdbc.mysql=true +profiler.jdbc.mysql.setautocommit=true +profiler.jdbc.mysql.commit=true +profiler.jdbc.mysql.rollback=true + +# +# MSSQL Jtds +# +profiler.jdbc.jtds=true +profiler.jdbc.jtds.setautocommit=true +profiler.jdbc.jtds.commit=true +profiler.jdbc.jtds.rollback=true + +# +# Oracle +# +profiler.jdbc.oracle=true +profiler.jdbc.oracle.setautocommit=true +profiler.jdbc.oracle.commit=true +profiler.jdbc.oracle.rollback=true + +# +# CUBRID +# +profiler.jdbc.cubrid=true +profiler.jdbc.cubrid.setautocommit=true +profiler.jdbc.cubrid.commit=true +profiler.jdbc.cubrid.rollback=true + +# +# DBCP +# +profiler.jdbc.dbcp=true +profiler.jdbc.dbcp.connectionclose=true + +# +# DBCP2 +# +profiler.jdbc.dbcp2=true +profiler.jdbc.dbcp2.connectionclose=true + +# +# HIKARICP +# +profiler.jdbc.hikaricp=true +profiler.jdbc.hikaricp.connectionclose=true + +########################################################### +# Apache HTTP Client 4.x # +########################################################### +profiler.apache.httpclient4=true +profiler.apache.httpclient4.cookie=true + +# When cookies should be dumped. It could be ALWAYS or EXCEPTION. +profiler.apache.httpclient4.cookie.dumptype=ALWAYS +profiler.apache.httpclient4.cookie.sampling.rate=1 + +# Dump entities of POST or PUT request. limited to entities which is HttpEntity.isRepeatable() == true. +profiler.apache.httpclient4.entity=true + +# When entities should be dumped. ALWAYS or EXCEPTION. +profiler.apache.httpclient4.entity.dumptype=ALWAYS +profiler.apache.httpclient4.entity.sampling.rate=1 + +profiler.apache.nio.httpclient4=true + + +########################################################### +# JDK HTTPURLConnection # +########################################################### +profiler.jdk.httpurlconnection=true + + +########################################################### +# Ning Async HTTP Client # +########################################################### +profiler.ning.asynchttpclient=true +profiler.ning.asynchttpclient.cookie=true +profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS +profiler.ning.asynchttpclient.cookie.dumpsize=1024 +profiler.ning.asynchttpclient.cookie.sampling.rate=1 +profiler.ning.asynchttpclient.entity=true +profiler.ning.asynchttpclient.entity.dumptype=ALWAYS +profiler.ning.asynchttpclient.entity.dumpsize=1024 +profiler.ning.asynchttpclient.entity.sampling.rate=1 +profiler.ning.asynchttpclient.param=true +profiler.ning.asynchttpclient.param.dumptype=ALWAYS +profiler.ning.asynchttpclient.param.dumpsize=1024 +profiler.ning.asynchttpclient.param.sampling.rate=1 + +########################################################### +# RestTemplate # +########################################################### +profiler.resttemplate=true + +########################################################### +# Arcus # +########################################################### +profiler.arcus=true +profiler.arcus.keytrace=true + + +########################################################### +# Memcached # +########################################################### +profiler.memcached=true +profiler.memcached.keytrace=true + + +########################################################### +# ibatis # +########################################################### +profiler.orm.ibatis=true + + +########################################################### +# mybatis # +########################################################### +profiler.orm.mybatis=true + + +########################################################### +# spring-beans +########################################################### +# Profile spring-beans +profiler.spring.beans=true + +# filters +# filter +# filter OR filters +# filter +# value +# value AND filter +# value +# token +# token OR token +# token +# profiler.spring.beans.n.scope= [component-scan | post-processor] default is component-scan. +# profiler.spring.beans.n.base-packages= [package name, ...] +# profiler.spring.beans.n.name.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.class.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.annotation= [annotation name, ...] +# +# Scope: +# component-scan: or @ComponentScan +# post-processor: BeanPostProcessor - Slow!!! +# +# ANT Style pattern rules: +# ? - matches on character +# * - matches zero or more characters +# ** - matches zero or more 'directories' in a path + +# Examples +# profiler.spring.beans.1.scope=component-scan +# profiler.spring.beans.1.base-packages=com.foo, com.bar +# profiler.spring.beans.1.name.pattern=.*Foo, regex:.*Bar, antstyle:*Controller +# profiler.spring.beans.1.class.pattern= +# profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository +# +# profiler.spring.beans.2.scope=post-processor +# profiler.spring.beans.2.base-packages=com.foo +# profiler.spring.beans.2.name.pattern= +# profiler.spring.beans.2.class.pattern=antstyle:com.foo.repository.*Repository, antstyle:com.foo.Service.Main* +# profiler.spring.beans.2.annotation= + +profiler.spring.beans.1.name.pattern=ma.*, outer +profiler.spring.beans.2.class.pattern=.*Morae +profiler.spring.beans.3.annotation=org.springframework.stereotype.Component + +profiler.spring.beans.mark.error=false + +########################################################### +# log4j +########################################################### +profiler.log4j.logging.transactioninfo=false + +########################################################### +# logback +########################################################### +profiler.logback.logging.transactioninfo=false + +########################################################### +# gson +########################################################### +profiler.json.gson=true + +########################################################### +# jackson +########################################################### +profiler.json.jackson=true + +########################################################### +# json-lib +########################################################### +profiler.json.jsonlib=true + +########################################################### +# Netty +########################################################### +# recommend netty plugin disable, when using VERTX. +profiler.netty=false +profiler.netty.http=false + +########################################################### +# GRPC (Reliability and stability can not be guaranteed) +# Version 1.6.0+ is supported. +########################################################### +profiler.grpc.client.enable=true +profiler.grpc.server.enable=true +profiler.grpc.server.streaming.onmessage.enable=true \ No newline at end of file diff --git a/agent/src/test/resources/pinpoint-netty-plugin-test.config b/agent-it/src/test/resources/pinpoint-netty-plugin-test.config similarity index 100% rename from agent/src/test/resources/pinpoint-netty-plugin-test.config rename to agent-it/src/test/resources/pinpoint-netty-plugin-test.config diff --git a/agent/src/test/resources/pinpoint-spring-bean-test.config b/agent-it/src/test/resources/pinpoint-spring-bean-test.config similarity index 100% rename from agent/src/test/resources/pinpoint-spring-bean-test.config rename to agent-it/src/test/resources/pinpoint-spring-bean-test.config diff --git a/agent-it/src/test/resources/rabbitmq/client/pinpoint-rabbitmq.config b/agent-it/src/test/resources/rabbitmq/client/pinpoint-rabbitmq.config new file mode 100644 index 000000000000..2f8e629abe91 --- /dev/null +++ b/agent-it/src/test/resources/rabbitmq/client/pinpoint-rabbitmq.config @@ -0,0 +1,178 @@ +# +# Pinpoint agent configuration +# + +########################################################### +# Collector server # +########################################################### +profiler.collector.ip=127.0.0.1 + +# placeHolder support "${key}" +profiler.collector.span.ip=${profiler.collector.ip} +profiler.collector.span.port=9996 + +# placeHolder support "${key}" +profiler.collector.stat.ip=${profiler.collector.ip} +profiler.collector.stat.port=9995 + +# placeHolder support "${key}" +profiler.collector.tcp.ip=${profiler.collector.ip} +profiler.collector.tcp.port=9994 + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +profiler.interceptorregistry.size=8192 + +# Manually override jvm vendor name (Oracle, IBM, OpenJDK, etc) +# You probably won't ever need to set this value. +profiler.jvm.vendor.name= + +# Interval (in milliseconds) at which agent stat data is collected. (default : 5000, min : 1000, max : 5000) +profiler.jvm.stat.collect.interval=5000 +# Number of agent stat data sent to the collector in a single batch. (default : 6) +profiler.jvm.stat.batch.send.count=6 + +# Allow to add detailed collector's metrics +profiler.jvm.stat.collect.detailed.metrics=true + +# Allow sampling. +profiler.sampling.enable=true + +# 1 out of n transactions will be sampled where n is the rate. (1: 100%) +profiler.sampling.rate=1 + +# Allow buffering when flushing span to IO. +profiler.io.buffering.enable=true + +# How many spans to store if buffering enabled. +profiler.io.buffering.buffersize=20 + +# Capacity of the SpanDataSender write queue. +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 +profiler.spandatasender.chunk.size=16384 +profiler.spandatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.spandatasender.transport.type=UDP + +# Capacity of the StatDataSender write queue. +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 +profiler.statdatasender.chunk.size=16384 +profiler.statdatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.statdatasender.transport.type=UDP + +# Interval to retry sending agent info. Unit is milliseconds. +profiler.agentInfo.send.retry.interval=300000 + +# Allow TCP data command. +profiler.tcpdatasender.command.accept.enable=true +profiler.tcpdatasender.command.activethread.enable=true +profiler.tcpdatasender.command.activethread.count.enable=true +profiler.tcpdatasender.command.activethread.threaddump.enable=true +profiler.tcpdatasender.command.activethread.threadlightdump.enable=true + +# Trace Agent active thread info. +profiler.pinpoint.activethread=true + +# Trace DataSource +profiler.pinpoint.datasource=true + +# Deadlock Monitor +profiler.monitor.deadlock.enable=true +profiler.monitor.deadlock.interval=60000 + +## Call Stack +# Set max depth, if -1 is unlimited and min is 2. +profiler.callstack.max.depth=64 + +# weather or not to propagate exceptions occurred at interceptor +profiler.interceptor.exception.propagate=false + +# Allow bytecode framework (JAVASSIST or ASM) +profiler.instrument.engine=ASM + +# bytecode dump option +# java bytecode debug option +bytecode.dump.enable=false +#bytecode.dump.classlist=com.naver.user.UserService,com.pinpoint.debug.TestClass +bytecode.dump.classlist= +bytecode.dump.bytecode=false +bytecode.dump.verify=false +bytecode.dump.asm=false + +# Matcher +profiler.instrument.matcher.enable=true +# Matcher cache. max size is 64. +profiler.instrument.matcher.interface.cache.size=4 +profiler.instrument.matcher.interface.cache.entry.size=16 +profiler.instrument.matcher.annotation.cache.size=4 +profiler.instrument.matcher.annotation.cache.entry.size=4 +profiler.instrument.matcher.super.cache.size=4 +profiler.instrument.matcher.super.cache.entry.size=4 + +# Lambda expressions. +profiler.lambda.expressions.support=true + +# Proxy HTTP headers. +# Please see (https://github.com/naver/pinpoint/blob/master/doc/proxy-http-header.md) for more information. +profiler.proxy.http.header.enable=true + +# HTTP status code with request failure. +# 1xx, 2xx, 3xx, 4xx, 5xx, 100, 101, 200, 201, ... 501, 502, 503, 504, 505 +# e.g. profiler.http.status.code.errors=5xx, 401, 403 +profiler.http.status.code.errors=5xx + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + +########################################################### +# application type detect order # +########################################################### +profiler.type.detect.order= + +profiler.plugin.disable= + +########################################################### +# user defined classes # +########################################################### +# Specify classes and methods you want to profile here. + +# Needs to be a comma separated list of fully qualified class names, or fully qualified package names with wild card class. +profiler.include= +# Ex: foo.bar.MyClass, foo.baz.* + +# Needs to be a comma separated list of fully qualified method names. Wild card not supported. +profiler.entrypoint=com.navercorp.test.pinpoint.plugin.rabbitmq.PropagationMarker.mark +# Ex: foo.bar.MyClass.myMethod, foo.bar.MyClass.anotherMethod + +# Message queue listener invoker methods. +# This is usually for when a separate implementation or a framework provides a separate handler for invoking callbacks +# when consuming messages. +# Comma-separated list of fully qualified method names with a Message argument. +profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener,org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener + +########################################################### +# RabbitMQ Client +########################################################### +profiler.rabbitmq.client.enable=true +profiler.rabbitmq.client.producer.enable=true +profiler.rabbitmq.client.consumer.enable=true +# Custom consumer classes to be traced (comma separated list of fully qualified class names) +# If a consumer class is an inner class, specify the outer class +profiler.rabbitmq.client.consumer.classes=com.navercorp.test.pinpoint.plugin.rabbitmq.TestConsumer +# RabbitMQ exchange to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.rabbitmq.client.exchange.exclude= \ No newline at end of file diff --git a/agent/src/test/resources/qpid/qpid-config.json b/agent-it/src/test/resources/rabbitmq/qpid/qpid-config.json similarity index 100% rename from agent/src/test/resources/qpid/qpid-config.json rename to agent-it/src/test/resources/rabbitmq/qpid/qpid-config.json diff --git a/agent/src/test/resources/rxjava/pinpoint-rxjava.config b/agent-it/src/test/resources/rxjava/pinpoint-rxjava.config similarity index 100% rename from agent/src/test/resources/rxjava/pinpoint-rxjava.config rename to agent-it/src/test/resources/rxjava/pinpoint-rxjava.config diff --git a/agent-it/src/test/resources/spring-beans-test.xml b/agent-it/src/test/resources/spring-beans-test.xml new file mode 100644 index 000000000000..46ebce4cac2d --- /dev/null +++ b/agent-it/src/test/resources/spring-beans-test.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/agent-it/src/test/resources/spring-web-test.xml b/agent-it/src/test/resources/spring-web-test.xml new file mode 100644 index 000000000000..7d99309e8a2d --- /dev/null +++ b/agent-it/src/test/resources/spring-web-test.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/agent/src/test/resources/thrift/Echo.thrift b/agent-it/src/test/resources/thrift/Echo.thrift similarity index 100% rename from agent/src/test/resources/thrift/Echo.thrift rename to agent-it/src/test/resources/thrift/Echo.thrift diff --git a/agent/clover.license b/agent/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/agent/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-agent pinpoint-agent-distribution - jar @@ -45,233 +61,25 @@ com.navercorp.pinpoint - pinpoint-bootstrap-core-optional + pinpoint-bootstrap-java8 runtime - - com.navercorp.pinpoint - pinpoint-tools + pinpoint-bootstrap-java9 runtime - - com.navercorp.pinpoint - pinpoint-test - test - - - - org.springframework - spring-test - test - - - org.springframework - spring-context - test - - - org.springframework - spring-webmvc - test - - - - javax.servlet - javax.servlet-api - test - - - - org.mariadb.jdbc - mariadb-java-client - test - - - ch.vorburger.mariaDB4j - mariaDB4j - 2.2.2 - test - - - - com.google.code.gson - gson - 2.3.1 - test - - - net.sf.json-lib - json-lib - 2.3 - jdk15 - test - - - com.google.http-client - google-http-client - test - - - org.apache.ibatis - ibatis-sqlmap - 2.3.4.726 - test - - - org.springframework - spring-ibatis - 2.0.8 - test - - - org.mybatis - mybatis - test - - - org.mybatis - mybatis-spring - test - - - - - org.apache.httpcomponents - httpcore - test - - - org.apache.httpcomponents - httpasyncclient - test - - - org.apache.httpcomponents - httpcore-nio - test - - - org.apache.httpcomponents - httpclient - test - - - commons-httpclient - commons-httpclient - test - - - com.ning - async-http-client - test - - - - com.squareup.okhttp - okhttp - provided - - - - com.alibaba - dubbo - ${dubbo.version} - test - - - - com.datastax.cassandra - cassandra-driver-core - test - - - org.apache.cassandra - cassandra-all - 2.1.13 - test - - - - org.apache.activemq - activemq-all - 5.13.2 - test - - - - com.netflix.hystrix - hystrix-core - 1.5.12 - test - - - - io.reactivex - rxjava - 1.2.0 - test - - - - org.codehaus.jackson - jackson-core-asl - 1.9.13 - test - - - org.codehaus.jackson - jackson-mapper-asl - 1.9.13 - test - - - - com.fasterxml.jackson.core - jackson-core - test - - - com.fasterxml.jackson.core - jackson-annotations - test - - - com.fasterxml.jackson.core - jackson-databind - test - - - - org.nanohttpd - nanohttpd - 2.3.1 - test - - - - - com.zaxxer - HikariCP-java6 - 2.3.13 - test + pinpoint-bootstrap-core-optional + runtime - - - com.rabbitmq - amqp-client - 3.5.5 - test - + - org.apache.qpid - qpid-broker - 6.1.1 - test + com.navercorp.pinpoint + pinpoint-tools + runtime @@ -293,66 +101,17 @@ - - org.apache.maven.plugins - maven-surefire-plugin - 2.19.1 - - true - - - - org.apache.maven.plugins - maven-failsafe-plugin - 2.18.1 - - - test-on-jvm6 - - integration-test - verify - - - - **/jdk7/**/ - **/jdk8/**/ - - - false - true - ${env.JAVA_6_HOME}/bin/java - - - - test-on-jvm7 - - integration-test - verify - - - - **/jdk7/**/ - - - false - true - ${env.JAVA_7_HOME}/bin/java - - - - org.apache.maven.plugins maven-assembly-plugin - 2.5.3 + ${plugin.assembly.version} src/assembly/distribution.xml ${project.build.directory} false + @@ -364,40 +123,6 @@ - - com.spotify - docker-maven-plugin - ${docker.maven.plugin.version} - - false - naver/${project.artifactId}:${project.version} - alpine:3.2 - - ["/usr/local/bin/configure-agent.sh"] - - - - /assets/pinpoint-agent - ${project.build.directory} - ${project.artifactId}-${project.version}.tar.gz - - - /usr/local/bin/ - ${project.basedir}/ - configure-agent.sh - - - - /assets/pinpoint-agent - - - apk add --update bash - cp -v /assets/pinpoint-agent/pinpoint.config /assets/pinpoint.config - chmod a+x /usr/local/bin/configure-agent.sh - rm /var/cache/apk/* - - - diff --git a/agent/src/assembly/distribution.xml b/agent/src/assembly/distribution.xml index 9bba8c47ec7a..80ba02cd131a 100644 --- a/agent/src/assembly/distribution.xml +++ b/agent/src/assembly/distribution.xml @@ -1,6 +1,21 @@ - + + + pinpoint-naver-agent dir @@ -10,13 +25,9 @@ false - - ${basedir}/src/main/resources - - ${basedir}/src/main/resources-${env} - + ./ ${basedir.parent}/tools/src/main/script @@ -35,6 +46,8 @@ com.navercorp.pinpoint:pinpoint-annotations com.navercorp.pinpoint:pinpoint-commons com.navercorp.pinpoint:pinpoint-bootstrap-core + com.navercorp.pinpoint:pinpoint-bootstrap-java8 + com.navercorp.pinpoint:pinpoint-bootstrap-java9 com.navercorp.pinpoint:pinpoint-bootstrap-core-optional boot @@ -44,10 +57,13 @@ com.navercorp.pinpoint:pinpoint-annotations com.navercorp.pinpoint:pinpoint-commons com.navercorp.pinpoint:pinpoint-bootstrap-core + com.navercorp.pinpoint:pinpoint-bootstrap-java8 + com.navercorp.pinpoint:pinpoint-bootstrap-java9 com.navercorp.pinpoint:pinpoint-bootstrap-core-optional com.navercorp.pinpoint:pinpoint-bootstrap com.navercorp.pinpoint:pinpoint-plugins com.navercorp.pinpoint:pinpoint-tools + com.navercorp.pinpoint:pinpoint-grpc *:pom lib @@ -59,6 +75,7 @@ com.navercorp.pinpoint:pinpoint-plugins + *:pom plugin diff --git a/agent/src/main/resources-local/pinpoint.config b/agent/src/main/resources-local/pinpoint.config index 40cd52287f4d..211ce16476d1 100644 --- a/agent/src/main/resources-local/pinpoint.config +++ b/agent/src/main/resources-local/pinpoint.config @@ -24,12 +24,20 @@ profiler.collector.tcp.port=9994 ########################################################### profiler.enable=true +# Application namespace +# Differentiate from external pinpoint agents. (e.g., com.pinpoint) +profiler.application.namespace= + profiler.interceptorregistry.size=8192 # Manually override jvm vendor name (Oracle, IBM, OpenJDK, etc) # You probably won't ever need to set this value. profiler.jvm.vendor.name= +# Manually override agent's OS name (MAC, Window, Linus, AIX, HP_UX, BSD) +# You probably won't ever need to set this value.(to collect file descriptor) +profiler.os.name= + # Interval (in milliseconds) at which agent stat data is collected. (default : 5000, min : 1000, max : 5000) profiler.jvm.stat.collect.interval=5000 # Number of agent stat data sent to the collector in a single batch. (default : 6) @@ -82,6 +90,12 @@ profiler.tcpdatasender.command.activethread.count.enable=true profiler.tcpdatasender.command.activethread.threaddump.enable=true profiler.tcpdatasender.command.activethread.threadlightdump.enable=true +profiler.tcpdatasender.client.write.timeout=3000 +profiler.tcpdatasender.client.request.timeout=3000 +profiler.tcpdatasender.client.reconnect.interval=3000 +profiler.tcpdatasender.client.ping.interval=300000 +profiler.tcpdatasender.client.handshake.interval=60000 + # Trace Agent active thread info. profiler.pinpoint.activethread=true @@ -99,7 +113,7 @@ profiler.callstack.max.depth=64 # weather or not to propagate exceptions occurred at interceptor profiler.interceptor.exception.propagate=false -# Allow bytecode framework (JAVASSIST or ASM) +# Allow bytecode framework (ASM only) profiler.instrument.engine=ASM # bytecode dump option @@ -163,7 +177,7 @@ profiler.entrypoint= # This is usually for when a separate implementation or a framework provides a separate handler for invoking callbacks # when consuming messages. # Comma-separated list of fully qualified method names with a Message argument. -profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener +profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener,org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener ########################################################### # TOMCAT # @@ -178,11 +192,14 @@ profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap profiler.tomcat.conditional.transform=true # Hide pinpoint headers. profiler.tomcat.hidepinpointheader=true -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html # HTTP Request methods to exclude from tracing #profiler.tomcat.excludemethod= profiler.tomcat.tracerequestparam=true +# HTTP Request methods to exclude from tracing +#profiler.tomcat.excludemethod=POST,PUT # original IP address header # https://en.wikipedia.org/wiki/X-Forwarded-For @@ -199,10 +216,22 @@ profiler.tomcat.tracerequestparam=true profiler.jetty.enable=true # Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.jetty.excludeurl= -# Hide pinpoint headers. 9.x only +# HTTP Request methods to exclude from tracing +#profiler.jetty.excludemethod= +# Hide pinpoint headers. profiler.jetty.hide-pinpoint-header=true +profiler.jetty.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jetty.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jetty.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jetty.realipemptyvalue}, Ignore header value. +#profiler.jetty.realipemptyvalue=unknown ########################################################### # DUBBO # @@ -224,7 +253,8 @@ profiler.jboss.bootstrap.main=org.jboss.modules.Main profiler.jboss.conditional.transform=true # Hide pinpoint headers. profiler.jboss.hidepinpointheader=true -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.jboss.excludeurl= # HTTP Request methods to exclude from tracing #profiler.jboss.excludemethod= @@ -238,10 +268,57 @@ profiler.jboss.tracerequestparam=true # optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. #profiler.jboss.realipemptyvalue=unknown +########################################################### +# Resin +########################################################### +# default enable resin plugin +profiler.resin.enable=true +# if empty , default value is : com.caucho.server.resin.Resin +profiler.resin.bootstrap.main= +# trace param in request ,default value is true +profiler.resin.tracerequestparam=true +# excudeurl eg: filter static resources : /**/*.jpg,/**/*.png,/**/*.css,/**/*.js +profiler.resin.excludeurl= +# Hide pinpoint headers. +profiler.resin.hidepinpointheader=true +# HTTP Request methods to exclude from tracing +#profiler.resin.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.resin.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.resin.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.resin.realipemptyvalue}, Ignore header value. +#profiler.resin.realipemptyvalue=unknown + +########################################################### +# Weblogic +########################################################### +profiler.weblogic.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.weblogic.bootstrap.main=weblogic.Server +# trace param in request ,default value is true +profiler.weblogic.tracerequestparam=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.weblogic.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.weblogic.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.weblogic.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.weblogic.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.weblogic.realipemptyvalue}, Ignore header value. +#profiler.weblogic.realipemptyvalue=unknown + + ########################################################### # Vert.x(Reliability and stability can not be guaranteed) # ########################################################### -profiler.vertx.enable=false +profiler.vertx.enable=true # Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. profiler.vertx.bootstrap.main=io.vertx.core.Starter # Track Vertx.runOnContext() & Vertx.executeBlocking(). @@ -251,10 +328,13 @@ profiler.vertx.handler.base-packages= # e.g. com.service.handler, com.server.http.handler # HTTP server -profiler.vertx.http.server.enable=false +profiler.vertx.http.server.enable=true +# Set HttpServerRequestHandler method name. The argument is io.vertx.core.http.HttpServerRequest. +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept profiler.vertx.http.server.tracerequestparam=true profiler.vertx.http.server.hidepinpointheader=true -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.vertx.http.server.excludeurl= # original IP address header # https://en.wikipedia.org/wiki/X-Forwarded-For @@ -267,7 +347,7 @@ profiler.vertx.http.server.excludeurl= #profiler.vertx.http.server.excludemethod= # HTTP client -profiler.vertx.http.client.enable=false +profiler.vertx.http.client.enable=true profiler.vertx.http.client.param=true profiler.vertx.http.client.cookie=true # When to dump cookies. Either ALWAYS or EXCEPTION. @@ -276,6 +356,28 @@ profiler.vertx.http.client.cookie.dumptype=ALWAYS profiler.vertx.http.client.cookie.sampling.rate=1 profiler.vertx.http.client.entity.statuscode=true +########################################################### +# Undertow +########################################################### +profiler.undertow.enable=true +# trace param in request ,default value is true +profiler.undertow.tracerequestparam=true +# Hide pinpoint headers. +profiler.undertow.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.undertow.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.undertow.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.undertow.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.undertow.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.undertow.realipemptyvalue}, Ignore header value. +#profiler.undertow.realipemptyvalue=unknown + ########################################################### # SPRING BOOT # ########################################################### @@ -390,6 +492,12 @@ profiler.jdbc.dbcp2.connectionclose=true profiler.jdbc.hikaricp=true profiler.jdbc.hikaricp.connectionclose=true +# +# DRUID +# +profiler.jdbc.druid=true +profiler.jdbc.druid.connectionclose=true + # # CASSANDRA # @@ -410,6 +518,12 @@ profiler.jdbc.postgresql.commit=true # Allow profiling of rollback. profiler.jdbc.postgresql.rollback=true +########################################################### +# MONGODB +########################################################### +profiler.mongo=true +profiler.mongo.collectjson=true +profiler.mongo.tracebsonbindvalue=true ########################################################### # Apache HTTP Client 3.x # @@ -602,6 +716,24 @@ profiler.spring.beans.1.class.pattern= profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository profiler.spring.beans.mark.error=false + +########################################################### +# spring @Async +########################################################### +profiler.spring.async.enable=true +# Add custom AsyncTaskExecutor classes. Comma separated list of fully qualified class names. Wildcard not supported. +# Default values +# org.springframework.scheduling.concurrent.ConcurrentTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.core.task.SimpleAsyncTaskExecutor +# org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor +# org.springframework.core.task.support.TaskExecutorAdapter +# org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.jca.work.WorkManagerTaskExecutor +# org.springframework.scheduling.commonj.WorkManagerTaskExecutor +profiler.spring.async.executor.class.names= + ########################################################### # log4j (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) ########################################################### @@ -637,10 +769,24 @@ profiler.okhttp.cookie=false # When to dump cookies. Either ALWAYS or EXCEPTION. profiler.okhttp.cookie.dumptype=EXCEPTION # 1 out of n cookies will be sampled where n is the rate. (1: 100%) -profiler.okhttp.cookie.sampling.rate=10 +profiler.okhttp.cookie.sampling.rate=1 # enqueue operation profiler.okhttp.async=true +########################################################### +# Apache CXF +# Version 2.6.2+ is supported. +# Note: logging.enable must use cxf logging +# see http://cxf.apache.org/docs/message-logging.html +########################################################### +profiler.cxf.service.enable=true +profiler.cxf.logging.enable=true + +########################################################### +# fastjson +########################################################### +profiler.json.fastjson=true + ########################################################### # gson ########################################################### @@ -681,24 +827,6 @@ profiler.rxjava=true # profiler.rxjava must also be enabled to properly trace hystrix commands profiler.hystrix=true -########################################################### -# Resin -########################################################### -# default enable resin plugin -profiler.resin.enable=true -# if empty , default value is : com.caucho.server.resin.Resin -profiler.resin.bootstrap.main= -# trace param in request ,default value is true -profiler.resin.tracerequestparam=true -# excudeurl eg: filter static resources : /**/*.jpg,/**/*.png,/**/*.css,/**/*.js -profiler.resin.excludeurl= -# trace cookies in request ,default value is true -profiler.resin.tracecookies=true -# cookie.sampling.rate ,default value is 10 -profiler.resin.cookie.sampling.rate=10 -# ALWAYS|EXCEPTION ,default value is EXCEPTION -profiler.resin.cookie.dumptype=ALWAYS - ########################################################### # RestTemplate ########################################################### @@ -717,5 +845,62 @@ profiler.netty.http=false profiler.rabbitmq.client.enable=true profiler.rabbitmq.client.producer.enable=true profiler.rabbitmq.client.consumer.enable=true +# Custom consumer classes to be traced (comma separated list of fully qualified class names) +# If a consumer class is an inner class, specify the outer class +profiler.rabbitmq.client.consumer.classes= # RabbitMQ exchange to exclude from tracing (comma seprated list of ant-matched destinations) -profiler.rabbitmq.client.exchange.exclude= \ No newline at end of file +profiler.rabbitmq.client.exchange.exclude= + +########################################################### +# Akka HTTP (Reliability and stability can not be guaranteed) +########################################################### +# HTTP server +profiler.akka.http.enable=false +# original IP address header +profiler.akka.http.realipheader=Remote-Address +# URLs to exclude from tracing +profiler.akka.http.excludeurl= +# HTTP Request methods to exclude from tracing +profiler.akka.http.excludemethod= +# Set transform target +# If you are using another directive, change below config +profiler.akka.http.transform.targetname=akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRequestContext$2 +profiler.akka.http.transform.targetparameter=scala.Function1,scala.Function1,akka.http.scaladsl.server.RequestContext + +########################################################### +# Kafka (Reliability and stability can not be guaranteed) +# Version 0.11+ is supported. +# Note: RemoteTrace will not occur if the method specified in the profiler.kafka.consumer.entryPoint is not the first trace point. +########################################################### +profiler.kafka.producer.enable=false +profiler.kafka.consumer.enable=false +// you must set target that handles ConsumerRecord or ConsumerRecords(Remote Trace feature is not enabled.) as a argument for remote trace +// ex) profiler.kafka.consumer.entryPoint=clazzName.methodName +profiler.kafka.consumer.entryPoint= + +########################################################### +# Hbase (Reliability and stability can not be guaranteed) +########################################################### +profiler.hbase.client.enable=true +profiler.hbase.client.admin.enable=true +profiler.hbase.client.table.enable=true +profiler.hbase.client.params.enable=true + +########################################################### +# GRPC (Reliability and stability can not be guaranteed) +# Version 1.6.0+ is supported. +########################################################### +profiler.grpc.client.enable=true +profiler.grpc.server.enable=true +profiler.grpc.server.streaming.onmessage.enable=false + +########################################################### +# Openwhisk (Reliability and stability can not be guaranteed) +# Note: To use Openwhisk plugin, please enable Akka HTTP Plugin and +# change transform target config as follows +# - profiler.akka.http.transform.targetname=akka.http.scaladsl.server.directives.ExecutionDirectives$$anonfun$handleExceptions$1$$anonfun$apply$1.apply +# - profiler.akka.http.transform.targetparameter=akka.http.scaladsl.server.RequestContext +########################################################### +profiler.openwhisk.enable=true +profiler.openwhisk.logging.message=true +profiler.openwhisk.transform.targetname=whisk.http.BasicHttpService$$anonfun$assignId$1$$anonfun$apply$13 diff --git a/agent/src/main/resources/pinpoint-real-env-lowoverhead-sample.config b/agent/src/main/resources-release/pinpoint-real-env-lowoverhead-sample.config similarity index 79% rename from agent/src/main/resources/pinpoint-real-env-lowoverhead-sample.config rename to agent/src/main/resources-release/pinpoint-real-env-lowoverhead-sample.config index 108c1de189e0..856cf8740bbb 100644 --- a/agent/src/main/resources/pinpoint-real-env-lowoverhead-sample.config +++ b/agent/src/main/resources-release/pinpoint-real-env-lowoverhead-sample.config @@ -24,6 +24,10 @@ profiler.collector.tcp.port=9994 ########################################################### profiler.enable=true +# Application namespace +# Differentiate from external pinpoint agents. (e.g., com.pinpoint) +profiler.application.namespace= + profiler.interceptorregistry.size=8192 profiler.jvm.collect.interval=1000 @@ -76,7 +80,7 @@ profiler.callstack.max.depth=64 # weather or not to propagate exceptions occurred at interceptor profiler.interceptor.exception.propagate=false -# Allow bytecode framework (JAVASSIST or ASM) +# Allow bytecode framework (ASM only) profiler.instrument.engine=ASM # java bytecode dump option @@ -151,6 +155,8 @@ profiler.tomcat.hidepinpointheader=true # URLs to exclude from tracing profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html profiler.tomcat.tracerequestparam=true +# HTTP Request methods to exclude from tracing +#profiler.tomcat.excludemethod=POST,PUT # original IP address header # https://en.wikipedia.org/wiki/X-Forwarded-For @@ -169,8 +175,19 @@ profiler.jetty.enable=true profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main # URLs to exclude from tracing profiler.jetty.excludeurl= -# Hide pinpoint headers. 9.x only +# HTTP Request methods to exclude from tracing +#profiler.jetty.excludemethod= +# Hide pinpoint headers. profiler.jetty.hide-pinpoint-header=true +profiler.jetty.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jetty.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jetty.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jetty.realipemptyvalue}, Ignore header value. +#profiler.jetty.realipemptyvalue=unknown ########################################################### # DUBBO # @@ -206,6 +223,53 @@ profiler.jboss.tracerequestparam=true # optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. #profiler.jboss.realipemptyvalue=unknown +########################################################### +# Resin +########################################################### +# default enable resin plugin +profiler.resin.enable=true +# if empty , default value is : com.caucho.server.resin.Resin +profiler.resin.bootstrap.main= +# trace param in request ,default value is true +profiler.resin.tracerequestparam=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.resin.excludeurl= +# Hide pinpoint headers. +profiler.resin.hidepinpointheader=true +# HTTP Request methods to exclude from tracing +#profiler.resin.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.resin.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.resin.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.resin.realipemptyvalue}, Ignore header value. +#profiler.resin.realipemptyvalue=unknown + +########################################################### +# Weblogic +########################################################### +profiler.weblogic.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.weblogic.bootstrap.main=weblogic.Server +# trace param in request ,default value is true +profiler.weblogic.tracerequestparam=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.weblogic.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.weblogic.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.weblogic.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.weblogic.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.weblogic.realipemptyvalue}, Ignore header value. +#profiler.weblogic.realipemptyvalue=unknown + ########################################################### # Vert.x(Reliability and stability can not be guaranteed) # ########################################################### @@ -219,6 +283,8 @@ profiler.vertx.handler.base-packages= # HTTP server profiler.vertx.http.server.enable=false +# Set HttpServerRequestHandler method name. The argument is io.vertx.core.http.HttpServerRequest. +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept profiler.vertx.http.server.tracerequestparam=true profiler.vertx.http.server.hidepinpointheader=true # URLs to exclude from tracing @@ -243,6 +309,28 @@ profiler.vertx.http.client.cookie.dumptype=ALWAYS profiler.vertx.http.client.cookie.sampling.rate=1 profiler.vertx.http.client.entity.statuscode=true +########################################################### +# Undertow +########################################################### +profiler.undertow.enable=true +# trace param in request ,default value is true +profiler.undertow.tracerequestparam=true +# Hide pinpoint headers. +profiler.undertow.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.undertow.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.undertow.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.undertow.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.undertow.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.undertow.realipemptyvalue}, Ignore header value. +#profiler.undertow.realipemptyvalue=unknown + ########################################################### # SPRING BOOT # ########################################################### @@ -346,6 +434,12 @@ profiler.jdbc.dbcp2.connectionclose=false profiler.jdbc.hikaricp=true profiler.jdbc.hikaricp.connectionclose=false +# +# DRUID +# +profiler.jdbc.druid=true +profiler.jdbc.druid.connectionclose=false + # # CASSANDRA # @@ -366,6 +460,13 @@ profiler.jdbc.postgresql.commit=false # Allow profiling of rollback. profiler.jdbc.postgresql.rollback=false +########################################################### +# MONGODB +########################################################### +profiler.mongo=true +profiler.mongo.collectjson=true +profiler.mongo.tracebsonbindvalue=true + ########################################################### # Apache HTTP Client 3.x # ########################################################### @@ -538,6 +639,24 @@ profiler.spring.beans.1.class.pattern= profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository profiler.spring.beans.mark.error=false + +########################################################### +# spring @Async +########################################################### +profiler.spring.async.enable=true +# Add custom AsyncTaskExecutor classes. Comma separated list of fully qualified class names. Wildcard not supported. +# Default values +# org.springframework.scheduling.concurrent.ConcurrentTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.core.task.SimpleAsyncTaskExecutor +# org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor +# org.springframework.core.task.support.TaskExecutorAdapter +# org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.jca.work.WorkManagerTaskExecutor +# org.springframework.scheduling.commonj.WorkManagerTaskExecutor +profiler.spring.async.executor.class.names= + ########################################################### # log4j (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) ########################################################### @@ -574,6 +693,20 @@ profiler.okhttp.cookie.sampling.rate=10 # enqueue operation profiler.okhttp.async=true +########################################################### +# Apache CXF +# Version 2.6.2+ is supported. +# Note: logging.enable must use cxf logging +# see http://cxf.apache.org/docs/message-logging.html +########################################################### +profiler.cxf.service.enable=false +profiler.cxf.logging.enable=false + +########################################################### +# fastjson +########################################################### +profiler.json.fastjson=false + ########################################################### # gson ########################################################### @@ -589,24 +722,6 @@ profiler.json.jackson=false ########################################################### profiler.json.jsonlib=false -########################################################### -# Resin -########################################################### -# default enable resin plugin -profiler.resin.enable=true -# if empty , default value is : com.caucho.server.resin.Resin -profiler.resin.bootstrap.main= -# trace param in request ,default value is true -profiler.resin.tracerequestparam=true -# excudeurl eg: filter static resources : /**/*.jpg,/**/*.png,/**/*.css,/**/*.js -profiler.resin.excludeurl= -# trace cookies in request ,default value is true -profiler.resin.tracecookies=true -# cookie.sampling.rate ,default value is 10 -profiler.resin.cookie.sampling.rate=10 -# ALWAYS|EXCEPTION ,default value is EXCEPTION -profiler.resin.cookie.dumptype=ALWAYS - ########################################################### # RestTemplate ########################################################### @@ -617,4 +732,22 @@ profiler.resttemplate=false ########################################################### # recommend netty plugin disable, when using VERTX. profiler.netty=false -profiler.netty.http=false \ No newline at end of file +profiler.netty.http=false + +########################################################### +# Kafka +# Version 0.11+ is supported. +########################################################### +profiler.kafka.producer.enable=false +profiler.kafka.consumer.enable=false +// you must set target that handles ConsumerRecord or ConsumerRecords(Remote Trace feature is not enabled.) as a argument for remote trace +// ex) profiler.kafka.consumer.entryPoint=clazzName.methodName +profiler.kafka.consumer.entryPoint= + +########################################################### +# Hbase (Reliability and stability can not be guaranteed) +########################################################### +profiler.hbase.client.enable=true +profiler.hbase.client.admin.enable=false +profiler.hbase.client.table.enable=false +profiler.hbase.client.params.enable=false diff --git a/agent/src/main/resources-release/pinpoint.config b/agent/src/main/resources-release/pinpoint.config index 3714ac7998ae..1d227c3c7f9b 100644 --- a/agent/src/main/resources-release/pinpoint.config +++ b/agent/src/main/resources-release/pinpoint.config @@ -24,6 +24,10 @@ profiler.collector.tcp.port=9994 ########################################################### profiler.enable=true +# Application namespace +# Differentiate from external pinpoint agents. (e.g., com.pinpoint) +profiler.application.namespace= + profiler.interceptorregistry.size=8192 # Manually override jvm vendor name (Oracle, IBM, OpenJDK, etc) @@ -42,7 +46,7 @@ profiler.jvm.stat.collect.detailed.metrics=true profiler.sampling.enable=true # 1 out of n transactions will be sampled where n is the rate. (20: 5%) -profiler.sampling.rate=20 +profiler.sampling.rate=1 # Allow buffering when flushing span to IO. profiler.io.buffering.enable=true @@ -82,6 +86,12 @@ profiler.tcpdatasender.command.activethread.count.enable=true profiler.tcpdatasender.command.activethread.threaddump.enable=true profiler.tcpdatasender.command.activethread.threadlightdump.enable=true +profiler.tcpdatasender.client.write.timeout=3000 +profiler.tcpdatasender.client.request.timeout=3000 +profiler.tcpdatasender.client.reconnect.interval=3000 +profiler.tcpdatasender.client.ping.interval=300000 +profiler.tcpdatasender.client.handshake.interval=60000 + # Trace Agent active thread info. profiler.pinpoint.activethread=true @@ -99,7 +109,7 @@ profiler.callstack.max.depth=64 # weather or not to propagate exceptions occurred at interceptor profiler.interceptor.exception.propagate=false -# Allow bytecode framework (JAVASSIST or ASM) +# Allow bytecode framework (ASM only) profiler.instrument.engine=ASM # bytecode dump option @@ -163,7 +173,7 @@ profiler.entrypoint= # This is usually for when a separate implementation or a framework provides a separate handler for invoking callbacks # when consuming messages. # Comma-separated list of fully qualified method names with a Message argument. -profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener +profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener,org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener ########################################################### # TOMCAT # @@ -178,9 +188,12 @@ profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap profiler.tomcat.conditional.transform=true # Hide pinpoint headers. profiler.tomcat.hidepinpointheader=true -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html profiler.tomcat.tracerequestparam=true +# HTTP Request methods to exclude from tracing +#profiler.tomcat.excludemethod=POST,PUT # original IP address header # https://en.wikipedia.org/wiki/X-Forwarded-For @@ -197,10 +210,22 @@ profiler.tomcat.tracerequestparam=true profiler.jetty.enable=true # Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.jetty.excludeurl= -# Hide pinpoint headers. 9.x only +# HTTP Request methods to exclude from tracing +#profiler.jetty.excludemethod= +# Hide pinpoint headers. profiler.jetty.hide-pinpoint-header=true +profiler.jetty.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jetty.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jetty.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jetty.realipemptyvalue}, Ignore header value. +#profiler.jetty.realipemptyvalue=unknown ########################################################### # DUBBO # @@ -222,7 +247,8 @@ profiler.jboss.bootstrap.main=org.jboss.modules.Main profiler.jboss.conditional.transform=true # Hide pinpoint headers. profiler.jboss.hidepinpointheader=true -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.jboss.excludeurl= # HTTP Request methods to exclude from tracing #profiler.jboss.excludemethod= @@ -236,10 +262,58 @@ profiler.jboss.tracerequestparam=true # optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. #profiler.jboss.realipemptyvalue=unknown +########################################################### +# Resin +########################################################### +# default enable resin plugin +profiler.resin.enable=true +# if empty , default value is : com.caucho.server.resin.Resin +profiler.resin.bootstrap.main= +# trace param in request ,default value is true +profiler.resin.tracerequestparam=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.resin.excludeurl= +# Hide pinpoint headers. +profiler.resin.hidepinpointheader=true +# HTTP Request methods to exclude from tracing +#profiler.resin.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.resin.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.resin.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.resin.realipemptyvalue}, Ignore header value. +#profiler.resin.realipemptyvalue=unknown + + +########################################################### +# Weblogic +########################################################### +profiler.weblogic.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.weblogic.bootstrap.main=weblogic.Server +# trace param in request ,default value is true +profiler.weblogic.tracerequestparam=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.weblogic.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.weblogic.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.weblogic.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.weblogic.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.weblogic.realipemptyvalue}, Ignore header value. +#profiler.weblogic.realipemptyvalue=unknown + ########################################################### # Vert.x(Reliability and stability can not be guaranteed) # ########################################################### -profiler.vertx.enable=false +profiler.vertx.enable=true # Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. profiler.vertx.bootstrap.main=io.vertx.core.Starter # Track Vertx.runOnContext() & Vertx.executeBlocking(). @@ -248,10 +322,13 @@ profiler.vertx.handler.base-packages= # e.g. com.service.handler, com.server.http.handler # HTTP server -profiler.vertx.http.server.enable=false +profiler.vertx.http.server.enable=true +# Set HttpServerRequestHandler method name. The argument is io.vertx.core.http.HttpServerRequest. +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept profiler.vertx.http.server.tracerequestparam=true profiler.vertx.http.server.hidepinpointheader=true -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.vertx.http.server.excludeurl= # original IP address header # https://en.wikipedia.org/wiki/X-Forwarded-For @@ -264,7 +341,7 @@ profiler.vertx.http.server.excludeurl= #profiler.vertx.http.server.excludemethod= # HTTP client -profiler.vertx.http.client.enable=false +profiler.vertx.http.client.enable=true profiler.vertx.http.client.param=true profiler.vertx.http.client.cookie=true # When to dump cookies. Either ALWAYS or EXCEPTION. @@ -273,6 +350,29 @@ profiler.vertx.http.client.cookie.dumptype=ALWAYS profiler.vertx.http.client.cookie.sampling.rate=1 profiler.vertx.http.client.entity.statuscode=true + +########################################################### +# Undertow +########################################################### +profiler.undertow.enable=true +# trace param in request ,default value is true +profiler.undertow.tracerequestparam=true +# Hide pinpoint headers. +profiler.undertow.hidepinpointheader=true +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html +profiler.undertow.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.undertow.excludemethod= + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.undertow.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.undertow.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.undertow.realipemptyvalue}, Ignore header value. +#profiler.undertow.realipemptyvalue=unknown + ########################################################### # SPRING BOOT # ########################################################### @@ -387,6 +487,12 @@ profiler.jdbc.dbcp2.connectionclose=true profiler.jdbc.hikaricp=true profiler.jdbc.hikaricp.connectionclose=true +# +# DRUID +# +profiler.jdbc.druid=true +profiler.jdbc.druid.connectionclose=true + # # CASSANDRA # @@ -407,6 +513,12 @@ profiler.jdbc.postgresql.commit=true # Allow profiling of rollback. profiler.jdbc.postgresql.rollback=true +########################################################### +# MONGODB +########################################################### +profiler.mongo=true +profiler.mongo.collectjson=true +profiler.mongo.tracebsonbindvalue=true ########################################################### # Apache HTTP Client 3.x # @@ -477,6 +589,10 @@ profiler.jdk.http.param=true ########################################################### # Profile Ning Async HTTP Client. profiler.ning.asynchttpclient=true + +# Record parameters. (unsupported in 1.8.x, 1.9.x versions) +profiler.ning.asynchttpclient.param=true + # Record cookies. profiler.ning.asynchttpclient.cookie=true # When to dump cookies. Either ALWAYS or EXCEPTION. @@ -485,6 +601,7 @@ profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS profiler.ning.asynchttpclient.cookie.dumpsize=1024 # 1 out of n cookies will be sampled where n is the rate. (1: 100%) profiler.ning.asynchttpclient.cookie.sampling.rate=1 + # Record Entities. profiler.ning.asynchttpclient.entity=true # When to dump entities. Either ALWAYS or EXCEPTION. @@ -493,15 +610,6 @@ profiler.ning.asynchttpclient.entity.dumptype=ALWAYS profiler.ning.asynchttpclient.entity.dumpsize=1024 # 1 out of n cookies will be sampled where n is the rate. (1: 100%) profiler.ning.asynchttpclient.entity.sampling.rate=1 -# Record parameters. (unsupported in 1.8.x, 1.9.x versions) -profiler.ning.asynchttpclient.param=true -# When to dump parameters. Either ALWAYS or EXCEPTION. -profiler.ning.asynchttpclient.param.dumptype=ALWAYS -# Parameter dump size. -profiler.ning.asynchttpclient.param.dumpsize=1024 -# 1 out of n parameters will be sampled where n is the rate. (1: 100%) -profiler.ning.asynchttpclient.param.sampling.rate=1 - ########################################################### # Arcus # @@ -599,6 +707,24 @@ profiler.spring.beans.1.class.pattern= profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository profiler.spring.beans.mark.error=false + +########################################################### +# spring @Async +########################################################### +profiler.spring.async.enable=true +# Add custom AsyncTaskExecutor classes. Comma separated list of fully qualified class names. Wildcard not supported. +# Default values +# org.springframework.scheduling.concurrent.ConcurrentTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.core.task.SimpleAsyncTaskExecutor +# org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor +# org.springframework.core.task.support.TaskExecutorAdapter +# org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.jca.work.WorkManagerTaskExecutor +# org.springframework.scheduling.commonj.WorkManagerTaskExecutor +profiler.spring.async.executor.class.names= + ########################################################### # log4j (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) ########################################################### @@ -634,10 +760,24 @@ profiler.okhttp.cookie=false # When to dump cookies. Either ALWAYS or EXCEPTION. profiler.okhttp.cookie.dumptype=EXCEPTION # 1 out of n cookies will be sampled where n is the rate. (1: 100%) -profiler.okhttp.cookie.sampling.rate=10 +profiler.okhttp.cookie.sampling.rate=1 # enqueue operation profiler.okhttp.async=true +########################################################### +# Apache CXF +# Version 2.6.2+ is supported. +# Note: logging.enable must use cxf logging +# see http://cxf.apache.org/docs/message-logging.html +########################################################### +profiler.cxf.service.enable=true +profiler.cxf.logging.enable=false + +########################################################### +# fastjson +########################################################### +profiler.json.fastjson=false + ########################################################### # gson ########################################################### @@ -678,24 +818,6 @@ profiler.rxjava=false # profiler.rxjava must also be enabled to properly trace hystrix commands profiler.hystrix=false -########################################################### -# Resin -########################################################### -# default enable resin plugin -profiler.resin.enable=true -# if empty , default value is : com.caucho.server.resin.Resin -profiler.resin.bootstrap.main= -# trace param in request ,default value is true -profiler.resin.tracerequestparam=true -# excudeurl eg: filter static resources : /**/*.jpg,/**/*.png,/**/*.css,/**/*.js -profiler.resin.excludeurl= -# trace cookies in request ,default value is true -profiler.resin.tracecookies=true -# cookie.sampling.rate ,default value is 10 -profiler.resin.cookie.sampling.rate=10 -# ALWAYS|EXCEPTION ,default value is EXCEPTION -profiler.resin.cookie.dumptype=ALWAYS - ########################################################### # RestTemplate ########################################################### @@ -714,5 +836,62 @@ profiler.netty.http=false profiler.rabbitmq.client.enable=true profiler.rabbitmq.client.producer.enable=true profiler.rabbitmq.client.consumer.enable=true +# Custom consumer classes to be traced (comma separated list of fully qualified class names) +# If a consumer class is an inner class, specify the outer class +profiler.rabbitmq.client.consumer.classes= # RabbitMQ exchange to exclude from tracing (comma seprated list of ant-matched destinations) -profiler.rabbitmq.client.exchange.exclude= \ No newline at end of file +profiler.rabbitmq.client.exchange.exclude= + +########################################################### +# Akka HTTP (Reliability and stability can not be guaranteed) +########################################################### +# HTTP server +profiler.akka.http.enable=false +# original IP address header +profiler.akka.http.realipheader=Remote-Address +# URLs to exclude from tracing +profiler.akka.http.excludeurl= +# HTTP Request methods to exclude from tracing +profiler.akka.http.excludemethod= +# Set transform target +# If you are using another directive, change below config +profiler.akka.http.transform.targetname=akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRequestContext$2 +profiler.akka.http.transform.targetparameter=scala.Function1,scala.Function1,akka.http.scaladsl.server.RequestContext + +########################################################### +# Kafka (Reliability and stability can not be guaranteed) +# Version 0.11+ is supported. +# Note: RemoteTrace will not occur if the method specified in the profiler.kafka.consumer.entryPoint is not the first trace point. +########################################################### +profiler.kafka.producer.enable=false +profiler.kafka.consumer.enable=false +// you must set target that handles ConsumerRecord or ConsumerRecords(Remote Trace feature is not enabled.) as a argument for remote trace +// ex) profiler.kafka.consumer.entryPoint=clazzName.methodName +profiler.kafka.consumer.entryPoint= + +########################################################### +# Hbase (Reliability and stability can not be guaranteed) +########################################################### +profiler.hbase.client.enable=true +profiler.hbase.client.admin.enable=true +profiler.hbase.client.table.enable=true +profiler.hbase.client.params.enable=false + +########################################################### +# GRPC (Reliability and stability can not be guaranteed) +# Version 1.6.0+ is supported. +########################################################### +profiler.grpc.client.enable=false +profiler.grpc.server.enable=false +profiler.grpc.server.streaming.onmessage.enable=false + +########################################################### +# Openwhisk (Reliability and stability can not be guaranteed) +# Note: To use Openwhisk plugin, please enable Akka HTTP Plugin and +# change transform target config as follows +# - profiler.akka.http.transform.targetname=akka.http.scaladsl.server.directives.ExecutionDirectives$$anonfun$handleExceptions$1$$anonfun$apply$1.apply +# - profiler.akka.http.transform.targetparameter=akka.http.scaladsl.server.RequestContext +########################################################### +profiler.openwhisk.enable=false +profiler.openwhisk.logging.message=false +profiler.openwhisk.transform.targetname=whisk.http.BasicHttpService$$anonfun$assignId$1$$anonfun$apply$13 diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/dubbo/consumer/DubboConsumerIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/dubbo/consumer/DubboConsumerIT.java deleted file mode 100644 index d57059fb5f49..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/dubbo/consumer/DubboConsumerIT.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.navercorp.pinpoint.plugin.dubbo.consumer; - -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.monitor.MonitorService; -import com.alibaba.dubbo.rpc.Invocation; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcInvocation; -import com.alibaba.dubbo.rpc.cluster.Directory; -import com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker; -import com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker; -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.lang.reflect.Method; - -import static org.mockito.Mockito.when; - -/** - * @author Jinkai.Ma - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({ "com.alibaba:dubbo:2.5.3", "org.mockito:mockito-all:1.8.4" }) -public class DubboConsumerIT { - - @Mock - private RpcInvocation rpcInvocation; - private URL url; - @Mock - private Directory directory; - - private AbstractClusterInvoker abstractClusterInvoker; - - @Before - public void setUp() { - url = new URL("dubbo", "1.2.3.4", 5678); - MockitoAnnotations.initMocks(this); - when(directory.getUrl()).thenReturn(url); - } - - @Test - public void testConsumer() throws NoSuchMethodException { - Exception expected = null; - abstractClusterInvoker = new FailoverClusterInvoker(directory); - when(abstractClusterInvoker.getInterface()).thenReturn(String.class); - - try { - abstractClusterInvoker.invoke(rpcInvocation); - } catch (RpcException e) { - expected = e; - } - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - - Method invoke = AbstractClusterInvoker.class.getMethod("invoke", Invocation.class); - verifier.verifyTrace(Expectations.event("DUBBO_CONSUMER", invoke, expected)); - - verifier.verifyTraceCount(0); - } - - @Test - public void testConsumerMonitor() { - abstractClusterInvoker = new FailoverClusterInvoker(directory); - when(abstractClusterInvoker.getInterface()).thenReturn(MonitorService.class); - - try { - abstractClusterInvoker.invoke(rpcInvocation); - } catch (RpcException ignore) { - // ignore - } - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - - verifier.verifyTraceCount(0); - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/dubbo/provider/DubboProviderIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/dubbo/provider/DubboProviderIT.java deleted file mode 100644 index 2823f2b8292e..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/dubbo/provider/DubboProviderIT.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.navercorp.pinpoint.plugin.dubbo.provider; - -import com.alibaba.dubbo.common.URL; -import com.alibaba.dubbo.rpc.Invoker; -import com.alibaba.dubbo.rpc.RpcException; -import com.alibaba.dubbo.rpc.RpcInvocation; -import com.alibaba.dubbo.rpc.cluster.Directory; -import com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.navercorp.pinpoint.plugin.dubbo.DubboConstants; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import com.navercorp.pinpoint.test.plugin.TraceObjectManagable; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.lang.reflect.Method; - -import static org.mockito.Mockito.when; - -/** - * @author Jinkai.Ma - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({ "com.alibaba:dubbo:2.5.3", "org.mockito:mockito-all:1.8.4" }) -@TraceObjectManagable -public class DubboProviderIT { - - @Mock - private RpcInvocation rpcInvocation; - private URL url; - @Mock - private Directory directory; - @Mock - private Invoker invoker; - - @Before - public void setUp() { - url = new URL("dubbo", "1.2.3.4", 5678); - MockitoAnnotations.initMocks(this); - when(directory.getUrl()).thenReturn(url); - when(rpcInvocation.getMethodName()).thenReturn("toString"); - when(rpcInvocation.getInvoker()).thenReturn(invoker); - when(invoker.getInterface()).thenReturn(String.class); - when(rpcInvocation.getAttachment(DubboConstants.META_TRANSACTION_ID)).thenReturn("frontend.agent^1234567890^123321"); - when(rpcInvocation.getAttachment(DubboConstants.META_SPAN_ID)).thenReturn("9876543210"); - when(rpcInvocation.getAttachment(DubboConstants.META_PARENT_SPAN_ID)).thenReturn("1357913579"); - when(rpcInvocation.getAttachment(DubboConstants.META_PARENT_APPLICATION_TYPE)).thenReturn("1000"); - when(rpcInvocation.getAttachment(DubboConstants.META_PARENT_APPLICATION_NAME)).thenReturn("test.dubbo.consumer"); - when(rpcInvocation.getAttachment(DubboConstants.META_FLAGS)).thenReturn("0"); - } - - @Test - public void testProvider() throws NoSuchMethodException { - AbstractProxyInvoker abstractProxyInvoker = new AbstractProxyInvoker(new String(), String.class, url) { - @Override - protected Object doInvoke(Object proxy, String methodName, Class[] parameterTypes, Object[] arguments) throws Throwable { - Method method = proxy.getClass().getMethod(methodName, parameterTypes); - return method.invoke(proxy, arguments); - } - }; - try { - abstractProxyInvoker.invoke(rpcInvocation); - } catch (RpcException ignore) { - ignore.printStackTrace(); - } - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - - verifier.verifyTraceCount(1); - } - - @Test - public void testDoNotTrace() throws Exception { - when(rpcInvocation.getAttachment(DubboConstants.META_DO_NOT_TRACE)).thenReturn("1"); - - AbstractProxyInvoker abstractProxyInvoker = new AbstractProxyInvoker(new String(), String.class, url) { - @Override - protected Object doInvoke(Object proxy, String methodName, Class[] parameterTypes, Object[] arguments) throws Throwable { - Method method = proxy.getClass().getMethod(methodName, parameterTypes); - return method.invoke(proxy, arguments); - } - }; - try { - abstractProxyInvoker.invoke(rpcInvocation); - } catch (RpcException ignore) { - ignore.printStackTrace(); - } - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - verifier.verifyTraceCount(0); - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClientIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClientIT.java deleted file mode 100644 index 83638421e7e5..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClientIT.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.httpclient3; - -import com.navercorp.pinpoint.plugin.WebServer; -import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; -import org.apache.commons.httpclient.HostConfiguration; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.NameValuePair; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.params.HttpMethodParams; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - * @author jaehong.kim - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({ "commons-httpclient:commons-httpclient:[3.0],[3.0.1],[3.1]", "org.nanohttpd:nanohttpd:2.3.1"}) -public class HttpClientIT { - - private static WebServer webServer; - - @BeforeClass - public static void BeforeClass() throws Exception { - webServer = WebServer.newTestWebServer(); - } - - @AfterClass - public static void AfterClass() throws Exception { - final WebServer copy = webServer; - if (copy != null) { - copy.stop(); - webServer = null; - } - } - - private static final long CONNECTION_TIMEOUT = 10000; - private static final int SO_TIMEOUT = 10000; - - @Test - public void test() throws Exception { - HttpClient client = new HttpClient(); - client.getParams().setConnectionManagerTimeout(CONNECTION_TIMEOUT); - client.getParams().setSoTimeout(SO_TIMEOUT); - - GetMethod method = new GetMethod(webServer.getCallHttpUrl()); - - // Provide custom retry handler is necessary - method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false)); - method.setQueryString(new NameValuePair[] { new NameValuePair("key2", "value2") }); - - try { - // Execute the method. - client.executeMethod(method); - } catch (Exception ignored) { - } finally { - method.releaseConnection(); - } - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - } - - @Test - public void hostConfig() throws Exception { - HttpClient client = new HttpClient(); - client.getParams().setConnectionManagerTimeout(CONNECTION_TIMEOUT); - client.getParams().setSoTimeout(SO_TIMEOUT); - - HostConfiguration config = new HostConfiguration(); - config.setHost("weather.naver.com", 80, "http"); - GetMethod method = new GetMethod("/rgn/cityWetrMain.nhn"); - - // Provide custom retry handler is necessary - method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false)); - method.setQueryString(new NameValuePair[] { new NameValuePair("key2", "value2") }); - - try { - // Execute the method. - client.executeMethod(config, method); - } catch (Exception ignored) { - } finally { - method.releaseConnection(); - } - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - } -} \ No newline at end of file diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClientIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClientIT.java deleted file mode 100644 index 202032f0bca7..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClientIT.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.httpclient4; - -import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.*; - -import com.navercorp.pinpoint.plugin.WebServer; -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpRequest; -import org.apache.http.client.HttpClient; -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.routing.HttpRoute; -import org.apache.http.impl.client.AbstractHttpClient; -import org.apache.http.impl.client.BasicResponseHandler; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpRequestExecutor; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - * @author jaehong.kim - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({ "org.apache.httpcomponents:httpclient:[4.0],[4.0.1],[4.0.2],[4.0.3],[4.1],[4.1.1],[4.1.2],[4.1.3],[4.2],[4.2.1],[4.2.2],[4.2.3],[4.2.4],[4.2.4],[4.2.6]", - "org.nanohttpd:nanohttpd:2.3.1"}) -public class HttpClientIT { - - private static WebServer webServer; - - @BeforeClass - public static void BeforeClass() throws Exception { - webServer = WebServer.newTestWebServer(); - } - - @AfterClass - public static void AfterClass() throws Exception { - final WebServer copy = webServer; - if (copy != null) { - copy.stop(); - webServer = null; - } - } - - @Test - public void test() throws Exception { - HttpClient httpClient = new DefaultHttpClient(); - try { - HttpPost post = new HttpPost(webServer.getCallHttpUrl()); - post.addHeader("Content-Type", "application/json;charset=UTF-8"); - - ResponseHandler responseHandler = new BasicResponseHandler(); - httpClient.execute(post, responseHandler); - } catch (Exception ignored) { - } finally { - if (null != httpClient && null != httpClient.getConnectionManager()) { - httpClient.getConnectionManager().shutdown(); - } - } - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - - Class connectorClass; - - try { - connectorClass = Class.forName("org.apache.http.impl.conn.ManagedClientConnectionImpl"); - } catch (ClassNotFoundException e) { - connectorClass = Class.forName("org.apache.http.impl.conn.AbstractPooledConnAdapter"); - } - - verifier.verifyTrace(event("HTTP_CLIENT_4_INTERNAL", AbstractHttpClient.class.getMethod("execute", HttpUriRequest.class, ResponseHandler.class))); - final String hostname = webServer.getHostAndPort(); - verifier.verifyTrace(event("HTTP_CLIENT_4_INTERNAL", connectorClass.getMethod("open", HttpRoute.class, HttpContext.class, HttpParams.class), annotation("http.internal.display", hostname))); - verifier.verifyTrace(event("HTTP_CLIENT_4", HttpRequestExecutor.class.getMethod("execute", HttpRequest.class, HttpClientConnection.class, HttpContext.class), null, null, hostname, annotation("http.url", "/"), annotation("http.status.code", 200), annotation("http.io", anyAnnotationValue()))); - verifier.verifyTraceCount(0); - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBroker.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBroker.java deleted file mode 100644 index 9e8cf0dc9d0c..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/activemq/client/util/TestBroker.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.jdk7.activemq.client.util; - -import org.apache.activemq.ActiveMQConnection; -import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.broker.BrokerService; -import org.apache.activemq.broker.TransportConnector; - -import javax.jms.JMSException; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * @author HyunGil Jeong - */ -public class TestBroker { - - public static final String DEFAULT_BROKER_URL = "tcp://127.0.0.1:61616"; - - private final String brokerName; - private final BrokerService brokerService; - private final Map connectionFactories; - private final Map connections = new HashMap(); - - private TestBroker(String brokerName, BrokerService brokerService, Map connectionFactories) throws Exception { - this.brokerName = brokerName; - this.brokerService = brokerService; - this.connectionFactories = Collections.unmodifiableMap(connectionFactories); - } - - String getBrokerName() { - return this.brokerName; - } - - ActiveMQConnection getConnection(String connectUri) throws JMSException { - if (!this.connections.containsKey(connectUri)) { - throw new IllegalArgumentException("Connection for connectUri [" + connectUri + "] does not exist"); - } - return this.connections.get(connectUri); - } - - boolean start() throws Exception { - this.brokerService.start(); - // it might be better to wait until the broker has fully started using BrokerService#waitUntilStarted - // but this method was only introduced in 5.3.0 - for (Map.Entry e : this.connectionFactories.entrySet()) { - String connectUri = e.getKey(); - ActiveMQConnectionFactory connectionFactory = e.getValue(); - ActiveMQConnection connection = (ActiveMQConnection) connectionFactory.createConnection(); - connection.setClientID("client_" + connectUri); - connection.start(); - this.connections.put(connectUri, connection); - } - return true; - } - - void stop() throws Exception { - for (Map.Entry e : this.connections.entrySet()) { - ActiveMQConnection connection = e.getValue(); - connection.close(); - } - this.brokerService.stop(); - this.brokerService.waitUntilStopped(); - } - - public static class TestBrokerBuilder { - - private final String brokerName; - private final Set connectors = new HashSet(); - private final Set networkConnectors = new HashSet(); - - public TestBrokerBuilder(String brokerName) { - if (brokerName == null) { - throw new NullPointerException("brokerName must not be empty"); - } - this.brokerName = brokerName; - } - - public TestBrokerBuilder addConnector(String bindAddress) { - this.connectors.add(bindAddress); - return this; - } - - public TestBrokerBuilder addNetworkConnector(String discoveryAddress) { - this.networkConnectors.add(discoveryAddress); - return this; - } - - public TestBroker build() throws Exception { - if (this.connectors.isEmpty()) { - this.connectors.add(DEFAULT_BROKER_URL); - } - BrokerService brokerService = new BrokerService(); - brokerService.setBrokerName(this.brokerName); - brokerService.setPersistent(false); - brokerService.setUseJmx(false); - Map connectionFactories = new HashMap(); - for (String bindAddress : this.connectors) { - TransportConnector connector = brokerService.addConnector(bindAddress); - connectionFactories.put(bindAddress, new ActiveMQConnectionFactory(connector.getConnectUri())); - } - for (String discoveryAddress : this.networkConnectors) { - brokerService.addNetworkConnector(discoveryAddress); - } - return new TestBroker(this.brokerName, brokerService, connectionFactories); - } - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_0_x_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_0_x_IT.java deleted file mode 100644 index 6f26d90f1d0e..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_0_x_IT.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.jdk7.cassandra; - -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; - -/** - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({ - "com.datastax.cassandra:cassandra-driver-core:[2.0.12,2.0.max]", - "org.apache.cassandra:cassandra-all:2.0.17", - "com.google.guava:guava:17.0", - "org.codehaus.plexus:plexus-utils:3.0.22"}) -public class CassandraDatastax_2_0_x_IT extends CassandraDatastaxITBase { - - private static final String CASSANDRA_VERSION = "2_0_x"; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - initializeCluster(CASSANDRA_VERSION); - } - - @AfterClass - public static void tearDownAfterClass() { - cleanUpCluster(); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_1_x_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_1_x_IT.java deleted file mode 100644 index a2962934e17c..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_1_x_IT.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.jdk7.cassandra; - -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; - -/** - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({ - "com.datastax.cassandra:cassandra-driver-core:[2.1.9,2.1.max]", - "org.apache.cassandra:cassandra-all:2.1.13", - "com.google.guava:guava:17.0", - "org.codehaus.plexus:plexus-utils:3.0.22"}) -public class CassandraDatastax_2_1_x_IT extends CassandraDatastaxITBase { - - private static final String CASSANDRA_VERSION = "2_1_x"; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - initializeCluster(CASSANDRA_VERSION); - } - - @AfterClass - public static void tearDownAfterClass() { - cleanUpCluster(); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_2_x_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_2_x_IT.java deleted file mode 100644 index 7b6bf1e1c307..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_2_2_x_IT.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.jdk7.cassandra; - -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; - -/** - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({ - "com.datastax.cassandra:cassandra-driver-core:[2.2.0-rc3,2.2.max]", - "org.apache.cassandra:cassandra-all:2.1.13", - "com.google.guava:guava:17.0", - "org.codehaus.plexus:plexus-utils:3.0.22"}) -public class CassandraDatastax_2_2_x_IT extends CassandraDatastaxITBase { - - private static final String CASSANDRA_VERSION = "2_2_x"; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - initializeCluster(CASSANDRA_VERSION); - } - - @AfterClass - public static void tearDownAfterClass() { - cleanUpCluster(); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_3_0_x_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_3_0_x_IT.java deleted file mode 100644 index 4e7f4015786c..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraDatastax_3_0_x_IT.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.jdk7.cassandra; - -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; - -/** - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({ - "com.datastax.cassandra:cassandra-driver-core:[3.0.0,3.0.max]", - "org.apache.cassandra:cassandra-all:2.1.13", - "com.google.guava:guava:17.0", - "org.codehaus.plexus:plexus-utils:3.0.22"}) -public class CassandraDatastax_3_0_x_IT extends CassandraDatastaxITBase { - - private static final String CASSANDRA_VERSION = "3_0_x"; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - initializeCluster(CASSANDRA_VERSION); - } - - @AfterClass - public static void tearDownAfterClass() { - cleanUpCluster(); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraTestHelper.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraTestHelper.java deleted file mode 100644 index a8b884c81be3..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/cassandra/CassandraTestHelper.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.jdk7.cassandra; - -import org.apache.cassandra.config.DatabaseDescriptor; -import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.cassandra.service.EmbeddedCassandraService; -import org.codehaus.plexus.util.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -/** - * @author HyunGil Jeong - */ -public class CassandraTestHelper { - - private static final String CASSANDRA_HOME = "target/test-classes/cassandra"; - - private CassandraTestHelper() { - } - - public static void init(final String cassandraVersion) throws IOException, ConfigurationException { - final String cassandraStorageDir = String.format("%s/data_%s", CASSANDRA_HOME, cassandraVersion); - final String cassandraConfigFile = String.format("cassandra/cassandra_%s.yaml", cassandraVersion); - System.setProperty("cassandra.storagedir", cassandraStorageDir); - System.setProperty("cassandra.config", cassandraConfigFile); - prepareEnvironment(); - EmbeddedCassandraService cassandra = new EmbeddedCassandraService(); - cassandra.start(); - } - - public static String getHost() { - return DatabaseDescriptor.getListenAddress().getHostAddress(); - } - - public static int getNativeTransportPort() { - return DatabaseDescriptor.getNativeTransportPort(); - } - - private static void prepareEnvironment() throws IOException { - try { - cleanUpFiles(); - } catch (IOException e) { - // ignore - just let the server start - } - } - - private static void cleanUpFiles() throws IOException { - Set fileLocations = new HashSet(); - for (String dataFileLocation : DatabaseDescriptor.getAllDataFileLocations()) { - fileLocations.add(dataFileLocation); - } - fileLocations.add(DatabaseDescriptor.getCommitLogLocation()); - fileLocations.add(DatabaseDescriptor.getSavedCachesLocation()); - for (String fileLocation : fileLocations) { - File location = new File(fileLocation); - if (location.exists() && location.isDirectory()) { - FileUtils.deleteDirectory(fileLocation); - } - } - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClientBackwardCompatibilityIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClientBackwardCompatibilityIT.java deleted file mode 100644 index 348f09ba6ae9..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClientBackwardCompatibilityIT.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.jdk7.okhttp; - -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.navercorp.pinpoint.plugin.WebServer; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import com.squareup.okhttp.*; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.lang.reflect.Method; - -/** - * @author jaehong.kim - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({"com.squareup.okhttp:okhttp:[2.0.0],[2.1.0],[2.2.0],[2.3.0]", "org.nanohttpd:nanohttpd:2.3.1"}) -public class OkHttpClientBackwardCompatibilityIT { - - private static WebServer webServer; - - - @BeforeClass - public static void BeforeClass() throws Exception { - webServer = WebServer.newTestWebServer(); - } - - - @AfterClass - public static void AfterClass() throws Exception { - final WebServer copy = webServer; - if (copy != null) { - copy.stop(); - webServer = null; - } - } - - @Test - public void execute() throws Exception { - Request request = new Request.Builder().url(webServer.getCallHttpUrl()).build(); - OkHttpClient client = new OkHttpClient(); - Response response = client.newCall(request).execute(); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - - Method callMethod = Call.class.getDeclaredMethod("execute"); - verifier.verifyTrace(Expectations.event("OK_HTTP_CLIENT_INTERNAL", callMethod)); - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClientIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClientIT.java deleted file mode 100644 index b72074852c04..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/okhttp/OkHttpClientIT.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.jdk7.okhttp; - -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.navercorp.pinpoint.plugin.WebServer; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import com.squareup.okhttp.*; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * @author jaehong.kim - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({"com.squareup.okhttp:okhttp:[2.4.0],[2.5.0]", "org.nanohttpd:nanohttpd:2.3.1"}) -public class OkHttpClientIT { - - private static WebServer webServer; - - - @BeforeClass - public static void BeforeClass() throws Exception { - webServer = WebServer.newTestWebServer(); - } - - - @AfterClass - public static void AfterClass() throws Exception { - final WebServer copy = webServer; - if (copy != null) { - copy.stop(); - webServer = null; - } - } - - @Test - public void execute() throws Exception { - Request request = new Request.Builder().url(webServer.getCallHttpUrl()).build(); - OkHttpClient client = new OkHttpClient(); - Response response = client.newCall(request).execute(); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - - Method callMethod = Call.class.getDeclaredMethod("execute"); - verifier.verifyTrace(Expectations.event("OK_HTTP_CLIENT_INTERNAL", callMethod)); - } - - @Test - public void enqueue() throws Exception { - Request request = new Request.Builder().url(webServer.getCallHttpUrl()).build(); - OkHttpClient client = new OkHttpClient(); - final CountDownLatch latch = new CountDownLatch(1); - client.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(Request request, IOException e) { - latch.countDown(); - } - - @Override - public void onResponse(Response response) throws IOException { - latch.countDown(); - } - }); - latch.await(3, TimeUnit.SECONDS); - - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - - - Method enqueueMethod = Call.class.getDeclaredMethod("enqueue", com.squareup.okhttp.Callback.class); - verifier.verifyTrace(Expectations.event("OK_HTTP_CLIENT_INTERNAL", enqueueMethod)); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitmqIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitmqIT.java deleted file mode 100644 index 4ce077da5685..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/RabbitmqIT.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; - -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Channel; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.ConnectionFactory; -import com.rabbitmq.client.Consumer; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; -import com.rabbitmq.client.LongString; -import com.rabbitmq.client.SaslConfig; -import com.rabbitmq.client.SaslMechanism; -import com.rabbitmq.client.impl.LongStringHelper; -import org.apache.qpid.server.Broker; -import org.apache.qpid.server.BrokerOptions; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import static com.navercorp.pinpoint.bootstrap.plugin.test.Expectations.annotation; -import static org.junit.Assert.assertTrue; - -/** - * @author Jiaqi Feng - */ - -public abstract class RabbitmqIT { - public static String publishClassSignature="com.rabbitmq.client.impl.ChannelN.basicPublish(java.lang.String, java.lang.String, boolean, boolean, com.rabbitmq.client.AMQP$BasicProperties, byte[])"; - - public static String RUNNABLE_NAME="ConsumerDispatcher$5"; - public static Broker broker; - - public RabbitmqIT() {} - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - Broker broker = new Broker(); - BrokerOptions brokerOptions = new BrokerOptions(); - brokerOptions.setConfigProperty("qpid.amqp_port", "20179"); - brokerOptions.setConfigurationStoreType("Memory"); - System.setProperty("qpid.work_dir", "/tmp/qpidworktmp"); - System.setProperty("qpid.initialConfigurationLocation", "qpid/qpid-config.json"); - brokerOptions.setStartupLoggedToSystemOut(false); - - //System.out.println("--------------------- start qpid option="+brokerOptions.toString()); - try { - broker.startup(brokerOptions); - } catch (Exception e) { - e.printStackTrace(); - //System.out.println("--------------------- start qpid failed "); - return; - } - //System.out.println("--------------------- start qpid successed "); - } - - @AfterClass - public static void tearDownAfterClass() { - if (broker!=null) { - //System.out.println("--------------------- shutdown qpid successed "); - broker.shutdown(); - broker=null; - } - } - - @Test - public void testRabbitmq() throws Exception { - PluginTestVerifier verifier = PluginTestVerifierHolder.getInstance(); - verifier.printCache(); - - String exchange="test-pp"; - String queuename="queue-pp"; - String routingKey = "test"; - String message="hello rabbit mq"; - - SaslConfig saslConfig = new SaslConfig() { - public SaslMechanism getSaslMechanism(String[] mechanisms) { - return new SaslMechanism() { - public String getName() { - return "ANONYMOUS"; - } - - public LongString handleChallenge(LongString challenge, String username, String password) { - return LongStringHelper.asLongString(""); - } - }; - } - }; - // producer side - //System.out.println("RabbitmqSender.doGet() ---- start"); - - ConnectionFactory factory = new ConnectionFactory(); - factory.setHost("localhost"); - factory.setPort(20179); - factory.setSaslConfig(saslConfig); - - // enable below to test AutorecoveringChannel - //factory.setAutomaticRecoveryEnabled(true); - - Connection connection = factory.newConnection(); - Channel channel = connection.createChannel(); - - channel.exchangeDeclare(exchange, "direct", false); - channel.queueDeclare(queuename, false, false, false, null); - channel.queueBind(queuename, exchange, routingKey); - - AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder(); - channel.basicPublish(exchange, routingKey, false, false, builder.appId("test").build(), message.getBytes()); - //System.out.println("RabbitmqSender ---- Sent message:" + message); - - channel.close(); - connection.close(); - - //comsumer - factory = new ConnectionFactory(); - factory.setHost("localhost"); - factory.setPort(20179); - factory.setSaslConfig(saslConfig); - connection = factory.newConnection(); - channel = connection.createChannel(); - - channel.queueDeclare(queuename, false, false, false, null); - //System.out.println("Receiver ---- Waiting for messages"); - - final CountDownLatch latch = new CountDownLatch(1); - - Consumer consumer = new DefaultConsumer(channel) { - @Override - public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, - byte[] body) throws IOException { - super.handleDelivery(consumerTag, envelope, properties, body); - String message = new String(body, "UTF-8"); - //System.out.println("Receiver ---- Received exchange=" + envelope.getExchange() + ", routingkey=" + envelope.getRoutingKey() + ", message=" + message); - latch.countDown(); - } - }; - channel.basicConsume(queuename, true, consumer); - - // wait consumer - assertTrue(latch.await(10, TimeUnit.SECONDS)); - - final String remoteAddress = connection.getAddress().getHostAddress() + ":" + connection.getPort(); - - verifier.printCache(); - verifier.verifyTrace(Expectations.event("RABBITMQ", publishClassSignature, - annotation("rabbitmq.exchange", exchange), - annotation("rabbitmq.routingkey", routingKey)), - Expectations.root("RABBITMQ", "com.rabbitmq.client.DefaultConsumer.handleDelivery(java.lang.String, com.rabbitmq.client.Envelope, com.rabbitmq.client.AMQP$BasicProperties, byte[])", null, "exchange:" + exchange, remoteAddress, - annotation("rabbitmq.routingkey", routingKey))); - - verifier.verifyTraceCount(0); - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/Rabbitmq_3_1_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/Rabbitmq_3_1_IT.java deleted file mode 100644 index d74482ff4c22..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/Rabbitmq_3_1_IT.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; - -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.JvmArgument; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import org.junit.runner.RunWith; - -/** - * @author Jiaqi Feng - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({"com.rabbitmq:amqp-client:[3.0.0,3.2.0)", "org.apache.qpid:qpid-broker:6.1.1"}) -@JvmArgument({"-Dpinpoint.configcenter=false"}) -public class Rabbitmq_3_1_IT extends RabbitmqIT { - public Rabbitmq_3_1_IT() { - super(); - RUNNABLE_NAME="ConsumerDispatcher$4"; - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/Rabbitmq_3_2_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/Rabbitmq_3_2_IT.java deleted file mode 100644 index 7d1aba80baf1..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/Rabbitmq_3_2_IT.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; - -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.JvmArgument; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import org.junit.runner.RunWith; - -/** - * @author Jiaqi Feng - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({"com.rabbitmq:amqp-client:[3.2.0,4.0.0)", "org.apache.qpid:qpid-broker:6.1.1"}) -@JvmArgument({"-Dpinpoint.configcenter=false"}) -public class Rabbitmq_3_2_IT extends RabbitmqIT { - public Rabbitmq_3_2_IT() { - super(); - RUNNABLE_NAME="ConsumerDispatcher$5"; - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/Rabbitmq_4_x_IT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/Rabbitmq_4_x_IT.java deleted file mode 100644 index 98824076561d..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/jdk7/rabbitmq/Rabbitmq_4_x_IT.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.navercorp.pinpoint.plugin.jdk7.rabbitmq; - -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.JvmArgument; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; -import org.junit.runner.RunWith; - -/** - * @author Jiaqi Feng - */ -@RunWith(PinpointPluginTestSuite.class) -@Dependency({"com.rabbitmq:amqp-client:[4.0.0,4.max)", - "org.apache.qpid:qpid-broker:6.1.1"}) -@JvmArgument({"-Dpinpoint.configcenter=false"}) -public class Rabbitmq_4_x_IT extends RabbitmqIT { - public Rabbitmq_4_x_IT() { - super(); - publishClassSignature="com.rabbitmq.client.impl.recovery.AutorecoveringChannel.basicPublish(java.lang.String, java.lang.String, boolean, boolean, com.rabbitmq.client.AMQP$BasicProperties, byte[])"; - } -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/TestEnvironment.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/TestEnvironment.java deleted file mode 100644 index 3bf78413f224..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/TestEnvironment.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.common; - -import java.net.InetSocketAddress; - -import org.apache.thrift.protocol.TBinaryProtocol; -import org.apache.thrift.protocol.TProtocolFactory; - -/** - * @author HyunGil Jeong - */ -public class TestEnvironment { - - private static final int MIN_SERVER_PORT = 9091; - private static final int MAX_SERVER_PORT = 9099; - - private static final String SERVER_IP = "127.0.0.1"; - private static final TProtocolFactory PROTOCOL_FACTORY = new TBinaryProtocol.Factory(); - - private final String serverIp = SERVER_IP; - private final int port = MIN_SERVER_PORT + (int)(Math.random() * (MAX_SERVER_PORT - MIN_SERVER_PORT) + 1); - private final InetSocketAddress serverAddress = new InetSocketAddress(SERVER_IP, this.port); - private final TProtocolFactory protocolFactory = PROTOCOL_FACTORY; - - public String getServerIp() { - return this.serverIp; - } - - public int getPort() { - return this.port; - } - - public InetSocketAddress getServerAddress() { - return this.serverAddress; - } - - public TProtocolFactory getProtocolFactory() { - return this.protocolFactory; - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/EchoTestServer.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/EchoTestServer.java deleted file mode 100644 index c9b4db5317f6..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/common/server/EchoTestServer.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.common.server; - -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.client.AsyncEchoTestClient; -import com.navercorp.pinpoint.plugin.thrift.common.client.SyncEchoTestClient; -import com.navercorp.pinpoint.plugin.thrift.dto.EchoService; -import org.apache.thrift.TException; -import org.apache.thrift.async.AsyncMethodCallback; -import org.apache.thrift.protocol.TProtocol; -import org.apache.thrift.server.ServerContext; -import org.apache.thrift.server.TServer; -import org.apache.thrift.server.TServerEventHandler; -import org.apache.thrift.transport.TTransport; -import org.apache.thrift.transport.TTransportException; - -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; - -/** - * @author HyunGil Jeong - */ -public abstract class EchoTestServer { - - protected static class EchoServiceHandler implements EchoService.Iface { - @Override - public String echo(String message) throws TException { - return message; - } - } - - protected static class EchoServiceAsyncHandler implements EchoService.AsyncIface { - - private final EchoServiceHandler syncHandler = new EchoServiceHandler(); - - @SuppressWarnings("unchecked") - @Override - public void echo(String message, AsyncMethodCallback resultHandler) throws TException { - try { - final String echo = this.syncHandler.echo(message); - resultHandler.onComplete(echo); - } catch (Exception e) { - resultHandler.onError(e); - } - } - } - - private final T server; - - protected final TestEnvironment environment; - - protected EchoTestServer(T server, TestEnvironment environment) throws TTransportException { - if (server == null) { - throw new IllegalArgumentException("server cannot be null"); - } - this.server = server; - this.environment = environment; - } - - public void start(ExecutorService executor) throws TTransportException, InterruptedException { - if (this.server.isServing()) { - return; - } - - CountDownLatch waitToServeLatch = new CountDownLatch(1); - server.setServerEventHandler(new WaitToServeHandler(waitToServeLatch)); - - executor.execute(new Runnable() { - @Override - public void run() { - server.serve(); - } - }); - - waitToServeLatch.await(); - } - - public void stop() { - this.server.stop(); - } - - public void verifyTraces(PluginTestVerifier verifier) throws Exception { - this.verifyServerTraces(verifier); - } - - protected abstract void verifyServerTraces(PluginTestVerifier verifier) throws Exception; - - public abstract SyncEchoTestClient getSynchronousClient() throws TTransportException; - - public abstract AsyncEchoTestClient getAsynchronousClient() throws IOException; - - - private class WaitToServeHandler implements TServerEventHandler { - - private final CountDownLatch waitToServeLatch; - - public WaitToServeHandler(CountDownLatch waitToServeLatch) { - this.waitToServeLatch = waitToServeLatch; - } - - @Override - public void preServe() { - waitToServeLatch.countDown(); - } - - @Override - public ServerContext createContext(TProtocol tProtocol, TProtocol tProtocol1) { - return null; - } - - @Override - public void deleteContext(ServerContext serverContext, TProtocol tProtocol, TProtocol tProtocol1) { - - } - - @Override - public void processContext(ServerContext serverContext, TTransport tTransport, TTransport tTransport1) { - - } - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/dto/EchoService.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/dto/EchoService.java deleted file mode 100644 index 0f4464a789c5..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/dto/EchoService.java +++ /dev/null @@ -1,969 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Autogenerated by Thrift Compiler (0.10.0) - * - * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING - * @generated - */ -package com.navercorp.pinpoint.plugin.thrift.dto; - -@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-01-25") -public class EchoService { - - public interface Iface { - - public String echo(String message) throws org.apache.thrift.TException; - - } - - public interface AsyncIface { - - public void echo(String message, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; - - } - - public static class Client extends org.apache.thrift.TServiceClient implements Iface { - public static class Factory implements org.apache.thrift.TServiceClientFactory { - public Factory() {} - public Client getClient(org.apache.thrift.protocol.TProtocol prot) { - return new Client(prot); - } - public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) { - return new Client(iprot, oprot); - } - } - - public Client(org.apache.thrift.protocol.TProtocol prot) - { - super(prot, prot); - } - - public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) { - super(iprot, oprot); - } - - public String echo(String message) throws org.apache.thrift.TException - { - send_echo(message); - return recv_echo(); - } - - public void send_echo(String message) throws org.apache.thrift.TException - { - echo_args args = new echo_args(); - args.setMessage(message); - sendBase("echo", args); - } - - public String recv_echo() throws org.apache.thrift.TException - { - echo_result result = new echo_result(); - receiveBase(result, "echo"); - if (result.isSetSuccess()) { - return result.success; - } - throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "echo failed: unknown result"); - } - - } - public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface { - public static class Factory implements org.apache.thrift.async.TAsyncClientFactory { - private org.apache.thrift.async.TAsyncClientManager clientManager; - private org.apache.thrift.protocol.TProtocolFactory protocolFactory; - public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) { - this.clientManager = clientManager; - this.protocolFactory = protocolFactory; - } - public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) { - return new AsyncClient(protocolFactory, clientManager, transport); - } - } - - public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) { - super(protocolFactory, clientManager, transport); - } - - public void echo(String message, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { - checkReady(); - echo_call method_call = new echo_call(message, resultHandler, this, ___protocolFactory, ___transport); - this.___currentMethod = method_call; - ___manager.call(method_call); - } - - public static class echo_call extends org.apache.thrift.async.TAsyncMethodCall { - private String message; - public echo_call(String message, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { - super(client, protocolFactory, transport, resultHandler, false); - this.message = message; - } - - public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { - prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("echo", org.apache.thrift.protocol.TMessageType.CALL, 0)); - echo_args args = new echo_args(); - args.setMessage(message); - args.write(prot); - prot.writeMessageEnd(); - } - - public String getResult() throws org.apache.thrift.TException { - if (getState() != State.RESPONSE_READ) { - throw new IllegalStateException("Method call not finished!"); - } - org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); - org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); - return (new Client(prot)).recv_echo(); - } - } - - } - - public static class Processor extends org.apache.thrift.TBaseProcessor implements org.apache.thrift.TProcessor { - private static final org.slf4j.Logger _LOGGER = org.slf4j.LoggerFactory.getLogger(Processor.class.getName()); - public Processor(I iface) { - super(iface, getProcessMap(new java.util.HashMap>())); - } - - protected Processor(I iface, java.util.Map> processMap) { - super(iface, getProcessMap(processMap)); - } - - private static java.util.Map> getProcessMap(java.util.Map> processMap) { - processMap.put("echo", new echo()); - return processMap; - } - - public static class echo extends org.apache.thrift.ProcessFunction { - public echo() { - super("echo"); - } - - public echo_args getEmptyArgsInstance() { - return new echo_args(); - } - - protected boolean isOneway() { - return false; - } - - public echo_result getResult(I iface, echo_args args) throws org.apache.thrift.TException { - echo_result result = new echo_result(); - result.success = iface.echo(args.message); - return result; - } - } - - } - - public static class AsyncProcessor extends org.apache.thrift.TBaseAsyncProcessor { - private static final org.slf4j.Logger _LOGGER = org.slf4j.LoggerFactory.getLogger(AsyncProcessor.class.getName()); - public AsyncProcessor(I iface) { - super(iface, getProcessMap(new java.util.HashMap>())); - } - - protected AsyncProcessor(I iface, java.util.Map> processMap) { - super(iface, getProcessMap(processMap)); - } - - private static java.util.Map> getProcessMap(java.util.Map> processMap) { - processMap.put("echo", new echo()); - return processMap; - } - - public static class echo extends org.apache.thrift.AsyncProcessFunction { - public echo() { - super("echo"); - } - - public echo_args getEmptyArgsInstance() { - return new echo_args(); - } - - public org.apache.thrift.async.AsyncMethodCallback getResultHandler(final org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final int seqid) { - final org.apache.thrift.AsyncProcessFunction fcall = this; - return new org.apache.thrift.async.AsyncMethodCallback() { - public void onComplete(String o) { - echo_result result = new echo_result(); - result.success = o; - try { - fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid); - } catch (org.apache.thrift.transport.TTransportException e) { - _LOGGER.error("TTransportException writing to internal frame buffer", e); - fb.close(); - } catch (Exception e) { - _LOGGER.error("Exception writing to internal frame buffer", e); - onError(e); - } - } - public void onError(Exception e) { - byte msgType = org.apache.thrift.protocol.TMessageType.REPLY; - org.apache.thrift.TSerializable msg; - echo_result result = new echo_result(); - if (e instanceof org.apache.thrift.transport.TTransportException) { - _LOGGER.error("TTransportException inside handler", e); - fb.close(); - return; - } else if (e instanceof org.apache.thrift.TApplicationException) { - _LOGGER.error("TApplicationException inside handler", e); - msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; - msg = (org.apache.thrift.TApplicationException)e; - } else { - _LOGGER.error("Exception inside handler", e); - msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; - msg = new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage()); - } - try { - fcall.sendResponse(fb,msg,msgType,seqid); - } catch (Exception ex) { - _LOGGER.error("Exception writing to internal frame buffer", ex); - fb.close(); - } - } - }; - } - - protected boolean isOneway() { - return false; - } - - public void start(I iface, echo_args args, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { - iface.echo(args.message,resultHandler); - } - } - - } - - public static class echo_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { - private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("echo_args"); - - private static final org.apache.thrift.protocol.TField MESSAGE_FIELD_DESC = new org.apache.thrift.protocol.TField("message", org.apache.thrift.protocol.TType.STRING, (short)1); - - private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new echo_argsStandardSchemeFactory(); - private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new echo_argsTupleSchemeFactory(); - - private String message; // required - - /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ - public enum _Fields implements org.apache.thrift.TFieldIdEnum { - MESSAGE((short)1, "message"); - - private static final java.util.Map byName = new java.util.HashMap(); - - static { - for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { - byName.put(field.getFieldName(), field); - } - } - - /** - * Find the _Fields constant that matches fieldId, or null if its not found. - */ - public static _Fields findByThriftId(int fieldId) { - switch(fieldId) { - case 1: // MESSAGE - return MESSAGE; - default: - return null; - } - } - - /** - * Find the _Fields constant that matches fieldId, throwing an exception - * if it is not found. - */ - public static _Fields findByThriftIdOrThrow(int fieldId) { - _Fields fields = findByThriftId(fieldId); - if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); - return fields; - } - - /** - * Find the _Fields constant that matches name, or null if its not found. - */ - public static _Fields findByName(String name) { - return byName.get(name); - } - - private final short _thriftId; - private final String _fieldName; - - _Fields(short thriftId, String fieldName) { - _thriftId = thriftId; - _fieldName = fieldName; - } - - public short getThriftFieldId() { - return _thriftId; - } - - public String getFieldName() { - return _fieldName; - } - } - - // isset id assignments - public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; - static { - java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); - tmpMap.put(_Fields.MESSAGE, new org.apache.thrift.meta_data.FieldMetaData("message", org.apache.thrift.TFieldRequirementType.DEFAULT, - new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); - metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); - org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(echo_args.class, metaDataMap); - } - - public echo_args() { - } - - public echo_args( - String message) - { - this(); - this.message = message; - } - - /** - * Performs a deep copy on other. - */ - public echo_args(echo_args other) { - if (other.isSetMessage()) { - this.message = other.message; - } - } - - public echo_args deepCopy() { - return new echo_args(this); - } - - @Override - public void clear() { - this.message = null; - } - - public String getMessage() { - return this.message; - } - - public void setMessage(String message) { - this.message = message; - } - - public void unsetMessage() { - this.message = null; - } - - /** Returns true if field message is set (has been assigned a value) and false otherwise */ - public boolean isSetMessage() { - return this.message != null; - } - - public void setMessageIsSet(boolean value) { - if (!value) { - this.message = null; - } - } - - public void setFieldValue(_Fields field, Object value) { - switch (field) { - case MESSAGE: - if (value == null) { - unsetMessage(); - } else { - setMessage((String)value); - } - break; - - } - } - - public Object getFieldValue(_Fields field) { - switch (field) { - case MESSAGE: - return getMessage(); - - } - throw new IllegalStateException(); - } - - /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ - public boolean isSet(_Fields field) { - if (field == null) { - throw new IllegalArgumentException(); - } - - switch (field) { - case MESSAGE: - return isSetMessage(); - } - throw new IllegalStateException(); - } - - @Override - public boolean equals(Object that) { - if (that == null) - return false; - if (that instanceof echo_args) - return this.equals((echo_args)that); - return false; - } - - public boolean equals(echo_args that) { - if (that == null) - return false; - if (this == that) - return true; - - boolean this_present_message = true && this.isSetMessage(); - boolean that_present_message = true && that.isSetMessage(); - if (this_present_message || that_present_message) { - if (!(this_present_message && that_present_message)) - return false; - if (!this.message.equals(that.message)) - return false; - } - - return true; - } - - @Override - public int hashCode() { - int hashCode = 1; - - hashCode = hashCode * 8191 + ((isSetMessage()) ? 131071 : 524287); - if (isSetMessage()) - hashCode = hashCode * 8191 + message.hashCode(); - - return hashCode; - } - - @Override - public int compareTo(echo_args other) { - if (!getClass().equals(other.getClass())) { - return getClass().getName().compareTo(other.getClass().getName()); - } - - int lastComparison = 0; - - lastComparison = Boolean.valueOf(isSetMessage()).compareTo(other.isSetMessage()); - if (lastComparison != 0) { - return lastComparison; - } - if (isSetMessage()) { - lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.message, other.message); - if (lastComparison != 0) { - return lastComparison; - } - } - return 0; - } - - public _Fields fieldForId(int fieldId) { - return _Fields.findByThriftId(fieldId); - } - - public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { - scheme(iprot).read(iprot, this); - } - - public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { - scheme(oprot).write(oprot, this); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("echo_args("); - boolean first = true; - - sb.append("message:"); - if (this.message == null) { - sb.append("null"); - } else { - sb.append(this.message); - } - first = false; - sb.append(")"); - return sb.toString(); - } - - public void validate() throws org.apache.thrift.TException { - // check for required fields - // check for sub-struct validity - } - - private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { - try { - write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); - } catch (org.apache.thrift.TException te) { - throw new java.io.IOException(te); - } - } - - private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { - try { - read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); - } catch (org.apache.thrift.TException te) { - throw new java.io.IOException(te); - } - } - - private static class echo_argsStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { - public echo_argsStandardScheme getScheme() { - return new echo_argsStandardScheme(); - } - } - - private static class echo_argsStandardScheme extends org.apache.thrift.scheme.StandardScheme { - - public void read(org.apache.thrift.protocol.TProtocol iprot, echo_args struct) throws org.apache.thrift.TException { - org.apache.thrift.protocol.TField schemeField; - iprot.readStructBegin(); - while (true) - { - schemeField = iprot.readFieldBegin(); - if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { - break; - } - switch (schemeField.id) { - case 1: // MESSAGE - if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { - struct.message = iprot.readString(); - struct.setMessageIsSet(true); - } else { - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); - } - break; - default: - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); - } - iprot.readFieldEnd(); - } - iprot.readStructEnd(); - struct.validate(); - } - - public void write(org.apache.thrift.protocol.TProtocol oprot, echo_args struct) throws org.apache.thrift.TException { - struct.validate(); - - oprot.writeStructBegin(STRUCT_DESC); - if (struct.message != null) { - oprot.writeFieldBegin(MESSAGE_FIELD_DESC); - oprot.writeString(struct.message); - oprot.writeFieldEnd(); - } - oprot.writeFieldStop(); - oprot.writeStructEnd(); - } - - } - - private static class echo_argsTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { - public echo_argsTupleScheme getScheme() { - return new echo_argsTupleScheme(); - } - } - - private static class echo_argsTupleScheme extends org.apache.thrift.scheme.TupleScheme { - - @Override - public void write(org.apache.thrift.protocol.TProtocol prot, echo_args struct) throws org.apache.thrift.TException { - org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; - java.util.BitSet optionals = new java.util.BitSet(); - if (struct.isSetMessage()) { - optionals.set(0); - } - oprot.writeBitSet(optionals, 1); - if (struct.isSetMessage()) { - oprot.writeString(struct.message); - } - } - - @Override - public void read(org.apache.thrift.protocol.TProtocol prot, echo_args struct) throws org.apache.thrift.TException { - org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; - java.util.BitSet incoming = iprot.readBitSet(1); - if (incoming.get(0)) { - struct.message = iprot.readString(); - struct.setMessageIsSet(true); - } - } - } - - private static S scheme(org.apache.thrift.protocol.TProtocol proto) { - return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); - } - } - - public static class echo_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { - private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("echo_result"); - - private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.STRING, (short)0); - - private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new echo_resultStandardSchemeFactory(); - private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new echo_resultTupleSchemeFactory(); - - private String success; // required - - /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ - public enum _Fields implements org.apache.thrift.TFieldIdEnum { - SUCCESS((short)0, "success"); - - private static final java.util.Map byName = new java.util.HashMap(); - - static { - for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { - byName.put(field.getFieldName(), field); - } - } - - /** - * Find the _Fields constant that matches fieldId, or null if its not found. - */ - public static _Fields findByThriftId(int fieldId) { - switch(fieldId) { - case 0: // SUCCESS - return SUCCESS; - default: - return null; - } - } - - /** - * Find the _Fields constant that matches fieldId, throwing an exception - * if it is not found. - */ - public static _Fields findByThriftIdOrThrow(int fieldId) { - _Fields fields = findByThriftId(fieldId); - if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!"); - return fields; - } - - /** - * Find the _Fields constant that matches name, or null if its not found. - */ - public static _Fields findByName(String name) { - return byName.get(name); - } - - private final short _thriftId; - private final String _fieldName; - - _Fields(short thriftId, String fieldName) { - _thriftId = thriftId; - _fieldName = fieldName; - } - - public short getThriftFieldId() { - return _thriftId; - } - - public String getFieldName() { - return _fieldName; - } - } - - // isset id assignments - public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; - static { - java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); - tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT, - new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); - metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); - org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(echo_result.class, metaDataMap); - } - - public echo_result() { - } - - public echo_result( - String success) - { - this(); - this.success = success; - } - - /** - * Performs a deep copy on other. - */ - public echo_result(echo_result other) { - if (other.isSetSuccess()) { - this.success = other.success; - } - } - - public echo_result deepCopy() { - return new echo_result(this); - } - - @Override - public void clear() { - this.success = null; - } - - public String getSuccess() { - return this.success; - } - - public void setSuccess(String success) { - this.success = success; - } - - public void unsetSuccess() { - this.success = null; - } - - /** Returns true if field success is set (has been assigned a value) and false otherwise */ - public boolean isSetSuccess() { - return this.success != null; - } - - public void setSuccessIsSet(boolean value) { - if (!value) { - this.success = null; - } - } - - public void setFieldValue(_Fields field, Object value) { - switch (field) { - case SUCCESS: - if (value == null) { - unsetSuccess(); - } else { - setSuccess((String)value); - } - break; - - } - } - - public Object getFieldValue(_Fields field) { - switch (field) { - case SUCCESS: - return getSuccess(); - - } - throw new IllegalStateException(); - } - - /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ - public boolean isSet(_Fields field) { - if (field == null) { - throw new IllegalArgumentException(); - } - - switch (field) { - case SUCCESS: - return isSetSuccess(); - } - throw new IllegalStateException(); - } - - @Override - public boolean equals(Object that) { - if (that == null) - return false; - if (that instanceof echo_result) - return this.equals((echo_result)that); - return false; - } - - public boolean equals(echo_result that) { - if (that == null) - return false; - if (this == that) - return true; - - boolean this_present_success = true && this.isSetSuccess(); - boolean that_present_success = true && that.isSetSuccess(); - if (this_present_success || that_present_success) { - if (!(this_present_success && that_present_success)) - return false; - if (!this.success.equals(that.success)) - return false; - } - - return true; - } - - @Override - public int hashCode() { - int hashCode = 1; - - hashCode = hashCode * 8191 + ((isSetSuccess()) ? 131071 : 524287); - if (isSetSuccess()) - hashCode = hashCode * 8191 + success.hashCode(); - - return hashCode; - } - - @Override - public int compareTo(echo_result other) { - if (!getClass().equals(other.getClass())) { - return getClass().getName().compareTo(other.getClass().getName()); - } - - int lastComparison = 0; - - lastComparison = Boolean.valueOf(isSetSuccess()).compareTo(other.isSetSuccess()); - if (lastComparison != 0) { - return lastComparison; - } - if (isSetSuccess()) { - lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, other.success); - if (lastComparison != 0) { - return lastComparison; - } - } - return 0; - } - - public _Fields fieldForId(int fieldId) { - return _Fields.findByThriftId(fieldId); - } - - public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { - scheme(iprot).read(iprot, this); - } - - public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { - scheme(oprot).write(oprot, this); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("echo_result("); - boolean first = true; - - sb.append("success:"); - if (this.success == null) { - sb.append("null"); - } else { - sb.append(this.success); - } - first = false; - sb.append(")"); - return sb.toString(); - } - - public void validate() throws org.apache.thrift.TException { - // check for required fields - // check for sub-struct validity - } - - private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { - try { - write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); - } catch (org.apache.thrift.TException te) { - throw new java.io.IOException(te); - } - } - - private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { - try { - read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); - } catch (org.apache.thrift.TException te) { - throw new java.io.IOException(te); - } - } - - private static class echo_resultStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { - public echo_resultStandardScheme getScheme() { - return new echo_resultStandardScheme(); - } - } - - private static class echo_resultStandardScheme extends org.apache.thrift.scheme.StandardScheme { - - public void read(org.apache.thrift.protocol.TProtocol iprot, echo_result struct) throws org.apache.thrift.TException { - org.apache.thrift.protocol.TField schemeField; - iprot.readStructBegin(); - while (true) - { - schemeField = iprot.readFieldBegin(); - if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { - break; - } - switch (schemeField.id) { - case 0: // SUCCESS - if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { - struct.success = iprot.readString(); - struct.setSuccessIsSet(true); - } else { - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); - } - break; - default: - org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); - } - iprot.readFieldEnd(); - } - iprot.readStructEnd(); - struct.validate(); - } - - public void write(org.apache.thrift.protocol.TProtocol oprot, echo_result struct) throws org.apache.thrift.TException { - struct.validate(); - - oprot.writeStructBegin(STRUCT_DESC); - if (struct.success != null) { - oprot.writeFieldBegin(SUCCESS_FIELD_DESC); - oprot.writeString(struct.success); - oprot.writeFieldEnd(); - } - oprot.writeFieldStop(); - oprot.writeStructEnd(); - } - - } - - private static class echo_resultTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { - public echo_resultTupleScheme getScheme() { - return new echo_resultTupleScheme(); - } - } - - private static class echo_resultTupleScheme extends org.apache.thrift.scheme.TupleScheme { - - @Override - public void write(org.apache.thrift.protocol.TProtocol prot, echo_result struct) throws org.apache.thrift.TException { - org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; - java.util.BitSet optionals = new java.util.BitSet(); - if (struct.isSetSuccess()) { - optionals.set(0); - } - oprot.writeBitSet(optionals, 1); - if (struct.isSetSuccess()) { - oprot.writeString(struct.success); - } - } - - @Override - public void read(org.apache.thrift.protocol.TProtocol prot, echo_result struct) throws org.apache.thrift.TException { - org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; - java.util.BitSet incoming = iprot.readBitSet(1); - if (incoming.get(0)) { - struct.success = iprot.readString(); - struct.setSuccessIsSet(true); - } - } - } - - private static S scheme(org.apache.thrift.protocol.TProtocol proto) { - return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); - } - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/EchoTestRunner.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/EchoTestRunner.java deleted file mode 100644 index 7517a2c6c043..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/EchoTestRunner.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.it; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import org.apache.thrift.server.TServer; -import org.apache.thrift.transport.TTransportException; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; - -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.client.EchoTestClient; -import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; - -/** - * @author HyunGil Jeong - */ -public abstract class EchoTestRunner { - - private static ExecutorService SERVER_EXECUTOR; - - private EchoTestServer echoServer; - - PluginTestVerifier verifier; - - @BeforeClass - public static void setUpBeforeClass() throws InterruptedException { - SERVER_EXECUTOR = Executors.newSingleThreadExecutor(); - } - - @Before - public void setUp() throws TTransportException, InterruptedException { - this.echoServer = createEchoServer(new TestEnvironment()); - this.verifier = PluginTestVerifierHolder.getInstance(); - this.echoServer.start(SERVER_EXECUTOR); - } - - @After - public void tearDown() { - if (this.echoServer != null) { - this.echoServer.stop(); - } - } - - @AfterClass - public static void tearDownAfterClass() { - SERVER_EXECUTOR.shutdown(); - } - - protected String invokeEcho(String message) throws Exception { - final EchoTestClient echoClient = this.echoServer.getSynchronousClient(); - return invokeAndVerify(echoClient, message); - } - - protected String invokeEchoAsync(String message) throws Exception { - final EchoTestClient echoClient = this.echoServer.getAsynchronousClient(); - return invokeAndVerify(echoClient, message); - } - - private String invokeAndVerify(EchoTestClient echoClient, String message) throws Exception { - try { - return echoClient.echo(message); - } finally { - echoClient.close(); - // give a chance to flush out span data - Thread.sleep(500L); - this.verifyTraces(echoClient, message); - } - } - - protected abstract EchoTestServer createEchoServer(TestEnvironment environment) throws TTransportException; - - private void verifyTraces(EchoTestClient echoClient, String expectedMessage) throws Exception { - this.verifier.printCache(System.out); - echoClient.verifyTraces(this.verifier, expectedMessage); - this.echoServer.verifyTraces(this.verifier); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftHalfSyncHalfAsyncServerAsyncIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftHalfSyncHalfAsyncServerAsyncIT.java deleted file mode 100644 index ca81c84c6703..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftHalfSyncHalfAsyncServerAsyncIT.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.it.asynchronous; - -import static org.junit.Assert.assertEquals; - -import org.apache.thrift.server.THsHaServer; -import org.apache.thrift.transport.TTransportException; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; -import com.navercorp.pinpoint.plugin.thrift.common.server.AsyncEchoTestServer.AsyncEchoTestServerFactory; -import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - *

Integration test for THsHaServer with asynchronous processor.

- * - *

Tests against libthrift 0.9.2+ due to THRIFT-2274
- * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

- * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", "log4j:log4j:1.2.16", "org.slf4j:slf4j-log4j12:1.7.22" }) -public class ThriftHalfSyncHalfAsyncServerAsyncIT extends EchoTestRunner { - - @Override - protected EchoTestServer createEchoServer(TestEnvironment environment) throws TTransportException { - return AsyncEchoTestServerFactory.halfSyncHalfAsyncServer(environment); - } - - @Test - public void testSynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEcho(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - - @Test - public void testAsynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEchoAsync(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftNonblockingServerAsyncIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftNonblockingServerAsyncIT.java deleted file mode 100644 index f4cbce4e686b..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftNonblockingServerAsyncIT.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.it.asynchronous; - -import static org.junit.Assert.assertEquals; - -import org.apache.thrift.server.TNonblockingServer; -import org.apache.thrift.transport.TTransportException; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; -import com.navercorp.pinpoint.plugin.thrift.common.server.AsyncEchoTestServer.AsyncEchoTestServerFactory; -import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - *

Integration test for TNonblockingServer with asynchronous processor.

- * - *

Tests against libthrift 0.9.2+ due to THRIFT-2274
- * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

- * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", "log4j:log4j:1.2.16", "org.slf4j:slf4j-log4j12:1.7.22" }) -public class ThriftNonblockingServerAsyncIT extends EchoTestRunner { - - @Override - protected EchoTestServer createEchoServer(TestEnvironment environment) - throws TTransportException { - return AsyncEchoTestServerFactory.nonblockingServer(environment); - } - - @Test - public void testSynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEcho(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - - @Test - public void testAsynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEchoAsync(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftThreadedSelectorServerAsyncIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftThreadedSelectorServerAsyncIT.java deleted file mode 100644 index a4a4a7d41a81..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/asynchronous/ThriftThreadedSelectorServerAsyncIT.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.it.asynchronous; - -import static org.junit.Assert.assertEquals; - -import org.apache.thrift.server.TThreadedSelectorServer; -import org.apache.thrift.transport.TTransportException; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; -import com.navercorp.pinpoint.plugin.thrift.common.server.AsyncEchoTestServer.AsyncEchoTestServerFactory; -import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - *

Integration test for TThreadedSelectorServer with asynchronous processor.

- * - *

Tests against libthrift 0.9.2+ due to THRIFT-2274
- * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

- * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", "log4j:log4j:1.2.16", "org.slf4j:slf4j-log4j12:1.7.22" }) -public class ThriftThreadedSelectorServerAsyncIT extends EchoTestRunner { - - @Override - protected EchoTestServer createEchoServer(TestEnvironment environment) - throws TTransportException { - return AsyncEchoTestServerFactory.threadedSelectorServer(environment); - } - - @Test - public void testSynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEcho(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - - @Test - public void testAsynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEchoAsync(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftHalfSyncHalfAsyncServerIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftHalfSyncHalfAsyncServerIT.java deleted file mode 100644 index 3586061edcc1..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftHalfSyncHalfAsyncServerIT.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.it.synchronous; - -import static org.junit.Assert.assertEquals; - -import org.apache.thrift.server.THsHaServer; -import org.apache.thrift.transport.TTransportException; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; -import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; -import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - *

Integration test for THsHaServer with synchronous processor.

- * - *

Tests against libthrift 0.9.2+ due to THRIFT-2274
- * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

- * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", "log4j:log4j:1.2.16", "org.slf4j:slf4j-log4j12:1.7.22" }) -public class ThriftHalfSyncHalfAsyncServerIT extends EchoTestRunner { - - @Override - protected EchoTestServer createEchoServer(TestEnvironment environment) throws TTransportException { - return SyncEchoTestServerFactory.halfSyncHalfAsyncServer(environment); - } - - @Test - public void testSynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEcho(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - - @Test - public void testAsynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEchoAsync(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftNonblockingServerIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftNonblockingServerIT.java deleted file mode 100644 index ee8178541fe0..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftNonblockingServerIT.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.it.synchronous; - -import static org.junit.Assert.assertEquals; - -import org.apache.thrift.server.TNonblockingServer; -import org.apache.thrift.transport.TTransportException; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; -import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; -import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - *

Integration test for TNonblockingServer with synchronous processor.

- * - *

Tests against libthrift 0.9.2+ due to THRIFT-2274 - * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

- * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", "log4j:log4j:1.2.16", "org.slf4j:slf4j-log4j12:1.7.22" }) -public class ThriftNonblockingServerIT extends EchoTestRunner { - - @Override - protected EchoTestServer createEchoServer(TestEnvironment environment) - throws TTransportException { - return SyncEchoTestServerFactory.nonblockingServer(environment); - } - - @Test - public void testSynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEcho(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - - @Test - public void testAsynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEchoAsync(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftSimpleServerIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftSimpleServerIT.java deleted file mode 100644 index f7de2509b844..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftSimpleServerIT.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.it.synchronous; - -import static org.junit.Assert.*; - -import org.apache.thrift.server.TSimpleServer; -import org.apache.thrift.transport.TTransportException; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; -import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; -import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - * Integration test for TSimpleServer with synchronous processor. - * - * Tests against libthrift 0.9.1+ - * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.thrift:libthrift:[0.9.1,)", "log4j:log4j:1.2.16", "org.slf4j:slf4j-log4j12:1.7.22" }) -public class ThriftSimpleServerIT extends EchoTestRunner { - - @Override - protected EchoTestServer createEchoServer(TestEnvironment environment) throws TTransportException { - return SyncEchoTestServerFactory.simpleServer(environment); - } - - @Test - public void testSynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEcho(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadPoolServerIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadPoolServerIT.java deleted file mode 100644 index 680260666dd9..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadPoolServerIT.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.it.synchronous; - -import static org.junit.Assert.assertEquals; - -import org.apache.thrift.server.TThreadPoolServer; -import org.apache.thrift.transport.TTransportException; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; -import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; -import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - * Integration test for TThreadPoolServer with synchronous processor. - * - * Tests against libthrift 0.9.1+ - * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.thrift:libthrift:[0.9.1,)", "log4j:log4j:1.2.16", "org.slf4j:slf4j-log4j12:1.7.22" }) -public class ThriftThreadPoolServerIT extends EchoTestRunner { - - @Override - protected EchoTestServer createEchoServer(TestEnvironment environment) - throws TTransportException { - return SyncEchoTestServerFactory.threadedPoolServer(environment); - } - - @Test - public void testSynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEcho(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - -} diff --git a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadedSelectorServerIT.java b/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadedSelectorServerIT.java deleted file mode 100644 index a1cdd41e107a..000000000000 --- a/agent/src/test/java/com/navercorp/pinpoint/plugin/thrift/it/synchronous/ThriftThreadedSelectorServerIT.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.thrift.it.synchronous; - -import static org.junit.Assert.assertEquals; - -import org.apache.thrift.server.TThreadedSelectorServer; -import org.apache.thrift.transport.TTransportException; -import org.junit.Test; -import org.junit.runner.RunWith; - -import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.plugin.thrift.common.TestEnvironment; -import com.navercorp.pinpoint.plugin.thrift.common.server.EchoTestServer; -import com.navercorp.pinpoint.plugin.thrift.common.server.SyncEchoTestServer.SyncEchoTestServerFactory; -import com.navercorp.pinpoint.plugin.thrift.it.EchoTestRunner; -import com.navercorp.pinpoint.test.plugin.Dependency; -import com.navercorp.pinpoint.test.plugin.PinpointAgent; -import com.navercorp.pinpoint.test.plugin.PinpointPluginTestSuite; - -/** - *

Integration test for TThreadedSelectorServer with synchronous processor.

- * - *

Tests against libthrift 0.9.2+ due to THRIFT-2274 - * Tests against libthrift 0.10.0+ (0.9.x -> 0.10.x introduces breaking change to generated thrift code)

- * - * @author HyunGil Jeong - */ -@RunWith(PinpointPluginTestSuite.class) -@PinpointAgent("agent/target/pinpoint-agent-" + Version.VERSION) -@Dependency({ "org.apache.thrift:libthrift:[0.10.0,)", "log4j:log4j:1.2.16", "org.slf4j:slf4j-log4j12:1.7.22" }) -public class ThriftThreadedSelectorServerIT extends EchoTestRunner { - - @Override - protected EchoTestServer createEchoServer(TestEnvironment environment) - throws TTransportException { - return SyncEchoTestServerFactory.threadedSelectorServer(environment); - } - - @Test - public void testSynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEcho(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - - @Test - public void testAsynchronousRpcCall() throws Exception { - // Given - final String expectedMessage = "TEST_MESSAGE"; - // When - final String result = super.invokeEchoAsync(expectedMessage); - // Then - assertEquals(expectedMessage, result); - } - -} diff --git a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoService.java b/agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoService.java deleted file mode 100644 index 39827d1e6181..000000000000 --- a/agent/src/test/java/com/navercorp/test/pinpoint/plugin/rxjava/service/EchoService.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.test.pinpoint.plugin.rxjava.service; - -import com.navercorp.test.pinpoint.plugin.rxjava.repository.EchoRepository; -import rx.Single; -import rx.SingleSubscriber; - -/** - * @author HyunGil Jeong - */ -public class EchoService { - - private final EchoRepository echoRepository = new EchoRepository(); - - public Single echo(final String message) { - return Single.create(new Single.OnSubscribe() { - @Override - public void call(SingleSubscriber singleSubscriber) { - if (!singleSubscriber.isUnsubscribed()) { - String echo = echoRepository.echo(message); - singleSubscriber.onSuccess(echo); - } - } - }); - } - - public Single echo(final String message, final Exception expected) { - return Single.create(new Single.OnSubscribe() { - @Override - public void call(SingleSubscriber singleSubscriber) { - try { - if (!singleSubscriber.isUnsubscribed()) { - String echo = echoRepository.echo(message, expected); - singleSubscriber.onSuccess(echo); - } - } catch (Exception e) { - singleSubscriber.onError(e); - } - } - }); - } - -} diff --git a/agent/src/test/resources/spring-beans-test.xml b/agent/src/test/resources/spring-beans-test.xml deleted file mode 100644 index 6c7cf261c650..000000000000 --- a/agent/src/test/resources/spring-beans-test.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/agent/src/test/resources/spring-web-test.xml b/agent/src/test/resources/spring-web-test.xml deleted file mode 100644 index 22abaf53f5ec..000000000000 --- a/agent/src/test/resources/spring-web-test.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/annotations/clover.license b/annotations/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/annotations/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/BootLoader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/BootLoader.java new file mode 100644 index 000000000000..bab7c9acb6a3 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/BootLoader.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; + +/** + * @author Woonduk Kang(emeroad) + */ +interface BootLoader { + Enumeration findResources(String name) throws IOException; + + URL findResource(String name); + + Class findBootstrapClassOrNull(ClassLoader classLoader, String name); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/BootLoaderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/BootLoaderFactory.java new file mode 100644 index 000000000000..da036fdac33a --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/BootLoaderFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import com.navercorp.pinpoint.common.util.JvmType; +import com.navercorp.pinpoint.common.util.JvmUtils; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class BootLoaderFactory { + + private static final boolean isJ9Vm = isJ9VM(); + + private BootLoaderFactory() { + } + + + public static BootLoader newBootLoader() { + if (isJ9Vm) { + try { + return new J9BootLoader(); + } catch (Error linkageError) { + // TODO log + throw new IllegalStateException("J9BootLoader create fail Caused by:" + linkageError.getMessage(), linkageError); + } + } + return new LauncherBootLoader(); + } + + private static boolean isJ9VM() { + JvmType jvmType = JvmUtils.getType(); + return jvmType == JvmType.IBM; + } + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ClassLoaderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ClassLoaderFactory.java new file mode 100644 index 000000000000..19fdc48dea2f --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ClassLoaderFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.net.URL; +import java.util.List; + +/** + * @author Taejin Koo + */ +interface ClassLoaderFactory { + + ClassLoader createClassLoader(String name, URL[] urls, ClassLoader parent, List libClass); + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/DefaultPinpointClassLoaderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/DefaultPinpointClassLoaderFactory.java deleted file mode 100644 index 68c5aafe0622..000000000000 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/DefaultPinpointClassLoaderFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.bootstrap.classloader; - -import java.net.URL; -import java.net.URLClassLoader; - -/** - * @author Taejin Koo - */ -class DefaultPinpointClassLoaderFactory implements InnerPinpointClassLoaderFactory { - - @Override - public URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent) { - return new PinpointURLClassLoader(urls, parent); - } - - @Override - public URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent, LibClass libClass) { - return new PinpointURLClassLoader(urls, parent, libClass); - } - -} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/DynamicClassLoaderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/DynamicClassLoaderFactory.java new file mode 100644 index 000000000000..466185a3ecdb --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/DynamicClassLoaderFactory.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.lang.reflect.Constructor; +import java.net.URL; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DynamicClassLoaderFactory implements ClassLoaderFactory { + + private final Constructor constructor; + + public DynamicClassLoaderFactory(String classLoaderName, ClassLoader classLoader) { + this.constructor = getConstructor(classLoaderName, classLoader); + } + + + private static Constructor getConstructor(String classLoaderName, ClassLoader classLoader) { + try { + final Class classLoaderClazz = + (Class) Class.forName(classLoaderName, true, classLoader); + Constructor constructor = classLoaderClazz.getDeclaredConstructor(String.class, URL[].class, ClassLoader.class, List.class); + return constructor; + } catch (Exception ex) { + throw new IllegalStateException(classLoaderName + " initialize fail Caused by:" + ex.getMessage(), ex); + } + } + + + @Override + public ClassLoader createClassLoader(String name, URL[] urls, ClassLoader parent, List libClass) { + try { + return constructor.newInstance(name, urls, parent, libClass); + } catch (Exception ex) { + throw new IllegalStateException(constructor + " invoke fail Caused by:" + ex.getMessage(), ex); + } + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/InnerPinpointClassLoaderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/InnerPinpointClassLoaderFactory.java deleted file mode 100644 index 5b0a607178c6..000000000000 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/InnerPinpointClassLoaderFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.bootstrap.classloader; - -import java.net.URL; -import java.net.URLClassLoader; - -/** - * @author Taejin Koo - */ -interface InnerPinpointClassLoaderFactory { - - URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent); - - URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent, LibClass libClass); - -} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/J9BootLoader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/J9BootLoader.java new file mode 100644 index 000000000000..b0e11b3aa218 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/J9BootLoader.java @@ -0,0 +1,115 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.Enumeration; + +/** + * for ibm j9 jvm + * + * @author Woonduk Kang(emeroad) + */ +public class J9BootLoader implements BootLoader { + + private static final ClassLoader bootstrapClassLoader ; + private static final Method findResource; + private static final Method findResources; + private static final boolean isJ9VM; + + static { + bootstrapClassLoader = findBootstrapClassLoader(); + final Class abstractClassLoader = getAbstractClassLoader("com.ibm.oti.vm.AbstractClassLoader"); + findResource = getMethod(abstractClassLoader, "findResource", String.class); + findResources = getMethod(abstractClassLoader, "findResources", String.class); + isJ9VM = true; + } + + private static ClassLoader findBootstrapClassLoader() { + Field bootstrapClassLoader; + try { + bootstrapClassLoader = ClassLoader.class.getDeclaredField("bootstrapClassLoader"); + } catch (NoSuchFieldException e) { + try { + bootstrapClassLoader = ClassLoader.class.getDeclaredField("systemClassLoader"); + } catch (NoSuchFieldException e2) { + throw new IllegalStateException("bootstrapClassLoader not found Caused by:" + e.getMessage() + ", and " + e2.getMessage(), e2); + } + } + try { + bootstrapClassLoader.setAccessible(true); + return (ClassLoader) bootstrapClassLoader.get(ClassLoader.class); + } catch (IllegalAccessException e) { + throw new IllegalStateException("bootstrapClassLoader access fail Caused by:" + e.getMessage(), e); + } + } + + private static Class getAbstractClassLoader(String className) { + try { + return Class.forName(className, false, Object.class.getClassLoader()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(className + " not found Caused by:" + e.getMessage(), e); + } + } + + + private static Method getMethod(Class bootstrapClassLoader, String methodName, Class... parameterTypes) { + try { + Method declaredMethod = bootstrapClassLoader.getDeclaredMethod(methodName, parameterTypes); + declaredMethod.setAccessible(true); + return declaredMethod; + } catch (NoSuchMethodException e) { + throw new IllegalStateException(methodName + " not found Caused by:" + e.getMessage(), e); + } + + } + + @Override + public Enumeration findResources(String name) throws IOException { + try { + return (Enumeration) findResources.invoke(bootstrapClassLoader, name); + } catch (IllegalAccessException e) { + throw new IllegalStateException("access fail Caused by:" + e.getMessage(), e); + } catch (InvocationTargetException e) { + throw new IllegalStateException("invoke fail Caused by:" + e.getMessage(), e); + } + } + + @Override + public URL findResource(String name) { + try { + return (URL) findResource.invoke(bootstrapClassLoader, name); + } catch (IllegalAccessException e) { + throw new IllegalStateException("access fail Caused by:" + e.getMessage(), e); + } catch (InvocationTargetException e) { + throw new IllegalStateException("invoke fail Caused by:" + e.getMessage(), e); + } + } + + @Override + public Class findBootstrapClassOrNull(ClassLoader classLoader, String name) { + try { + return bootstrapClassLoader.loadClass(name); + } catch (ClassNotFoundException e) { + return null; + } + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/Java6ClassLoader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/Java6ClassLoader.java new file mode 100644 index 000000000000..d0e734d2dabc --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/Java6ClassLoader.java @@ -0,0 +1,138 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Enumeration; +import java.util.List; + +/** + * this ClassLoader loads a class in the profiler lib directory and delegates to load the other classes to parent classloader + * Dead lock could happen in case of standalone java application. + * Don't delegate to parents classlaoder if classes are in the profiler lib directory + * + * @author emeroad + */ +public class Java6ClassLoader extends URLClassLoader { + + private final BootLoader bootLoader = BootLoaderFactory.newBootLoader(); + // @Nullable + // WARNING : if parentClassLoader is null. it is bootstrapClassloader + private final ClassLoader parent; + private final LibClass libClass; + private final String name; + + public Java6ClassLoader(String name, URL[] urls, ClassLoader parent, List libClass) { + super(urls, parent); + if (name == null) { + throw new NullPointerException("name must not be null"); + } + this.name = name; + + if (libClass == null) { + throw new NullPointerException("libClass must not be null"); + } + this.parent = parent; + this.libClass = new ProfilerLibClass(libClass); + } + + + private Object getClassLoadingLock0(String name) { + return this; + } + + @Override + public URL getResource(String name) { + URL url = findResource(name); + if (url == null) { + if (parent != null) { + url = parent.getResource(name); + } else { + url = this.bootLoader.findResource(name); + } + } + + return url; + } + + @Override + public Enumeration getResources(String name) throws IOException { + final Enumeration currentResource = findResources(name); + + Enumeration parentResource; + if (parent != null) { + parentResource = parent.getResources(name); + } else { + parentResource = this.bootLoader.findResources(name); + } + + return new MergedEnumeration2(currentResource, parentResource); + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + synchronized (getClassLoadingLock0(name)) { + // First, check if the class has already been loaded + Class clazz = findLoadedClass(name); + if (clazz == null) { + if (onLoadClass(name)) { + // load a class used for Pinpoint itself by this ClassLoader + clazz = findClass(name); + } else { + try { + // load a class by parent ClassLoader + if (parent != null) { + clazz = parent.loadClass(name); + } else { + clazz = this.bootLoader.findBootstrapClassOrNull(this, name); + } + } catch (ClassNotFoundException ignore) { + } + if (clazz == null) { + // if not found, try to load a class by this ClassLoader + clazz = findClass(name); + } + } + } + if (resolve) { + resolveClass(clazz); + } + return clazz; + } + } + + // for test + private boolean onLoadClass(String name) { + return libClass.onLoadClass(name); + } + + /** + * java9 JPMS + */ + public String getName() { + return name; + } + + @Override + public String toString() { + return "Java6ClassLoader{" + + "name='" + name + '\'' + + "} " + super.toString(); + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/Java6ClassLoaderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/Java6ClassLoaderFactory.java new file mode 100644 index 000000000000..ba033a769dd9 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/Java6ClassLoaderFactory.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.net.URL; +import java.util.List; + +/** + * @author Taejin Koo + */ +class Java6ClassLoaderFactory implements ClassLoaderFactory { + + + @Override + public ClassLoader createClassLoader(String name, URL[] urls, ClassLoader parent, List libClass) { + return new Java6ClassLoader(name, urls, parent, libClass); + } + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/LauncherBootLoader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/LauncherBootLoader.java new file mode 100644 index 000000000000..2f00f6db7873 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/LauncherBootLoader.java @@ -0,0 +1,126 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import sun.misc.Launcher; +import sun.misc.Resource; +import sun.misc.URLClassPath; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.Enumeration; + +/** + * @author Woonduk Kang(emeroad) + */ +final class LauncherBootLoader implements BootLoader { + + private final URLClassPath bootstrapClassPath = getBootstrapClassPath(); + + private static final Method FIND_BOOTSTRAP_CLASS_OR_NULL = findBootstrapClassOrNullMethod(); + + private static Method findBootstrapClassOrNullMethod() { + // findBootstrapClassOrNull() jdk Compatibility + // oracleJdk + // oracleJdk 9~10 : reflection is not recommended + + // old OracleJdk : + // oracleJdk6_24 : success + + // openjdk + // openjdk8 : success + // openjdk7 : success + // openjdk6 : fail (findBootstrapClass0) + NoSuchMethodException rootException; + try { + Method findBootstrapClassOrNull = ClassLoader.class.getDeclaredMethod("findBootstrapClassOrNull", String.class); + findBootstrapClassOrNull.setAccessible(true); + return findBootstrapClassOrNull; + } catch (NoSuchMethodException ex) { + rootException = ex; + } + try { + // for openjdk6 + Method findBootstrapClass0 = ClassLoader.class.getDeclaredMethod("findBootstrapClass0", String.class); + findBootstrapClass0.setAccessible(true); + return findBootstrapClass0; + } catch (NoSuchMethodException ignore) { + // skip + } + throw new IllegalStateException("ClassLoader.findBootstrapClassOrNull api not found", rootException); + } + + LauncherBootLoader() { + } + + private static URLClassPath getBootstrapClassPath() { + // pre classload + @SuppressWarnings("unused") + Enumeration urlEnumeration = new URLEnumeration(null); + return Launcher.getBootstrapClassPath(); + } + + @Override + public URL findResource(String name) { + final Resource res = bootstrapClassPath.getResource(name); + if (res == null) { + return null; + } + return res.getURL(); + } + + @Override + public Class findBootstrapClassOrNull(ClassLoader classLoader, String name) { + try { + return (Class) FIND_BOOTSTRAP_CLASS_OR_NULL.invoke(classLoader, name); + } catch (IllegalAccessException ex) { + throw new IllegalStateException(FIND_BOOTSTRAP_CLASS_OR_NULL.getName() + "() access fail " + ex.getMessage(), ex); + } catch (InvocationTargetException ex) { + final Throwable cause = ex.getCause(); + if (cause instanceof ClassNotFoundException) { + // fix openjdk6 + return null; + } + throw new IllegalStateException(FIND_BOOTSTRAP_CLASS_OR_NULL.getName() + "() internal error " + ex.getMessage(), ex); + } + } + + @Override + public Enumeration findResources(String name) throws IOException { + final Enumeration enumeration = bootstrapClassPath.getResources(name); + return new URLEnumeration(enumeration); + } + + private static class URLEnumeration implements Enumeration { + private final Enumeration enumeration; + + private URLEnumeration(Enumeration enumeration) { + this.enumeration = enumeration; + } + + public URL nextElement() { + Resource resource = enumeration.nextElement(); + return resource.getURL(); + } + + public boolean hasMoreElements() { + return enumeration.hasMoreElements(); + } + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/MergedEnumeration2.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/MergedEnumeration2.java new file mode 100644 index 000000000000..a65a10de65f4 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/MergedEnumeration2.java @@ -0,0 +1,78 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * @author Woonduk Kang(emeroad) + */ +class MergedEnumeration2 implements Enumeration { + private static final int MAX = 2; + + private final Enumeration enum0; + private final Enumeration enum1; + private int index = 0; + + public MergedEnumeration2(Enumeration enum0, Enumeration enum1) { + this.enum0 = enum0; + this.enum1 = enum1; + } + + private boolean next() { + while (this.index < MAX) { + final Enumeration enumeration = getEnumeration(); + if (enumeration != null && enumeration.hasMoreElements()) { + return true; + } + + nextIndex(); + } + + return false; + } + + private void nextIndex() { + this.index++; + } + + private Enumeration getEnumeration() { + switch (index) { + case 0: + return enum0; + case 1: + return enum1; + default: + throw new NoSuchElementException("index out of range:" + index); + } + } + + public boolean hasMoreElements() { + return this.next(); + } + + public E nextElement() { + if (!this.next()) { + throw new NoSuchElementException(); + } + + Enumeration enumeration = getEnumeration(); + return enumeration.nextElement(); + } + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointClassLoaderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointClassLoaderFactory.java index c8143eab11fe..e9b90d2e48bf 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointClassLoaderFactory.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointClassLoaderFactory.java @@ -21,9 +21,9 @@ import com.navercorp.pinpoint.common.util.JvmUtils; import com.navercorp.pinpoint.common.util.JvmVersion; -import java.lang.reflect.Method; +import java.lang.reflect.Constructor; import java.net.URL; -import java.net.URLClassLoader; +import java.util.List; /** * @author Taejin Koo @@ -32,71 +32,65 @@ public final class PinpointClassLoaderFactory { private static final PLogger LOGGER = PLoggerFactory.getLogger(PinpointClassLoaderFactory.class); - private static final InnerPinpointClassLoaderFactory CLASS_LOADER_FACTORY = createClassLoaderFactory(); + private static final ClassLoaderFactory CLASS_LOADER_FACTORY = createClassLoaderFactory(); // Jdk 7+ - private static final String PARALLEL_CAPABLE_CLASS_LOADER_FACTORY = "com.navercorp.pinpoint.bootstrap.classloader.ParallelCapablePinpointClassLoaderFactory"; + private static final String PARALLEL_CLASS_LOADER_FACTORY = "com.navercorp.pinpoint.bootstrap.classloader.ParallelClassLoaderFactory"; + + // jdk9 + private static final String JAVA9_CLASSLOADER = "com.navercorp.pinpoint.bootstrap.java9.classloader.Java9ClassLoader"; + private PinpointClassLoaderFactory() { throw new IllegalAccessError(); } - private static InnerPinpointClassLoaderFactory createClassLoaderFactory() { + public static ClassLoaderFactory createClassLoaderFactory() { final JvmVersion jvmVersion = JvmUtils.getVersion(); - if (jvmVersion == JvmVersion.JAVA_6) { - return new DefaultPinpointClassLoaderFactory(); - } else if (jvmVersion.onOrAfter(JvmVersion.JAVA_7)) { - boolean hasRegisterAsParallelCapableMethod = hasRegisterAsParallelCapableMethod(); - if (hasRegisterAsParallelCapableMethod) { - try { - ClassLoader classLoader = getClassLoader(PinpointClassLoaderFactory.class.getClassLoader()); - final Class parallelCapableClassLoaderFactoryClass = - (Class) Class.forName(PARALLEL_CAPABLE_CLASS_LOADER_FACTORY, true, classLoader); - return parallelCapableClassLoaderFactoryClass.newInstance(); - } catch (ClassNotFoundException e) { - logError(e); - } catch (InstantiationException e) { - logError(e); - } catch (IllegalAccessException e) { - logError(e); - } - return new DefaultPinpointClassLoaderFactory(); - } else { - return new DefaultPinpointClassLoaderFactory(); - } - } else { - throw new RuntimeException("Unsupported jvm version " + jvmVersion); + + if (jvmVersion.onOrAfter(JvmVersion.JAVA_9)) { + return newClassLoaderFactory(JAVA9_CLASSLOADER); + } + + // URLClassLoader not work for java9 + if (disableChildFirst()) { + return new URLClassLoaderFactory(); } - } - private static boolean hasRegisterAsParallelCapableMethod() { - Method[] methods = ClassLoader.class.getDeclaredMethods(); - for (Method method : methods) { - if (method.getName().equals("registerAsParallelCapable")) { - return true; - } + if (jvmVersion.onOrAfter(JvmVersion.JAVA_7)) { + return newParallelClassLoaderFactory(); } - return false; + // JDK6 -- + return new Java6ClassLoaderFactory(); } - private static ClassLoader getClassLoader(ClassLoader classLoader) { - if (classLoader == null) { - return ClassLoader.getSystemClassLoader(); - } - return classLoader; + private static boolean disableChildFirst() { + String disable = System.getProperty("pinpoint.agent.classloader.childfirst.disable"); + return "true".equalsIgnoreCase(disable); } - private static void logError(Exception e) { - LOGGER.info("ParallelCapablePinpointClassLoader not found."); + private static ClassLoaderFactory newClassLoaderFactory(String factoryName) { + ClassLoader classLoader = PinpointClassLoaderFactory.class.getClassLoader(); + + return new DynamicClassLoaderFactory(factoryName, classLoader); } - public static URLClassLoader createClassLoader(URL[] urls, ClassLoader parent) { - return CLASS_LOADER_FACTORY.createURLClassLoader(urls, parent); + private static ClassLoaderFactory newParallelClassLoaderFactory() { + try { + ClassLoader classLoader = PinpointClassLoaderFactory.class.getClassLoader(); + final Class classLoaderFactoryClazz = + (Class) Class.forName(PARALLEL_CLASS_LOADER_FACTORY, true, classLoader); + Constructor constructor = classLoaderFactoryClazz.getDeclaredConstructor(); + return constructor.newInstance(); + } catch (Exception e) { + throw new IllegalStateException(PARALLEL_CLASS_LOADER_FACTORY + " create fail Caused by:" + e.getMessage(), e); + } } - public static URLClassLoader createClassLoader(URL[] urls, ClassLoader parent, LibClass libClass) { - return CLASS_LOADER_FACTORY.createURLClassLoader(urls, parent, libClass); + + public static ClassLoader createClassLoader(String name, URL[] urls, ClassLoader parent, List libClass) { + return CLASS_LOADER_FACTORY.createClassLoader(name, urls, parent, libClass); } } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointURLClassLoader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointURLClassLoader.java deleted file mode 100644 index 3679f41a03b7..000000000000 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointURLClassLoader.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.bootstrap.classloader; - -import java.net.URL; -import java.net.URLClassLoader; - -/** - * PinpointURLClassLoader loads a class in the profiler lib directory and delegates to load the other classes to parent classloader - * Dead lock could happen in case of standalone java application. - * Don't delegate to parents classlaoder if classes are in the profiler lib directory - * - * @author emeroad - */ -public class PinpointURLClassLoader extends URLClassLoader { - - private static final LibClass PROFILER_LIB_CLASS = new ProfilerLibClass(); - - private final ClassLoader parent; - - private final LibClass libClass; - - public PinpointURLClassLoader(URL[] urls, ClassLoader parent, LibClass libClass) { - super(urls, parent); - - if (parent == null) { - throw new NullPointerException("parent must not be null"); - } - if (libClass == null) { - throw new NullPointerException("libClass must not be null"); - } - - this.parent = parent; - this.libClass = libClass; - } - - public PinpointURLClassLoader(URL[] urls, ClassLoader parent) { - this(urls, parent, PROFILER_LIB_CLASS); - } - - - @Override - protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - // First, check if the class has already been loaded - Class clazz = findLoadedClass(name); - if (clazz == null) { - if (onLoadClass(name)) { - // load a class used for Pinpoint itself by this PinpointURLClassLoader - clazz = findClass(name); - } else { - try { - // load a class by parent ClassLoader - clazz = parent.loadClass(name); - } catch (ClassNotFoundException ignore) { - } - if (clazz == null) { - // if not found, try to load a class by this PinpointURLClassLoader - clazz = findClass(name); - } - } - } - if (resolve) { - resolveClass(clazz); - } - return clazz; - } - - // for test - boolean onLoadClass(String name) { - return libClass.onLoadClass(name); - } - -} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibClass.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibClass.java index 33af0b419585..4971784f07bb 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibClass.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibClass.java @@ -16,38 +16,28 @@ package com.navercorp.pinpoint.bootstrap.classloader; +import java.util.List; + /** * @author emeroad */ public class ProfilerLibClass implements LibClass { - private static final String[] PINPOINT_PROFILER_CLASS = new String[] { - "com.navercorp.pinpoint.profiler", - "com.navercorp.pinpoint.thrift", - "com.navercorp.pinpoint.rpc", - /* - * @deprecated javassist - */ - "javassist", - "org.objectweb.asm", - "org.slf4j", - "org.apache.thrift", - "org.jboss.netty", - "com.google.common", - // google guice - "com.google.inject", - "org.aopalliance", + private String[] profilerClass; + + public ProfilerLibClass(List profilerClass) { + if (profilerClass == null) { + throw new NullPointerException("profilerClass must not be null"); + } - "org.apache.commons.lang", - "org.apache.log4j", - "com.nhncorp.nelo2" - }; + this.profilerClass = profilerClass.toArray(new String[0]); + } @Override public boolean onLoadClass(String clazzName) { - final int length = PINPOINT_PROFILER_CLASS.length; + final int length = profilerClass.length; for (int i = 0; i < length; i++) { - if (clazzName.startsWith(PINPOINT_PROFILER_CLASS[i])) { + if (clazzName.startsWith(profilerClass[i])) { return ON_LOAD_CLASS; } } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibs.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibs.java new file mode 100644 index 000000000000..423b173b2850 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibs.java @@ -0,0 +1,57 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ProfilerLibs { + + public static final List PINPOINT_PROFILER_CLASS; + + static { + String[] lib = new String[] { + "com.navercorp.pinpoint.profiler", + "com.navercorp.pinpoint.thrift", + "com.navercorp.pinpoint.io", + "com.navercorp.pinpoint.rpc", + /* + * @deprecated javassist + */ + "javassist", + "org.objectweb.asm", + "org.slf4j", + "org.apache.thrift", + "org.jboss.netty", + "com.google.common", + // google guice + "com.google.inject", + "org.aopalliance", + + "org.apache.commons.lang", + "org.apache.log4j", + "com.nhncorp.nelo2" + }; + + PINPOINT_PROFILER_CLASS = Collections.unmodifiableList(Arrays.asList(lib)); + } + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/URLClassLoaderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/URLClassLoaderFactory.java new file mode 100644 index 000000000000..63e1c11598c4 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/classloader/URLClassLoaderFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +class URLClassLoaderFactory implements ClassLoaderFactory{ + + @Override + public ClassLoader createClassLoader(String name, URL[] urls, ClassLoader parent, List libClass) { + return new URLClassLoader(urls, parent); + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/DefaultProfilerConfig.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/DefaultProfilerConfig.java index 4df07e5f2dc0..650511b717f5 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/DefaultProfilerConfig.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/DefaultProfilerConfig.java @@ -18,6 +18,7 @@ import com.navercorp.pinpoint.bootstrap.util.NumberUtils; import com.navercorp.pinpoint.bootstrap.util.spring.PropertyPlaceholderHelper; +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; import com.navercorp.pinpoint.common.util.StringUtils; import com.navercorp.pinpoint.common.util.logger.CommonLogger; import com.navercorp.pinpoint.common.util.PropertyUtils; @@ -43,8 +44,6 @@ public class DefaultProfilerConfig implements ProfilerConfig { private final Properties properties; private final PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper("${", "}"); - @Deprecated - public static final String INSTRUMENT_ENGINE_JAVASSIST = "JAVASSIST"; public static final String INSTRUMENT_ENGINE_ASM = "ASM"; public static final int DEFAULT_AGENT_STAT_COLLECTION_INTERVAL_MS = 5 * 1000; @@ -98,6 +97,9 @@ public static ProfilerConfig load(String pinpointConfigFileName) throws IOExcept private int interceptorRegistrySize = 1024 * 8; + @VisibleForTesting + private boolean staticResourceCleanup = false; + private String collectorSpanServerIp = DEFAULT_IP; private int collectorSpanServerPort = 9996; @@ -127,6 +129,17 @@ public static ProfilerConfig load(String pinpointConfigFileName) throws IOExcept private boolean tcpDataSenderCommandActiveThreadDumpEnable = false; private boolean tcpDataSenderCommandActiveThreadLightDumpEnable = false; + private static long DEFAULT_DATA_SENDER_PINPOINT_CLIENT_WRITE_TIMEOUT = 3 * 1000; + private long tcpDataSenderPinpointClientWriteTimeout = DEFAULT_DATA_SENDER_PINPOINT_CLIENT_WRITE_TIMEOUT; + private static long DEFAULT_DATA_SENDER_PINPOINT_CLIENT_REQUEST_TIMEOUT = 3 * 1000; + private long tcpDataSenderPinpointClientRequestTimeout = DEFAULT_DATA_SENDER_PINPOINT_CLIENT_REQUEST_TIMEOUT; + private static long DEFAULT_DATA_SENDER_PINPOINT_CLIENT_RECONNECT_INTERVAL = 3 * 1000; + private long tcpDataSenderPinpointClientReconnectInterval = DEFAULT_DATA_SENDER_PINPOINT_CLIENT_RECONNECT_INTERVAL; + private static long DEFAULT_DATA_SENDER_PINPOINT_CLIENT_PING_INTERVAL = 60 * 1000 * 5; + private long tcpDataSenderPinpointClientPingInterval = DEFAULT_DATA_SENDER_PINPOINT_CLIENT_PING_INTERVAL; + private static long DEFAULT_DATA_SENDER_PINPOINT_CLIENT_HANDSHAKE_INTERVAL = 60 * 1000 * 1; + private long tcpDataSenderPinpointClientHandshakeInterval = DEFAULT_DATA_SENDER_PINPOINT_CLIENT_HANDSHAKE_INTERVAL; + private boolean traceAgentActiveThread = true; private boolean traceAgentDataSource = false; @@ -150,6 +163,7 @@ public static ProfilerConfig load(String pinpointConfigFileName) throws IOExcept private int ioBufferingBufferSize; private String profileJvmVendorName; + private String profileOsName; private int profileJvmStatCollectIntervalMs = DEFAULT_AGENT_STAT_COLLECTION_INTERVAL_MS; private int profileJvmStatBatchSendCount = DEFAULT_NUM_AGENT_STAT_BATCH_SEND; private boolean profilerJvmStatCollectDetailedMetrics; @@ -168,7 +182,10 @@ public static ProfilerConfig load(String pinpointConfigFileName) throws IOExcept private boolean proxyHttpHeaderEnable = true; - private List httpStatusCodeErrors = Collections.emptyList(); + private HttpStatusCodeErrors httpStatusCodeErrors = new HttpStatusCodeErrors(); + + private String injectionModuleFactoryClazzName = null; + private String applicationNamespace = ""; public DefaultProfilerConfig() { this.properties = new Properties(); @@ -277,6 +294,31 @@ public boolean isTcpDataSenderCommandActiveThreadLightDumpEnable() { return tcpDataSenderCommandActiveThreadLightDumpEnable; } + @Override + public long getTcpDataSenderPinpointClientWriteTimeout() { + return tcpDataSenderPinpointClientWriteTimeout; + } + + @Override + public long getTcpDataSenderPinpointClientRequestTimeout() { + return tcpDataSenderPinpointClientRequestTimeout; + } + + @Override + public long getTcpDataSenderPinpointClientReconnectInterval() { + return tcpDataSenderPinpointClientReconnectInterval; + } + + @Override + public long getTcpDataSenderPinpointClientPingInterval() { + return tcpDataSenderPinpointClientPingInterval; + } + + @Override + public long getTcpDataSenderPinpointClientHandshakeInterval() { + return tcpDataSenderPinpointClientHandshakeInterval; + } + @Override public boolean isTraceAgentActiveThread() { return traceAgentActiveThread; @@ -373,6 +415,11 @@ public String getProfilerJvmVendorName() { return profileJvmVendorName; } + @Override + public String getProfilerOSName() { + return profileOsName; + } + @Override public int getProfileJvmStatCollectIntervalMs() { return profileJvmStatCollectIntervalMs; @@ -393,6 +440,15 @@ public long getAgentInfoSendRetryInterval() { return agentInfoSendRetryInterval; } + @Override + public boolean getStaticResourceCleanup() { + return staticResourceCleanup; + } + + public void setStaticResourceCleanup(boolean staticResourceCleanup) { + this.staticResourceCleanup = staticResourceCleanup; + } + @Override public Filter getProfilableClassFilter() { @@ -458,10 +514,20 @@ public boolean isProxyHttpHeaderEnable() { } @Override - public List getHttpStatusCodeErrors() { + public HttpStatusCodeErrors getHttpStatusCodeErrors() { return httpStatusCodeErrors; } + @Override + public String getInjectionModuleFactoryClazzName() { + return injectionModuleFactoryClazzName; + } + + @Override + public String getApplicationNamespace() { + return applicationNamespace; + } + // for test void readPropertyValues() { // TODO : use Properties' default value instead of using a temp variable. @@ -509,6 +575,12 @@ void readPropertyValues() { this.tcpDataSenderCommandActiveThreadDumpEnable = readBoolean("profiler.tcpdatasender.command.activethread.threaddump.enable", false); this.tcpDataSenderCommandActiveThreadLightDumpEnable = readBoolean("profiler.tcpdatasender.command.activethread.threadlightdump.enable", false); + this.tcpDataSenderPinpointClientWriteTimeout = readLong("profiler.tcpdatasender.client.write.timeout", DEFAULT_DATA_SENDER_PINPOINT_CLIENT_WRITE_TIMEOUT); + this.tcpDataSenderPinpointClientRequestTimeout = readLong("profiler.tcpdatasender.client.request.timeout", DEFAULT_DATA_SENDER_PINPOINT_CLIENT_REQUEST_TIMEOUT); + this.tcpDataSenderPinpointClientReconnectInterval = readLong("profiler.tcpdatasender.client.reconnect.interval", DEFAULT_DATA_SENDER_PINPOINT_CLIENT_RECONNECT_INTERVAL); + this.tcpDataSenderPinpointClientPingInterval = readLong("profiler.tcpdatasender.client.ping.interval", DEFAULT_DATA_SENDER_PINPOINT_CLIENT_PING_INTERVAL); + this.tcpDataSenderPinpointClientHandshakeInterval = readLong("profiler.tcpdatasender.client.handshake.interval", DEFAULT_DATA_SENDER_PINPOINT_CLIENT_HANDSHAKE_INTERVAL); + this.traceAgentActiveThread = readBoolean("profiler.pinpoint.activethread", true); this.traceAgentDataSource = readBoolean("profiler.pinpoint.datasource", false); @@ -537,11 +609,14 @@ void readPropertyValues() { // it may be a problem to be here. need to modify(delete or move or .. ) this configuration. this.ioBufferingBufferSize = readInt("profiler.io.buffering.buffersize", 20); + //OS + this.profileOsName = readString("profiler.os.name", null); + // JVM this.profileJvmVendorName = readString("profiler.jvm.vendor.name", null); this.profileJvmStatCollectIntervalMs = readInt("profiler.jvm.stat.collect.interval", DEFAULT_AGENT_STAT_COLLECTION_INTERVAL_MS); this.profileJvmStatBatchSendCount = readInt("profiler.jvm.stat.batch.send.count", DEFAULT_NUM_AGENT_STAT_BATCH_SEND); - this.profilerJvmStatCollectDetailedMetrics = readBoolean("profiler.stat.jvm.collect.detailed.metrics", false); + this.profilerJvmStatCollectDetailedMetrics = readBoolean("profiler.jvm.stat.collect.detailed.metrics", false); this.agentInfoSendRetryInterval = readLong("profiler.agentInfo.send.retry.interval", DEFAULT_AGENT_INFO_SEND_RETRY_INTERVAL); @@ -568,7 +643,11 @@ void readPropertyValues() { // proxy http header names this.proxyHttpHeaderEnable = readBoolean("profiler.proxy.http.header.enable", true); - this.httpStatusCodeErrors = readList("profiler.http.status.code.errors"); + this.httpStatusCodeErrors = new HttpStatusCodeErrors(readList("profiler.http.status.code.errors")); + + this.injectionModuleFactoryClazzName = readString("profiler.guice.module.factory", null); + + this.applicationNamespace = readString("profiler.application.namespace", ""); logger.info("configuration loaded successfully."); } @@ -703,6 +782,11 @@ public String toString() { sb.append(", tcpDataSenderCommandActiveThreadCountEnable=").append(tcpDataSenderCommandActiveThreadCountEnable); sb.append(", tcpDataSenderCommandActiveThreadDumpEnable=").append(tcpDataSenderCommandActiveThreadDumpEnable); sb.append(", tcpDataSenderCommandActiveThreadLightDumpEnable=").append(tcpDataSenderCommandActiveThreadLightDumpEnable); + sb.append(", tcpDataSenderPinpointClientWriteTimeout=").append(tcpDataSenderPinpointClientWriteTimeout); + sb.append(", tcpDataSenderPinpointClientRequestTimeout=").append(tcpDataSenderPinpointClientRequestTimeout); + sb.append(", tcpDataSenderPinpointClientReconnectInterval=").append(tcpDataSenderPinpointClientReconnectInterval); + sb.append(", tcpDataSenderPinpointClientPingInterval=").append(tcpDataSenderPinpointClientPingInterval); + sb.append(", tcpDataSenderPinpointClientHandshakeInterval=").append(tcpDataSenderPinpointClientHandshakeInterval); sb.append(", traceAgentActiveThread=").append(traceAgentActiveThread); sb.append(", traceAgentDataSource=").append(traceAgentDataSource); sb.append(", dataSourceTraceLimitSize=").append(dataSourceTraceLimitSize); @@ -716,6 +800,7 @@ public String toString() { sb.append(", samplingRate=").append(samplingRate); sb.append(", ioBufferingEnable=").append(ioBufferingEnable); sb.append(", ioBufferingBufferSize=").append(ioBufferingBufferSize); + sb.append(", profileOsName='").append(profileOsName).append('\''); sb.append(", profileJvmVendorName='").append(profileJvmVendorName).append('\''); sb.append(", profileJvmStatCollectIntervalMs=").append(profileJvmStatCollectIntervalMs); sb.append(", profileJvmStatBatchSendCount=").append(profileJvmStatBatchSendCount); @@ -730,7 +815,10 @@ public String toString() { sb.append(", supportLambdaExpressions=").append(supportLambdaExpressions); sb.append(", proxyHttpHeaderEnable=").append(proxyHttpHeaderEnable); sb.append(", httpStatusCodeErrors=").append(httpStatusCodeErrors); + sb.append(", injectionModuleFactoryClazzName='").append(injectionModuleFactoryClazzName).append('\''); + sb.append(", applicationNamespace='").append(applicationNamespace).append('\''); sb.append('}'); return sb.toString(); } + } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/ExcludePathFilter.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/ExcludePathFilter.java index fbb3c8ee7ac7..62f4f7f9c098 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/ExcludePathFilter.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/ExcludePathFilter.java @@ -66,7 +66,7 @@ public PathMatcher[] toArray(Collection collection) { if (collection == null) { throw new NullPointerException("collection must not be null"); } - return collection.toArray(new PathMatcher[collection.size()]); + return collection.toArray(new PathMatcher[0]); } protected PathMatcher createPathMatcher(String pattern, String pathSeparator) { diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/HttpDumpConfig.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/HttpDumpConfig.java index df87580b7a09..32e43f708b44 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/HttpDumpConfig.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/HttpDumpConfig.java @@ -20,9 +20,8 @@ import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; /** - * * @author netspider - * + * @author jaehong.kim */ public class HttpDumpConfig { @@ -39,14 +38,26 @@ public static HttpDumpConfig getDefault() { config.setEntitySampler(SimpleSamplerFactory.createSampler(false, 1)); config.setEntityDumpSize(128); - config.setDumpParam(false); - config.setParamDumpType(DumpType.EXCEPTION); - config.setParamSampler(SimpleSamplerFactory.createSampler(false, 1)); - config.setParamDumpSize(128); + return config; + } + + public static HttpDumpConfig get(final boolean cookie, final DumpType cookieDumpType, final int cookieDumpSamplingRate, final int cookieDumpSize, final boolean entity, final DumpType entityDumpType, final int entityDumpSamplingRate, final int entityDumpSize) { + HttpDumpConfig config = new HttpDumpConfig(); + + config.setDumpCookie(cookie); + config.setCookieDumpType(cookieDumpType); + config.setCookieSampler(SimpleSamplerFactory.createSampler(cookie, cookieDumpSamplingRate)); + config.setCookieDumpSize(cookieDumpSize); + + config.setDumpEntity(entity); + config.setEntityDumpType(entityDumpType); + config.setEntitySampler(SimpleSamplerFactory.createSampler(entity, entityDumpSamplingRate)); + config.setEntityDumpSize(entityDumpSize); return config; } + private boolean dumpCookie = false; private DumpType cookieDumpType = DumpType.EXCEPTION; private SimpleSampler cookieSampler; @@ -57,11 +68,6 @@ public static HttpDumpConfig getDefault() { private SimpleSampler entitySampler; private int entityDumpSize; - private boolean dumpParam; - private DumpType paramDumpType; - private SimpleSampler paramSampler; - private int paramDumpSize; - public boolean isDumpCookie() { return dumpCookie; } @@ -125,36 +131,4 @@ public int getEntityDumpSize() { public void setEntityDumpSize(int entityDumpSize) { this.entityDumpSize = entityDumpSize; } - - public boolean isDumpParam() { - return dumpParam; - } - - public void setDumpParam(boolean dumpParam) { - this.dumpParam = dumpParam; - } - - public DumpType getParamDumpType() { - return paramDumpType; - } - - public void setParamDumpType(DumpType paramDumpType) { - this.paramDumpType = paramDumpType; - } - - public SimpleSampler getParamSampler() { - return paramSampler; - } - - public void setParamSampler(SimpleSampler paramSampler) { - this.paramSampler = paramSampler; - } - - public int getParamDumpSize() { - return paramDumpSize; - } - - public void setParamDumpSize(int paramDumpSize) { - this.paramDumpSize = paramDumpSize; - } } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/HttpStatusCodeErrors.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/HttpStatusCodeErrors.java new file mode 100644 index 000000000000..7467d0626fe7 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/HttpStatusCodeErrors.java @@ -0,0 +1,188 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.config; + +import com.navercorp.pinpoint.common.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author jaehong.kim + */ +public class HttpStatusCodeErrors { + private static final StatusCode ALL_STATUS_CODES = new StatusCode() { + @Override + public boolean isCode(int statusCode) { + return 100 <= statusCode && statusCode <= 599; + } + }; + private static final List DEFAULT_ERROR_CODES = Arrays.asList("5xx"); + + private final StatusCode[] errors; + + public HttpStatusCodeErrors() { + this(DEFAULT_ERROR_CODES); + } + + public HttpStatusCodeErrors(final List errorCodes) { + this.errors = newErrorCode(errorCodes); + } + + public boolean isHttpStatusCode(final int statusCode) { + return ALL_STATUS_CODES.isCode(statusCode); + } + + public boolean isErrorCode(final int statusCode) { + for (StatusCode code : this.errors) { + if (code.isCode(statusCode)) { + return true; + } + } + return false; + } + + private StatusCode[] newErrorCode(List errorCodes) { + if (CollectionUtils.isEmpty(errorCodes)) { + return new StatusCode[0]; + } + + List statusCodeList = new ArrayList(); + for (String errorCode : errorCodes) { + if (errorCode.equalsIgnoreCase("5xx")) { + statusCodeList.add(new ServerError()); + } else if (errorCode.equalsIgnoreCase("4xx")) { + statusCodeList.add(new ClientError()); + } else if (errorCode.equalsIgnoreCase("3xx")) { + statusCodeList.add(new Redirection()); + } else if (errorCode.equalsIgnoreCase("2xx")) { + statusCodeList.add(new Success()); + } else if (errorCode.equalsIgnoreCase("1xx")) { + statusCodeList.add(new Informational()); + } else { + try { + final int statusCode = Integer.parseInt(errorCode); + statusCodeList.add(new DefaultStatusCode(statusCode)); + } catch (NumberFormatException ignored) { + } + } + } + return toArray(statusCodeList); + } + + private StatusCode[] toArray(List list) { + if (CollectionUtils.isEmpty(list)) { + return new StatusCode[0]; + } + return list.toArray(new StatusCode[0]); + } + + + private interface StatusCode { + boolean isCode(int statusCode); + } + + private static class DefaultStatusCode implements StatusCode { + private final int statusCode; + + public DefaultStatusCode(final int statusCode) { + this.statusCode = statusCode; + } + + @Override + public boolean isCode(int statusCode) { + return this.statusCode == statusCode; + } + + @Override + public String toString() { + return String.valueOf(statusCode); + } + } + + private static class Informational implements StatusCode { + @Override + public boolean isCode(int statusCode) { + return 100 <= statusCode && statusCode <= 199; + } + + @Override + public String toString() { + return "1xx"; + } + } + + private static class Success implements StatusCode { + @Override + public boolean isCode(int statusCode) { + return 200 <= statusCode && statusCode <= 299; + } + + @Override + public String toString() { + return "2xx"; + } + + } + + private static class Redirection implements StatusCode { + @Override + public boolean isCode(int statusCode) { + return 300 <= statusCode && statusCode <= 399; + } + + @Override + public String toString() { + return "3xx"; + } + + } + + private static class ClientError implements StatusCode { + @Override + public boolean isCode(int statusCode) { + return 400 <= statusCode && statusCode <= 499; + } + + @Override + public String toString() { + return "4xx"; + } + + } + + private static class ServerError implements StatusCode { + @Override + public boolean isCode(int statusCode) { + return 500 <= statusCode && statusCode <= 599; + } + + @Override + public String toString() { + return "5xx"; + } + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("HttpStatusCodeErrors{"); + sb.append("errors=").append(Arrays.toString(errors)); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/ProfilerConfig.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/ProfilerConfig.java index 4a5c27283d8c..e990dc946393 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/ProfilerConfig.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/config/ProfilerConfig.java @@ -16,6 +16,9 @@ package com.navercorp.pinpoint.bootstrap.config; +import com.navercorp.pinpoint.common.annotations.InterfaceAudience; +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; + import java.util.List; import java.util.Map; @@ -62,6 +65,16 @@ public interface ProfilerConfig { boolean isTcpDataSenderCommandActiveThreadLightDumpEnable(); + long getTcpDataSenderPinpointClientWriteTimeout(); + + long getTcpDataSenderPinpointClientRequestTimeout(); + + long getTcpDataSenderPinpointClientReconnectInterval(); + + long getTcpDataSenderPinpointClientPingInterval(); + + long getTcpDataSenderPinpointClientHandshakeInterval(); + boolean isTraceAgentActiveThread(); boolean isTraceAgentDataSource(); @@ -100,6 +113,8 @@ public interface ProfilerConfig { String getProfilerJvmVendorName(); + String getProfilerOSName(); + int getProfileJvmStatCollectIntervalMs(); int getProfileJvmStatBatchSendCount(); @@ -108,6 +123,10 @@ public interface ProfilerConfig { long getAgentInfoSendRetryInterval(); + @InterfaceAudience.Private + @VisibleForTesting + boolean getStaticResourceCleanup(); + Filter getProfilableClassFilter(); @@ -131,7 +150,11 @@ public interface ProfilerConfig { boolean isProxyHttpHeaderEnable(); - List getHttpStatusCodeErrors(); + HttpStatusCodeErrors getHttpStatusCodeErrors(); + + String getInjectionModuleFactoryClazzName(); + + String getApplicationNamespace(); String readString(String propertyName, String defaultValue); diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/Header.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/Header.java index cdc2dcff93cd..0e96e4bbf5be 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/Header.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/Header.java @@ -30,6 +30,7 @@ public enum Header { HTTP_FLAGS("Pinpoint-Flags"), HTTP_PARENT_APPLICATION_NAME("Pinpoint-pAppName"), HTTP_PARENT_APPLICATION_TYPE("Pinpoint-pAppType"), + HTTP_PARENT_APPLICATION_NAMESPACE("Pinpoint-pAppNamespace"), HTTP_HOST("Pinpoint-Host"), HTTP_PROXY_NGINX("Pinpoint-ProxyNginx"), HTTP_PROXY_APACHE("Pinpoint-ProxyApache"), diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/RemoteAddressResolver.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/RemoteAddressResolver.java index d9382f8bb17c..e206e21cf20a 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/RemoteAddressResolver.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/RemoteAddressResolver.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,9 +16,11 @@ package com.navercorp.pinpoint.bootstrap.context; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; + /** * @author emeroad */ public interface RemoteAddressResolver { - String resolve(T target); + String resolve(RequestAdaptor requestAdaptor, T target); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/SpanEventRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/SpanEventRecorder.java index e1f106d9bbbe..3d9dbda77b87 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/SpanEventRecorder.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/SpanEventRecorder.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.bootstrap.context; import com.navercorp.pinpoint.common.annotations.InterfaceStability; @@ -7,7 +23,7 @@ public interface SpanEventRecorder extends FrameAttachment { void recordTime(boolean time); - + void recordException(Throwable throwable); void recordException(boolean markError, Throwable throwable); @@ -38,6 +54,10 @@ public interface SpanEventRecorder extends FrameAttachment { void recordServiceType(ServiceType serviceType); + /** + * @since 1.8.1 + */ + @Deprecated void recordRpcName(String rpc); void recordDestinationId(String destinationId); @@ -58,24 +78,5 @@ public interface SpanEventRecorder extends FrameAttachment { @InterfaceStability.Evolving AsyncContext recordNextAsyncContext(boolean stateful); - /** - * @deprecated Since 1.7.0 Use {@link SpanEventRecorder#recordNextAsyncContext()} - * This API will be removed in 1.8.0 - */ - @Deprecated - void recordAsyncId(int asyncId); - /** - * @deprecated Since 1.7.0 Use {@link SpanEventRecorder#recordNextAsyncContext()} - * This API will be removed in 1.8.0 - */ - @Deprecated - void recordNextAsyncId(int asyncId); - - /** - * @deprecated Since 1.7.0 Use {@link SpanEventRecorder#recordNextAsyncContext()} - * This API will be removed in 1.8.0 - */ - @Deprecated - void recordAsyncSequence(short sequence); } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentContext.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentContext.java index b6c7826ea2e2..d2d0bd5db460 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentContext.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentContext.java @@ -21,6 +21,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; import java.io.InputStream; +import java.security.ProtectionDomain; /** * @author Woonduk Kang(emeroad) @@ -28,9 +29,9 @@ */ public interface InstrumentContext { - InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, byte[] classfileBuffer); + InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, ProtectionDomain protectionDomain, byte[] classfileBuffer); - boolean exist(ClassLoader classLoader, String className); + boolean exist(ClassLoader classLoader, String className, ProtectionDomain protectionDomain); InterceptorScope getInterceptorScope(String name); diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/Instrumentor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/Instrumentor.java index b3eed2bbbfcd..2683e5eefed2 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/Instrumentor.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/Instrumentor.java @@ -18,6 +18,8 @@ import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import java.security.ProtectionDomain; + /** * @author Jongho Moon * @@ -25,10 +27,15 @@ public interface Instrumentor { ProfilerConfig getProfilerConfig(); - + + + InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, ProtectionDomain protectionDomain, byte[] classfileBuffer); + InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, byte[] classfileBuffer); - + boolean exist(ClassLoader classLoader, String className); + + boolean exist(ClassLoader classLoader, String className, ProtectionDomain protectionDomain); InterceptorScope getInterceptorScope(String scopeName); diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentorDelegate.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentorDelegate.java index e42c3ae29541..3901de10d509 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentorDelegate.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/InstrumentorDelegate.java @@ -21,6 +21,8 @@ import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import java.security.ProtectionDomain; + /** * @author emeroad */ @@ -44,14 +46,24 @@ public ProfilerConfig getProfilerConfig() { return profilerConfig; } + @Override + public InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + return instrumentContext.getInstrumentClass(classLoader, className, protectionDomain, classfileBuffer); + } + @Override public InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, byte[] classfileBuffer) { - return instrumentContext.getInstrumentClass(classLoader, className, classfileBuffer); + return instrumentContext.getInstrumentClass(classLoader, className, null, classfileBuffer); } @Override public boolean exist(ClassLoader classLoader, String className) { - return instrumentContext.exist(classLoader, className); + return instrumentContext.exist(classLoader, className, null); + } + + @Override + public boolean exist(ClassLoader classLoader, String className, ProtectionDomain protectionDomain) { + return instrumentContext.exist(classLoader, className, protectionDomain); } @Override diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilters.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilters.java index bf738c8ea61e..73ff2b485a0b 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilters.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/MethodFilters.java @@ -35,7 +35,11 @@ public boolean accept(InstrumentMethod method) { }; public static MethodFilter name(String... names) { - return new MethodNameFilter(null, names); + return new MethodNameFilter(null, names, false); + } + + public static MethodFilter nameExclude(String... names) { + return new MethodNameFilter(null, names, true); } public static MethodFilter modifier(int required) { @@ -64,9 +68,11 @@ public static MethodFilter chain(MethodFilter... methodFilters) { private static final class MethodNameFilter implements MethodFilter { private final String[] names; + private final boolean inverter; - public MethodNameFilter(int[] rejectModifiers, String[] names) { + public MethodNameFilter(int[] rejectModifiers, String[] names, boolean inverter) { this.names = names; + this.inverter = inverter; } @Override @@ -77,11 +83,11 @@ public boolean accept(InstrumentMethod method) { for (String name : names) { if (name != null && name.equals(method.getName())) { - return ACCEPT; + return ACCEPT^inverter; } } - return REJECT; + return REJECT^inverter; } } @@ -154,7 +160,6 @@ public boolean accept(InstrumentMethod method) { return REJECT; } } - return ACCEPT; } } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/lambda/LambdaBytecodeHandler.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/lambda/LambdaBytecodeHandler.java new file mode 100644 index 000000000000..796449238ed7 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/instrument/lambda/LambdaBytecodeHandler.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.instrument.lambda; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface LambdaBytecodeHandler { + byte[] handleLambdaBytecode(Class hostClass, byte[] data, Object[] cpPatches); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleApiIdAwareAroundInterceptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleApiIdAwareAroundInterceptor.java index e15122ebbbac..bd4529561a0e 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleApiIdAwareAroundInterceptor.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleApiIdAwareAroundInterceptor.java @@ -20,13 +20,19 @@ public class ExceptionHandleApiIdAwareAroundInterceptor implements ApiIdAwareAroundInterceptor { private final ApiIdAwareAroundInterceptor delegate; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleApiIdAwareAroundInterceptor(ApiIdAwareAroundInterceptor delegate) { + public ExceptionHandleApiIdAwareAroundInterceptor(ApiIdAwareAroundInterceptor delegate, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } + this.delegate = delegate; + this.exceptionHandler = exceptionHandler; } @Override @@ -34,7 +40,7 @@ public void before(Object target, int apiId, Object[] args) { try { this.delegate.before(target, apiId, args); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } @@ -43,7 +49,7 @@ public void after(Object target, int apiId, Object[] args, Object result, Throwa try { this.delegate.after(target, apiId, args, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor.java index 5ec5b65cc9fc..f596316a0baa 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor.java @@ -20,13 +20,18 @@ public class ExceptionHandleAroundInterceptor implements AroundInterceptor { private final AroundInterceptor delegate; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleAroundInterceptor(AroundInterceptor delegate) { + public ExceptionHandleAroundInterceptor(AroundInterceptor delegate, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.delegate = delegate; + this.exceptionHandler = exceptionHandler; } @Override @@ -34,7 +39,7 @@ public void before(Object target, Object[] args) { try { this.delegate.before(target, args); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } @@ -43,7 +48,7 @@ public void after(Object target, Object[] args, Object result, Throwable throwab try { this.delegate.after(target, args, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor0.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor0.java index 906d4bc2be45..d570387d7f07 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor0.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor0.java @@ -20,13 +20,18 @@ public class ExceptionHandleAroundInterceptor0 implements AroundInterceptor0 { private final AroundInterceptor0 delegate; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleAroundInterceptor0(AroundInterceptor0 delegate) { + public ExceptionHandleAroundInterceptor0(AroundInterceptor0 delegate, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.delegate = delegate; + this.exceptionHandler = exceptionHandler; } @Override @@ -34,7 +39,7 @@ public void before(Object target) { try { this.delegate.before(target); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } @@ -44,7 +49,7 @@ public void after(Object target, Object result, Throwable throwable) { try { this.delegate.after(target, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor1.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor1.java index 7700e7399252..87203a0d5fb9 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor1.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor1.java @@ -20,13 +20,18 @@ public class ExceptionHandleAroundInterceptor1 implements AroundInterceptor1 { private final AroundInterceptor1 delegate; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleAroundInterceptor1(AroundInterceptor1 delegate) { + public ExceptionHandleAroundInterceptor1(AroundInterceptor1 delegate, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.delegate = delegate; + this.exceptionHandler = exceptionHandler; } @Override @@ -34,7 +39,7 @@ public void before(Object target, Object arg0) { try { this.delegate.before(target, arg0); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } @@ -43,7 +48,7 @@ public void after(Object target, Object arg0, Object result, Throwable throwable try { this.delegate.after(target, arg0, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor2.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor2.java index abbe87e544ce..fa7bf87911e3 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor2.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor2.java @@ -20,13 +20,18 @@ public class ExceptionHandleAroundInterceptor2 implements AroundInterceptor2 { private final AroundInterceptor2 delegate; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleAroundInterceptor2(AroundInterceptor2 delegate) { + public ExceptionHandleAroundInterceptor2(AroundInterceptor2 delegate, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.delegate = delegate; + this.exceptionHandler = exceptionHandler; } @Override @@ -34,7 +39,7 @@ public void before(Object target, Object arg0, Object arg1) { try { this.delegate.before(target, arg0, arg1); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } @@ -43,7 +48,7 @@ public void after(Object target, Object arg0, Object arg1, Object result, Throwa try { this.delegate.after(target, arg0, arg1, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor3.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor3.java index 86f1e47ba2b9..093f5861d424 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor3.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor3.java @@ -20,13 +20,18 @@ public class ExceptionHandleAroundInterceptor3 implements AroundInterceptor3 { private final AroundInterceptor3 delegate; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleAroundInterceptor3(AroundInterceptor3 delegate) { + public ExceptionHandleAroundInterceptor3(AroundInterceptor3 delegate, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.delegate = delegate; + this.exceptionHandler = exceptionHandler; } @Override @@ -34,7 +39,7 @@ public void before(Object target, Object arg0, Object arg1, Object arg2) { try { this.delegate.before(target, arg0, arg1, arg2); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } @@ -43,7 +48,7 @@ public void after(Object target, Object arg0, Object arg1, Object arg2, Object r try { this.delegate.after(target, arg0, arg1, arg2, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor4.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor4.java index eeb144d635a9..387600927eb2 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor4.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor4.java @@ -20,13 +20,18 @@ public class ExceptionHandleAroundInterceptor4 implements AroundInterceptor4 { private final AroundInterceptor4 delegate; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleAroundInterceptor4(AroundInterceptor4 delegate) { + public ExceptionHandleAroundInterceptor4(AroundInterceptor4 delegate, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.delegate = delegate; + this.exceptionHandler = exceptionHandler; } @Override @@ -34,7 +39,7 @@ public void before(Object target, Object arg0, Object arg1, Object arg2, Object try { this.delegate.before(target, arg0, arg1, arg2, arg3); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } @@ -43,7 +48,7 @@ public void after(Object target, Object arg0, Object arg1, Object arg2, Object a try { this.delegate.after(target, arg0, arg1, arg2, arg3, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor5.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor5.java index 6d9c3fe680c0..eba9a480a455 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor5.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleAroundInterceptor5.java @@ -20,13 +20,15 @@ public class ExceptionHandleAroundInterceptor5 implements AroundInterceptor5 { private final AroundInterceptor5 delegate; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleAroundInterceptor5(AroundInterceptor5 delegate) { + public ExceptionHandleAroundInterceptor5(AroundInterceptor5 delegate, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } this.delegate = delegate; + this.exceptionHandler = exceptionHandler; } @Override @@ -34,7 +36,7 @@ public void before(Object target, Object arg0, Object arg1, Object arg2, Object try { this.delegate.before(target, arg0, arg1, arg2, arg3, arg4); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } @@ -43,7 +45,7 @@ public void after(Object target, Object arg0, Object arg1, Object arg2, Object a try { this.delegate.after(target, arg0, arg1, arg2, arg3, arg4, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleStaticAroundInterceptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleStaticAroundInterceptor.java index 903b89e444da..1eb965bc073c 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleStaticAroundInterceptor.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandleStaticAroundInterceptor.java @@ -20,13 +20,17 @@ public class ExceptionHandleStaticAroundInterceptor implements StaticAroundInterceptor { private final StaticAroundInterceptor delegate; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleStaticAroundInterceptor(StaticAroundInterceptor delegate) { + public ExceptionHandleStaticAroundInterceptor(StaticAroundInterceptor delegate, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } - + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.delegate = delegate; + this.exceptionHandler = exceptionHandler; } @Override @@ -34,7 +38,7 @@ public void before(Object target, String className, String methodName, String pa try { this.delegate.before(target, className, methodName, parameterDescription, args); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } @@ -43,7 +47,7 @@ public void after(Object target, String className, String methodName, String par try { this.delegate.after(target, className, methodName, parameterDescription, args, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } } \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandler.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandler.java new file mode 100644 index 000000000000..d1d94801a4c7 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/ExceptionHandler.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.interceptor; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface ExceptionHandler { + void handleException(Throwable t); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/InterceptorInvokerHelper.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/InterceptorInvokerHelper.java deleted file mode 100644 index f980500e8c82..000000000000 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/InterceptorInvokerHelper.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.bootstrap.interceptor; - -import com.navercorp.pinpoint.bootstrap.logging.PLogger; -import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; - -/** - * @author Jongho Moon - * - */ -public class InterceptorInvokerHelper { - private static boolean propagateException = false; - private static final PLogger logger = PLoggerFactory.getLogger(InterceptorInvokerHelper.class.getName()); - - public static void handleException(Throwable t) { - if (propagateException) { - throw new RuntimeException(t); - } else { - logger.warn("Exception occurred from interceptor", t); - } - } - - public static void setPropagateException(boolean propagate) { - propagateException = propagate; - } -} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SpanRecursiveAroundInterceptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SpanRecursiveAroundInterceptor.java new file mode 100644 index 000000000000..78538340c70c --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/SpanRecursiveAroundInterceptor.java @@ -0,0 +1,221 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.scope.TraceScope; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public abstract class SpanRecursiveAroundInterceptor implements AroundInterceptor { + protected final PLogger logger = PLoggerFactory.getLogger(getClass()); + protected final boolean isDebug = logger.isDebugEnabled(); + + protected final MethodDescriptor methodDescriptor; + protected final TraceContext traceContext; + protected final String scopeName; + + protected SpanRecursiveAroundInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, final String scopeName) { + this.traceContext = Assert.requireNonNull(traceContext, "traceContext must not be null"); + this.methodDescriptor = Assert.requireNonNull(methodDescriptor, "methodDescriptor must not be null"); + this.scopeName = Assert.requireNonNull(scopeName, "scopeName must not be null"); + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (isSkipTrace()) { + // Skip recursive invoked or duplicated span(entry point) + return; + } + + try { + final Trace trace = createTrace(target, args); + if (isDebug) { + logger.debug("Created trace. trace={}", trace); + } + + if (trace == null) { + // Skip + return; + } + + // init entry point scope + if (!initScope(trace)) { + // Defense code + deleteTrace(trace); + return; + } + + // entry point scope + entryScope(trace); + + if (!trace.canSampled()) { + return; + } + // ------------------------------------------------------ + final SpanEventRecorder recorder = trace.traceBlockBegin(); + doInBeforeTrace(recorder, target, args); + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("BEFORE. Caused:{}", th.getMessage(), th); + } + } + } + + private boolean isSkipTrace() { + final Trace trace = traceContext.currentRawTraceObject(); + if (trace == null) { + return false; + } + if (hasScope(trace)) { + // Entry Scope + entryScope(trace); + if (isDebug) { + logger.debug("Skip recursive invoked"); + } + } else { + if (isDebug) { + logger.debug("Skip duplicated entry point"); + } + } + // Skip recursive invoke or duplicated entry point + return true; + } + + + protected abstract void doInBeforeTrace(final SpanEventRecorder recorder, Object target, final Object[] args); + + protected abstract Trace createTrace(final Object target, final Object[] args); + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentRawTraceObject(); + if (trace == null) { + return; + } + + if (!hasScope(trace)) { + // Not in scope + return; + } + + if (!leaveScope(trace)) { + // Defense code + deleteTrace(trace); + return; + } + + if (!isEndScope(trace)) { + // Ignored recursive call. + return; + } + + if (!trace.canSampled()) { + deleteTrace(trace); + return; + } + + // ------------------------------------------------------ + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + doInAfterTrace(recorder, target, args, result, throwable); + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER. Caused:{}", th.getMessage(), th); + } + } finally { + trace.traceBlockEnd(); + deleteTrace(trace); + } + } + + protected abstract void doInAfterTrace(final SpanEventRecorder recorder, final Object target, final Object[] args, final Object result, Throwable throwable); + + private boolean initScope(final Trace trace) { + final TraceScope oldScope = trace.addScope(this.scopeName); + if (oldScope != null) { + // delete corrupted trace. + if (logger.isInfoEnabled()) { + logger.info("Duplicated trace scope={}.", oldScope.getName()); + } + return false; + } + + return true; + } + + private void entryScope(final Trace trace) { + final TraceScope scope = trace.getScope(this.scopeName); + if (scope != null) { + scope.tryEnter(); + if (isDebug) { + logger.debug("Try enter trace scope={}", scope.getName()); + } + } + } + + private boolean leaveScope(final Trace trace) { + final TraceScope scope = trace.getScope(this.scopeName); + if (scope != null) { + if (scope.canLeave()) { + scope.leave(); + if (isDebug) { + logger.debug("Leave trace scope={}", scope.getName()); + } + } else { + if (logger.isInfoEnabled()) { + logger.info("Failed to leave scope. trace={}", trace); + } + return false; + } + } + return true; + } + + private boolean hasScope(final Trace trace) { + final TraceScope scope = trace.getScope(this.scopeName); + return scope != null; + } + + private boolean isEndScope(final Trace trace) { + final TraceScope scope = trace.getScope(this.scopeName); + return scope != null && !scope.isActive(); + } + + private void deleteTrace(final Trace trace) { + traceContext.removeTraceObject(); + trace.close(); + if (isDebug) { + logger.debug("Delete trace."); + } + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedApiIdAwareAroundInterceptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedApiIdAwareAroundInterceptor.java index d63e6edc3bd3..9bcdf499235c 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedApiIdAwareAroundInterceptor.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedApiIdAwareAroundInterceptor.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.bootstrap.interceptor.scope; import com.navercorp.pinpoint.bootstrap.interceptor.ApiIdAwareAroundInterceptor; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,8 +32,9 @@ public class ExceptionHandleScopedApiIdAwareAroundInterceptor implements ApiIdAw private final ApiIdAwareAroundInterceptor delegate; private final InterceptorScope scope; private final ExecutionPolicy policy; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleScopedApiIdAwareAroundInterceptor(ApiIdAwareAroundInterceptor delegate, InterceptorScope scope, ExecutionPolicy policy) { + public ExceptionHandleScopedApiIdAwareAroundInterceptor(ApiIdAwareAroundInterceptor delegate, InterceptorScope scope, ExecutionPolicy policy, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } @@ -43,9 +44,13 @@ public ExceptionHandleScopedApiIdAwareAroundInterceptor(ApiIdAwareAroundIntercep if (policy == null) { throw new NullPointerException("policy must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.delegate = delegate; this.scope = scope; this.policy = policy; + this.exceptionHandler = exceptionHandler; } @Override @@ -56,7 +61,7 @@ public void before(Object target, int apiId, Object[] args) { try { this.delegate.before(target, apiId, args); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } else { if (debugEnabled) { @@ -73,7 +78,7 @@ public void after(Object target, int apiId, Object[] args, Object result, Throwa try { this.delegate.after(target, apiId, args, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } finally { transaction.leave(policy); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor.java index 8dce9ecf1c85..fefbc9d556fe 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.bootstrap.interceptor.scope; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,8 +32,9 @@ public class ExceptionHandleScopedInterceptor implements AroundInterceptor { private final AroundInterceptor interceptor; private final InterceptorScope scope; private final ExecutionPolicy policy; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleScopedInterceptor(AroundInterceptor interceptor, InterceptorScope scope, ExecutionPolicy policy) { + public ExceptionHandleScopedInterceptor(AroundInterceptor interceptor, InterceptorScope scope, ExecutionPolicy policy, ExceptionHandler exceptionHandler) { if (interceptor == null) { throw new NullPointerException("interceptor must not be null"); } @@ -43,9 +44,13 @@ public ExceptionHandleScopedInterceptor(AroundInterceptor interceptor, Intercept if (policy == null) { throw new NullPointerException("policy must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.interceptor = interceptor; this.scope = scope; this.policy = policy; + this.exceptionHandler = exceptionHandler; } @Override @@ -56,7 +61,7 @@ public void before(Object target, Object[] args) { try { interceptor.before(target, args); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } else { if (debugEnabled) { @@ -73,7 +78,7 @@ public void after(Object target, Object[] args, Object result, Throwable throwab try { interceptor.after(target, args, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } finally { transaction.leave(policy); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor0.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor0.java index 97d8873ed578..8f2f1da610c4 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor0.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor0.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.bootstrap.interceptor.scope; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor0; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,8 +32,9 @@ public class ExceptionHandleScopedInterceptor0 implements AroundInterceptor0 { private final AroundInterceptor0 interceptor; private final InterceptorScope scope; private final ExecutionPolicy policy; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleScopedInterceptor0(AroundInterceptor0 interceptor, InterceptorScope scope, ExecutionPolicy policy) { + public ExceptionHandleScopedInterceptor0(AroundInterceptor0 interceptor, InterceptorScope scope, ExecutionPolicy policy, ExceptionHandler exceptionHandler) { if (interceptor == null) { throw new NullPointerException("interceptor must not be null"); } @@ -43,9 +44,13 @@ public ExceptionHandleScopedInterceptor0(AroundInterceptor0 interceptor, Interce if (policy == null) { throw new NullPointerException("policy must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.interceptor = interceptor; this.scope = scope; this.policy = policy; + this.exceptionHandler = exceptionHandler; } @Override @@ -56,7 +61,7 @@ public void before(Object target) { try { this.interceptor.before(target); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } else { if (debugEnabled) { @@ -73,7 +78,7 @@ public void after(Object target, Object result, Throwable throwable) { try { this.interceptor.after(target, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } finally { transaction.leave(policy); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor1.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor1.java index d17a534f94cb..012cdc76a800 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor1.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor1.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.bootstrap.interceptor.scope; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor1; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,8 +32,9 @@ public class ExceptionHandleScopedInterceptor1 implements AroundInterceptor1 { private final AroundInterceptor1 interceptor; private final InterceptorScope scope; private final ExecutionPolicy policy; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleScopedInterceptor1(AroundInterceptor1 interceptor, InterceptorScope scope, ExecutionPolicy policy) { + public ExceptionHandleScopedInterceptor1(AroundInterceptor1 interceptor, InterceptorScope scope, ExecutionPolicy policy, ExceptionHandler exceptionHandler) { if (interceptor == null) { throw new NullPointerException("interceptor must not be null"); } @@ -43,9 +44,13 @@ public ExceptionHandleScopedInterceptor1(AroundInterceptor1 interceptor, Interce if (policy == null) { throw new NullPointerException("policy must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.interceptor = interceptor; this.scope = scope; this.policy = policy; + this.exceptionHandler = exceptionHandler; } @Override @@ -56,7 +61,7 @@ public void before(Object target, Object arg0) { try { this.interceptor.before(target, arg0); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } else { if (debugEnabled) { @@ -73,7 +78,7 @@ public void after(Object target, Object arg1, Object result, Throwable throwable try { this.interceptor.after(target, arg1, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } finally { transaction.leave(policy); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor2.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor2.java index a07156f5fe76..48c607896b4a 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor2.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor2.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.bootstrap.interceptor.scope; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor2; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,8 +32,9 @@ public class ExceptionHandleScopedInterceptor2 implements AroundInterceptor2 { private final AroundInterceptor2 interceptor; private final InterceptorScope scope; private final ExecutionPolicy policy; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleScopedInterceptor2(AroundInterceptor2 interceptor, InterceptorScope scope, ExecutionPolicy policy) { + public ExceptionHandleScopedInterceptor2(AroundInterceptor2 interceptor, InterceptorScope scope, ExecutionPolicy policy, ExceptionHandler exceptionHandler) { if (interceptor == null) { throw new NullPointerException("interceptor must not be null"); } @@ -43,9 +44,13 @@ public ExceptionHandleScopedInterceptor2(AroundInterceptor2 interceptor, Interce if (policy == null) { throw new NullPointerException("policy must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.interceptor = interceptor; this.scope = scope; this.policy = policy; + this.exceptionHandler = exceptionHandler;; } @Override @@ -56,7 +61,7 @@ public void before(Object target, Object arg0, Object arg1) { try { this.interceptor.before(target, arg0, arg1); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } else { if (debugEnabled) { @@ -73,7 +78,7 @@ public void after(Object target, Object arg0, Object arg1, Object result, Throwa try { this.interceptor.after(target, arg0, arg1, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } finally { transaction.leave(policy); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor3.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor3.java index 1d10aa7548bc..ddd60d490a8c 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor3.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor3.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.bootstrap.interceptor.scope; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor3; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,8 +32,9 @@ public class ExceptionHandleScopedInterceptor3 implements AroundInterceptor3 { private final AroundInterceptor3 interceptor; private final InterceptorScope scope; private final ExecutionPolicy policy; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleScopedInterceptor3(AroundInterceptor3 interceptor, InterceptorScope scope, ExecutionPolicy policy) { + public ExceptionHandleScopedInterceptor3(AroundInterceptor3 interceptor, InterceptorScope scope, ExecutionPolicy policy, ExceptionHandler exceptionHandler) { if (interceptor == null) { throw new NullPointerException("interceptor must not be null"); } @@ -43,9 +44,13 @@ public ExceptionHandleScopedInterceptor3(AroundInterceptor3 interceptor, Interce if (policy == null) { throw new NullPointerException("policy must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.interceptor = interceptor; this.scope = scope; this.policy = policy; + this.exceptionHandler = exceptionHandler; } @Override @@ -56,7 +61,7 @@ public void before(Object target, Object arg0, Object arg1, Object arg2) { try { this.interceptor.before(target, arg0, arg1, arg2); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } else { if (debugEnabled) { @@ -73,7 +78,7 @@ public void after(Object target, Object arg0, Object arg1, Object arg2, Object r try { this.interceptor.after(target, arg0, arg1, arg2, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } finally { transaction.leave(policy); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor4.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor4.java index 0f2c05824297..2b3c4c93e8da 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor4.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor4.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.bootstrap.interceptor.scope; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor4; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,8 +32,9 @@ public class ExceptionHandleScopedInterceptor4 implements AroundInterceptor4 { private final AroundInterceptor4 interceptor; private final InterceptorScope scope; private final ExecutionPolicy policy; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleScopedInterceptor4(AroundInterceptor4 interceptor, InterceptorScope scope, ExecutionPolicy policy) { + public ExceptionHandleScopedInterceptor4(AroundInterceptor4 interceptor, InterceptorScope scope, ExecutionPolicy policy, ExceptionHandler exceptionHandler) { if (interceptor == null) { throw new NullPointerException("interceptor must not be null"); } @@ -43,9 +44,13 @@ public ExceptionHandleScopedInterceptor4(AroundInterceptor4 interceptor, Interce if (policy == null) { throw new NullPointerException("policy must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.interceptor = interceptor; this.scope = scope; this.policy = policy; + this.exceptionHandler = exceptionHandler; } @Override @@ -56,7 +61,7 @@ public void before(Object target, Object arg0, Object arg1, Object arg2, Object try { this.interceptor.before(target, arg0, arg1, arg2, arg3); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } else { if (debugEnabled) { @@ -73,7 +78,7 @@ public void after(Object target, Object arg0, Object arg1, Object arg2, Object a try { this.interceptor.after(target, arg0, arg1, arg2, arg3, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } finally { transaction.leave(policy); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor5.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor5.java index e0446753a081..e3d10ff7f976 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor5.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedInterceptor5.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.bootstrap.interceptor.scope; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor5; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,8 +32,9 @@ public class ExceptionHandleScopedInterceptor5 implements AroundInterceptor5 { private final AroundInterceptor5 interceptor; private final InterceptorScope scope; private final ExecutionPolicy policy; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleScopedInterceptor5(AroundInterceptor5 interceptor, InterceptorScope scope, ExecutionPolicy policy) { + public ExceptionHandleScopedInterceptor5(AroundInterceptor5 interceptor, InterceptorScope scope, ExecutionPolicy policy, ExceptionHandler exceptionHandler) { if (interceptor == null) { throw new NullPointerException("interceptor must not be null"); } @@ -43,9 +44,13 @@ public ExceptionHandleScopedInterceptor5(AroundInterceptor5 interceptor, Interce if (policy == null) { throw new NullPointerException("policy must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.interceptor = interceptor; this.scope = scope; this.policy = policy; + this.exceptionHandler = exceptionHandler; } @Override @@ -56,7 +61,7 @@ public void before(Object target, Object arg0, Object arg1, Object arg2, Object try { this.interceptor.before(target, arg0, arg1, arg2, arg3, arg4); } catch(Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } else { if (debugEnabled) { @@ -73,7 +78,7 @@ public void after(Object target, Object arg0, Object arg1, Object arg2, Object a try { this.interceptor.after(target, arg0, arg1, arg2, arg3, arg4, result, throwable); } catch(Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } finally { transaction.leave(policy); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedStaticAroundInterceptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedStaticAroundInterceptor.java index b6f62d5ddd26..8cfa0f018319 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedStaticAroundInterceptor.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/interceptor/scope/ExceptionHandleScopedStaticAroundInterceptor.java @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.bootstrap.interceptor.scope; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.interceptor.StaticAroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,8 +32,9 @@ public class ExceptionHandleScopedStaticAroundInterceptor implements StaticAroun private final StaticAroundInterceptor delegate; private final InterceptorScope scope; private final ExecutionPolicy policy; + private final ExceptionHandler exceptionHandler; - public ExceptionHandleScopedStaticAroundInterceptor(StaticAroundInterceptor delegate, InterceptorScope scope, ExecutionPolicy policy) { + public ExceptionHandleScopedStaticAroundInterceptor(StaticAroundInterceptor delegate, InterceptorScope scope, ExecutionPolicy policy, ExceptionHandler exceptionHandler) { if (delegate == null) { throw new NullPointerException("delegate must not be null"); } @@ -43,9 +44,13 @@ public ExceptionHandleScopedStaticAroundInterceptor(StaticAroundInterceptor dele if (policy == null) { throw new NullPointerException("policy must not be null"); } + if (exceptionHandler == null) { + throw new NullPointerException("exceptionHandler must not be null"); + } this.delegate = delegate; this.scope = scope; this.policy = policy; + this.exceptionHandler = exceptionHandler; } @Override @@ -56,7 +61,7 @@ public void before(Object target, String className, String methodName, String pa try { this.delegate.before(target, className, methodName, parameterDescription, args); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } } else { if (debugEnabled) { @@ -73,7 +78,7 @@ public void after(Object target, String className, String methodName, String par try { this.delegate.after(target, className, methodName, parameterDescription, args, result, throwable); } catch (Throwable t) { - InterceptorInvokerHelper.handleException(t); + exceptionHandler.handleException(t); } finally { transaction.leave(policy); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/ClassFileTransformModuleAdaptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/ClassFileTransformModuleAdaptor.java new file mode 100644 index 000000000000..0fbc7ec7ba5b --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/ClassFileTransformModuleAdaptor.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.module; + +import java.lang.instrument.IllegalClassFormatException; +import java.security.ProtectionDomain; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface ClassFileTransformModuleAdaptor { + byte[] transform(Object transformedModule, ClassLoader loader, String className, Class classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException; +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/JavaModule.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/JavaModule.java new file mode 100644 index 000000000000..be44338adc88 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/JavaModule.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.module; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface JavaModule { + boolean isSupported(); + + boolean isNamed(); + + String getName(); + + void addReads(JavaModule target); + + void addExports(String packageName, JavaModule target); + + void addOpens(String packageName, JavaModule target); + + void addUses(Class target); + + boolean isExported(String packageName, JavaModule targetJavaModule); + + boolean isOpen(String packageName, JavaModule targetJavaModule); + + boolean canRead(JavaModule targetJavaModule); + + boolean canRead(Class targetClazz); + + ClassLoader getClassLoader(); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/JavaModuleFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/JavaModuleFactory.java new file mode 100644 index 000000000000..787075bb318d --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/JavaModuleFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.module; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface JavaModuleFactory { + JavaModule wrapFromClass(Class clazz); + + JavaModule wrapFromModule(Object module); + + boolean isNamedModule(Object module); + + Object getUnnamedModule(ClassLoader classLoader); + + Object getModule(Class clazz); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/UnsupportedJavaModule.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/UnsupportedJavaModule.java new file mode 100644 index 000000000000..68166fa0e399 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/module/UnsupportedJavaModule.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.module; + +/** + * @author Woonduk Kang(emeroad) + */ +class UnsupportedJavaModule implements JavaModule { + public static JavaModule INSTANCE = new UnsupportedJavaModule(); + + UnsupportedJavaModule() { + } + + @Override + public boolean isSupported() { + return false; + } + + @Override + public boolean isNamed() { + return false; + } + + @Override + public String getName() { + return null; + } + + @Override + public void addReads(JavaModule target) { + // non + } + + @Override + public void addExports(String packageName, JavaModule target) { + // non + } + + @Override + public void addOpens(String packageName, JavaModule target) { + // non + } + + @Override + public void addUses(Class target) { + // non + } + + @Override + public boolean isExported(String packageName, JavaModule targetJavaModule) { + return false; + } + + @Override + public boolean isOpen(String packageName, JavaModule targetJavaModule) { + return false; + } + + @Override + public boolean canRead(JavaModule targetJavaModule) { + return false; + } + + @Override + public boolean canRead(Class targetClazz) { + return false; + } + + @Override + public ClassLoader getClassLoader() { + throw new UnsupportedOperationException("getClassLoader()"); + } + + @Override + public String toString() { + return "UnsupportedJavaModule"; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/RequestWrapper.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/RequestWrapper.java new file mode 100644 index 000000000000..f1f7c0b05ab5 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/RequestWrapper.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin; + +/** + * @author jaehong.kim + */ +public interface RequestWrapper { + String getHeader(String name); +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/http/HttpStatusCodeRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/http/HttpStatusCodeRecorder.java index 6d43807a6658..0061dd2d0cbf 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/http/HttpStatusCodeRecorder.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/http/HttpStatusCodeRecorder.java @@ -16,72 +16,22 @@ package com.navercorp.pinpoint.bootstrap.plugin.http; +import com.navercorp.pinpoint.bootstrap.config.HttpStatusCodeErrors; import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.common.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; /** * @author jaehong.kim */ public class HttpStatusCodeRecorder { - private static final StatusCode ALL_STATUS_CODES = new StatusCode() { - @Override - public boolean isCode(int statusCode) { - return 100 <= statusCode && statusCode <= 599; - } - }; - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private final StatusCode[] errors; - - public HttpStatusCodeRecorder(final List errorCodes) { - this.errors = newErrorCode(errorCodes); - - if (isDebug) { - logger.debug("Initialized HTTP status code of errors={}", this.errors); - } - } + private final HttpStatusCodeErrors errors; - private StatusCode[] newErrorCode(List errorCodes) { - if (CollectionUtils.isEmpty(errorCodes)) { - return new StatusCode[0]; - } - - List statusCodeList = new ArrayList(); - for (String errorCode : errorCodes) { - if (errorCode.equalsIgnoreCase("5xx")) { - statusCodeList.add(new ServerError()); - } else if (errorCode.equalsIgnoreCase("4xx")) { - statusCodeList.add(new ClientError()); - } else if (errorCode.equalsIgnoreCase("3xx")) { - statusCodeList.add(new Redirection()); - } else if (errorCode.equalsIgnoreCase("2xx")) { - statusCodeList.add(new Success()); - } else if (errorCode.equalsIgnoreCase("1xx")) { - statusCodeList.add(new Informational()); - } else { - try { - final int statusCode = Integer.parseInt(errorCode); - statusCodeList.add(new DefaultStatusCode(statusCode)); - } catch (NumberFormatException ignored) { - } - } - } - return toArray(statusCodeList); - } - - private StatusCode[] toArray(List list) { - if (CollectionUtils.isEmpty(list)) { - return new StatusCode[0]; - } - return list.toArray(new StatusCode[list.size()]); + public HttpStatusCodeRecorder(final HttpStatusCodeErrors errors) { + this.errors = errors; } public void record(final SpanRecorder spanRecorder, final int statusCode) { @@ -90,16 +40,18 @@ public void record(final SpanRecorder spanRecorder, final int statusCode) { return; } - if (!ALL_STATUS_CODES.isCode(statusCode)) { - // out of range status codes. + if (!this.errors.isHttpStatusCode(statusCode)) { + if (isDebug) { + logger.debug("Out of range HTTP status code. statusCode={}", statusCode); + } return; } spanRecorder.recordStatusCode(statusCode); if (isDebug) { - logger.debug("Record HTTP status code annotation. status-code={}", statusCode); + logger.debug("Record HTTP status code annotation. statusCode={}", statusCode); } - if (isFailed(statusCode)) { + if (this.errors.isErrorCode(statusCode)) { spanRecorder.recordError(); if (isDebug) { logger.debug("Record error"); @@ -107,104 +59,10 @@ public void record(final SpanRecorder spanRecorder, final int statusCode) { } } - public boolean isFailed(final int statusCode) { - for (StatusCode code : this.errors) { - if (code.isCode(statusCode)) { - return true; - } - } - return false; - } - - private interface StatusCode { - boolean isCode(int statusCode); - } - - private class DefaultStatusCode implements StatusCode { - private final int statusCode; - - public DefaultStatusCode(final int statusCode) { - this.statusCode = statusCode; - } - - @Override - public boolean isCode(int statusCode) { - return this.statusCode == statusCode; - } - - @Override - public String toString() { - return String.valueOf(statusCode); - } - } - - private class Informational implements StatusCode { - @Override - public boolean isCode(int statusCode) { - return 100 <= statusCode && statusCode <= 199; - } - - @Override - public String toString() { - return "1xx"; - } - } - - private class Success implements StatusCode { - @Override - public boolean isCode(int statusCode) { - return 200 <= statusCode && statusCode <= 299; - } - - @Override - public String toString() { - return "2xx"; - } - - } - - private class Redirection implements StatusCode { - @Override - public boolean isCode(int statusCode) { - return 300 <= statusCode && statusCode <= 399; - } - - @Override - public String toString() { - return "3xx"; - } - - } - - private class ClientError implements StatusCode { - @Override - public boolean isCode(int statusCode) { - return 400 <= statusCode && statusCode <= 499; - } - - @Override - public String toString() { - return "4xx"; - } - - } - - private class ServerError implements StatusCode { - @Override - public boolean isCode(int statusCode) { - return 500 <= statusCode && statusCode <= 599; - } - - @Override - public String toString() { - return "5xx"; - } - } - @Override public String toString() { final StringBuilder sb = new StringBuilder("HttpStatusCodeRecorder{"); - sb.append("errors=").append(Arrays.toString(errors)); + sb.append(", errors=").append(errors); sb.append('}'); return sb.toString(); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/JdbcConfig.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/JdbcConfig.java index 0b246d09507e..bfbac6eb7eff 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/JdbcConfig.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/JdbcConfig.java @@ -25,7 +25,7 @@ public class JdbcConfig { private final int maxSqlBindValueSize; - protected JdbcConfig( boolean pluginEnable, boolean traceSqlBindValue, int maxSqlBindValue) { + protected JdbcConfig(boolean pluginEnable, boolean traceSqlBindValue, int maxSqlBindValue) { this.pluginEnable = pluginEnable; this.traceSqlBindValue = traceSqlBindValue; this.maxSqlBindValueSize = maxSqlBindValue; diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/MongoDatabaseInfo.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/MongoDatabaseInfo.java new file mode 100644 index 000000000000..c3b36f2dd335 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/MongoDatabaseInfo.java @@ -0,0 +1,150 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.jdbc; + +import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; +import com.navercorp.pinpoint.common.trace.ServiceType; + +import java.util.List; + +/** + * @author Roy Kim + */ +public class MongoDatabaseInfo implements DatabaseInfo { + + private final ServiceType type; + private final ServiceType executeQueryType; + private final String databaseId; + private final String realUrl; // URL BEFORE refinement + private final String normalizedUrl; + private final List host; + private final String multipleHost; + private final boolean parsingComplete; + private final String collectionName; + private final String readPreference; + private final String writeConcern; + + public MongoDatabaseInfo(ServiceType type, ServiceType executeQueryType, String realUrl, String normalizedUrl, List host, String databaseId, String collectionName, String readWriteOption, String writeConcern) { + this(type, executeQueryType, realUrl, normalizedUrl, host, databaseId, collectionName, true, readWriteOption, writeConcern); + } + + public MongoDatabaseInfo(ServiceType type, ServiceType executeQueryType, String realUrl, String normalizedUrl, List host, String databaseId, String collectionName, boolean parsingComplete, String readPreference, String writeConcern) { + if (type == null) { + throw new NullPointerException("type must not be null"); + } + if (executeQueryType == null) { + throw new NullPointerException("executeQueryType must not be null"); + } + this.type = type; + this.executeQueryType = executeQueryType; + this.realUrl = realUrl; + this.normalizedUrl = normalizedUrl; + this.host = host; + this.multipleHost = merge(host); + this.databaseId = databaseId; + this.parsingComplete = parsingComplete; + this.readPreference = readPreference; + this.writeConcern = writeConcern; + this.collectionName = collectionName; + } + + private String merge(List host) { + if (host.isEmpty()) { + return ""; + } + String single = host.get(0); + StringBuilder sb = new StringBuilder(); + sb.append(single); + for(int i =1; i getHost() { + // With replication, this is not simple because there could be multiple hosts or ports. + return host; + } + + @Override + public String getMultipleHost() { + return multipleHost; + } + + @Override + public String getDatabaseId() { + return databaseId; + } + + @Override + public String getRealUrl() { + return realUrl; + } + + @Override + public String getUrl() { + return normalizedUrl; + } + + @Override + public ServiceType getType() { + return type; + } + + @Override + public ServiceType getExecuteQueryType() { + return executeQueryType; + } + + @Override + public boolean isParsingComplete() { + return parsingComplete; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("MongoDatabaseInfo{"); + sb.append("type=").append(type); + sb.append(", executeQueryType=").append(executeQueryType); + sb.append(", databaseId='").append(databaseId).append('\''); + sb.append(", realUrl='").append(realUrl).append('\''); + sb.append(", normalizedUrl='").append(normalizedUrl).append('\''); + sb.append(", host=").append(host); + sb.append(", multipleHost='").append(multipleHost).append('\''); + sb.append(", parsingComplete=").append(parsingComplete); + sb.append(", readPreference=").append(readPreference); + sb.append(", writeConcern=").append(writeConcern); + sb.append(", collectionName=").append(collectionName); + sb.append('}'); + return sb.toString(); + } + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/PreparedStatementUtils.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/PreparedStatementUtils.java index 8dd806e3596c..14ec2a5193f3 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/PreparedStatementUtils.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/PreparedStatementUtils.java @@ -18,8 +18,6 @@ import java.lang.reflect.Method; -import java.sql.PreparedStatement; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; @@ -33,14 +31,11 @@ public final class PreparedStatementUtils { private static final Pattern BIND_SETTER = Pattern.compile("set[A-Z]([a-zA-Z]+)"); - private static final List bindMethod; + private static final List bindMethod = findBindVariableSetMethod0(); private PreparedStatementUtils() { } - static { - bindMethod = findBindVariableSetMethod0(); - } public static List findBindVariableSetMethod() { return bindMethod; @@ -60,12 +55,17 @@ public static List findBindVariableSetMethod(BindVariableFilter filter) return temp; } + static List findBindVariableSetMethod0() { - Method[] methods = PreparedStatement.class.getDeclaredMethods(); + if (!SqlModule.isSqlModuleEnable()) { + return Collections.emptyList(); + } + final Class preparedStatement = SqlModule.getSqlPreparedStatement(); + Method[] methods = preparedStatement.getDeclaredMethods(); List bindMethod = new LinkedList(); for (Method method : methods) { if (isSetter(method.getName())) { - Class[] parameterTypes = method.getParameterTypes(); + final Class[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length < 2) { continue; @@ -89,7 +89,7 @@ private static boolean throwSqlException(Method method) { Class[] exceptionTypes = method.getExceptionTypes(); if (exceptionTypes.length == 1) { Class exceptionType = exceptionTypes[0]; - if (exceptionType.equals(SQLException.class)) { + if (exceptionType.getName().equals("java.sql.SQLException")) { return true; } } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/SqlModule.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/SqlModule.java new file mode 100644 index 000000000000..989230ad09ef --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/SqlModule.java @@ -0,0 +1,111 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.jdbc; + +import com.navercorp.pinpoint.bootstrap.util.PlatformClassLoaderUtils; +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.JvmVersion; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class SqlModule { + private static final boolean SQL_MODULE; + private static final Class SQL_DATE; + private static final Class SQL_TIME; + private static final Class SQL_TIMESTAMP; + private static final Class SQL_CLOB; + private static final Class SQL_BLOB; + + private static final Class SQL_CONNECTION; + private static final Class SQL_PREPARED_STATEMENT; + + static { + if (JvmUtils.getVersion().onOrAfter(JvmVersion.JAVA_9)) { + if (PlatformClassLoaderUtils.findClassFromPlatformClassLoader("java.sql.Date") != null) { + SQL_MODULE = true; + } else { + SQL_MODULE = false; + } + } else { + SQL_MODULE = true; + } + if (SQL_MODULE) { + SQL_DATE = getSqlClass("java.sql.Date"); + SQL_TIME = getSqlClass("java.sql.Time"); + SQL_TIMESTAMP = getSqlClass("java.sql.Timestamp"); + SQL_CLOB = getSqlClass("java.sql.Clob"); + SQL_BLOB = getSqlClass("java.sql.Blob"); + + SQL_CONNECTION = getSqlClass("java.sql.Connection"); + SQL_PREPARED_STATEMENT = getSqlClass("java.sql.PreparedStatement"); + } else { + SQL_DATE = null; + SQL_TIME = null; + SQL_TIMESTAMP = null; + SQL_CLOB = null; + SQL_BLOB = null; + + SQL_CONNECTION = null; + SQL_PREPARED_STATEMENT = null; + } + } + + private SqlModule() { + } + + public static boolean isSqlModuleEnable() { + return SQL_MODULE; + } + + public static Class getSqlDate() { + return SQL_DATE; + } + + public static Class getSqlTime() { + return SQL_TIME; + } + + public static Class getSqlTimestamp() { + return SQL_TIMESTAMP; + } + + public static Class getSqlClob() { + return SQL_CLOB; + } + + public static Class getSqlBlob() { + return SQL_BLOB; + } + + public static Class getSqlConnection() { + return SQL_CONNECTION; + } + + public static Class getSqlPreparedStatement() { + return SQL_PREPARED_STATEMENT; + } + + private static Class getSqlClass(String className) { + final Class clazz = PlatformClassLoaderUtils.findClassFromPlatformClassLoader(className); + if (clazz == null) { + throw new IllegalStateException(className + " class not exist"); + } + return clazz; + } + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/BindValueConverter.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/BindValueConverter.java index fadeb4738735..4426566c9fe6 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/BindValueConverter.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/BindValueConverter.java @@ -26,7 +26,7 @@ public class BindValueConverter { converter.register(); } - public final Map convertermap = new HashMap() ; + private final Map convertermap = new HashMap() ; private void register() { simpleType(); @@ -94,8 +94,8 @@ private void simpleType() { convertermap.put("setNString", simpleTypeConverter); } - public String convert0(String methodName, Object[] args) { - Converter converter = this.convertermap.get(methodName); + private String convert0(String methodName, Object[] args) { + final Converter converter = this.convertermap.get(methodName); if (converter == null) { return ""; } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/BindValueUtils.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/BindValueUtils.java index 6f72e85c186f..bc6f8080223d 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/BindValueUtils.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/BindValueUtils.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.bootstrap.plugin.jdbc.bindvalue; +import com.navercorp.pinpoint.common.util.MapUtils; import com.navercorp.pinpoint.common.util.StringUtils; import java.util.Map; @@ -30,10 +31,7 @@ private BindValueUtils() { } public static String bindValueToString(final Map bindValueMap, int limit) { - if (bindValueMap == null) { - return ""; - } - if (bindValueMap.isEmpty()) { + if (MapUtils.isEmpty(bindValueMap)) { return ""; } final int maxParameterIndex = getMaxParameterIndex(bindValueMap); diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/ObjectConverter.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/ObjectConverter.java index 1c49be043450..efeca4594625 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/ObjectConverter.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/ObjectConverter.java @@ -19,9 +19,8 @@ import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; -import java.sql.Time; -import java.sql.Timestamp; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.SqlModule; import com.navercorp.pinpoint.common.util.ArrayUtils; import com.navercorp.pinpoint.common.util.StringUtils; @@ -29,6 +28,23 @@ * @author emeroad */ public class ObjectConverter implements Converter { + private static final boolean SQL_MODULE; + private static final Class SQL_DATE; + private static final Class SQL_TIME; + private static final Class SQL_TIMESTAMP; + private static final Class SQL_CLOB; + private static final Class SQL_BLOB; + + static { + SQL_MODULE = SqlModule.isSqlModuleEnable(); + SQL_DATE = SqlModule.getSqlDate(); + SQL_TIME = SqlModule.getSqlTime(); + SQL_TIMESTAMP = SqlModule.getSqlTimestamp(); + SQL_CLOB = SqlModule.getSqlClob(); + SQL_BLOB = SqlModule.getSqlBlob(); + } + + @Override public String convert(Object[] args) { if (args == null) { @@ -37,8 +53,8 @@ public String convert(Object[] args) { if (args.length == 2) { final Object param = args[1]; return getParameter(param); - - } else if (args.length == 3) { + } + if (args.length == 3) { final Object param = args[1]; return getParameter(param); } @@ -48,51 +64,77 @@ public String convert(Object[] args) { private String getParameter(Object param) { if (param == null) { return "null"; - } else { - if (param instanceof Byte) { - return abbreviate(param); - } else if (param instanceof String) { - return abbreviate(param); - } else if (param instanceof BigDecimal) { - return abbreviate(param); - } else if (param instanceof Short) { - return abbreviate(param); - } else if (param instanceof Integer) { - return abbreviate(param); - } else if (param instanceof Long) { - return abbreviate(param); - } else if (param instanceof Float) { - return abbreviate(param); - } else if (param instanceof Double) { - return abbreviate(param); - } else if (param instanceof BigInteger) { - return abbreviate(param); - } else if (param instanceof java.sql.Date) { - return abbreviate(param); - } else if (param instanceof Time) { - return abbreviate(param); - } else if (param instanceof Timestamp) { - return abbreviate(param); - } else if (param instanceof Boolean) { - return abbreviate(param); - } else if (param instanceof byte[]) { - return ArrayUtils.abbreviate((byte[]) param); - } else if (param instanceof InputStream) { - return getClassName(param); - } else if (param instanceof java.sql.Blob) { - return getClassName(param); - } else if (param instanceof java.sql.Clob) { + } + if (param instanceof String) { + return abbreviate(param); + } + if (param instanceof Boolean) { + return bypass(param); + } + if (param instanceof Integer) { + return bypass(param); + } + if (param instanceof Long) { + return bypass(param); + } + if (param instanceof Short) { + return bypass(param); + } + if (param instanceof Float) { + return bypass(param); + } + if (param instanceof Double) { + return bypass(param); + } + if (param instanceof Byte) { + return bypass(param); + } + + if (param instanceof byte[]) { + return ArrayUtils.abbreviate((byte[]) param); + } + if (param instanceof InputStream) { + return getClassName(param); + } + + if (param instanceof BigDecimal) { + return bypass(param); + } + if (param instanceof BigInteger) { + return bypass(param); + } + + + + if (SQL_MODULE) { + if (SQL_DATE.isInstance(param)) { + return bypass(param); + } + if (SQL_TIME.isInstance(param)) { + return bypass(param); + } + if (SQL_TIMESTAMP.isInstance(param)) { + return bypass(param); + } + if (SQL_BLOB.isInstance(param)) { return getClassName(param); - } else { + } + if (SQL_CLOB.isInstance(param)) { return getClassName(param); } } + return getClassName(param); } private String abbreviate(Object param) { return StringUtils.abbreviate(param.toString()); } + private String bypass(Object param) { + return param.toString(); + } + + private String getClassName(Object param) { return param.getClass().getName(); } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/interceptor/StatementCreateInterceptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/interceptor/StatementCreateInterceptor.java index 0398881202c3..bcdf64d44c3f 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/interceptor/StatementCreateInterceptor.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/interceptor/StatementCreateInterceptor.java @@ -16,8 +16,6 @@ package com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor; -import java.sql.Connection; - import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; import com.navercorp.pinpoint.bootstrap.context.Trace; import com.navercorp.pinpoint.bootstrap.context.TraceContext; @@ -26,6 +24,7 @@ import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor; import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.SqlModule; import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; /** @@ -40,6 +39,16 @@ //}) public class StatementCreateInterceptor implements AroundInterceptor { + private static final Class CONNECTION_CLASS = getConnectionClass(); + + private static Class getConnectionClass() { + if (!SqlModule.isSqlModuleEnable()) { + // If SqlModule does not exist in java9, StatementCreateInterceptor class should not be initialized. + throw new IllegalStateException("java.sql.Connection not exist"); + } + return SqlModule.getSqlConnection(); + } + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); @@ -69,15 +78,22 @@ public void after(Object target, Object[] args, Object result, Throwable throwab if (trace == null) { return; } - if (target instanceof Connection) { - DatabaseInfo databaseInfo = (target instanceof DatabaseInfoAccessor) ? ((DatabaseInfoAccessor)target)._$PINPOINT$_getDatabaseInfo() : null; - - if (databaseInfo == null) { - databaseInfo = UnKnownDatabaseInfo.INSTANCE; - } + if (CONNECTION_CLASS.isInstance(target)) { + final DatabaseInfo databaseInfo = getDatabaseInfo(target); if (result instanceof DatabaseInfoAccessor) { ((DatabaseInfoAccessor) result)._$PINPOINT$_setDatabaseInfo(databaseInfo); } } } + + private DatabaseInfo getDatabaseInfo(Object target) { + DatabaseInfo databaseInfo = null; + if (target instanceof DatabaseInfoAccessor) { + databaseInfo = ((DatabaseInfoAccessor) target)._$PINPOINT$_getDatabaseInfo(); + } + if (databaseInfo == null) { + databaseInfo = UnKnownDatabaseInfo.INSTANCE; + } + return databaseInfo; + } } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderHandler.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderHandler.java deleted file mode 100644 index c4a49702bfd1..000000000000 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.bootstrap.plugin.proxy; - -/** - * @author jaehong.kim - */ -public interface ProxyHttpHeaderHandler { - - String read(String name); -} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderRecorder.java index 8e49746cbffd..c0b7ffeb3d49 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderRecorder.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderRecorder.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,23 +20,28 @@ import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; /** * @author jaehong.kim */ -public class ProxyHttpHeaderRecorder { +public class ProxyHttpHeaderRecorder { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final boolean isInfo = logger.isInfoEnabled(); private final ProxyHttpHeaderParser parser = new ProxyHttpHeaderParser(); private final boolean enable; + private final RequestAdaptor requestAdaptor; - public ProxyHttpHeaderRecorder(final boolean enable) { + public ProxyHttpHeaderRecorder(final boolean enable, RequestAdaptor requestAdaptor) { this.enable = enable; + this.requestAdaptor = Assert.requireNonNull(requestAdaptor, "requestAdaptor must not be null"); } - public void record(final SpanRecorder recorder, final ProxyHttpHeaderHandler handler) { - if (recorder == null || handler == null) { + public void record(final SpanRecorder recorder, final T request) { + if (recorder == null || request == null) { return; } @@ -48,9 +53,9 @@ public void record(final SpanRecorder recorder, final ProxyHttpHeaderHandler han } try { - parseAndRecord(recorder, handler, Header.HTTP_PROXY_APP.toString(), ProxyHttpHeader.TYPE_APP); - parseAndRecord(recorder, handler, Header.HTTP_PROXY_NGINX.toString(), ProxyHttpHeader.TYPE_NGINX); - parseAndRecord(recorder, handler, Header.HTTP_PROXY_APACHE.toString(), ProxyHttpHeader.TYPE_APACHE); + parseAndRecord(recorder, request, Header.HTTP_PROXY_APP.toString(), ProxyHttpHeader.TYPE_APP); + parseAndRecord(recorder, request, Header.HTTP_PROXY_NGINX.toString(), ProxyHttpHeader.TYPE_NGINX); + parseAndRecord(recorder, request, Header.HTTP_PROXY_APACHE.toString(), ProxyHttpHeader.TYPE_APACHE); } catch (Exception e) { // for handler operations. if (isInfo) { @@ -60,9 +65,9 @@ public void record(final SpanRecorder recorder, final ProxyHttpHeaderHandler han } - private void parseAndRecord(final SpanRecorder recorder, final ProxyHttpHeaderHandler handler, final String name, final int type) { - final String value = handler.read(name); - if (value == null || value.isEmpty()) { + private void parseAndRecord(final SpanRecorder recorder, final T request, final String name, final int type) { + final String value = requestAdaptor.getHeader(request, name); + if (StringUtils.isEmpty(value)) { return; } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/AsyncListenerInterceptorHelper.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/AsyncListenerInterceptorHelper.java new file mode 100644 index 000000000000..8ee8e234ac6d --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/AsyncListenerInterceptorHelper.java @@ -0,0 +1,143 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.AsyncState; +import com.navercorp.pinpoint.bootstrap.context.AsyncStateSupport; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.http.HttpStatusCodeRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.method.AsyncListenerOnCompleteMethodDescriptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.method.AsyncListenerOnErrorMethodDescriptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.method.AsyncListenerOnTimeoutMethodDescriptor; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public class AsyncListenerInterceptorHelper { + private static final MethodDescriptor ASYNC_LISTENER_ON_COMPLETE_METHOD_DESCRIPTOR = new AsyncListenerOnCompleteMethodDescriptor(); + private static final MethodDescriptor ASYNC_LISTENER_ON_ERROR_METHOD_DESCRIPTOR = new AsyncListenerOnErrorMethodDescriptor(); + private static final MethodDescriptor ASYNC_LISTENER_ON_TIMEOUT_METHOD_DESCRIPTOR = new AsyncListenerOnTimeoutMethodDescriptor(); + + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final AsyncContext asyncContext; + private final HttpStatusCodeRecorder httpStatusCodeRecorder; + + public AsyncListenerInterceptorHelper(final TraceContext traceContext, final AsyncContext asyncContext) { + Assert.requireNonNull(traceContext, "traceContext must not be null"); + this.asyncContext = Assert.requireNonNull(asyncContext, "asyncContext must not be null"); + this.httpStatusCodeRecorder = new HttpStatusCodeRecorder(traceContext.getProfilerConfig().getHttpStatusCodeErrors()); + + traceContext.cacheApi(ASYNC_LISTENER_ON_COMPLETE_METHOD_DESCRIPTOR); + traceContext.cacheApi(ASYNC_LISTENER_ON_ERROR_METHOD_DESCRIPTOR); + traceContext.cacheApi(ASYNC_LISTENER_ON_TIMEOUT_METHOD_DESCRIPTOR); + } + + public void complete(Throwable throwable, int statusCode) { + if (isDebug) { + logger.debug("Complete async listener. throwable={}, statusCode={}", throwable, statusCode); + } + + final Trace trace = this.asyncContext.continueAsyncTraceObject(); + if (trace == null) { + return; + } + + try { + // Record http status code + recordHttpStatusCode(trace, statusCode); + // Record event + recordAsyncEvent(trace, throwable, ASYNC_LISTENER_ON_COMPLETE_METHOD_DESCRIPTOR); + } finally { + // Close async trace + close(trace); + // End Point + finish(); + } + } + + private void recordHttpStatusCode(final Trace trace, final int statusCode) { + // Record http status code + final SpanRecorder spanRecorder = trace.getSpanRecorder(); + this.httpStatusCodeRecorder.record(spanRecorder, statusCode); + } + + public void error(Throwable throwable) { + if (isDebug) { + logger.debug("Error async listener. throwable={}", throwable); + } + + final Trace trace = this.asyncContext.continueAsyncTraceObject(); + if (trace == null) { + return; + } + + try { + recordAsyncEvent(trace, throwable, ASYNC_LISTENER_ON_ERROR_METHOD_DESCRIPTOR); + } finally { + close(trace); + } + } + + public void timeout(Throwable throwable) { + if (isDebug) { + logger.debug("Timeout async listener. throwable={}", throwable); + } + + final Trace trace = this.asyncContext.continueAsyncTraceObject(); + if (trace == null) { + return; + } + + try { + recordAsyncEvent(trace, throwable, ASYNC_LISTENER_ON_TIMEOUT_METHOD_DESCRIPTOR); + } finally { + close(trace); + } + } + + private void recordAsyncEvent(final Trace trace, final Throwable throwable, MethodDescriptor methodDescriptor) { + final SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(ServiceType.SERVLET); + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + trace.traceBlockEnd(); + } + + private void close(final Trace trace) { + trace.close(); + this.asyncContext.close(); + } + + private void finish() { + if (this.asyncContext instanceof AsyncStateSupport) { + final AsyncStateSupport asyncStateSupport = (AsyncStateSupport) this.asyncContext; + AsyncState asyncState = asyncStateSupport.getAsyncState(); + asyncState.finish(); + } + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientHeaderAdaptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientHeaderAdaptor.java new file mode 100644 index 000000000000..bf001b8715b3 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientHeaderAdaptor.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface ClientHeaderAdaptor { + void setHeader(T header, String name, String value); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestAdaptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestAdaptor.java new file mode 100644 index 000000000000..f3fcd44dbb43 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestAdaptor.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface ClientRequestAdaptor { + + /** + * The DestinationId is logical name of the destination. + *

+ * + * @return If the value does not exist, it should return "Unknown". + */ + String getDestinationId(T request); + + /** + * URL + * + * @return If the value does not exist, it should return null. + */ + String getUrl(T request); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestRecorder.java new file mode 100644 index 000000000000..da3b1b36a360 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestRecorder.java @@ -0,0 +1,77 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public class ClientRequestRecorder { + private static final String DEFAULT_DESTINATION_ID = "Unknown"; + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final boolean param; + private final ClientRequestAdaptor clientRequestAdaptor; + + public ClientRequestRecorder(final boolean param, ClientRequestAdaptor clientRequestAdaptor) { + this.param = param; + this.clientRequestAdaptor = Assert.requireNonNull(clientRequestAdaptor, "clientRequestAdaptor must not be null"); + } + + // Records the client's request information. + public void record(final SpanEventRecorder recorder, final T clientRequest, final Throwable throwable) { + if (recorder == null || clientRequest == null) { + return; + } + + final String destinationId = clientRequestAdaptor.getDestinationId(clientRequest); + if (destinationId != null) { + recorder.recordDestinationId(destinationId); + if (isDebug) { + logger.debug("Record destinationId={}", destinationId); + } + } else { + // Set default value + recorder.recordDestinationId(DEFAULT_DESTINATION_ID); + if (isDebug) { + logger.debug("Record destinationId={}", DEFAULT_DESTINATION_ID); + } + } + + final String url = clientRequestAdaptor.getUrl(clientRequest); + if (url != null) { + final String httpUrl = InterceptorUtils.getHttpUrl(url, this.param); + recorder.recordAttribute(AnnotationKey.HTTP_URL, httpUrl); + if (isDebug) { + logger.debug("Record url={}", httpUrl); + } + } + + + } + + + +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestWrapper.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestWrapper.java new file mode 100644 index 000000000000..1a70ca29963b --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestWrapper.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author jaehong.kim + */ +public interface ClientRequestWrapper { + + /** + * The DestinationId is logical name of the destination. + *

+ * + * @return If the value does not exist, it should return "Unknown". + */ + String getDestinationId(); + + /** + * URL + * + * @return If the value does not exist, it should return null. + */ + String getUrl(); + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestWrapperAdaptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestWrapperAdaptor.java new file mode 100644 index 000000000000..7af0a17a6f96 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ClientRequestWrapperAdaptor.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClientRequestWrapperAdaptor implements ClientRequestAdaptor { + + public static final ClientRequestAdaptor INSTANCE = new ClientRequestWrapperAdaptor(); + + @Override + public String getDestinationId(ClientRequestWrapper request) { + return request.getDestinationId(); + } + + @Override + public String getUrl(ClientRequestWrapper request) { + return request.getUrl(); + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ContinueTraceHeader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ContinueTraceHeader.java new file mode 100644 index 000000000000..e444930fd426 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ContinueTraceHeader.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.plugin.request.TraceHeader; +import com.navercorp.pinpoint.bootstrap.plugin.request.TraceHeaderState; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ContinueTraceHeader implements TraceHeader { + private final String transactionId; + private long parentSpanId; + private long spanId; + private short flags; + + public ContinueTraceHeader(String transactionId, long parentSpanId, long spanId, short flags) { + this.transactionId = Assert.requireNonNull(transactionId, "transactionId must not be null"); + this.parentSpanId = parentSpanId; + this.spanId = spanId; + this.flags = flags; + } + + + @Override + public TraceHeaderState getState() { + return TraceHeaderState.CONTINUE; + } + + @Override + public String getTransactionId() { + return transactionId; + } + + @Override + public long getParentSpanId() { + return parentSpanId; + } + + @Override + public long getSpanId() { + return spanId; + } + + @Override + public short getFlags() { + return flags; + } + + @Override + public String toString() { + return "ContinueTraceHeader{" + + "transactionId='" + transactionId + '\'' + + ", parentSpanId=" + parentSpanId + + ", spanId=" + spanId + + ", flags=" + flags + + '}'; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/DefaultRequestTraceWriter.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/DefaultRequestTraceWriter.java new file mode 100644 index 000000000000..b37e3c97d9af --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/DefaultRequestTraceWriter.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public class DefaultRequestTraceWriter implements RequestTraceWriter { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final ClientHeaderAdaptor clientHeaderAdaptor; + private final String applicationName; + private final short serverTypeCode; + private final String applicationNamespace; + + public DefaultRequestTraceWriter(ClientHeaderAdaptor clientHeaderAdaptor, TraceContext traceContext) { + this(clientHeaderAdaptor, traceContext.getApplicationName(), traceContext.getServerTypeCode(), traceContext.getApplicationName()); + } + + public DefaultRequestTraceWriter(ClientHeaderAdaptor clientHeaderAdaptor, String applicationName, short serverTypeCode, String applicationNamespace) { + this.clientHeaderAdaptor = Assert.requireNonNull(clientHeaderAdaptor, "clientHeaderAdaptor must not be null"); + + this.applicationName = Assert.requireNonNull(applicationName, "applicationName must not be null"); + this.serverTypeCode = serverTypeCode; + this.applicationNamespace = Assert.requireNonNull(applicationNamespace, "applicationNamespace must not be null"); + } + + @Override + public void write(T header) { + if (isDebug) { + logger.debug("Set request header that is not to be sampled."); + } + clientHeaderAdaptor.setHeader(header, Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); + } + + // Set transaction information in the request. + @Override + public void write(T header, final TraceId traceId, final String host) { + Assert.requireNonNull(traceId, "traceId must not be null"); + + if (isDebug) { + logger.debug("Set request header. traceId={}, applicationName={}, serverTypeCode={}, applicationNamespace={}", traceId, applicationName, serverTypeCode, applicationNamespace); + } + clientHeaderAdaptor.setHeader(header, Header.HTTP_TRACE_ID.toString(), traceId.getTransactionId()); + clientHeaderAdaptor.setHeader(header, Header.HTTP_SPAN_ID.toString(), String.valueOf(traceId.getSpanId())); + clientHeaderAdaptor.setHeader(header, Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(traceId.getParentSpanId())); + clientHeaderAdaptor.setHeader(header, Header.HTTP_FLAGS.toString(), String.valueOf(traceId.getFlags())); + clientHeaderAdaptor.setHeader(header, Header.HTTP_PARENT_APPLICATION_NAME.toString(), applicationName); + clientHeaderAdaptor.setHeader(header, Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(serverTypeCode)); + + if (applicationNamespace != null) { + clientHeaderAdaptor.setHeader(header, Header.HTTP_PARENT_APPLICATION_NAMESPACE.toString(), applicationNamespace); + } + + if (host != null) { + clientHeaderAdaptor.setHeader(header, Header.HTTP_HOST.toString(), host); + } + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/DefaultTraceHeaderReader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/DefaultTraceHeaderReader.java new file mode 100644 index 000000000000..5317012a0163 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/DefaultTraceHeaderReader.java @@ -0,0 +1,90 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.context.SpanId; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.bootstrap.util.NumberUtils; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public class DefaultTraceHeaderReader implements TraceHeaderReader { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final RequestAdaptor requestAdaptor; + + + public DefaultTraceHeaderReader(RequestAdaptor requestAdaptor) { + this.requestAdaptor = Assert.requireNonNull(requestAdaptor, "requestAdaptor must not be null"); + } + + // Read the transaction information from the request. + @Override + public TraceHeader read(T request) { + Assert.requireNonNull(request, "request must not be null"); + + // Check sampling flag from client. If the flag is false, do not sample this request. + final String samplingFlag = requestAdaptor.getHeader(request, Header.HTTP_SAMPLED.toString()); + if (isDebug) { + logger.debug("SamplingFlag={}", samplingFlag); + } + final boolean sampling = samplingEnable(request); + if (!sampling) { + return DisableTraceHeader.INSTANCE; + } + + final String transactionId = requestAdaptor.getHeader(request, Header.HTTP_TRACE_ID.toString()); + // TODO miss validation check + if (transactionId == null) { + return NewTraceHeader.INSTANCE; + } + final String parentSpanIdStr = requestAdaptor.getHeader(request, Header.HTTP_PARENT_SPAN_ID.toString()); + if (parentSpanIdStr == null) { + return NewTraceHeader.INSTANCE; + } + final long parentSpanId = NumberUtils.parseLong(parentSpanIdStr, SpanId.NULL); +// if (parentSpanId == SpanId.NULL) { +// throw new IllegalArgumentException(); +// } + final String spanIdStr = requestAdaptor.getHeader(request, Header.HTTP_SPAN_ID.toString()); + if (spanIdStr == null) { + return NewTraceHeader.INSTANCE; + } + final long spanId = NumberUtils.parseLong(spanIdStr, SpanId.NULL); +// if (spanId == SpanId.NULL) { +// throw new IllegalArgumentException(); +// } + final short flags = NumberUtils.parseShort(requestAdaptor.getHeader(request, Header.HTTP_FLAGS.toString()), (short) 0); + return new ContinueTraceHeader(transactionId, parentSpanId, spanId, flags); + } + + private boolean samplingEnable(final T request) { + final String samplingFlag = requestAdaptor.getHeader(request, Header.HTTP_SAMPLED.toString()); + if (isDebug) { + logger.debug("SamplingFlag={}", samplingFlag); + } + + return SamplingFlagUtils.isSamplingFlag(samplingFlag); + } + +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/DisableTraceHeader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/DisableTraceHeader.java new file mode 100644 index 000000000000..c7210518e45d --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/DisableTraceHeader.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DisableTraceHeader implements TraceHeader { + + public static final TraceHeader INSTANCE = new DisableTraceHeader(); + + @Override + public TraceHeaderState getState() { + return TraceHeaderState.DISABLE; + } + + @Override + public String getTransactionId() { + throw new UnsupportedOperationException(); + } + + @Override + public long getParentSpanId() { + throw new UnsupportedOperationException(); + } + + @Override + public long getSpanId() { + throw new UnsupportedOperationException(); + } + + @Override + public short getFlags() { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return "DisableTraceHeader"; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/NewTraceHeader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/NewTraceHeader.java new file mode 100644 index 000000000000..afd5227d0022 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/NewTraceHeader.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public class NewTraceHeader implements TraceHeader { + + public static final TraceHeader INSTANCE = new NewTraceHeader(); + + @Override + public TraceHeaderState getState() { + return TraceHeaderState.NEW_TRACE; + } + + @Override + public String getTransactionId() { + throw new UnsupportedOperationException(); + } + + @Override + public long getParentSpanId() { + throw new UnsupportedOperationException(); + } + + @Override + public long getSpanId() { + throw new UnsupportedOperationException(); + } + + @Override + public short getFlags() { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return "NewTraceHeader"; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestAdaptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestAdaptor.java new file mode 100644 index 000000000000..d2905737a64b --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestAdaptor.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface RequestAdaptor { + + String getHeader(T request, String name); + + + /** + * Procedure name(optional) + * + * @return + */ + String getRpcName(T request); + + /** + * Server address + * + * @return + */ + String getEndPoint(T request); + + /** + * Client address + * + * @return + */ + String getRemoteAddress(T request); + + /** + * Server address that the client used + * + * @return + */ + String getAcceptorHost(T request); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestTraceReader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestTraceReader.java new file mode 100644 index 000000000000..f496c36acca0 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestTraceReader.java @@ -0,0 +1,138 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.NameSpaceCheckFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.NameSpaceChecker; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public class RequestTraceReader { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final RequestAdaptor requestAdaptor; + private final boolean async; + + private final TraceHeaderReader traceHeaderReader; + private final NameSpaceChecker nameSpaceChecker; + + public RequestTraceReader(final TraceContext traceContext, RequestAdaptor requestAdaptor) { + this(traceContext, requestAdaptor, false); + } + + public RequestTraceReader(final TraceContext traceContext, RequestAdaptor requestAdaptor, final boolean async) { + this.traceContext = Assert.requireNonNull(traceContext, "traceContext must not be null"); + this.requestAdaptor = Assert.requireNonNull(requestAdaptor, "requestAdaptor must not be null"); + this.traceHeaderReader = new DefaultTraceHeaderReader(requestAdaptor); + this.async = async; + String applicationNamespace = traceContext.getProfilerConfig().getApplicationNamespace(); + this.nameSpaceChecker = NameSpaceCheckFactory.newNamespace(requestAdaptor, applicationNamespace); + } + + // Read the transaction information from the request. + public Trace read(T request) { + Assert.requireNonNull(request, "request must not be null"); + + final TraceHeader traceHeader = traceHeaderReader.read(request); + // Check sampling flag from client. If the flag is false, do not sample this request. + final TraceHeaderState state = traceHeader.getState(); + if (state == TraceHeaderState.DISABLE) { + // Even if this transaction is not a sampling target, we have to create Trace object to mark 'not sampling'. + // For example, if this transaction invokes rpc call, we can add parameter to tell remote node 'don't sample this transaction' + final Trace trace = this.traceContext.disableSampling(); + if (isDebug) { + logger.debug("Remote call sampling flag found. skip trace requestUrl:{}, remoteAddr:{}", requestAdaptor.getRpcName(request), requestAdaptor.getRemoteAddress(request)); + } + return trace; + } + + if (state == TraceHeaderState.CONTINUE) { + if (!nameSpaceChecker.checkNamespace(request)) { + return newTrace(request); + } + + return continueTrace(request, traceHeader); + } + if (state == TraceHeaderState.NEW_TRACE) { + return newTrace(request); + } + throw new UnsupportedOperationException("Unsupported state=" + state); + } + + private Trace newTrace(T request) { + final Trace trace = newTrace(); + if (trace.canSampled()) { + if (isDebug) { + logger.debug("TraceID not exist. start new trace. requestUrl:{}, remoteAddr:{}", requestAdaptor.getRpcName(request), requestAdaptor.getRemoteAddress(request)); + } + } else { + if (isDebug) { + logger.debug("TraceID not exist. canSampled is false. skip trace. requestUrl:{}, remoteAddr:{}", requestAdaptor.getRpcName(request), requestAdaptor.getRemoteAddress(request)); + } + } + return trace; + } + + public Trace continueTrace(T request, TraceHeader traceHeader) { + final TraceId traceId = newTraceId(traceHeader); + // TODO Maybe we should decide to trace or not even if the sampling flag is true to prevent too many requests are traced. + final Trace trace = continueTrace(traceId); + if (trace.canSampled()) { + if (isDebug) { + logger.debug("TraceID exist. continue trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, requestAdaptor.getRpcName(request), requestAdaptor.getRemoteAddress(request)); + } + } else { + if (isDebug) { + logger.debug("TraceID exist. camSampled is false. skip trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, requestAdaptor.getRpcName(request), requestAdaptor.getRemoteAddress(request)); + } + } + return trace; + } + + private TraceId newTraceId(TraceHeader traceHeader) { + final String transactionId = traceHeader.getTransactionId(); + final long parentSpanId = traceHeader.getParentSpanId(); + final long spanId = traceHeader.getSpanId(); + final short flags = traceHeader.getFlags(); + final TraceId id = this.traceContext.createTraceId(transactionId, parentSpanId, spanId, flags); + return id; + } + + + private Trace continueTrace(final TraceId traceId) { + if (this.async) { + return this.traceContext.continueAsyncTraceObject(traceId); + } + return this.traceContext.continueTraceObject(traceId); + } + + private Trace newTrace() { + if (this.async) { + return this.traceContext.newAsyncTraceObject(); + } + return this.traceContext.newTraceObject(); + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestTraceWriter.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestTraceWriter.java new file mode 100644 index 000000000000..aa4a550d83a9 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestTraceWriter.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.context.TraceId; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface RequestTraceWriter { + void write(T header); + + // Set transaction information in the request. + void write(T header, TraceId traceId, String host); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServerRequestRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServerRequestRecorder.java new file mode 100644 index 000000000000..6dcf9d9f085d --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServerRequestRecorder.java @@ -0,0 +1,91 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.util.NumberUtils; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public class ServerRequestRecorder { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final RequestAdaptor requestAdaptor; + + public ServerRequestRecorder(RequestAdaptor requestAdaptor) { + this.requestAdaptor = Assert.requireNonNull(requestAdaptor, "requestAdaptor must not be null"); + } + + // Records the server's request information. + public void record(final SpanRecorder recorder, final T request) { + if (recorder == null || request == null) { + return; + } + final String rpcName = requestAdaptor.getRpcName(request); + recorder.recordRpcName(rpcName); + if (isDebug) { + logger.debug("Record rpcName={}", rpcName); + } + + final String endPoint = requestAdaptor.getEndPoint(request); + recorder.recordEndPoint(endPoint); + if (isDebug) { + logger.debug("Record endPoint={}", endPoint); + } + + final String remoteAddress = requestAdaptor.getRemoteAddress(request); + recorder.recordRemoteAddress(remoteAddress); + if (isDebug) { + logger.debug("Record remoteAddress={}", remoteAddress); + } + + if (!recorder.isRoot()) { + recordParentInfo(recorder, request); + } + } + + private void recordParentInfo(final SpanRecorder recorder, final T request) { + final String parentApplicationName = requestAdaptor.getHeader(request, Header.HTTP_PARENT_APPLICATION_NAME.toString()); + if (parentApplicationName != null) { + String host = requestAdaptor.getHeader(request, Header.HTTP_HOST.toString()); + if (host == null) { + host = requestAdaptor.getAcceptorHost(request); + } + recorder.recordAcceptorHost(host); + if (isDebug) { + logger.debug("Record acceptorHost={}", host); + } + + final String type = requestAdaptor.getHeader(request, Header.HTTP_PARENT_APPLICATION_TYPE.toString()); + final short parentApplicationType = NumberUtils.parseShort(type, ServiceType.UNDEFINED.getCode()); + recorder.recordParentApplication(parentApplicationName, parentApplicationType); + if (isDebug) { + logger.debug("Record parentApplicationName={}, parentApplicationType={}", parentApplicationName, parentApplicationType); + } + } else { + if (isDebug) { + logger.debug("Not found parentApplication"); + } + } + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServerRequestWrapper.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServerRequestWrapper.java new file mode 100644 index 000000000000..5b5db7b6f9ae --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServerRequestWrapper.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.plugin.RequestWrapper; + +/** + * @author jaehong.kim + */ +public interface ServerRequestWrapper extends RequestWrapper { + /** + * Procedure name(optional) + * + * @return + */ + String getRpcName(); + + /** + * Server address + * + * @return + */ + String getEndPoint(); + + /** + * Client address + * + * @return + */ + String getRemoteAddress(); + + /** + * Server address that the client used + * + * @return + */ + String getAcceptorHost(); +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServerRequestWrapperAdaptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServerRequestWrapperAdaptor.java new file mode 100644 index 000000000000..b6992ca2ed47 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServerRequestWrapperAdaptor.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ServerRequestWrapperAdaptor implements RequestAdaptor { + + @Override + public String getHeader(ServerRequestWrapper request, String name) { + return request.getHeader(name); + } + + @Override + public String getRpcName(ServerRequestWrapper request) { + return request.getRpcName(); + } + + @Override + public String getEndPoint(ServerRequestWrapper request) { + return request.getEndPoint(); + } + + @Override + public String getRemoteAddress(ServerRequestWrapper request) { + return request.getRemoteAddress(); + } + + @Override + public String getAcceptorHost(ServerRequestWrapper request) { + return request.getAcceptorHost(); + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServletRequestListenerInterceptorHelper.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServletRequestListenerInterceptorHelper.java new file mode 100644 index 000000000000..9a706a5fdd50 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/ServletRequestListenerInterceptorHelper.java @@ -0,0 +1,152 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.config.SkipFilter; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.http.HttpStatusCodeRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.method.ServletSyncMethodDescriptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public class ServletRequestListenerInterceptorHelper { + private static final MethodDescriptor SERVLET_SYNC_METHOD_DESCRIPTOR = new ServletSyncMethodDescriptor(); + + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isTrace = logger.isTraceEnabled(); + + private final TraceContext traceContext; + private final ServiceType serviceType; + private final RequestAdaptor requestAdaptor; + + private final Filter excludeUrlFilter; + private final RequestTraceReader requestTraceReader; + private final ProxyHttpHeaderRecorder proxyHttpHeaderRecorder; + private final ServerRequestRecorder serverRequestRecorder; + private final HttpStatusCodeRecorder httpStatusCodeRecorder; + + private final ParameterRecorder parameterRecorder; + + public ServletRequestListenerInterceptorHelper(final ServiceType serviceType, final TraceContext traceContext, RequestAdaptor requestAdaptor, final Filter excludeUrlFilter, ParameterRecorder parameterRecorder) { + this.serviceType = Assert.requireNonNull(serviceType, "serviceType must not be null"); + this.traceContext = Assert.requireNonNull(traceContext, "traceContext must not be null"); + this.requestAdaptor = Assert.requireNonNull(requestAdaptor, "requestAdaptor must not be null"); + this.requestTraceReader = new RequestTraceReader(traceContext, requestAdaptor, true); + this.proxyHttpHeaderRecorder = new ProxyHttpHeaderRecorder(traceContext.getProfilerConfig().isProxyHttpHeaderEnable(), requestAdaptor); + this.excludeUrlFilter = defaultFilter(excludeUrlFilter); + this.parameterRecorder = Assert.requireNonNull(parameterRecorder, "parameterRecorder must not be null"); + this.serverRequestRecorder = new ServerRequestRecorder(requestAdaptor); + this.httpStatusCodeRecorder = new HttpStatusCodeRecorder(traceContext.getProfilerConfig().getHttpStatusCodeErrors()); + + this.traceContext.cacheApi(SERVLET_SYNC_METHOD_DESCRIPTOR); + } + + private Filter defaultFilter(Filter excludeUrlFilter) { + if (excludeUrlFilter == null) { + return new SkipFilter(); + } + return excludeUrlFilter; + } + + public void initialized(T request, final ServiceType serviceType, final MethodDescriptor methodDescriptor) { + Assert.requireNonNull(request, "request must not be null"); + Assert.requireNonNull(serviceType, "serviceType must not be null"); + Assert.requireNonNull(methodDescriptor, "methodDescriptor must not be null"); + + if (isDebug) { + logger.debug("Initialized requestEvent. request={}, serviceType={}, methodDescriptor={}", request, serviceType, methodDescriptor); + } + + final Trace trace = createTrace(request); + if (trace == null) { + return; + } + + if (!trace.canSampled()) { + return; + } + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(serviceType); + recorder.recordApi(methodDescriptor); + } + + private Trace createTrace(T request) { + final String requestURI = requestAdaptor.getRpcName(request); + if (this.excludeUrlFilter.filter(requestURI)) { + if (isTrace) { + logger.trace("Filter requestURI={}", requestURI); + } + return null; + } + + final Trace trace = this.requestTraceReader.read(request); + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + // record root span + recorder.recordServiceType(this.serviceType); + recorder.recordApi(SERVLET_SYNC_METHOD_DESCRIPTOR); + this.serverRequestRecorder.record(recorder, request); + // record proxy HTTP header. + this.proxyHttpHeaderRecorder.record(recorder, request); + } + return trace; + } + + public void destroyed(T request, final Throwable throwable, final int statusCode) { + if (isDebug) { + logger.debug("Destroyed requestEvent. request={}, throwable={}, statusCode={}", request, throwable, statusCode); + } + + final Trace trace = this.traceContext.currentRawTraceObject(); + if (trace == null) { + return; + } + + // TODO STATDISABLE this logic was added to disable statistics tracing + if (!trace.canSampled()) { + traceContext.removeTraceObject(); + trace.close(); + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordException(throwable); + this.httpStatusCodeRecorder.record(trace.getSpanRecorder(), statusCode); + // Must be executed in destroyed() + this.parameterRecorder.record(recorder, request, throwable); + } finally { + trace.traceBlockEnd(); + this.traceContext.removeTraceObject(); + trace.close(); + } + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/TraceHeader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/TraceHeader.java new file mode 100644 index 000000000000..da094217e715 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/TraceHeader.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + + +/** + * @author Woonduk Kang(emeroad) + */ +public interface TraceHeader { + TraceHeaderState getState(); + + String getTransactionId(); + long getParentSpanId(); + long getSpanId(); + short getFlags(); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/TraceHeaderReader.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/TraceHeaderReader.java new file mode 100644 index 000000000000..8ae9586f7e18 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/TraceHeaderReader.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface TraceHeaderReader { + // Read the transaction information from the request. + TraceHeader read(T request); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/TraceHeaderState.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/TraceHeaderState.java new file mode 100644 index 000000000000..b66873a7fdc6 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/TraceHeaderState.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public enum TraceHeaderState { + NEW_TRACE, + + CONTINUE, + DISABLE +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/AsyncListenerOnCompleteMethodDescriptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/AsyncListenerOnCompleteMethodDescriptor.java new file mode 100644 index 000000000000..0f70437b1f6c --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/AsyncListenerOnCompleteMethodDescriptor.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.method; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; + +/** + * @author jaehong.kim + */ +public class AsyncListenerOnCompleteMethodDescriptor implements MethodDescriptor { + + private int apiId; + + @Override + public String getMethodName() { + return null; + } + + @Override + public String getClassName() { + return null; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return null; + } + + @Override + public int getLineNumber() { + return 0; + } + + @Override + public String getFullName() { + return "javax.servlet.AsyncListener.onComplete(javax.servlet.AsyncEvent asyncEvent)"; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return this.apiId; + } + + @Override + public String getApiDescriptor() { + return "AsyncListener.onComplete(javax.servlet.AsyncEvent asyncEvent)"; + } + + @Override + public int getType() { + return 0; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/AsyncListenerOnErrorMethodDescriptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/AsyncListenerOnErrorMethodDescriptor.java new file mode 100644 index 000000000000..1eb0eb7a9e1d --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/AsyncListenerOnErrorMethodDescriptor.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.method; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; + +/** + * @author jaehong.kim + */ +public class AsyncListenerOnErrorMethodDescriptor implements MethodDescriptor { + + private int apiId; + + @Override + public String getMethodName() { + return null; + } + + @Override + public String getClassName() { + return null; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return null; + } + + @Override + public int getLineNumber() { + return 0; + } + + @Override + public String getFullName() { + return "javax.servlet.AsyncListener.onError(javax.servlet.AsyncEvent asyncEvent)"; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return this.apiId; + } + + @Override + public String getApiDescriptor() { + return "AsyncListener.onError(javax.servlet.AsyncEvent asyncEvent)"; + } + + @Override + public int getType() { + return 0; + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/AsyncListenerOnTimeoutMethodDescriptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/AsyncListenerOnTimeoutMethodDescriptor.java new file mode 100644 index 000000000000..8842a3b23cde --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/AsyncListenerOnTimeoutMethodDescriptor.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.method; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; + +/** + * @author jaehong.kim + */ +public class AsyncListenerOnTimeoutMethodDescriptor implements MethodDescriptor { + + private int apiId; + + @Override + public String getMethodName() { + return null; + } + + @Override + public String getClassName() { + return null; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return null; + } + + @Override + public int getLineNumber() { + return 0; + } + + @Override + public String getFullName() { + return "javax.servlet.AsyncListener.onTimeout(javax.servlet.AsyncEvent asyncEvent)"; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return this.apiId; + } + + @Override + public String getApiDescriptor() { + return "AsyncListener.onTimeout(javax.servlet.AsyncEvent asyncEvent)"; + } + + @Override + public int getType() { + return 0; + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/ServletAsyncMethodDescriptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/ServletAsyncMethodDescriptor.java new file mode 100644 index 000000000000..aa4b39df5b11 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/ServletAsyncMethodDescriptor.java @@ -0,0 +1,86 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.method; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; + +/** + * @author jaehong.kim + */ +public class ServletAsyncMethodDescriptor implements MethodDescriptor { + private int apiId = 0; + private int type = MethodType.WEB_REQUEST; + + @Override + public String getMethodName() { + return ""; + } + + @Override + public String getClassName() { + return ""; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return "()"; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return "com.navercorp.pinpoint.bootstrap.plugin.request.method.ServletAsyncMethodDescriptor.invoke()"; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return apiId; + } + + @Override + public String getApiDescriptor() { + return "Servlet Asynchronous Process"; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/ServletRequestListenerMethodDescriptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/ServletRequestListenerMethodDescriptor.java new file mode 100644 index 000000000000..f9a05fc33278 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/ServletRequestListenerMethodDescriptor.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.method; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; + +/** + * @author jaehong.kim + */ +public class ServletRequestListenerMethodDescriptor implements MethodDescriptor { + + private int apiId; + + @Override + public String getMethodName() { + return null; + } + + @Override + public String getClassName() { + return null; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return null; + } + + @Override + public int getLineNumber() { + return 0; + } + + @Override + public String getFullName() { + return "javax.servlet.ServletRequestListener.request(javax.servlet.ServletRequestEvent servletRequestEvent)"; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return this.apiId; + } + + @Override + public String getApiDescriptor() { + return "ServletRequestListener.request(javax.servlet.ServletRequestEvent servletRequestEvent)"; + } + + @Override + public int getType() { + return 0; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/ServletSyncMethodDescriptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/ServletSyncMethodDescriptor.java new file mode 100644 index 000000000000..7349b655964b --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/method/ServletSyncMethodDescriptor.java @@ -0,0 +1,86 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.method; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; + +/** + * @author jaehong.kim + */ +public class ServletSyncMethodDescriptor implements MethodDescriptor { + private int apiId = 0; + private int type = MethodType.WEB_REQUEST; + + @Override + public String getMethodName() { + return ""; + } + + @Override + public String getClassName() { + return ""; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return "()"; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return "com.navercorp.pinpoint.bootstrap.plugin.request.method.ServletSyncMethodDescriptor.invoke()"; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return apiId; + } + + @Override + public String getApiDescriptor() { + return "Servlet Process"; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} \ No newline at end of file diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/BypassNameSpaceChecker.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/BypassNameSpaceChecker.java new file mode 100644 index 000000000000..1a378d518e5a --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/BypassNameSpaceChecker.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +/** + * @author Woonduk Kang(emeroad) + */ +public class BypassNameSpaceChecker implements NameSpaceChecker { + @Override + public boolean checkNamespace(T request) { + return true; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/CookieExtractor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/CookieExtractor.java new file mode 100644 index 000000000000..79c2aaa28fc8 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/CookieExtractor.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface CookieExtractor { + /** + * Cookie + * + * @return If the value does not exist, it should return null. + */ + String getCookie(T request); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/CookieRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/CookieRecorder.java new file mode 100644 index 000000000000..08cf1b1b78b6 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/CookieRecorder.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface CookieRecorder { + void record(final SpanEventRecorder recorder, final T cookie, final Throwable throwable); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/CookieRecorderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/CookieRecorderFactory.java new file mode 100644 index 000000000000..7ae01a6e7da2 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/CookieRecorderFactory.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author Woonduk Kang(emeroad) + */ +public class CookieRecorderFactory { + + + public static CookieRecorder newCookieRecorder(HttpDumpConfig httpDumpConfig, CookieExtractor extractor) { + Assert.requireNonNull(httpDumpConfig, "httpDumpConfig must not be null"); + + if (!httpDumpConfig.isDumpCookie()) { + return new DisableCookieRecorder(); + } + return new DefaultCookieRecorder(httpDumpConfig, extractor); + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DefaultCookieRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DefaultCookieRecorder.java new file mode 100644 index 000000000000..0cb9e03f6cc8 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DefaultCookieRecorder.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.config.DumpType; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultCookieRecorder implements CookieRecorder { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final HttpDumpConfig httpDumpConfig; + private final CookieExtractor cookieExtractor; + + public DefaultCookieRecorder(HttpDumpConfig httpDumpConfig, CookieExtractor cookieExtractor) { + this.httpDumpConfig = Assert.requireNonNull(httpDumpConfig, "httpDumpConfig must not be null"); + this.cookieExtractor = Assert.requireNonNull(cookieExtractor, "cookieExtractor must not be null"); + } + + @Override + public void record(SpanEventRecorder recorder, T cookie, Throwable throwable) { + + if (DumpType.ALWAYS == this.httpDumpConfig.getCookieDumpType()) { + recordCookie(recorder, cookie); + } else if (DumpType.EXCEPTION == this.httpDumpConfig.getCookieDumpType() && InterceptorUtils.isThrowable(throwable)) { + recordCookie(recorder, cookie); + } + } + + private void recordCookie(final SpanEventRecorder recorder, final T cookie) { + if (this.httpDumpConfig.getCookieSampler().isSampling()) { + final String cookieValue = cookieExtractor.getCookie(cookie); + if (cookieValue != null) { + final int cookieDumpSize = this.httpDumpConfig.getCookieDumpSize(); + final String cookieString = StringUtils.abbreviate(cookieValue, cookieDumpSize); + recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, cookieString); + if (isDebug) { + logger.debug("Record cookie={}", cookieValue); + } + } + } + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DefaultEntityRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DefaultEntityRecorder.java new file mode 100644 index 000000000000..ecdb204f16a7 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DefaultEntityRecorder.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.config.DumpType; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultEntityRecorder implements EntityRecorder { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final HttpDumpConfig httpDumpConfig; + private final EntityExtractor entityExtractor; + + public DefaultEntityRecorder(HttpDumpConfig httpDumpConfig, EntityExtractor entityExtractor) { + this.httpDumpConfig = Assert.requireNonNull(httpDumpConfig, "httpDumpConfig must not be null"); + this.entityExtractor = Assert.requireNonNull(entityExtractor, "entityExtractor must not be null"); + } + + @Override + public void record(SpanEventRecorder recorder, T entity, Throwable throwable) { + if (DumpType.ALWAYS == this.httpDumpConfig.getEntityDumpType()) { + recordEntity(recorder, entity); + } else if (DumpType.EXCEPTION == this.httpDumpConfig.getEntityDumpType() && InterceptorUtils.isThrowable(throwable)) { + recordEntity(recorder, entity); + } + } + + private void recordEntity(final SpanEventRecorder recorder, final T entity) { + if (this.httpDumpConfig.getEntitySampler().isSampling()) { + final String entityValue = entityExtractor.getEntity(entity); + if (entityValue != null) { + final int entityDumpSize = this.httpDumpConfig.getEntityDumpSize(); + final String entityString = StringUtils.abbreviate(entityValue, entityDumpSize); + recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, entityString); + if (isDebug) { + logger.debug("Record entity={}", entityValue); + } + } + } + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DefaultNameSpaceChecker.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DefaultNameSpaceChecker.java new file mode 100644 index 000000000000..754d24f12071 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DefaultNameSpaceChecker.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultNameSpaceChecker implements NameSpaceChecker { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private final RequestAdaptor requestAdaptor; + private final String applicationNamespace; + + + public DefaultNameSpaceChecker(RequestAdaptor requestAdaptor, String applicationNamespace) { + this.requestAdaptor = Assert.requireNonNull(requestAdaptor, "requestAdaptor must not be null"); + + if (StringUtils.isEmpty(applicationNamespace)) { + throw new IllegalArgumentException("applicationNamespace must not be empty"); + } + this.applicationNamespace = applicationNamespace; + } + + @Override + public boolean checkNamespace(T request) { + + final String parentApplicationNamespace = requestAdaptor.getHeader(request, Header.HTTP_PARENT_APPLICATION_NAMESPACE.toString()); + // If parentApplicationNamespace is null, it is ignored for backwards compatibility. + if (parentApplicationNamespace == null) { + return true; + } + if (this.applicationNamespace.equals(parentApplicationNamespace)) { + // collision. + return true; + } + if (logger.isDebugEnabled()) { + logger.debug("Collision namespace. applicationNamespace={}, parentApplicationNamespace={}", this.applicationNamespace, parentApplicationNamespace); + } + return false; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DisableCookieRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DisableCookieRecorder.java new file mode 100644 index 000000000000..f80cd1b6fed8 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DisableCookieRecorder.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DisableCookieRecorder implements CookieRecorder { + + @Override + public void record(SpanEventRecorder recorder, T cookie, Throwable throwable) { + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DisableEntityRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DisableEntityRecorder.java new file mode 100644 index 000000000000..0c39e1b99c20 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DisableEntityRecorder.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DisableEntityRecorder implements EntityRecorder { + @Override + public void record(SpanEventRecorder recorder, T entity, Throwable throwable) { + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DisableParameterRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DisableParameterRecorder.java new file mode 100644 index 000000000000..d883c5acf476 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/DisableParameterRecorder.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DisableParameterRecorder implements ParameterRecorder { + + @Override + public void record(SpanEventRecorder spanRecorder, T request, Throwable throwable) { + + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/EntityExtractor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/EntityExtractor.java new file mode 100644 index 000000000000..1cae44364a91 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/EntityExtractor.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface EntityExtractor { + /** + * Entity + * + * @return If the value does not exist, it should return null. + */ + String getEntity(T request); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/EntityRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/EntityRecorder.java new file mode 100644 index 000000000000..0b5c108cdb72 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/EntityRecorder.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface EntityRecorder { + void record(final SpanEventRecorder recorder, final T entity, final Throwable throwable); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/EntityRecorderFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/EntityRecorderFactory.java new file mode 100644 index 000000000000..d506b3fcc931 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/EntityRecorderFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author Woonduk Kang(emeroad) + */ +public class EntityRecorderFactory { + + public static EntityRecorder newEntityRecorder(HttpDumpConfig httpDumpConfig, EntityExtractor extractor) { + Assert.requireNonNull(httpDumpConfig, "httpDumpConfig must not be null"); + + if (!httpDumpConfig.isDumpEntity()) { + return new DisableEntityRecorder(); + } + return new DefaultEntityRecorder(httpDumpConfig, extractor); + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/HeaderResolveRequestAdaptor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/HeaderResolveRequestAdaptor.java new file mode 100644 index 000000000000..3c5f1049996b --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/HeaderResolveRequestAdaptor.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + + +import com.navercorp.pinpoint.bootstrap.context.RemoteAddressResolver; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HeaderResolveRequestAdaptor implements RequestAdaptor { + + private final RequestAdaptor delegate; + private final RemoteAddressResolver remoteAddressResolver; + + public HeaderResolveRequestAdaptor(RequestAdaptor delegate, RemoteAddressResolver remoteAddressResolver) { + this.delegate = Assert.requireNonNull(delegate, "delegate must not be null"); + this.remoteAddressResolver = Assert.requireNonNull(remoteAddressResolver, "remoteAddressResolver must not be null"); + } + + @Override + public String getHeader(T request, String name) { + return delegate.getHeader(request, name); + } + + @Override + public String getRpcName(T request) { + return delegate.getRpcName(request); + } + + @Override + public String getEndPoint(T request) { + return delegate.getEndPoint(request); + } + + @Override + public String getRemoteAddress(T request) { + final String remoteAddress = remoteAddressResolver.resolve(delegate, request); + if (remoteAddress != null) { + return remoteAddress; + } + return delegate.getRemoteAddress(request); + } + + @Override + public String getAcceptorHost(T request) { + return delegate.getAcceptorHost(request); + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/HttpParameterRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/HttpParameterRecorder.java new file mode 100644 index 000000000000..909c846deece --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/HttpParameterRecorder.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpParameterRecorder implements ParameterRecorder { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final ParameterExtractor parameterExtractor; + + public HttpParameterRecorder(ParameterExtractor parameterExtractor) { + this.parameterExtractor = Assert.requireNonNull(parameterExtractor, "parameterExtractor must not be null"); + } + + @Override + public void record(SpanEventRecorder spanRecorder, T request, Throwable throwable) { + + final String parameters = parameterExtractor.extractParameter(request); + if (StringUtils.hasLength(parameters)) { + spanRecorder.recordAttribute(AnnotationKey.HTTP_PARAM, parameters); + if (logger.isDebugEnabled()) { + logger.debug("Record httpParam={}", parameters); + } + } + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/NameSpaceCheckFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/NameSpaceCheckFactory.java new file mode 100644 index 000000000000..86cbfb551d60 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/NameSpaceCheckFactory.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.common.util.StringUtils; + +/** + * @author Woonduk Kang(emeroad) + */ +public class NameSpaceCheckFactory { + public static NameSpaceChecker newNamespace(RequestAdaptor requestAdaptor, String applicationNamespace) { + if (StringUtils.isEmpty(applicationNamespace)) { + return new BypassNameSpaceChecker(); + } + + return new DefaultNameSpaceChecker(requestAdaptor, applicationNamespace); + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/NameSpaceChecker.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/NameSpaceChecker.java new file mode 100644 index 000000000000..44508b965bc9 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/NameSpaceChecker.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface NameSpaceChecker { + boolean checkNamespace(T request); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/ParameterExtractor.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/ParameterExtractor.java new file mode 100644 index 000000000000..0513ff611f58 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/ParameterExtractor.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + + +/** + * @author Woonduk Kang(emeroad) + */ +public interface ParameterExtractor { + + String extractParameter(T request); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/ParameterRecorder.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/ParameterRecorder.java new file mode 100644 index 000000000000..e738bfa0b10a --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/ParameterRecorder.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; + + +/** + * @author Woonduk Kang(emeroad) + */ +public interface ParameterRecorder { + void record(SpanEventRecorder spanRecorder, T request, Throwable throwable); +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/RealIpHeaderResolver.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/RealIpHeaderResolver.java new file mode 100644 index 000000000000..0e428113f409 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/RealIpHeaderResolver.java @@ -0,0 +1,57 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.context.RemoteAddressResolver; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class RealIpHeaderResolver implements RemoteAddressResolver { + + private final String realIpHeaderName; + private final String realIpHeaderEmptyValue; + + public RealIpHeaderResolver(final String realIpHeaderName, final String realIpHeaderEmptyValue) { + this.realIpHeaderName = Assert.requireNonNull(realIpHeaderName, "realIpHeaderName must not be null"); + this.realIpHeaderEmptyValue = realIpHeaderEmptyValue; + } + + @Override + public String resolve(RequestAdaptor requestAdaptor, T request) { + final String realIp = requestAdaptor.getHeader(request, realIpHeaderName); + if (StringUtils.isEmpty(realIp)) { + return null; + } + + if (realIpHeaderEmptyValue != null && realIpHeaderEmptyValue.equalsIgnoreCase(realIp)) { + return null; + } + + final int firstIndex = realIp.indexOf(','); + if (firstIndex == -1) { + return realIp; + } else { + return realIp.substring(0, firstIndex); + } + } + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/RemoteAddressResolverFactory.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/RemoteAddressResolverFactory.java new file mode 100644 index 000000000000..26c244a62024 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/RemoteAddressResolverFactory.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + + +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.common.util.StringUtils; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RemoteAddressResolverFactory { + + + public static RequestAdaptor wrapRealIpSupport(RequestAdaptor requestAdaptor, final String realIpHeaderName, final String realIpHeaderEmptyValue) { + if (!StringUtils.hasLength(realIpHeaderName)) { + return requestAdaptor; + } + RealIpHeaderResolver tealIpHeaderResolver = new RealIpHeaderResolver(realIpHeaderName, realIpHeaderEmptyValue); + RequestAdaptor wrap = new HeaderResolveRequestAdaptor(requestAdaptor, tealIpHeaderResolver); + return wrap; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/Expectations.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/Expectations.java index e24e322e68e5..f3705389f15d 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/Expectations.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/Expectations.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,77 +14,152 @@ */ package com.navercorp.pinpoint.bootstrap.plugin.test; -import java.lang.reflect.Member; - import com.navercorp.pinpoint.common.util.AnnotationKeyUtils; +import java.lang.reflect.Member; + /** * @author Jongho Moon - * */ public final class Expectations { - + private static final Object ANY_ANNOTATION_VALUE = new Object(); - - - private Expectations() {} - + + private Expectations() { + } + public static Object anyAnnotationValue() { return ANY_ANNOTATION_VALUE; } - + public static ExpectedTrace root(String serviceType, Member method, String rpc, String endPoint, String remoteAddr, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.ROOT, serviceType, method, null, null, rpc, endPoint, remoteAddr, null, annotations, null); + ExpectedTrace.Builder rootBuilder = ExpectedTrace.createRootBuilder(serviceType); + rootBuilder.setMethod(method); + rootBuilder.setRpc(rpc); + rootBuilder.setEndPoint(endPoint); + rootBuilder.setRemoteAddr(remoteAddr); + rootBuilder.setAnnotations(annotations); + return rootBuilder.build(); } public static ExpectedTrace root(String serviceType, Member method, Exception exception, String rpc, String endPoint, String remoteAddr, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.ROOT, serviceType, method, null, exception, rpc, endPoint, remoteAddr, null, annotations, null); + ExpectedTrace.Builder rootBuilder = ExpectedTrace.createRootBuilder(serviceType); + rootBuilder.setMethod(method); + rootBuilder.setException(exception); + rootBuilder.setRpc(rpc); + rootBuilder.setEndPoint(endPoint); + rootBuilder.setRemoteAddr(remoteAddr); + rootBuilder.setAnnotations(annotations); + return rootBuilder.build(); } - + public static ExpectedTrace root(String serviceType, String methodDescriptor, String rpc, String endPoint, String remoteAddr, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.ROOT, serviceType, null, methodDescriptor, null, rpc, endPoint, remoteAddr, null, annotations, null); + ExpectedTrace.Builder rootBuilder = ExpectedTrace.createRootBuilder(serviceType); + rootBuilder.setMethodSignature(methodDescriptor); + rootBuilder.setRpc(rpc); + rootBuilder.setEndPoint(endPoint); + rootBuilder.setRemoteAddr(remoteAddr); + rootBuilder.setAnnotations(annotations); + return rootBuilder.build(); } public static ExpectedTrace root(String serviceType, String methodDescriptor, Exception exception, String rpc, String endPoint, String remoteAddr, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.ROOT, serviceType, null, methodDescriptor, exception, rpc, endPoint, remoteAddr, null, annotations, null); + ExpectedTrace.Builder rootBuilder = ExpectedTrace.createRootBuilder(serviceType); + rootBuilder.setMethodSignature(methodDescriptor); + rootBuilder.setException(exception); + rootBuilder.setRpc(rpc); + rootBuilder.setEndPoint(endPoint); + rootBuilder.setRemoteAddr(remoteAddr); + rootBuilder.setAnnotations(annotations); + return rootBuilder.build(); } - + public static ExpectedTrace event(String serviceType, Member method, String rpc, String endPoint, String destinationId, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.EVENT, serviceType, method, null, null, rpc, endPoint, null, destinationId, annotations, null); + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createEventBuilder(serviceType); + eventBuilder.setMethod(method); + eventBuilder.setRpc(rpc); + eventBuilder.setEndPoint(endPoint); + eventBuilder.setDestinationId(destinationId); + eventBuilder.setAnnotations(annotations); + return eventBuilder.build(); } public static ExpectedTrace event(String serviceType, Member method, Exception exception, String rpc, String endPoint, String destinationId, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.EVENT, serviceType, method, null, exception, rpc, endPoint, null, destinationId, annotations, null); + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createEventBuilder(serviceType); + eventBuilder.setMethod(method); + eventBuilder.setException(exception); + eventBuilder.setRpc(rpc); + eventBuilder.setEndPoint(endPoint); + eventBuilder.setDestinationId(destinationId); + eventBuilder.setAnnotations(annotations); + return eventBuilder.build(); } public static ExpectedTrace event(String serviceType, Member method, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.EVENT, serviceType, method, null, null, null, null, null, null, annotations, null); + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createEventBuilder(serviceType); + eventBuilder.setMethod(method); + eventBuilder.setAnnotations(annotations); + return eventBuilder.build(); } public static ExpectedTrace event(String serviceType, Member method, Exception exception, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.EVENT, serviceType, method, null, exception, null, null, null, null, annotations, null); + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createEventBuilder(serviceType); + eventBuilder.setMethod(method); + eventBuilder.setException(exception); + eventBuilder.setAnnotations(annotations); + return eventBuilder.build(); } public static ExpectedTrace event(String serviceType, String methodDescriptor, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.EVENT, serviceType, null, methodDescriptor, null, null, null, null, null, annotations, null); + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createEventBuilder(serviceType); + eventBuilder.setMethodSignature(methodDescriptor); + eventBuilder.setAnnotations(annotations); + return eventBuilder.build(); } public static ExpectedTrace event(String serviceType, String methodDescriptor, Exception exception, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.EVENT, serviceType, null, methodDescriptor, exception, null, null, null, null, annotations, null); + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createEventBuilder(serviceType); + eventBuilder.setMethodSignature(methodDescriptor); + eventBuilder.setException(exception); + eventBuilder.setAnnotations(annotations); + return eventBuilder.build(); } public static ExpectedTrace event(String serviceType, String methodDescriptor, String rpc, String endPoint, String destinationId, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.EVENT, serviceType, null, methodDescriptor, null, rpc, endPoint, null, destinationId, annotations, null); + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createEventBuilder(serviceType); + eventBuilder.setMethodSignature(methodDescriptor); + eventBuilder.setRpc(rpc); + eventBuilder.setEndPoint(endPoint); + eventBuilder.setDestinationId(destinationId); + eventBuilder.setAnnotations(annotations); + return eventBuilder.build(); } public static ExpectedTrace event(String serviceType, String methodDescriptor, Exception exception, String rpc, String endPoint, String destinationId, ExpectedAnnotation... annotations) { - return new ExpectedTrace(TraceType.EVENT, serviceType, null, methodDescriptor, exception, rpc, endPoint, null, destinationId, annotations, null); + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createEventBuilder(serviceType); + eventBuilder.setMethodSignature(methodDescriptor); + eventBuilder.setException(exception); + eventBuilder.setRpc(rpc); + eventBuilder.setEndPoint(endPoint); + eventBuilder.setDestinationId(destinationId); + eventBuilder.setAnnotations(annotations); + return eventBuilder.build(); } - + public static ExpectedTrace async(ExpectedTrace initiator, ExpectedTrace... asyncTraces) { - return new ExpectedTrace(initiator.getType(), initiator.getServiceType(), initiator.getMethod(), initiator.getMethodSignature(), initiator.getException(), initiator.getRpc(), initiator.getEndPoint(), initiator.getRemoteAddr(), initiator.getDestinationId(), initiator.getAnnotations(), asyncTraces); + ExpectedTrace.Builder eventBuilder = ExpectedTrace.createBuilder(initiator.getType(), initiator.getServiceType()); + eventBuilder.setMethod(initiator.getMethod()); + eventBuilder.setMethodSignature(initiator.getMethodSignature()); + eventBuilder.setException(initiator.getException()); + eventBuilder.setRpc(initiator.getRpc()); + eventBuilder.setEndPoint(initiator.getEndPoint()); + eventBuilder.setRemoteAddr(initiator.getRemoteAddr()); + eventBuilder.setDestinationId(initiator.getDestinationId()); + eventBuilder.setAnnotations(initiator.getAnnotations()); + eventBuilder.setAsyncTraces(asyncTraces); + return eventBuilder.build(); } - + public static ExpectedAnnotation[] annotations(ExpectedAnnotation... annotations) { return annotations; } @@ -95,26 +170,25 @@ public static ExpectedAnnotation annotation(String annotationKeyName, Object val public static ExpectedAnnotation[] args(Object... args) { ExpectedAnnotation[] annotations = new ExpectedAnnotation[args.length]; - + for (int i = 0; i < args.length; i++) { annotations[i] = annotation(AnnotationKeyUtils.getArgs(i).getName(), args[i]); } - + return annotations; } public static ExpectedAnnotation[] cachedArgs(Object... args) { ExpectedAnnotation[] annotations = new ExpectedAnnotation[args.length]; - + for (int i = 0; i < args.length; i++) { annotations[i] = annotation(AnnotationKeyUtils.getCachedArgs(i).getName(), args[i]); } - + return annotations; } public static ExpectedAnnotation sql(String query, String output, Object... bindValues) { return new ExpectedSql(query, output, bindValues); } - } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedAnnotation.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedAnnotation.java index 60167e23a9b7..9cc740240fff 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedAnnotation.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedAnnotation.java @@ -19,7 +19,7 @@ public class ExpectedAnnotation { public static ExpectedAnnotation sql(String query, String output, Object... bindValues) { return new ExpectedSql(query, output, bindValues); } - + private final String keyName; private final Object value; diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTrace.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTrace.java index ae6f1dc3f0f9..57670eb0a0c5 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTrace.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTrace.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,7 +18,6 @@ /** * @author Jongho Moon - * */ public class ExpectedTrace { private final TraceType type; @@ -26,25 +25,25 @@ public class ExpectedTrace { private final Member method; private final String methodSignature; private final Exception exception; - private final String rpc; - private final String endPoint; - private final String remoteAddr; - private final String destinationId; + private final ExpectedTraceField rpc; + private final ExpectedTraceField endPoint; + private final ExpectedTraceField remoteAddr; + private final ExpectedTraceField destinationId; private final ExpectedAnnotation[] annotations; private final ExpectedTrace[] asyncTraces; - - public ExpectedTrace(TraceType type, String serviceType, Member method, String methodSignature, Exception exception, String rpc, String endPoint, String remoteAddr, String destinationId, ExpectedAnnotation[] annotations, ExpectedTrace[] asyncTraces) { - this.type = type; - this.serviceType = serviceType; - this.method = method; - this.methodSignature = methodSignature; - this.exception = exception; - this.rpc = rpc; - this.endPoint = endPoint; - this.remoteAddr = remoteAddr; - this.destinationId = destinationId; - this.annotations = annotations; - this.asyncTraces = asyncTraces; + + private ExpectedTrace(Builder builder) { + this.type = builder.type; + this.serviceType = builder.serviceType; + this.method = builder.method; + this.methodSignature = builder.methodSignature; + this.exception = builder.exception; + this.rpc = builder.rpc; + this.endPoint = builder.endPoint; + this.remoteAddr = builder.remoteAddr; + this.destinationId = builder.destinationId; + this.annotations = builder.annotations; + this.asyncTraces = builder.asyncTraces; } public TraceType getType() { @@ -67,19 +66,19 @@ public Exception getException() { return exception; } - public String getRpc() { + public ExpectedTraceField getRpc() { return rpc; } - public String getEndPoint() { + public ExpectedTraceField getEndPoint() { return endPoint; } - public String getRemoteAddr() { + public ExpectedTraceField getRemoteAddr() { return remoteAddr; } - public String getDestinationId() { + public ExpectedTraceField getDestinationId() { return destinationId; } @@ -90,4 +89,114 @@ public ExpectedAnnotation[] getAnnotations() { public ExpectedTrace[] getAsyncTraces() { return asyncTraces; } + + + public static Builder createBuilder(TraceType traceType, String serviceType) { + return new Builder(traceType, serviceType); + } + + public static Builder createRootBuilder(String serviceType) { + return new Builder(TraceType.ROOT, serviceType); + } + + public static Builder createEventBuilder(String serviceType) { + return new Builder(TraceType.EVENT, serviceType); + } + + public static class Builder { + + private final TraceType type; + private final String serviceType; + + private Member method; + private String methodSignature; + private Exception exception; + private ExpectedTraceField rpc = ExpectedTraceField.ALWAYS_TRUE; + private ExpectedTraceField endPoint = ExpectedTraceField.ALWAYS_TRUE; + private ExpectedTraceField remoteAddr = ExpectedTraceField.ALWAYS_TRUE; + private ExpectedTraceField destinationId = ExpectedTraceField.ALWAYS_TRUE; + private ExpectedAnnotation[] annotations; + private ExpectedTrace[] asyncTraces; + + public Builder(TraceType type, String serviceType) { + if (type == null) { + throw new NullPointerException("type must not be null"); + } + if (serviceType == null) { + throw new NullPointerException("serviceType must not be null"); + } + this.type = type; + this.serviceType = serviceType; + } + + public void setMethod(Member method) { + this.method = method; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public void setException(Exception exception) { + this.exception = exception; + } + + public void setRpc(String rpc) { + setRpc(ExpectedTraceField.create(rpc)); + } + + public void setRpc(ExpectedTraceField rpc) { + if (rpc == null) { + throw new NullPointerException("rpc must not be null"); + } + this.rpc = rpc; + } + + public void setEndPoint(String endPoint) { + setEndPoint(ExpectedTraceField.create(endPoint)); + } + + public void setEndPoint(ExpectedTraceField endPoint) { + if (endPoint == null) { + throw new NullPointerException("endPoint must not be null"); + } + this.endPoint = endPoint; + } + + public void setRemoteAddr(String remoteAddr) { + setRemoteAddr(ExpectedTraceField.create(remoteAddr)); + } + + public void setRemoteAddr(ExpectedTraceField remoteAddr) { + if (remoteAddr == null) { + throw new NullPointerException("remoteAddr must not be null"); + } + this.remoteAddr = remoteAddr; + } + + public void setDestinationId(String destinationId) { + setDestinationId(ExpectedTraceField.create(destinationId)); + } + + public void setDestinationId(ExpectedTraceField destinationId) { + if (destinationId == null) { + throw new NullPointerException("destinationId must not be null"); + } + this.destinationId = destinationId; + } + + public void setAnnotations(ExpectedAnnotation... annotations) { + this.annotations = annotations; + } + + public void setAsyncTraces(ExpectedTrace[] asyncTraces) { + this.asyncTraces = asyncTraces; + } + + public ExpectedTrace build() { + return new ExpectedTrace(this); + } + + } + } diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTraceField.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTraceField.java new file mode 100644 index 000000000000..49f94ea76fda --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTraceField.java @@ -0,0 +1,86 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.test; + +/** + * @author Taejin Koo + */ +public class ExpectedTraceField { + + public static ExpectedTraceField ALWAYS_TRUE = new ExpectedTraceField(ExpectedTraceFieldType.ALWAYS_TRUE); + public static ExpectedTraceField EMPTY = new ExpectedTraceField(ExpectedTraceFieldType.EMPTY); + public static ExpectedTraceField NOT_EMPTY = new ExpectedTraceField(ExpectedTraceFieldType.NOT_EMPTY); + + private final String expected; + private final ExpectedTraceFieldType expectedType; + + public ExpectedTraceField(ExpectedTraceFieldType expectedType) { + this(null, expectedType); + } + + public ExpectedTraceField(String expected, ExpectedTraceFieldType expectedType) { + if (expectedType == null) { + throw new NullPointerException("expectedType must not be null"); + } + this.expected = expected; + this.expectedType = expectedType; + } + + public static ExpectedTraceField create(String value) { + if (value == null) { + return createAlwaysTrue(); + } else { + return createEquals(value); + } + } + + public static ExpectedTraceField createEquals(String value) { + return new ExpectedTraceField(value, ExpectedTraceFieldType.EQUALS); + } + + public static ExpectedTraceField createAlwaysTrue() { + return ALWAYS_TRUE; + } + + public static ExpectedTraceField createNotEmpty() { + return NOT_EMPTY; + } + + public static ExpectedTraceField createEmpty() { + return EMPTY; + } + + public static ExpectedTraceField createStartWith(String value) { + return new ExpectedTraceField(value, ExpectedTraceFieldType.START_WITH); + } + + public static ExpectedTraceField createContains(String value) { + return new ExpectedTraceField(value, ExpectedTraceFieldType.CONTAINS); + } + + public boolean isEquals(String value) { + return expectedType.isEquals(expected, value); + } + + @Override + public String toString() { + return "ExpectedTraceField{" + + "expectedType=" + expectedType + + ", expected='" + expected + '\'' + + '}'; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTraceFieldType.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTraceFieldType.java new file mode 100644 index 000000000000..31084b3c45a0 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTraceFieldType.java @@ -0,0 +1,99 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.test; + +/** + * @author Taejin Koo + */ +public enum ExpectedTraceFieldType { + + EQUALS { + @Override + public boolean isEquals(String expected, String actual) { + if (expected == null && actual == null) { + return true; + } + if (expected == null) { + return false; + } + return expected.equals(actual); + } + }, + + ALWAYS_TRUE { + @Override + public boolean isEquals(String expected, String actual) { + return true; + } + }, + + NOT_EMPTY { + @Override + public boolean isEquals(String expected, String actual) { + if (actual == null || actual.length() == 0) { + return false; + } + return true; + } + }, + + EMPTY { + @Override + public boolean isEquals(String expected, String actual) { + if (actual == null || actual.length() == 0) { + return true; + } + return false; + } + }, + + START_WITH { + @Override + public boolean isEquals(String expected, String actual) { + if (expected == null && actual == null) { + return true; + } + if (expected == null) { + return true; + } + if (actual != null) { + return actual.startsWith(expected); + } + return false; + } + + }, + + CONTAINS { + @Override + public boolean isEquals(String expected, String actual) { + if (expected == null && actual == null) { + return true; + } + if (expected == null) { + return true; + } + if (actual != null) { + return actual.contains(expected); + } + return false; + } + }; + + public abstract boolean isEquals(String expected, String actual); + +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/util/SocketAddressUtils.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/util/SocketAddressUtils.java new file mode 100644 index 000000000000..77c75857598f --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/util/SocketAddressUtils.java @@ -0,0 +1,178 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.util; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.JvmUtils; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.InetSocketAddress; + +/** + * @author HyunGil Jeong + */ +public final class SocketAddressUtils { + + private static final PLogger LOGGER = PLoggerFactory.getLogger(SocketAddressUtils.class); + + // TODO JDK 7 InetSocketAddress.getHostString() - reflection not needed once we drop JDK 6 support. + private static final HostStringAccessor HOST_STRING_ACCESSOR = createHostStringAccessor(); + + private static HostStringAccessor createHostStringAccessor() { + try { + final Method m = InetSocketAddress.class.getDeclaredMethod("getHostString"); + m.setAccessible(true); + return new ReflectiveHostStringAccessor(m); + } catch (NoSuchMethodException e) { + LOGGER.error("[{}] {} - getHostString() not present in class InetSocketAddress.", + JvmUtils.getType(), JvmUtils.getVersion()); + throw new IllegalStateException("Unexpected InetSocketAddress class", e); + } + } + + private interface HostStringAccessor { + String getHostString(InetSocketAddress inetSocketAddress); + } + + private static class ReflectiveHostStringAccessor implements HostStringAccessor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private final Method method; + + private ReflectiveHostStringAccessor(Method method) { + if (method == null) { + throw new NullPointerException("method must not be null"); + } + this.method = method; + } + + @Override + public String getHostString(InetSocketAddress inetSocketAddress) { + try { + return (String) method.invoke(inetSocketAddress); + } catch (IllegalAccessException e) { + logger.error("[{}] {} - Cannot access method : {}", + JvmUtils.getType(), JvmUtils.getVersion(), method.getName(), e); + } catch (InvocationTargetException e) { + logger.error("[{}] {} - Error invoking method : {}", + JvmUtils.getType(), JvmUtils.getVersion(), method.getName(), e); + } catch (Exception e) { + logger.error("[{}] {} - Unexpected error retrieving hostString", + JvmUtils.getType(), JvmUtils.getVersion(), e); + } + return null; + } + } + + private SocketAddressUtils() {} + + /** + * Returns the hostname of the given {@link InetSocketAddress}, or the String form of the IP address + * if it does not have one. Returns {@code null} if neither can be retrieved. + * + *

This does not trigger a reverse DNS lookup if was created using an address and the hostname + * is not yet available. + * + * @param inetSocketAddress the socket address in which to retrieve the hostname from + * @return the hostname or the String representation of the address, or {@code null} if neither + * can be found. + * + * @see java.net.InetSocketAddress#getHostString() + */ + public static String getHostNameFirst(InetSocketAddress inetSocketAddress) { + if (inetSocketAddress == null) { + return null; + } + return HOST_STRING_ACCESSOR.getHostString(inetSocketAddress); + } + + /** + * Returns the hostname of the given {@link InetSocketAddress}, or the String form of the IP address + * if it does not have one. Returns {@code defaultHostName} if neither can be retrieved. + * + *

This does not trigger a reverse DNS lookup if was created using an address and the hostname + * is not yet available. + * + * @param inetSocketAddress the socket address in which to retrieve the hostname from + * @param defaultHostName the value to return if neither the hostname nor the string form of the + * address can be found + * @return the hostname or the String representation of the address, or the {@code defaultHostName} + * if neither can be found. + * + * @see java.net.InetSocketAddress#getHostString() + */ + public static String getHostNameFirst(InetSocketAddress inetSocketAddress, String defaultHostName) { + String hostName = getHostNameFirst(inetSocketAddress); + if (hostName == null) { + return defaultHostName; + } + return hostName; + } + + /** + * Returns the String form of the IP address of the given {@link InetSocketAddress}, or the hostname + * if it has not been resolved. Returns {@code null} if neither can be retrieved. + * + *

This does not trigger a DNS lookup if the address has not been resolved yet by simply + * returning the hostname. + * + * @param inetSocketAddress the socket address in which to retrieve the address from + * @return the String representation of the address or the hostname, or {@code null} if neither + * can be found. + * + * @see InetSocketAddress#isUnresolved() + */ + public static String getAddressFirst(InetSocketAddress inetSocketAddress) { + if (inetSocketAddress == null) { + return null; + } + InetAddress inetAddress = inetSocketAddress.getAddress(); + if (inetAddress != null) { + return inetAddress.getHostAddress(); + } + // This won't trigger a DNS lookup as if it got to here, the hostName should not be null on the basis + // that InetSocketAddress does not allow both address and hostName fields to be null. + return inetSocketAddress.getHostName(); + } + + /** + * Returns the String form of the IP address of the given {@link InetSocketAddress}, or the hostname + * if it has not been resolved. Returns {@code defaultAddress} if neither can be retrieved. + * + *

This does not trigger a DNS lookup if the address has not been resolved yet by simply + * returning the hostname. + * + * @param inetSocketAddress the socket address in which to retrieve the address from + * @param defaultAddress the value to return if neither the string form of the address nor the + * hostname can be found + * @return the String representation of the address or the hostname, or {@code defaultAddress} if neither + * can be found. + * + * @see InetSocketAddress#isUnresolved() + */ + public static String getAddressFirst(InetSocketAddress inetSocketAddress, String defaultAddress) { + String address = getAddressFirst(inetSocketAddress); + if (address == null) { + return defaultAddress; + } + return address; + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/NetworkUtils.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/NetworkUtils.java index 2b661f4ca3be..e029e6796d02 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/NetworkUtils.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/NetworkUtils.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.bootstrap.util; +import com.navercorp.pinpoint.common.util.NetUtils; import com.navercorp.pinpoint.common.util.logger.CommonLogger; import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; @@ -91,7 +92,6 @@ public static String getHostIp() { } public static List getHostIpList() { - List result = new ArrayList(); Enumeration interfaces = null; try { @@ -101,9 +101,10 @@ public static List getHostIpList() { } if (interfaces == null) { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } + List result = new ArrayList(); while (interfaces.hasMoreElements()) { NetworkInterface current = interfaces.nextElement(); if (isSkipNetworkInterface(current)) { @@ -167,23 +168,7 @@ public static boolean isLoopbackAddress(String ip) { } public static boolean validationIpV4FormatAddress(String address) { - try { - String[] eachDotAddress = address.split("\\."); - if (eachDotAddress.length != 4) { - return false; - } - - for (String eachAddress : eachDotAddress) { - if (Integer.parseInt(eachAddress) > 255) { - return false; - } - } - return true; - } catch (NumberFormatException ignore) { - // skip - } - - return false; + return NetUtils.validationIpV4FormatAddress(address); } private static CommonLogger getLogger() { diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/PlatformClassLoaderUtils.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/PlatformClassLoaderUtils.java new file mode 100644 index 000000000000..fc190e6a9fe3 --- /dev/null +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/PlatformClassLoaderUtils.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.util; + +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.JvmVersion; + +import java.lang.reflect.Method; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class PlatformClassLoaderUtils { + + private static ClassLoader platformClassLoader = lookupPlatformOrBootstrapClassLoader(); + + private PlatformClassLoaderUtils() { + } + + private static ClassLoader lookupPlatformOrBootstrapClassLoader() { + if (JvmUtils.getVersion().onOrAfter(JvmVersion.JAVA_9)) { + return getPlatformClassLoader0(); + } else { + // java 8 under + return Object.class.getClassLoader(); + } + } + + private static ClassLoader getPlatformClassLoader0() { +// Warning : Not recommended +// return ClassLoader.getSystemClassLoader().getParent(); + try { + // java9 : ClassLoader.getPlatformClassLoader() + Method getPlatformClassLoader = ClassLoader.class.getDeclaredMethod("getPlatformClassLoader"); + return (ClassLoader) getPlatformClassLoader.invoke(ClassLoader.class); + } catch (Exception ex) { + throw new IllegalStateException("ClassLoader.getPlatformClassLoader() invoke fail Caused by:" + ex.getMessage(), ex); + } + } + + public static ClassLoader getPlatformOrBootstrapClassLoader() { + return platformClassLoader; + } + + + public static Class findClassFromPlatformClassLoader(String className) { + try { + return Class.forName(className, false, platformClassLoader); + } catch (ClassNotFoundException e) { + return null; + } + } +} diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/jdk/ThreadLocalRandomUtils.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/jdk/ThreadLocalRandomUtils.java index f7caf55c708e..016219e24f55 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/jdk/ThreadLocalRandomUtils.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/jdk/ThreadLocalRandomUtils.java @@ -21,6 +21,8 @@ import com.navercorp.pinpoint.common.util.JvmUtils; import com.navercorp.pinpoint.common.util.JvmVersion; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.Random; /** @@ -45,17 +47,23 @@ private static ThreadLocalRandomFactory createThreadLocalRandomFactory() { return new PinpointThreadLocalRandomFactory(); } else if (jvmVersion.onOrAfter(JvmVersion.JAVA_7)) { try { - ClassLoader classLoader = getClassLoader(ThreadLocalRandomUtils.class.getClassLoader()); + // @Nullable + final ClassLoader classLoader = ThreadLocalRandomUtils.class.getClassLoader(); final Class threadLocalRandomFactoryClass = (Class) Class.forName(DEFAULT_THREAD_LOCAL_RANDOM_FACTORY, true, classLoader); - return threadLocalRandomFactoryClass.newInstance(); + Constructor constructor = threadLocalRandomFactoryClass.getDeclaredConstructor(); + return constructor.newInstance(); } catch (ClassNotFoundException e) { logError(e); } catch (InstantiationException e) { logError(e); } catch (IllegalAccessException e) { logError(e); + } catch (NoSuchMethodException e) { + logError(e); + } catch (InvocationTargetException e) { + logError(e); } return new PinpointThreadLocalRandomFactory(); } else { @@ -64,15 +72,8 @@ private static ThreadLocalRandomFactory createThreadLocalRandomFactory() { } - private static ClassLoader getClassLoader(ClassLoader classLoader) { - if (classLoader == null) { - return ClassLoader.getSystemClassLoader(); - } - return classLoader; - } - private static void logError(Exception e) { - LOGGER.info("JdkThreadLocalRandomFactory not found."); + LOGGER.info("JdkThreadLocalRandomFactory not found. Caused by:{}", e.getMessage(), e); } public static Random current() { diff --git a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/spring/StringUtils.java b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/spring/StringUtils.java index 10b42bf10a39..ff1de6bf0e18 100644 --- a/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/spring/StringUtils.java +++ b/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/util/spring/StringUtils.java @@ -168,7 +168,7 @@ public static String[] toStringArray(Collection collection) { if (collection == null) { return null; } - return collection.toArray(new String[collection.size()]); + return collection.toArray(new String[0]); } } diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/BootLoaderTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/BootLoaderTest.java new file mode 100644 index 000000000000..de435262f2e9 --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/BootLoaderTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class BootLoaderTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void testFindResource() { + BootLoader bootLoader = newBootLoader(); + String stringResource = getInternalName(String.class); + + URL url = bootLoader.findResource(stringResource); + Assert.assertNotNull(url); + } + + private BootLoader newBootLoader() { + return BootLoaderFactory.newBootLoader(); + } + + private String getInternalName(Class clazz) { + String name = clazz.getName(); + return name.replace('.', '/').concat(".class"); + } + + @Test + public void testFindResources() throws IOException { + BootLoader bootLoader = newBootLoader(); + String stringResource = getInternalName(String.class); + + Enumeration bootstrapResources = bootLoader.findResources(stringResource); + List list = Collections.list(bootstrapResources); + Assert.assertEquals(1, list.size()); + logger.debug("list:{}", list); + } + + @Test + public void testBootstrapClassLoader() throws Exception { + BootLoader bootLoader = newBootLoader(); + + ClassLoader parent = Object.class.getClassLoader(); + ClassLoader classLoader = new URLClassLoader(new URL[0], parent); + Class string1 = bootLoader.findBootstrapClassOrNull(classLoader, "java.lang.String"); + Class string2 = Class.forName("java.lang.String", false, parent); + + Assert.assertNotNull(string1); + Assert.assertNotNull(string2); + Assert.assertSame(string1, string2); + Assert.assertSame(string1.getClassLoader(), string2.getClassLoader()); + this.getClass().getClassLoader(); + + ClassLoaderUtils.close(classLoader); + } +} \ No newline at end of file diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/ClassLoaderUtils.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/ClassLoaderUtils.java new file mode 100644 index 000000000000..13199bb4d889 --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/ClassLoaderUtils.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import java.io.Closeable; +import java.io.IOException; + +/** + * @author Woonduk Kang(emeroad) + */ +class ClassLoaderUtils { + static void close(ClassLoader cl) throws IOException { + // for JDK 1.7 + if (cl instanceof Closeable) { + ((Closeable) cl).close(); + } + } +} diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/MergedEnumeration2Test.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/MergedEnumeration2Test.java new file mode 100644 index 000000000000..c7296a1ab6bb --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/MergedEnumeration2Test.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class MergedEnumeration2Test { + + @Test + public void hasMoreElements() { + Enumeration enumeration0 = newEnumeration("a", "b", "c"); + Enumeration enumeration1 = newEnumeration("1", "2", "3"); + + Enumeration mergedEnumeration = new MergedEnumeration2(enumeration0, enumeration1); + + List list = Collections.list(mergedEnumeration); + + Assert.assertEquals(6, list.size()); + Assert.assertEquals(Arrays.asList("a", "b", "c", "1", "2", "3"), list); + } + + private Enumeration newEnumeration(T... t) { + return Collections.enumeration(Arrays.asList(t)); + } + + @Test + public void null0() { + Enumeration enumeration0 = null; + Enumeration enumeration1 = newEnumeration("1", "2", "3"); + + Enumeration mergedEnumeration = new MergedEnumeration2(enumeration0, enumeration1); + + List list = Collections.list(mergedEnumeration); + + Assert.assertEquals(3, list.size()); + Assert.assertEquals(Arrays.asList("1", "2", "3"), list); + } + + + @Test + public void null1() { + Enumeration enumeration0 = newEnumeration("a", "b", "c"); + Enumeration enumeration1 = null; + + Enumeration mergedEnumeration = new MergedEnumeration2(enumeration0, enumeration1); + + List list = Collections.list(mergedEnumeration); + + Assert.assertEquals(3, list.size()); + Assert.assertEquals(Arrays.asList("a", "b", "c"), list); + } + +} \ No newline at end of file diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointClassLoaderTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointClassLoaderTest.java new file mode 100644 index 000000000000..254a859e64d2 --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointClassLoaderTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import com.navercorp.pinpoint.common.util.CodeSourceUtils; +import org.junit.Assert; +import org.junit.Test; + +import java.net.URL; + + +/** + * @author emeroad + */ +public class PinpointClassLoaderTest { + + private final Class slf4jClass = org.slf4j.LoggerFactory.class; + + @Test + public void testOnLoadClass() throws Exception { + ClassLoader classLoader = onLoadTest(Java6ClassLoader.class, slf4jClass); + + ClassLoaderUtils.close(classLoader); + } + + /** + * TODO duplicate code + */ + private ClassLoader onLoadTest(Class classLoaderType, Class testClass) throws ClassNotFoundException { + URL testClassJar = CodeSourceUtils.getCodeLocation(testClass); + URL[] urls = {testClassJar}; + ClassLoader cl = PinpointClassLoaderFactory.createClassLoader(this.getClass().getName(), urls, null, ProfilerLibs.PINPOINT_PROFILER_CLASS); + Assert.assertSame(cl.getClass(), classLoaderType); + + try { + cl.loadClass("test"); + Assert.fail(); + } catch (ClassNotFoundException ignored) { + } + + Class selfLoadClass = cl.loadClass(testClass.getName()); + Assert.assertNotSame(testClass, selfLoadClass); + Assert.assertSame(cl, selfLoadClass.getClassLoader()); + Assert.assertSame(testClass.getClassLoader(), this.getClass().getClassLoader()); + return cl; + } + +} diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointURLClassLoaderTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointURLClassLoaderTest.java deleted file mode 100644 index 37b64fab9c10..000000000000 --- a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/PinpointURLClassLoaderTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.bootstrap.classloader; - -import org.junit.Assert; -import org.junit.Test; - -import java.net.URL; -import java.net.URLClassLoader; - -/** - * @author emeroad - */ -public class PinpointURLClassLoaderTest { - - @Test - public void testOnLoadClass() throws Exception { - - URLClassLoader cl = PinpointClassLoaderFactory.createClassLoader(new URL[]{}, Thread.currentThread().getContextClassLoader()); - - try { - cl.loadClass("test"); - Assert.fail(); - } catch (ClassNotFoundException ignored) { - } - -// try { -// cl.loadClass("com.navercorp.pinpoint.profiler.DefaultAgent"); -// } catch (ClassNotFoundException e) { -// -// } - // should be able to test using the above code, but it is not possible from bootstrap testcase. - // it could be possible by specifying the full path to the URL classloader, but it would be harder to maintain. - // for now, just test if DefaultAgent is specified to be loaded - - if (cl instanceof PinpointURLClassLoader) { - Assert.assertTrue(((PinpointURLClassLoader)cl).onLoadClass("com.navercorp.pinpoint.profiler.DefaultAgent")); - } else { - Assert.fail(); - } - - } -} diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibClassTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibClassTest.java new file mode 100644 index 000000000000..036f24cc0bf9 --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/classloader/ProfilerLibClassTest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.classloader; + +import org.junit.Assert; +import org.junit.Test; +/** + * @author Woonduk Kang(emeroad) + */ +public class ProfilerLibClassTest { + + @Test + public void onLoadClass() { + LibClass libClass = new ProfilerLibClass(ProfilerLibs.PINPOINT_PROFILER_CLASS); + Assert.assertTrue(libClass.onLoadClass("com.navercorp.pinpoint.profiler.XXX")); + } +} \ No newline at end of file diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/config/HttpStatusCodeErrorsTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/config/HttpStatusCodeErrorsTest.java new file mode 100644 index 000000000000..93166be8ce2e --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/config/HttpStatusCodeErrorsTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.config; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.*; + +public class HttpStatusCodeErrorsTest { + @Test + public void isErrorCode() throws Exception { + // default 5xx + HttpStatusCodeErrors defaultHttpStatusCodeErrors = new HttpStatusCodeErrors(); + assertTrue(defaultHttpStatusCodeErrors.isErrorCode(500)); + assertTrue(defaultHttpStatusCodeErrors.isErrorCode(501)); + assertFalse(defaultHttpStatusCodeErrors.isErrorCode(200)); + assertFalse(defaultHttpStatusCodeErrors.isErrorCode(999)); + assertFalse(defaultHttpStatusCodeErrors.isErrorCode(0)); + assertFalse(defaultHttpStatusCodeErrors.isErrorCode(-1)); + + HttpStatusCodeErrors customHttpStatusCodeErrors = new HttpStatusCodeErrors(Arrays.asList("5xx", "401", "402")); + assertTrue(customHttpStatusCodeErrors.isErrorCode(500)); + assertTrue(customHttpStatusCodeErrors.isErrorCode(501)); + assertTrue(customHttpStatusCodeErrors.isErrorCode(401)); + assertTrue(customHttpStatusCodeErrors.isErrorCode(402)); + + assertFalse(customHttpStatusCodeErrors.isErrorCode(100)); + assertFalse(customHttpStatusCodeErrors.isErrorCode(200)); + assertFalse(customHttpStatusCodeErrors.isErrorCode(201)); + assertFalse(customHttpStatusCodeErrors.isErrorCode(300)); + assertFalse(customHttpStatusCodeErrors.isErrorCode(400)); + assertFalse(customHttpStatusCodeErrors.isErrorCode(404)); + } + + @Test + public void isHttpStatusCode() throws Exception { + HttpStatusCodeErrors httpStatusCodeErrors = new HttpStatusCodeErrors(); + assertTrue(httpStatusCodeErrors.isHttpStatusCode(200)); + assertTrue(httpStatusCodeErrors.isHttpStatusCode(300)); + assertTrue(httpStatusCodeErrors.isHttpStatusCode(500)); + + assertFalse(httpStatusCodeErrors.isHttpStatusCode(0)); + assertFalse(httpStatusCodeErrors.isHttpStatusCode(600)); + } +} \ No newline at end of file diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/http/HttpStatusCodeRecorderTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/http/HttpStatusCodeRecorderTest.java index 27eb021630f6..0aa7975bf861 100644 --- a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/http/HttpStatusCodeRecorderTest.java +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/http/HttpStatusCodeRecorderTest.java @@ -16,12 +16,12 @@ package com.navercorp.pinpoint.bootstrap.plugin.http; +import com.navercorp.pinpoint.bootstrap.config.HttpStatusCodeErrors; import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; import org.junit.Test; import java.util.Arrays; -import static org.junit.Assert.*; import static org.mockito.Mockito.mock; /** @@ -33,7 +33,8 @@ public class HttpStatusCodeRecorderTest { public void record() throws Exception { final SpanRecorder spanRecorder = mock(SpanRecorder.class); - HttpStatusCodeRecorder recorder = new HttpStatusCodeRecorder(Arrays.asList("5xx")); + HttpStatusCodeErrors errors = new HttpStatusCodeErrors(Arrays.asList("5xx", "401", "402")); + HttpStatusCodeRecorder recorder = new HttpStatusCodeRecorder(errors); recorder.record(spanRecorder, 500); recorder.record(spanRecorder, 200); @@ -45,27 +46,4 @@ public void record() throws Exception { recorder.record(spanRecorder, -1); recorder.record(spanRecorder, 999); } - - @Test - public void isFailed() throws Exception { - HttpStatusCodeRecorder recorder = new HttpStatusCodeRecorder(Arrays.asList("5xx", "401", "402")); - - assertTrue(recorder.isFailed(500)); - assertTrue(recorder.isFailed(501)); - assertTrue(recorder.isFailed(401)); - assertTrue(recorder.isFailed(402)); - - assertFalse(recorder.isFailed(100)); - assertFalse(recorder.isFailed(200)); - assertFalse(recorder.isFailed(201)); - assertFalse(recorder.isFailed(300)); - assertFalse(recorder.isFailed(400)); - assertFalse(recorder.isFailed(404)); - - // out of range - assertFalse(recorder.isFailed(0)); - assertFalse(recorder.isFailed(999)); - assertFalse(recorder.isFailed(-1)); - assertFalse(recorder.isFailed(99)); - } } \ No newline at end of file diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/ObjectConverterTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/ObjectConverterTest.java new file mode 100644 index 000000000000..34f65e61c993 --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/jdbc/bindvalue/ObjectConverterTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.jdbc.bindvalue; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.Time; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ObjectConverterTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void convert_sqlTime() { + Time sqlTime = new Time(System.currentTimeMillis()); + String convert = convert(sqlTime); + + logger.debug("{}", convert); + } + + @Test + public void convert_byte() { + byte byte1 = 0; + String convert = convert(byte1); + + logger.debug("{}", convert); + } + + private String convert(Object param) { + Object[] args = new Object[] { new Object(), param }; + ObjectConverter objectConverter = new ObjectConverter(); + return objectConverter.convert(args); + } +} \ No newline at end of file diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderRecorderTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderRecorderTest.java index 8e4eaefdf7b9..408532e1138a 100644 --- a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderRecorderTest.java +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/proxy/ProxyHttpHeaderRecorderTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,12 +19,16 @@ import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.plugin.RequestWrapper; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServerRequestWrapper; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServerRequestWrapperAdaptor; import org.junit.Test; import java.util.Arrays; import java.util.List; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -48,20 +52,61 @@ public void record() throws Exception { // SpanRecorder SpanRecorder spanRecorder = mock(SpanRecorder.class); + RequestAdaptor requestWrapperAdaptor = new ServerRequestWrapperAdaptor(); + ProxyHttpHeaderRecorder recorder = new ProxyHttpHeaderRecorder(true, requestWrapperAdaptor); - ProxyHttpHeaderRecorder recorder = new ProxyHttpHeaderRecorder(true); - recorder.record(spanRecorder, new ProxyHttpHeaderHandler() { + recorder.record(spanRecorder, new ServerRequestWrapper() { @Override - public String read(String name) { + public String getHeader(String name) { return name; } + + @Override + public String getRpcName() { + return null; + } + + @Override + public String getEndPoint() { + return null; + } + + @Override + public String getRemoteAddress() { + return null; + } + + @Override + public String getAcceptorHost() { + return null; + } }); - recorder.record(spanRecorder, new ProxyHttpHeaderHandler() { + recorder.record(spanRecorder, new ServerRequestWrapper() { @Override - public String read(String name) { + public String getHeader(String name) { throw new NullPointerException(); } + + @Override + public String getRpcName() { + return null; + } + + @Override + public String getEndPoint() { + return null; + } + + @Override + public String getRemoteAddress() { + return null; + } + + @Override + public String getAcceptorHost() { + return null; + } }); } } \ No newline at end of file diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestWrapperReaderTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestWrapperReaderTest.java new file mode 100644 index 000000000000..715a6f6271ad --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/request/RequestWrapperReaderTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request; + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import org.junit.Test; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyShort; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import static org.junit.Assert.*; + +/** + * @author jaehong.kim + */ +public class RequestWrapperReaderTest { + + @Test + public void read() throws Exception { + // disable sampling + Trace disableTrace = mock(Trace.class); + when(disableTrace.canSampled()).thenReturn(Boolean.FALSE); + + // continue trace + Trace continueTrace = mock(Trace.class); + when(continueTrace.canSampled()).thenReturn(Boolean.TRUE); + + // new trace + Trace newTrace = mock(Trace.class); + when(newTrace.canSampled()).thenReturn(Boolean.TRUE); + + TraceContext traceContext = mock(TraceContext.class); + when(traceContext.disableSampling()).thenReturn(disableTrace); + when(traceContext.continueTraceObject(any(TraceId.class))).thenReturn(continueTrace); + when(traceContext.newTraceObject()).thenReturn(newTrace); + when(traceContext.getProfilerConfig()).thenReturn(new DefaultProfilerConfig()); + + TraceId traceId = mock(TraceId.class); + when(traceContext.createTraceId(anyString(), anyLong(), anyLong(), anyShort())).thenReturn(traceId); + RequestAdaptor serverRequestWrapperAdaptor = new ServerRequestWrapperAdaptor(); + final RequestTraceReader reader = new RequestTraceReader(traceContext, serverRequestWrapperAdaptor); + + // sampling flag is true + ServerRequestWrapper samplingFlagServerRequestWrapper = mock(ServerRequestWrapper.class); + when(samplingFlagServerRequestWrapper.getHeader(Header.HTTP_SAMPLED.toString())).thenReturn("s0"); + assertEquals(disableTrace, reader.read(samplingFlagServerRequestWrapper)); + + // continue trace + ServerRequestWrapper continueServerRequestWrapper = mock(ServerRequestWrapper.class); + when(continueServerRequestWrapper.getHeader(Header.HTTP_TRACE_ID.toString())).thenReturn("avcrawler01.ugedit^1517877953952^1035131"); + when(continueServerRequestWrapper.getHeader(Header.HTTP_PARENT_SPAN_ID.toString())).thenReturn("1"); + when(continueServerRequestWrapper.getHeader(Header.HTTP_SPAN_ID.toString())).thenReturn("1"); + when(continueServerRequestWrapper.getHeader(Header.HTTP_FLAGS.toString())).thenReturn("1"); + assertEquals(continueTrace, reader.read(continueServerRequestWrapper)); + + // new trace + ServerRequestWrapper newServerRequestWrapper = mock(ServerRequestWrapper.class); + assertEquals(newTrace, reader.read(newServerRequestWrapper)); + } +} \ No newline at end of file diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/NameSpaceCheckFactoryTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/NameSpaceCheckFactoryTest.java new file mode 100644 index 000000000000..10c6445b284f --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/request/util/NameSpaceCheckFactoryTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.request.util; + +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServerRequestWrapper; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServerRequestWrapperAdaptor; +import org.junit.Assert; +import org.junit.Test; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author Woonduk Kang(emeroad) + */ +public class NameSpaceCheckFactoryTest { + + @Test + public void newNamespace_valid() { + String myNamespace = "myNamespace"; + NameSpaceChecker myNamespaceChecker = newNameSpaceChecker(myNamespace); + + ServerRequestWrapper serverRequestWrapper = mock(ServerRequestWrapper.class); + when(serverRequestWrapper.getHeader(anyString())).thenReturn(myNamespace); + + Assert.assertTrue(myNamespaceChecker.checkNamespace(serverRequestWrapper)); + } + + @Test + public void newNamespace_empty_namespace() { + String myNamespace = "myNamespace"; + NameSpaceChecker myNamespaceChecker = newNameSpaceChecker(myNamespace); + + ServerRequestWrapper serverRequestWrapper = mock(ServerRequestWrapper.class); + when(serverRequestWrapper.getHeader(anyString())).thenReturn(null); + + Assert.assertTrue(myNamespaceChecker.checkNamespace(serverRequestWrapper)); + } + + @Test + public void newNamespace_collision() { + String myNamespace = "myNamespace"; + NameSpaceChecker myNamespaceChecker = newNameSpaceChecker(myNamespace); + + ServerRequestWrapper serverRequestWrapper = mock(ServerRequestWrapper.class); + when(serverRequestWrapper.getHeader(anyString())).thenReturn("collision_namespace"); + + Assert.assertFalse(myNamespaceChecker.checkNamespace(serverRequestWrapper)); + } + + @Test + public void newNamespace_empty_config() { + String myNamespace = ""; + NameSpaceChecker myNamespaceChecker = newNameSpaceChecker(myNamespace); + + ServerRequestWrapper serverRequestWrapper = mock(ServerRequestWrapper.class); + when(serverRequestWrapper.getHeader(anyString())).thenReturn("invalid_namespace"); + + Assert.assertTrue(myNamespaceChecker.checkNamespace(serverRequestWrapper)); + } + + private NameSpaceChecker newNameSpaceChecker(String myNamespace) { + RequestAdaptor requestAdaptor = new ServerRequestWrapperAdaptor(); + return NameSpaceCheckFactory.newNamespace(requestAdaptor, myNamespace); + } +} \ No newline at end of file diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTraceFieldTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTraceFieldTest.java new file mode 100644 index 000000000000..60cff2ac1104 --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/test/ExpectedTraceFieldTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.test; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Taejin Koo + */ +public class ExpectedTraceFieldTest { + + private final String message = "message"; + private final String message1 = "message1"; + private final String message2 = "message2"; + private final String failMessage = "fail"; + private final String emptyMessage = ""; + private final String nullMessage = null; + + @Test + public void alwaysTrueTest() { + ExpectedTraceField expectedTraceField = ExpectedTraceField.create(null); + assertField(expectedTraceField, true, true, true, true, true, true); + } + + @Test + public void alwaysTrueTest2() { + ExpectedTraceField expectedTraceField = ExpectedTraceField.createAlwaysTrue(); + assertField(expectedTraceField, true, true, true, true, true, true); + } + + @Test + public void equalsTest() { + ExpectedTraceField expectedTraceField = ExpectedTraceField.create(message); + assertField(expectedTraceField, true, false, false, false, false, false); + } + + @Test + public void equalsTest2() { + ExpectedTraceField expectedTraceField = ExpectedTraceField.createEquals(message); + assertField(expectedTraceField, true, false, false, false, false, false); + } + + @Test + public void containsTest() { + ExpectedTraceField expectedTraceField = ExpectedTraceField.createContains(message); + assertField(expectedTraceField, true, true, true, false, false, false); + } + + @Test + public void emptyTest() { + ExpectedTraceField expectedTraceField = ExpectedTraceField.createEmpty(); + assertField(expectedTraceField, false, false, false, false, true, true); + } + + @Test + public void notEmptyTest() { + ExpectedTraceField expectedTraceField = ExpectedTraceField.createNotEmpty(); + assertField(expectedTraceField, true, true, true, true, false, false); + } + + @Test + public void startWithTest() { + ExpectedTraceField expectedTraceField = ExpectedTraceField.createStartWith(message); + assertField(expectedTraceField, true, true, true, false, false, false); + } + + + private void assertField(ExpectedTraceField expectedTraceField, boolean boolean1, boolean boolean2, boolean boolean3, boolean boolean4, boolean boolean5, boolean boolean6) { + Assert.assertEquals(boolean1, expectedTraceField.isEquals(message)); + Assert.assertEquals(boolean2, expectedTraceField.isEquals(message1)); + Assert.assertEquals(boolean3, expectedTraceField.isEquals(message2)); + Assert.assertEquals(boolean4, expectedTraceField.isEquals(failMessage)); + Assert.assertEquals(boolean5, expectedTraceField.isEquals(emptyMessage)); + Assert.assertEquals(boolean6, expectedTraceField.isEquals(nullMessage)); + } + +} diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/util/SocketAddressUtilsTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/util/SocketAddressUtilsTest.java new file mode 100644 index 000000000000..2ffa1c97abc1 --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/plugin/util/SocketAddressUtilsTest.java @@ -0,0 +1,290 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.plugin.util; + +import com.navercorp.pinpoint.common.util.JvmUtils; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.AssumptionViolatedException; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.Collections; + +/** + * @author HyunGil Jeong + */ +public class SocketAddressUtilsTest { + + private static final String VALID_HOST = "naver.com"; + private static final String INVALID_HOST = "pinpoint-none-existent-domain-hopefully"; + + private static final Logger LOGGER = LoggerFactory.getLogger(SocketAddressUtilsTest.class); + + private static NameServiceReplacer NAME_SERVICE_REPLACER; + + @BeforeClass + public static void setUpBeforeClass() { + NAME_SERVICE_REPLACER = createNameServiceReplacer(); + } + + @Test + public void fromValidHostName() { + String hostName = VALID_HOST; + InetSocketAddress socketAddress = new InetSocketAddress(hostName, 80); + assertResolved(socketAddress); + + final String expectedHostName = hostName; + final String expectedAddress = socketAddress.getAddress().getHostAddress(); + + verify(socketAddress, expectedHostName, expectedAddress); + } + + @Test + public void fromValidHostNameUnresolved() { + String hostName = VALID_HOST; + InetSocketAddress socketAddress = InetSocketAddress.createUnresolved(hostName, 80); + assertUnresolved(socketAddress); + + final String expectedHostName = hostName; + final String expectedAddress = hostName; + + verify(socketAddress, expectedHostName, expectedAddress); + } + + @Test + public void fromInvalidHostName() { + String hostName = INVALID_HOST; + InetSocketAddress socketAddress = new InetSocketAddress(hostName, 80); + assertUnresolved(socketAddress); + + final String expectedHostName = hostName; + final String expectedAddress = hostName; + + verify(socketAddress, expectedHostName, expectedAddress); + } + + @Test + public void fromAddress() { + String hostName = VALID_HOST; + InetAddress inetAddress = createAddressFromHostName(hostName); + Assume.assumeNotNull(inetAddress); + + String address = inetAddress.getHostAddress(); + InetSocketAddress socketAddress = new InetSocketAddress(address, 80); + assertResolved(socketAddress); + + final String expectedHostName = address; + final String expectedAddress = address; + + verify(socketAddress, expectedHostName, expectedAddress); + } + + @Test + public void fromLookedUpAddress() { + String hostName = VALID_HOST; + InetAddress inetAddress = createAddressFromHostName(hostName); + Assume.assumeNotNull(inetAddress); + + String address = inetAddress.getHostAddress(); + InetSocketAddress socketAddress = new InetSocketAddress(address, 80); + assertResolved(socketAddress); + + String expectedHostName = socketAddress.getHostName(); // lookup host name + String expectedAddress = address; + + verify(socketAddress, expectedHostName, expectedAddress); + } + + @Test + public void fromLocalAddress() { + InetAddress inetAddress = createLocalAddress(); + Assume.assumeNotNull(inetAddress); + + String address = inetAddress.getHostAddress(); + InetSocketAddress socketAddress = new InetSocketAddress(address, 80); + assertResolved(socketAddress); + + final String expectedHostName = address; + final String expectedAddress = address; + + verify(socketAddress, expectedHostName, expectedAddress); + } + + // Helpers + + private static void assertResolved(InetSocketAddress socketAddress) { + Assert.assertFalse(socketAddress.isUnresolved()); + } + + private static void assertUnresolved(InetSocketAddress socketAddress) { + Assert.assertTrue(socketAddress.isUnresolved()); + } + + private static void verify(InetSocketAddress socketAddress, String expectedHostName, String expectedAddress) { + NAME_SERVICE_REPLACER.replace(); + try { + String actualHostName = SocketAddressUtils.getHostNameFirst(socketAddress); + String actualAddress = SocketAddressUtils.getAddressFirst(socketAddress); + LOGGER.info("expectedHostName : {}, actualHostName : {}", expectedHostName, actualHostName); + LOGGER.info("expectedAddress : {}, actualAddress : {}", expectedAddress, actualAddress); + Assert.assertEquals(expectedHostName, actualHostName); + Assert.assertEquals(expectedAddress, actualAddress); + } finally { + NAME_SERVICE_REPLACER.rollback(); + } + } + + private static InetAddress createLocalAddress() { + try { + return InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + LOGGER.warn("Error creating local InetAddress", e); + return null; + } + } + + private static InetAddress createAddressFromHostName(String hostName) { + try { + return InetAddress.getByName(hostName); + } catch (UnknownHostException e) { + LOGGER.warn("Error creating InetAddress from host : {}", hostName, e); + return null; + } + } + + private interface NameServiceReplacer { + void replace(); + void rollback(); + } + + private static NameServiceReplacer createNameServiceReplacer() { + + Class nameServiceClass = null; + try { + // pre jdk 9 + nameServiceClass = Class.forName("sun.net.spi.nameservice.NameService"); + } catch (ClassNotFoundException e) { + try { + // post jdk 9 + nameServiceClass = Class.forName("java.net.InetAddress$NameService"); + } catch (ClassNotFoundException e1) { + // ignore and skip test below + } + } + + if (nameServiceClass == null) { + LOGGER.error("[{}] {} - NameService class not found, skipping test.", + JvmUtils.getType(), JvmUtils.getVersion()); + throw new AssumptionViolatedException("NameService class required for test not found."); + } + + ClassLoader cl = InetAddress.class.getClassLoader(); + final Object proxy = Proxy.newProxyInstance(cl, new Class[]{nameServiceClass}, new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String methodName = method.getName(); + if (methodName.equals("lookupAllHostAddr")) { + throw new UnsupportedOperationException("DNS lookup should not be made"); + } else if (methodName.equals("getHostByAddr")) { + throw new UnsupportedOperationException("Reverse DNS lookup should not be made"); + } else if (methodName.equals("toString")) { + return SocketAddressUtilsTest.class.getSimpleName() + " Name Service"; + } else { + LOGGER.error("[{}] {} - Unexpected method invocation : {}", + JvmUtils.getType(), JvmUtils.getVersion(), methodName); + throw new IllegalStateException("Unknown method : " + methodName + " invoked"); + } + } + }); + + // jdk 7, 8 + final String nameServicesFieldName = "nameServices"; + final Object nameServicesFieldValue = getNameServiceFieldValue(nameServicesFieldName); + if (nameServicesFieldValue != null) { + return new NameServiceReplacer() { + @Override + public void replace() { + setNameServiceFieldValue(nameServicesFieldName, Collections.singletonList(proxy)); + } + + @Override + public void rollback() { + setNameServiceFieldValue(nameServicesFieldName, nameServicesFieldValue); + } + }; + } + + // jdk 6, jdk 9+ + final String nameServiceFieldName = "nameService"; + final Object nameServiceFieldValue = getNameServiceFieldValue(nameServiceFieldName); + if (nameServiceFieldValue != null) { + return new NameServiceReplacer() { + @Override + public void replace() { + setNameServiceFieldValue(nameServiceFieldName, proxy); + } + + @Override + public void rollback() { + setNameServiceFieldValue(nameServiceFieldName, nameServiceFieldValue); + } + }; + } + + LOGGER.error("[{}] {} - Field for name service not found.", JvmUtils.getType(), JvmUtils.getVersion()); + throw new AssumptionViolatedException("Cannot find field for name service."); + } + + private static Object getNameServiceFieldValue(String fieldName) { + try { + Field nameServiceField = InetAddress.class.getDeclaredField(fieldName); + nameServiceField.setAccessible(true); + return nameServiceField.get(null); + } catch (NoSuchFieldException e) { + // This can happen depending on jvm + return null; + } catch (Exception e) { + LOGGER.error("[{}] {} - Unexpected error while getting field [{}], skipping test", + JvmUtils.getType(), JvmUtils.getVersion(), fieldName, e); + throw new AssumptionViolatedException("Unexpected reflection exception", e); + } + } + + private static void setNameServiceFieldValue(String fieldName, Object nameService) { + try { + Field nameServiceField = InetAddress.class.getDeclaredField(fieldName); + nameServiceField.setAccessible(true); + nameServiceField.set(null, nameService); + } catch (NoSuchFieldException e) { + throw new IllegalStateException("Expected field : [" + fieldName + "] not found"); + } catch (Exception e) { + LOGGER.error("[{}] {} - Unexpected error while setting field [{}], skipping test", + JvmUtils.getType(), JvmUtils.getVersion(), fieldName, e); + throw new AssumptionViolatedException("Unexpected reflection exception", e); + } + } +} diff --git a/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/util/PlatformClassLoaderUtilsTest.java b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/util/PlatformClassLoaderUtilsTest.java new file mode 100644 index 000000000000..e37a3e900a82 --- /dev/null +++ b/bootstrap-core/src/test/java/com/navercorp/pinpoint/bootstrap/util/PlatformClassLoaderUtilsTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.util; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PlatformClassLoaderUtilsTest { + + @Test + public void findClassFromPlatformClassLoader_java8() { + //java8 test + PlatformClassLoaderUtils.findClassFromPlatformClassLoader("java.sql.Date"); + } + + @Test + public void getPlatformOrBootstrapClassLoader_java8() { + //java8 test + ClassLoader platformOrBootstrapClassLoader = PlatformClassLoaderUtils.getPlatformOrBootstrapClassLoader(); + ClassLoader classLoader = Object.class.getClassLoader(); + Assert.assertSame(platformOrBootstrapClassLoader, classLoader); + } +} \ No newline at end of file diff --git a/bootstrap-java8/.gitignore b/bootstrap-java8/.gitignore new file mode 100644 index 000000000000..31dc463a2a2b --- /dev/null +++ b/bootstrap-java8/.gitignore @@ -0,0 +1,5 @@ +/.settings/ +/*.iml +/.project +/target/ +/.classpath diff --git a/bootstrap-java8/pom.xml b/bootstrap-java8/pom.xml new file mode 100644 index 000000000000..7e7e04357265 --- /dev/null +++ b/bootstrap-java8/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + 1.8.1-SNAPSHOT + + + pinpoint-bootstrap-java8 + pinpoint-bootstrap-java8 + jar + + + 1.8 + ${env.JAVA_8_HOME} + java18 + + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + + org.slf4j + slf4j-api + test + + + + diff --git a/bootstrap-java8/src/main/java/com/navercorp/pinpoint/bootstrap/java8/lambda/UnsafeDelegatorJava8.java b/bootstrap-java8/src/main/java/com/navercorp/pinpoint/bootstrap/java8/lambda/UnsafeDelegatorJava8.java new file mode 100644 index 000000000000..61a53da8f71b --- /dev/null +++ b/bootstrap-java8/src/main/java/com/navercorp/pinpoint/bootstrap/java8/lambda/UnsafeDelegatorJava8.java @@ -0,0 +1,57 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java8.lambda; + +import com.navercorp.pinpoint.bootstrap.instrument.lambda.LambdaBytecodeHandler; +import sun.misc.Unsafe; + +/** + * @author Woonduk Kang(emeroad) + */ +public class UnsafeDelegatorJava8 { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + private static LambdaBytecodeHandler handler; + + public static void register(LambdaBytecodeHandler handler) { + if (handler == null) { + throw new NullPointerException("handler must not be null"); + } + final LambdaBytecodeHandler localCopy = UnsafeDelegatorJava8.handler; + if (localCopy == null) { + UnsafeDelegatorJava8.handler = handler; + } else { + System.err.println("LambdaBytecodeHandler already registered"); + } + } + + public static Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches) { + if (hostClass == null || data == null) { + throw new NullPointerException(); + } + if (hostClass.isArray() || hostClass.isPrimitive()) { + throw new IllegalArgumentException(); + } + + final LambdaBytecodeHandler localCopy = UnsafeDelegatorJava8.handler; + if (localCopy != null) { + data = localCopy.handleLambdaBytecode(hostClass, data, cpPatches); + } + + return UNSAFE.defineAnonymousClass(hostClass, data, cpPatches); + } + +} diff --git a/bootstrap-java8/src/test/resources/log4j.xml b/bootstrap-java8/src/test/resources/log4j.xml new file mode 100644 index 000000000000..522006d4aa93 --- /dev/null +++ b/bootstrap-java8/src/test/resources/log4j.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bootstrap-java9/.gitignore b/bootstrap-java9/.gitignore new file mode 100644 index 000000000000..31dc463a2a2b --- /dev/null +++ b/bootstrap-java9/.gitignore @@ -0,0 +1,5 @@ +/.settings/ +/*.iml +/.project +/target/ +/.classpath diff --git a/bootstrap-java9/pom.xml b/bootstrap-java9/pom.xml new file mode 100644 index 000000000000..4e2c3ee52e89 --- /dev/null +++ b/bootstrap-java9/pom.xml @@ -0,0 +1,170 @@ + + + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + 1.8.1-SNAPSHOT + + + + 9 + ${env.JAVA_9_HOME} + + + pinpoint-bootstrap-java9 + pinpoint-bootstrap-java9 + jar + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + + + com.navercorp.pinpoint + pinpoint-commons + + + + + org.slf4j + slf4j-api + test + + + + org.slf4j + jcl-over-slf4j + test + + + org.slf4j + slf4j-log4j12 + test + + + log4j + log4j + test + + + commons-io + commons-io + test + + + + + org.openclover + clover + ${plugin.clover.version} + test + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + package + + + + + + pinpoint.bootstrap.java9 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${jdk.version} + ${jdk.version} + true + true + true + ${encoding} + true + ${jdk.version} + ${jdk.home}/bin/javac + + --add-exports=java.base/jdk.internal.loader=ALL-UNNAMED + --add-exports=java.base/jdk.internal.module=ALL-UNNAMED + --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + ${plugin.animal-sniffer.version} + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${plugin.surefire.version} + + + **/Mock* + **/Abstract* + **/*Helper + **/*$* + + + --add-exports java.base/jdk.internal.loader=ALL-UNNAMED + --add-exports java.base/jdk.internal.module=ALL-UNNAMED + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED + -Dfile.encoding=${encoding} + + ${test.jdk.home}/bin/java + once + + + + + + org.openclover + clover-maven-plugin + + + + ${plugin.clover.version} + + true + + + + + + diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9BootLoader.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9BootLoader.java new file mode 100644 index 000000000000..943bf1108d5e --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9BootLoader.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.classloader; + + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; + +/** + * @author Woonduk Kang(emeroad) + */ +class Java9BootLoader { + + Java9BootLoader() { + } + + Enumeration findResources(String name) throws IOException { + return jdk.internal.loader.BootLoader.findResources(name); + } + + URL findResource(String name) { + return jdk.internal.loader.BootLoader.findResource(name); + } + + Class findBootstrapClassOrNull(ClassLoader classLoader, String name) { + return jdk.internal.loader.BootLoader.loadClassOrNull(name); + } + + // SharedSecrets version +// private final jdk.internal.misc.JavaLangAccess javaLangAccess = jdk.internal.misc.SharedSecrets.getJavaLangAccess(); +// @Override +// public Class findBootstrapClassOrNull(ClassLoader classLoader, String name) { +// return javaLangAccess.findBootstrapClassOrNull(classLoader, name); +// } +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9ClassLoader.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9ClassLoader.java new file mode 100644 index 000000000000..73cedc26dee1 --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9ClassLoader.java @@ -0,0 +1,138 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.classloader; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Enumeration; +import java.util.List; + +public class Java9ClassLoader extends URLClassLoader { + + static { + if (!ClassLoader.registerAsParallelCapable()) { + throw new IllegalStateException("registerAsParallelCapable() fail"); + } + } + + private final Java9BootLoader bootLoader = new Java9BootLoader(); + // @Nullable + // WARNING : if parentClassLoader is null. it is bootstrapClassloader + private final ClassLoader parent; + private final ProfilerLibClass profilerLibClass; + + public Java9ClassLoader(String name, URL[] urls, ClassLoader parent, List libClass) { + super(name, urls, parent); + this.parent = parent; + + if (libClass == null) { + throw new NullPointerException("profilerLibClass must not be null"); + } + this.profilerLibClass = new ProfilerLibClass(libClass); + } + + @Override + protected URL findResource(String moduleName, String name) throws IOException { + if (getName().equals(moduleName)) { + return findResource(name); + } + return null; + } + + @Override + public InputStream getResourceAsStream(String name) { + return super.getResourceAsStream(name); + } + + private Object getClassLoadingLock0(String name) { + return getClassLoadingLock(name); + } + + @Override + public URL getResource(String name) { + URL url = findResource(name); + if (url == null) { + if (parent != null) { + url = parent.getResource(name); + } else { + url = bootLoader.findResource(name); + } + } + + return url; + } + + @Override + public Enumeration getResources(String name) throws IOException { + final Enumeration currentResource = findResources(name); + + Enumeration parentResource; + if (parent != null) { + parentResource = parent.getResources(name); + } else { + parentResource = bootLoader.findResources(name); + } + + return new MergedEnumeration2<>(currentResource, parentResource); + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + synchronized (getClassLoadingLock0(name)) { + // First, check if the class has already been loaded + Class clazz = findLoadedClass(name); + if (clazz == null) { + if (onLoadClass(name)) { + // load a class used for Pinpoint itself by this ClassLoader + clazz = findClass(name); + } else { + try { + // load a class by parent ClassLoader + if (parent != null) { + clazz = parent.loadClass(name); + } else { + clazz = bootLoader.findBootstrapClassOrNull(this, name); + } + } catch (ClassNotFoundException ignore) { + } + if (clazz == null) { + // if not found, try to load a class by this ClassLoader + clazz = findClass(name); + } + } + } + if (resolve) { + resolveClass(clazz); + } + return clazz; + } + } + + // for test + private boolean onLoadClass(String name) { + return profilerLibClass.onLoadClass(name); + } + + @Override + public String toString() { + return "Java9ClassLoader{" + + "name=" + getName() + + "} " + super.toString(); + } +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/MergedEnumeration2.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/MergedEnumeration2.java new file mode 100644 index 000000000000..dd1a9baa424d --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/MergedEnumeration2.java @@ -0,0 +1,78 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.classloader; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * @author Woonduk Kang(emeroad) + */ +class MergedEnumeration2 implements Enumeration { + private static final int MAX = 2; + + private final Enumeration enum0; + private final Enumeration enum1; + private int index = 0; + + public MergedEnumeration2(Enumeration enum0, Enumeration enum1) { + this.enum0 = enum0; + this.enum1 = enum1; + } + + private boolean next() { + while (this.index < MAX) { + final Enumeration enumeration = getEnumeration(); + if (enumeration != null && enumeration.hasMoreElements()) { + return true; + } + + nextIndex(); + } + + return false; + } + + private void nextIndex() { + this.index++; + } + + private Enumeration getEnumeration() { + switch (index) { + case 0: + return enum0; + case 1: + return enum1; + default: + throw new NoSuchElementException("index out of range:" + index); + } + } + + public boolean hasMoreElements() { + return this.next(); + } + + public E nextElement() { + if (!this.next()) { + throw new NoSuchElementException(); + } + + Enumeration enumeration = getEnumeration(); + return enumeration.nextElement(); + } + +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/ProfilerLibClass.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/ProfilerLibClass.java new file mode 100644 index 000000000000..33ac06bfc9d5 --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/classloader/ProfilerLibClass.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.classloader; + + +import java.util.List; + +/** + * @author emeroad + */ +public class ProfilerLibClass { + + static final boolean ON_LOAD_CLASS = true; + static final boolean DELEGATE_PARENT = false; + + private final String[] libClass; + + public ProfilerLibClass(List libClass) { + if (libClass == null) { + throw new NullPointerException("libClass must not be null"); + } + this.libClass = libClass.toArray(new String[0]); + } + + + public boolean onLoadClass(String clazzName) { + final int length = libClass.length; + for (int i = 0; i < length; i++) { + if (clazzName.startsWith(libClass[i])) { + return ON_LOAD_CLASS; + } + } + return DELEGATE_PARENT; + } +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/lambda/UnsafeDelegatorJava9.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/lambda/UnsafeDelegatorJava9.java new file mode 100644 index 000000000000..9a442e0cc506 --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/lambda/UnsafeDelegatorJava9.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.lambda; + +import com.navercorp.pinpoint.bootstrap.instrument.lambda.LambdaBytecodeHandler; +import jdk.internal.misc.Unsafe; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class UnsafeDelegatorJava9 { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + private static LambdaBytecodeHandler handler; + + public static void register(LambdaBytecodeHandler handler) { + if (handler == null) { + throw new NullPointerException("handler must not be null"); + } + final LambdaBytecodeHandler localCopy = UnsafeDelegatorJava9.handler; + if (localCopy == null) { + UnsafeDelegatorJava9.handler = handler; + } else { + System.err.println("LambdaBytecodeHandler already registered"); + } + } + + public static Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches) { + if (hostClass == null || data == null) { + throw new NullPointerException(); + } + if (hostClass.isArray() || hostClass.isPrimitive()) { + throw new IllegalArgumentException(); + } + + final LambdaBytecodeHandler localCopy = UnsafeDelegatorJava9.handler; + if (localCopy != null) { + data = localCopy.handleLambdaBytecode(hostClass, data, cpPatches); + } + + return UNSAFE.defineAnonymousClass(hostClass, data, cpPatches); + } + +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ClassFileTransformerModuleWrap.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ClassFileTransformerModuleWrap.java new file mode 100644 index 000000000000..9e4bbe3b4b54 --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ClassFileTransformerModuleWrap.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import com.navercorp.pinpoint.bootstrap.module.ClassFileTransformModuleAdaptor; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.security.ProtectionDomain; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClassFileTransformerModuleWrap implements ClassFileTransformer { + + private final ClassFileTransformModuleAdaptor delegate; + + public ClassFileTransformerModuleWrap(ClassFileTransformModuleAdaptor delegate) { + if (delegate == null) { + throw new NullPointerException("delegate must not be null"); + } + this.delegate = delegate; + } + + @Override + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + return delegate.transform(null, loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + } + + @Override + public byte[] transform(Module module, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + return delegate.transform(module, loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + } + + + +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/DefaultJavaModuleFactory.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/DefaultJavaModuleFactory.java new file mode 100644 index 000000000000..d25485d194d7 --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/DefaultJavaModuleFactory.java @@ -0,0 +1,77 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import com.navercorp.pinpoint.bootstrap.module.JavaModule; +import com.navercorp.pinpoint.bootstrap.module.JavaModuleFactory; + +import java.lang.instrument.Instrumentation; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultJavaModuleFactory implements JavaModuleFactory { + + private final Instrumentation instrumentation; + + public DefaultJavaModuleFactory(Instrumentation instrumentation) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + this.instrumentation = instrumentation; + } + + @Override + public JavaModule wrapFromClass(Class clazz) { + if (clazz == null) { + throw new NullPointerException("clazz must not be null"); + } + return new Java9Module(instrumentation, clazz.getModule()); + } + + @Override + public JavaModule wrapFromModule(Object module) { + if (!(module instanceof Module)) { + throw new IllegalArgumentException("module not java.lang.module"); + } + return new Java9Module(instrumentation, (Module) module); + } + + @Override + public boolean isNamedModule(Object module) { + if (!(module instanceof Module)) { + throw new IllegalArgumentException("module not java.lang.module"); + } + return ((Module) module).isNamed(); + } + + @Override + public Object getUnnamedModule(ClassLoader classLoader) { + if (classLoader == null) { + throw new NullPointerException("classLoader must not be null"); + } + return classLoader.getUnnamedModule(); + } + + @Override + public Object getModule(Class clazz) { + if (clazz == null) { + throw new NullPointerException("clazz must not be null"); + } + return clazz.getModule(); + } +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/JarPackageAnalyzer.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/JarPackageAnalyzer.java new file mode 100644 index 000000000000..0f6883906aed --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/JarPackageAnalyzer.java @@ -0,0 +1,108 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import com.navercorp.pinpoint.common.util.ClassUtils; + +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * @author Woonduk Kang(emeroad) + */ +public class JarPackageAnalyzer implements PackageAnalyzer { + + private static final String META_INF = "META-INF/"; + private static final String CLASS_EXTENSION = ".class"; + + private final JarFile jarFile; + private final JarEntryFilter filter; + + public JarPackageAnalyzer(JarFile jarFile) { + if (jarFile == null) { + throw new NullPointerException("jarFile must not be null"); + } + this.jarFile = jarFile; + this.filter = new PackageFilter(); + } + + @Override + public Set getPackage() { + + final Set packageSet = new HashSet<>(); + + final Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + final JarEntry jarEntry = entries.nextElement(); + + final String packageName = this.filter.filter(jarEntry); + if (packageName == null) { + continue; + } + + packageSet.add(packageName); + } + + return packageSet; + } + + + + interface JarEntryFilter { + String filter(JarEntry jarEntry); + } + + static class PackageFilter implements JarEntryFilter { + public String filter(JarEntry jarEntry) { + if (jarEntry.getName().startsWith(META_INF)) { + // skip META-INF + return null; + } + if (jarEntry.isDirectory()) { + // skip empty dir + return null; + } + + final String fileName = jarEntry.getName(); + if (!checkFIleExtension(fileName, CLASS_EXTENSION)) { + // skip non class file + return null; + } + + final String packageName = ClassUtils.getPackageName(fileName, '/', null); + if (packageName == null) { + return null; + } + return toPackageName(packageName); + } + + private boolean checkFIleExtension(String fileName, String extension) { + return fileName.endsWith(extension); + } + + + private String toPackageName(String dirFormat) { + if (dirFormat == null) { + return null; + } + return dirFormat.replace('/', '.'); + } + } +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/Java9Module.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/Java9Module.java new file mode 100644 index 000000000000..0f0bb600c329 --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/Java9Module.java @@ -0,0 +1,157 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import com.navercorp.pinpoint.bootstrap.module.JavaModule; + +import java.lang.instrument.Instrumentation; +import java.util.Map; +import java.util.Set; + +/** + * @author Woonduk Kang(emeroad) + */ +public class Java9Module implements JavaModule { + +// private final ModuleLogger logger = ModuleLogger.getLogger(Java9Module.class.getName()); + private final Instrumentation instrumentation; + private final Module module; + + + Java9Module(Instrumentation instrumentation, Module module) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + this.instrumentation = instrumentation; + this.module = module; + } + + @Override + public boolean isSupported() { + return true; + } + + @Override + public boolean isNamed() { + return this.module.isNamed(); + } + + @Override + public String getName() { + return this.module.getName(); + + } + + @Override + public void addReads(JavaModule targetJavaModule) { + final Java9Module target = checkJavaModule(targetJavaModule); + +// logger.info("addReads module:" + module.getName() +" target:" + target); + // for debug + final Set readModules = Set.of(target.module); + RedefineModuleUtils.addReads(instrumentation, module, readModules); + } + + @Override + public void addExports(String packageName, JavaModule targetJavaModule) { + if (packageName == null) { + throw new NullPointerException("packageName must not be null"); + } + final Java9Module target = checkJavaModule(targetJavaModule); + +// logger.info("addExports module:" + module.getName() + " pkg:" + packageName + " target:" + target); + final Map> extraModules = Map.of(packageName, Set.of(target.module)); + RedefineModuleUtils.addExports(instrumentation, module, extraModules); + } + + private Java9Module checkJavaModule(JavaModule targetJavaModule) { + if (targetJavaModule == null) { + throw new NullPointerException("targetJavaModule must not be null"); + } + if (targetJavaModule instanceof Java9Module) { + return (Java9Module) targetJavaModule; + } + throw new ModuleException("invalid JavaModule: " + targetJavaModule.getClass()); + } + + @Override + public void addOpens(String packageName, JavaModule javaModule) { + if (packageName == null) { + throw new NullPointerException("packageName must not be null"); + } + final Java9Module target = checkJavaModule(javaModule); + +// logger.info("addExports module:" + module.getName() + " pkg:" + packageName + " target:" + target); + + final Map> extraOpens = Map.of(packageName, Set.of(target.module)); + RedefineModuleUtils.addOpens(instrumentation, module, extraOpens); + } + + + @Override + public void addUses(Class target) { + if (target == null) { + throw new NullPointerException("target must not be null"); + } +// logger.info("addUses module:" + module.getName() +" target:" + target); + // for debug + final Set> extraUses = Set.of(target); + RedefineModuleUtils.addUses(instrumentation, module, extraUses); + } + + @Override + public boolean isExported(String packageName, JavaModule targetJavaModule) { + if (packageName == null) { + throw new NullPointerException("packageName must not be null"); + } + final Java9Module target = checkJavaModule(targetJavaModule); + return module.isExported(packageName, target.module); + } + + @Override + public boolean isOpen(String packageName, JavaModule targetJavaModule) { + if (packageName == null) { + throw new NullPointerException("packageName must not be null"); + } + final Java9Module target = checkJavaModule(targetJavaModule); + return module.isOpen(packageName, target.module); + } + + @Override + public boolean canRead(JavaModule targetJavaModule) { + final Java9Module target = checkJavaModule(targetJavaModule); + return this.module.canRead(target.module); + } + + @Override + public boolean canRead(Class targetClazz) { + return this.module.canUse(targetClazz); + } + + + @Override + public ClassLoader getClassLoader() { + return module.getClassLoader(); + } + + @Override + public String toString() { + return module.toString(); + } + + +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleBuilder.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleBuilder.java new file mode 100644 index 000000000000..759755da1254 --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleBuilder.java @@ -0,0 +1,138 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import jdk.internal.loader.BootLoader; +import jdk.internal.module.Modules; + +import java.io.Closeable; +import java.io.IOException; +import java.lang.module.ModuleDescriptor; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.JarFile; + +/** + * @author Woonduk Kang(emeroad) + */ +class ModuleBuilder { + + private final ModuleLogger logger = ModuleLogger.getLogger(getClass().getName()); + + Module defineModule(String moduleName, ClassLoader classLoader, URL[] urls) { + if (moduleName == null) { + throw new NullPointerException("moduleName must not be null"); + } + if (urls == null) { + throw new NullPointerException("urls must not be null"); + } + if (urls.length == 0) { + throw new IllegalArgumentException("urls.length is 0"); + } + logger.info("bootstrap unnamedModule:" + BootLoader.getUnnamedModule()); + logger.info("platform unnamedModule:" + ClassLoader.getPlatformClassLoader().getUnnamedModule()); + logger.info("system unnamedModule:" + ClassLoader.getSystemClassLoader().getUnnamedModule()); + + Module unnamedModule = classLoader.getUnnamedModule(); + logger.info("defineModule classLoader: " + classLoader); + logger.info("defineModule classLoader-unnamedModule: " + unnamedModule); + + + Set packages = getPackages(urls); + logger.info("packages:" + packages); + + ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(moduleName); + builder.packages(packages); + + ModuleDescriptor moduleDescriptor = builder.build(); + URI url = getInformationURI(urls); + + Module module = Modules.defineModule(classLoader, moduleDescriptor , url); + logger.info("defineModule module:" + module); + return module; + } + + private JarFile newJarFile(URL jarFile) { + try { + if (!jarFile.getProtocol().equals("file")) { + throw new IllegalStateException("invalid file " + jarFile); + } + return new JarFile(jarFile.getFile()); + } catch (IOException e) { + throw new ModuleException(jarFile.getFile() + " create fail " + e.getMessage(), e); + } + } + + private URI getInformationURI(URL[] urls) { + if (isEmpty(urls)) { + return null; + } + final URL url = urls[0]; + try { + return url.toURI(); + } catch (URISyntaxException e) { + throw new IllegalStateException(e); + } + } + + private boolean isEmpty(URL[] urls) { + return urls == null || urls.length == 0; + } + + private Set getPackages(URL[] urls) { + + final Set sum = new HashSet<>(); + for (URL url : urls) { + if (!isJar(url)) { + continue; + } + JarFile jarFile = null; + try { + jarFile = newJarFile(url); + PackageAnalyzer packageAnalyzer = new JarPackageAnalyzer(jarFile); + Set newPackage = packageAnalyzer.getPackage(); + sum.addAll(newPackage); + } finally { + close(jarFile); + } + } + return sum; + } + + private boolean isJar(URL url){ + // filter *.xml + if (url.getPath().endsWith(".jar")) { + return true; + } + return false; + } + + private void close(Closeable closeable) { + if (closeable == null) { + return; + } + try { + closeable.close(); + } catch (IOException ignore) { + // skip + } + } + +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleException.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleException.java new file mode 100644 index 000000000000..f1ed8264a326 --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleException.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ModuleException extends RuntimeException { + public ModuleException(String message) { + super(message); + } + + public ModuleException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleLogger.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleLogger.java new file mode 100644 index 000000000000..97dbacb2318b --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleLogger.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class ModuleLogger { + + private final String loggerName; + private final int prefixSize; + + public static ModuleLogger getLogger(String loggerName) { + return new ModuleLogger(loggerName); + } + + private ModuleLogger(String loggerName) { + this.loggerName = loggerName; + this.prefixSize = getLength(loggerName) + 3; + } + + public void info(String log) { + StringBuilder sb = new StringBuilder(getLength(log) + prefixSize); + sb.append('['); + sb.append(loggerName); + sb.append("] "); + sb.append(log); + System.out.println(sb.toString()); + } + + private int getLength(String log) { + if (log == null) { + return 4; + } + return log.length(); + } + +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleSupport.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleSupport.java new file mode 100644 index 000000000000..ec7ad5a4e333 --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleSupport.java @@ -0,0 +1,189 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + + +import com.navercorp.pinpoint.bootstrap.module.JavaModule; +import jdk.internal.module.Modules; + +import java.lang.instrument.Instrumentation; +import java.net.URL; +import java.util.Optional; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ModuleSupport { + + private final Instrumentation instrumentation; + + private final ModuleLogger logger = ModuleLogger.getLogger(this.getClass().getName()); + + private final JavaModule javaBaseModule; + private final JavaModule bootstrapModule; + + + ModuleSupport(Instrumentation instrumentation) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + this.instrumentation = instrumentation; + this.javaBaseModule = wrapJavaModule(Object.class); + this.bootstrapModule = wrapJavaModule(this.getClass()); + + } + + public void setup() { + // pinpoint module name : unnamed + JavaModule bootstrapModule = getBootstrapModule(); + logger.info("pinpoint Module id:" + bootstrapModule); + logger.info("pinpoint Module.isNamed:" + bootstrapModule.isNamed()); + logger.info("pinpoint Module.name:" + bootstrapModule.getName()); + + JavaModule baseModule = getJavaBaseModule(); + baseModule.addExports("jdk.internal.loader", bootstrapModule); + baseModule.addExports("jdk.internal.misc", bootstrapModule); + baseModule.addExports("jdk.internal.module", bootstrapModule); + + } + + public void defineAgentModule(ClassLoader classLoader, URL[] jarFileList) { + + final JavaModule agentModule = newAgentModule(classLoader, jarFileList); + + prepareAgentModule(agentModule); + + addPermissionToLog4jModule(agentModule); + addPermissionToGuiceModule(agentModule); + + } + + private JavaModule newAgentModule(ClassLoader classLoader, URL[] jarFileList) { + ModuleBuilder moduleBuilder = new ModuleBuilder(); + final Module agentModule = moduleBuilder.defineModule("pinpoint.agent", classLoader, jarFileList); + return wrapJavaModule(agentModule); + } + + + private void addPermissionToLog4jModule(JavaModule agentModule) { + // required log4j + // configuration parser + JavaModule xmlModule = loadModule("java.xml"); + agentModule.addReads(xmlModule); +// xml-api must be loaded from agentClassLoader -> ProfilerLibs.PINPOINT_PROFILER_CLASS +// ClassLoader agentClassLoader = agentModule.getClass().getClassLoader(); +// Class.forName("javax.xml.parsers.DocumentBuilderFactory", false, agentClassLoader) +// agentModule.addOpens("javax.xml.parsers.DocumentBuilderFactory"); + + // PropertySetter bean.Introspector + JavaModule desktopModule = loadModule("java.desktop"); + agentModule.addReads(desktopModule); + } + + private void addPermissionToGuiceModule(JavaModule agentModule) { + JavaModule loggingModule = loadModule("java.logging"); + agentModule.addReads(loggingModule); + + // google guice + // java.base does not "opens java.lang" to module pinpoint.agent + // at pinpoint.agent/com.google.inject.internal.cglib.core.$ReflectUtils.(ReflectUtils.java:42) + JavaModule javaBaseModule = getJavaBaseModule(); + javaBaseModule.addOpens("java.lang", agentModule); + } + + + private void prepareAgentModule(JavaModule agentModule) { + JavaModule bootstrapModule = getBootstrapModule(); + // Error:class com.navercorp.pinpoint.bootstrap.AgentBootLoader$1 cannot access class com.navercorp.pinpoint.profiler.DefaultAgent (in module pinpoint.agent) + // because module pinpoint.agent does not export com.navercorp.pinpoint.profiler to unnamed module @7bfcd12c + agentModule.addExports("com.navercorp.pinpoint.profiler", bootstrapModule); + agentModule.addReads(bootstrapModule); + + // Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected void java.net.URLClassLoader.addURL(java.net.URL) accessible: + // module java.base does not "opens java.net" to module pinpoint.agent + // at pinpoint.agent/pinpoint.agent/com.navercorp.pinpoint.profiler.instrument.classloading.URLClassLoaderHandler.(URLClassLoaderHandler.java:44) + JavaModule baseModule = getJavaBaseModule(); + baseModule.addOpens("java.net", agentModule); + + // for Java9DefineClass + baseModule.addExports("jdk.internal.misc", agentModule); + + final JavaModule instrumentModule = loadModule("java.instrument"); + agentModule.addReads(instrumentModule); + + final JavaModule managementModule = loadModule("java.management"); + agentModule.addReads(managementModule); + + // DefaultCpuLoadMetric : com.sun.management.OperatingSystemMXBean + final JavaModule jdkManagement = loadModule("jdk.management"); + agentModule.addReads(jdkManagement); + +// LongAdder +// final Module unsupportedModule = loadModule("jdk.unsupported"); +// Set readModules = Set.of(instrumentModule, managementModule, jdkManagement, unsupportedModule); + + ClassLoader bootstrapClassLoader = Object.class.getClassLoader(); + Class traceMataDataClass = forName("com.navercorp.pinpoint.common.trace.TraceMetadataProvider", bootstrapClassLoader); + agentModule.addUses(traceMataDataClass); + + Class pluginClazz = forName( "com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin", bootstrapClassLoader); + agentModule.addUses(pluginClazz); + } + + + + private Class forName(String className, ClassLoader classLoader) { + try { + return Class.forName(className, false, classLoader); + } catch (ClassNotFoundException e) { + throw new ModuleException(className + " not found Caused by:" + e.getMessage(), e); + } + } + + + private JavaModule loadModule(String moduleName) { + // force base-module loading + logger.info("loadModule:" + moduleName); + final Module module = Modules.loadModule(moduleName); + return wrapJavaModule(module); + +// final ModuleLayer boot = ModuleLayer.boot(); +// Optional optionalModule = boot.findModule(moduleName); +// if (optionalModule.isPresent()) { +// Module module = optionalModule.get(); +// return wrapJavaModule(module); +// } +// throw new ModuleException(moduleName + " not found"); + } + + private JavaModule wrapJavaModule(Class clazz) { + return new Java9Module(instrumentation, clazz.getModule()); + } + + private JavaModule wrapJavaModule(Module module) { + return new Java9Module(instrumentation, module); + } + + private JavaModule getJavaBaseModule() { + return javaBaseModule; + } + + private JavaModule getBootstrapModule() { + return bootstrapModule; + } + +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleSupportFactory.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleSupportFactory.java new file mode 100644 index 000000000000..50a99d4b5a2d --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleSupportFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import java.lang.instrument.Instrumentation; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ModuleSupportFactory { + public ModuleSupportFactory() { + } + + public ModuleSupport newModuleSupport(Instrumentation instrumentation) { + return new ModuleSupport(instrumentation); + } +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/PackageAnalyzer.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/PackageAnalyzer.java new file mode 100644 index 000000000000..dbeb7afdcbcd --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/PackageAnalyzer.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import java.util.Set; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface PackageAnalyzer { + + Set getPackage(); +} diff --git a/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/RedefineModuleUtils.java b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/RedefineModuleUtils.java new file mode 100644 index 000000000000..155f0a47636b --- /dev/null +++ b/bootstrap-java9/src/main/java/com/navercorp/pinpoint/bootstrap/java9/module/RedefineModuleUtils.java @@ -0,0 +1,112 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import java.lang.instrument.Instrumentation; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Woonduk Kang(emeroad) + */ +final class RedefineModuleUtils { + + private RedefineModuleUtils() { + } + + static void addReads(Instrumentation instrumentation, Module module, Set extraReads) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + if (module == null) { + throw new NullPointerException("module must not be null"); + } + if (extraReads == null) { + throw new NullPointerException("extraReads must not be null"); + } + + // for debug +// final Set extraReads0 = extraReads; + final Map> extraExports = Map.of(); + final Map> extraOpens = Map.of(); + final Set> extraUses = Set.of(); + final Map, List>> extraProvides = Map.of(); + instrumentation.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides); + } + + static void addExports(Instrumentation instrumentation, Module module, Map> extraExports) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + if (module == null) { + throw new NullPointerException("module must not be null"); + } + if (extraExports == null) { + throw new NullPointerException("extraExports must not be null"); + } + + // for debug + final Set extraReads = Set.of(); +// final Map> extraExports = Map.of(); + final Map> extraOpens = Map.of(); + final Set> extraUses = Set.of(); + final Map, List>> extraProvides = Map.of(); + instrumentation.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides); + } + + static void addOpens(Instrumentation instrumentation, Module module, Map> extraOpens) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + if (module == null) { + throw new NullPointerException("module must not be null"); + } + if (extraOpens == null) { + throw new NullPointerException("extraOpens must not be null"); + } + + // for debug + final Set extraReads = Set.of(); + final Map> extraExports = Map.of(); +// final Map> extraOpens = Map.of(); + final Set> extraUses = Set.of(); + final Map, List>> extraProvides = Map.of(); + instrumentation.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides); + } + + public static void addUses(Instrumentation instrumentation, Module module, Set> extraUses) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + if (module == null) { + throw new NullPointerException("module must not be null"); + } + if (extraUses == null) { + throw new NullPointerException("extraUses must not be null"); + } + + // for debug + final Set extraReads = Set.of(); + final Map> extraExports = Map.of(); + final Map> extraOpens = Map.of(); +// final Set> extraUses = Set.of(); + final Map, List>> extraProvides = Map.of(); + instrumentation.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides); + + } +} diff --git a/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9BootLoaderTest.java b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9BootLoaderTest.java new file mode 100644 index 000000000000..5a01abb28b01 --- /dev/null +++ b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9BootLoaderTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.classloader; + +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class Java9BootLoaderTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void testFindResource() { + + Java9BootLoader bootLoader = new Java9BootLoader(); + String stringResource = getInternalName(String.class); + + URL url = bootLoader.findResource(stringResource); + Assert.assertNotNull(url); + } + + private static String getInternalName(Class clazz) { + String name = clazz.getName(); + return name.replace('.', '/').concat(".class"); + } + + @Test + public void testFindResources() throws IOException { + Java9BootLoader bootLoader = new Java9BootLoader(); + String stringResource = getInternalName(String.class); + + Enumeration bootstrapResources = bootLoader.findResources(stringResource); + List list = Collections.list(bootstrapResources); + Assert.assertEquals(1, list.size()); + logger.debug("list:{}", list); + } +} \ No newline at end of file diff --git a/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9ClassLoaderTest.java b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9ClassLoaderTest.java new file mode 100644 index 000000000000..516275840769 --- /dev/null +++ b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/classloader/Java9ClassLoaderTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.classloader; + +import com.navercorp.pinpoint.bootstrap.classloader.PinpointClassLoaderFactory; +import com.navercorp.pinpoint.bootstrap.classloader.ProfilerLibs; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Closeable; +import java.io.IOException; +import java.net.URL; + +/** + * @author Woonduk Kang(emeroad) + */ +public class Java9ClassLoaderTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final Class slf4jClass = org.slf4j.LoggerFactory.class; + + @Test + public void newClassLoader_bootstrap() throws ClassNotFoundException, IOException { + ClassLoader classLoader = new Java9ClassLoader("test", new URL[0], null, ProfilerLibs.PINPOINT_PROFILER_CLASS); + classLoader.loadClass("java.lang.String"); + close(classLoader); + } + + @Test + public void testOnLoadClass() throws Exception { + + ClassLoader cl = onLoadTest(Java9ClassLoader.class, slf4jClass); + close(cl); + } + + /** + * TODO duplicate code + */ + private ClassLoader onLoadTest(Class classLoaderType, Class testClass) throws ClassNotFoundException { + URL testClassJar = CodeSourceUtils.getCodeLocation(testClass); + URL[] urls = {testClassJar}; + ClassLoader cl = PinpointClassLoaderFactory.createClassLoader(this.getClass().getName(), urls, null, ProfilerLibs.PINPOINT_PROFILER_CLASS); + Assert.assertSame(cl.getClass(), classLoaderType); + + try { + cl.loadClass("test"); + Assert.fail(); + } catch (ClassNotFoundException ignored) { + } + + Class selfLoadClass = cl.loadClass(testClass.getName()); + Assert.assertNotSame(testClass, selfLoadClass); + Assert.assertSame(cl, selfLoadClass.getClassLoader()); + Assert.assertSame(testClass.getClassLoader(), this.getClass().getClassLoader()); + return cl; + } + + + + @Test + public void loadClass_bootstrap() throws Exception { + + ClassLoader cl = PinpointClassLoaderFactory.createClassLoader(this.getClass().getName(), new URL[]{}, null, ProfilerLibs.PINPOINT_PROFILER_CLASS); + Assert.assertTrue(cl instanceof Java9ClassLoader); + + Class stringClazz1 = cl.loadClass("java.lang.String"); + Class stringClazz2 = ClassLoader.getSystemClassLoader().loadClass("java.lang.String"); + Assert.assertSame("reference", stringClazz1, stringClazz2); + Assert.assertSame("classLoader", stringClazz1.getClassLoader(), stringClazz2.getClassLoader()); + + close(cl); + } + + private void close(ClassLoader classLoader) throws IOException { + if (classLoader instanceof Closeable) { + ((Closeable) classLoader).close(); + } + } +} diff --git a/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/classloader/PlatformClassLoaderTest.java b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/classloader/PlatformClassLoaderTest.java new file mode 100644 index 000000000000..c124395d20b8 --- /dev/null +++ b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/classloader/PlatformClassLoaderTest.java @@ -0,0 +1,109 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.classloader; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigDecimal; +import java.sql.Date; + +//import java.util.Date; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PlatformClassLoaderTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Ignore + @Test + public void sqlDate() throws ClassNotFoundException { + Class sqlDateClazz = java.sql.Date.class; + logger.debug("sqlDate module name:{}", sqlDateClazz.getModule().getName()); + logger.debug("sqlDate classLoader:{}", java.sql.Date.class.getClassLoader()); + Class.forName("java.sql.Date", false, ClassLoader.getPlatformClassLoader()); + + try { + ClassLoader bootStrap = Object.class.getClassLoader(); + Class.forName("java.sql.Date", false, bootStrap); + Assert.fail(); + } catch (ClassNotFoundException e) { + // skip + } + } + + @Ignore + @Test + public void testBigDecimal() { + Class bigDecimalClass = BigDecimal.class; + Module module = bigDecimalClass.getModule(); + logger.debug("module:{}", module); + logger.debug("cl:{}", bigDecimalClass.getClassLoader()); + } + + + @Ignore + @Test + public void sqlDate_module() { + Class dateClass = Date.class; + logger.debug("sqlDate module name:{}", dateClass.getModule().getName()); + logger.debug("sqlDate module cl:{}", dateClass.getModule().getClassLoader()); + logger.debug("sqlDate module layer:{}", dateClass.getModule().getLayer()); + + Class objectClass = Object.class; + logger.debug("javaBase module name:{}", objectClass.getModule().getName()); + logger.debug("javaBase module cl:{}", objectClass.getModule().getClassLoader()); + logger.debug("javaBase module layer:{}", objectClass.getModule().getLayer()); + } + + @Ignore + @Test + public void moduleLayer() { + ModuleLayer layer = Object.class.getModule().getLayer(); + + logger.debug("bootstrap-------------"); + for (Module module : layer.modules()) { + if (module.getClassLoader() == null) { + logger.debug("module name:{} ", module.getName()); + } + } + logger.debug("bootstrap-------------"); + + logger.debug("platform-------------"); + for (Module module : layer.modules()) { + if (module.getClassLoader() == ClassLoader.getPlatformClassLoader()) { + logger.debug("module name:{} ", module.getName()); + } + } + logger.debug("platform-------------"); + + + logger.debug("system-------------"); + for (Module module : layer.modules()) { + if (module.getClassLoader() == ClassLoader.getSystemClassLoader()) { + logger.debug("module name:{} ", module.getName()); + } + } + logger.debug("system-------------"); + } +} + diff --git a/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/module/JarPackageAnalyzerTest.java b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/module/JarPackageAnalyzerTest.java new file mode 100644 index 000000000000..951e45f72612 --- /dev/null +++ b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/module/JarPackageAnalyzerTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import com.navercorp.pinpoint.common.util.CodeSourceUtils; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author Woonduk Kang(emeroad) + */ +public class JarPackageAnalyzerTest { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final Set SLF4J_API_PACKAGE = Set.of("org.slf4j", "org.slf4j.event", "org.slf4j.helpers", "org.slf4j.spi"); + + @Test + public void packageAnalyzer() throws IOException { + URL url = CodeSourceUtils.getCodeLocation(Logger.class); + + JarFile jarFile = new JarFile(url.getFile()); + logger.debug("jarFile:{}", jarFile.getName()); + + PackageAnalyzer packageAnalyzer = new JarPackageAnalyzer(jarFile); + Set packageSet = packageAnalyzer.getPackage(); + + logger.debug("package:{}", packageSet); + + Assert.assertEquals(packageSet, SLF4J_API_PACKAGE); + + } + + @Test + public void jarFileToURI() throws IOException { + URL url = CodeSourceUtils.getCodeLocation(Logger.class); + logger.debug("url:{}", url); + + + JarFile jarFile = new JarFile(url.getFile()); + logger.debug("jarFile:{}", jarFile.getName()); + File file = new File(jarFile.getName()); + logger.debug("url1:{}", file.toURI()); + } + + + @Test + public void filter_emptyPackage() { + JarPackageAnalyzer.JarEntryFilter filter = new JarPackageAnalyzer.PackageFilter(); + JarEntry jarEntry = mock(JarEntry.class); + when(jarEntry.getName()).thenReturn("test.class"); + + String empty = filter.filter(jarEntry); + Assert.assertNull(empty); + } +} \ No newline at end of file diff --git a/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleBuilderTest.java b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleBuilderTest.java new file mode 100644 index 000000000000..e2756aa43e29 --- /dev/null +++ b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/java9/module/ModuleBuilderTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.java9.module; + +import com.navercorp.pinpoint.bootstrap.java9.classloader.Java9ClassLoader; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; +import jdk.internal.module.Modules; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.lang.module.ModuleDescriptor; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Set; +import java.util.jar.JarFile; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ModuleBuilderTest { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final Class slf4jClass = org.slf4j.LoggerFactory.class; + + @Test + public void defineModuleTest() throws IOException, URISyntaxException, ClassNotFoundException { + URL testClassJar = CodeSourceUtils.getCodeLocation(slf4jClass); + URL[] urls = {testClassJar}; + + String moduleName = "slf4j.test"; + + + JarFile jarFile = new JarFile(testClassJar.getFile()); + PackageAnalyzer packageAnalyzer = new JarPackageAnalyzer(jarFile); + Set slf4j = packageAnalyzer.getPackage(); + logger.debug("slf4j packages:{}", slf4j); + + Java9ClassLoader classLoader = new Java9ClassLoader(moduleName, urls, this.getClass().getClassLoader(), new ArrayList<>(slf4j)); + + ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(moduleName); + builder.packages(slf4j); + ModuleDescriptor descriptor = builder.build(); + + + Module module = Modules.defineModule(classLoader, descriptor, testClassJar.toURI()); + logger.debug("module:{}", module); + + Class slf4jModule = classLoader.loadClass(slf4jClass.getName()); + logger.debug("slf4j:{}", slf4jModule); + + Assert.assertSame(module, slf4jModule.getModule()); + Assert.assertEquals(module.getName(), slf4jModule.getModule().getName()); + + classLoader.close(); + + } + + @Test + public void moduleBuilderTest() throws IOException { + URL testClassJar = CodeSourceUtils.getCodeLocation(slf4jClass); + URL[] urls = {testClassJar}; + + String moduleName = "slf4j.test"; + + + JarFile jarFile = new JarFile(testClassJar.getFile()); + PackageAnalyzer packageAnalyzer = new JarPackageAnalyzer(jarFile); + Set slf4j = packageAnalyzer.getPackage(); + logger.debug("slf4j packages:{}", slf4j); + + Java9ClassLoader classLoader = new Java9ClassLoader(moduleName, urls, this.getClass().getClassLoader(), new ArrayList<>(slf4j)); + + + ModuleBuilder moduleBuilder = new ModuleBuilder(); + Module module = moduleBuilder.defineModule(ModuleBuilderTest.class.getSimpleName(), classLoader, urls); + + classLoader.close(); + + } + +} \ No newline at end of file diff --git a/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/util/PlatformClassLoaderUtilsTest.java b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/util/PlatformClassLoaderUtilsTest.java new file mode 100644 index 000000000000..4fb4d6f342d0 --- /dev/null +++ b/bootstrap-java9/src/test/java/com/navercorp/pinpoint/bootstrap/util/PlatformClassLoaderUtilsTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.util; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PlatformClassLoaderUtilsTest { + + @Test + public void findClassFromPlatformClassLoader_java9() { + Class sqlDate = PlatformClassLoaderUtils.findClassFromPlatformClassLoader("java.sql.Date"); + Assert.assertNotNull(sqlDate); + } + + @Test + public void getPlatformClassLoader_java9() { + ClassLoader platformOrBootstrapClassLoader = PlatformClassLoaderUtils.getPlatformOrBootstrapClassLoader(); + ClassLoader platformClassLoader2 = ClassLoader.getPlatformClassLoader(); + Assert.assertSame(platformClassLoader2, platformOrBootstrapClassLoader); + } + +} diff --git a/bootstrap-java9/src/test/resources/log4j.xml b/bootstrap-java9/src/test/resources/log4j.xml new file mode 100644 index 000000000000..e26c5cff1277 --- /dev/null +++ b/bootstrap-java9/src/test/resources/log4j.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bootstrap/clover.license b/bootstrap/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/bootstrap/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-bootstrap @@ -65,6 +65,7 @@ true true ${project.version} + ${project.build.finalName}.jar diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentBootLoader.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentBootLoader.java new file mode 100644 index 000000000000..69c3d05dd739 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentBootLoader.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap; + +import java.lang.reflect.Constructor; +import java.net.URL; +import java.util.concurrent.Callable; + + +/** + * @author emeroad + */ +public class AgentBootLoader { + + private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); + + private final ClassLoader classLoader; + + private final String bootClass; + + private final ContextClassLoaderExecuteTemplate executeTemplate; + + public AgentBootLoader(String bootClass, URL[] urls, ClassLoader agentClassLoader) { + if (bootClass == null) { + throw new NullPointerException("bootClass must not be null"); + } + if (urls == null) { + throw new NullPointerException("urls"); + } + this.bootClass = bootClass; + this.classLoader = agentClassLoader; + this.executeTemplate = new ContextClassLoaderExecuteTemplate(agentClassLoader); + } + + public Agent boot(final AgentOption agentOption) { + + final Class bootStrapClazz = getBootStrapClass(); + + final Object agent = executeTemplate.execute(new Callable() { + @Override + public Object call() throws Exception { + try { + Constructor constructor = bootStrapClazz.getDeclaredConstructor(AgentOption.class); + return constructor.newInstance(agentOption); + } catch (InstantiationException e) { + throw new BootStrapException("boot create failed. Error:" + e.getMessage(), e); + } catch (IllegalAccessException e) { + throw new BootStrapException("boot method invoke failed. Error:" + e.getMessage(), e); + } + } + }); + + if (agent instanceof Agent) { + return (Agent) agent; + } else { + String agentClassName; + if (agent == null) { + agentClassName = "Agent is null"; + } else { + agentClassName = agent.getClass().getName(); + } + throw new BootStrapException("Invalid AgentType. boot failed. AgentClass:" + agentClassName); + } + } + + private Class getBootStrapClass() { + try { + return this.classLoader.loadClass(bootClass); + } catch (ClassNotFoundException e) { + throw new BootStrapException("boot class not found. bootClass:" + bootClass + " Error:" + e.getMessage(), e); + } + } + +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentClassLoader.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentClassLoader.java deleted file mode 100644 index f232d0da3e58..000000000000 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentClassLoader.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.bootstrap; - -import com.navercorp.pinpoint.bootstrap.classloader.PinpointClassLoaderFactory; - -import java.lang.reflect.Constructor; -import java.net.URL; -import java.net.URLClassLoader; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.concurrent.Callable; - - -/** - * @author emeroad - */ -public class AgentClassLoader { - - private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); - - private final URLClassLoader classLoader; - - private String bootClass; - - private final ContextClassLoaderExecuteTemplate executeTemplate; - - public AgentClassLoader(URL[] urls) { - if (urls == null) { - throw new NullPointerException("urls"); - } - - ClassLoader bootStrapClassLoader = AgentClassLoader.class.getClassLoader(); - this.classLoader = createClassLoader(urls, bootStrapClassLoader); - - this.executeTemplate = new ContextClassLoaderExecuteTemplate(classLoader); - } - - private URLClassLoader createClassLoader(final URL[] urls, final ClassLoader bootStrapClassLoader) { - if (SECURITY_MANAGER != null) { - return AccessController.doPrivileged(new PrivilegedAction() { - public URLClassLoader run() { - return PinpointClassLoaderFactory.createClassLoader(urls, bootStrapClassLoader); - } - }); - } else { - return PinpointClassLoaderFactory.createClassLoader(urls, bootStrapClassLoader); - } - } - - public void setBootClass(String bootClass) { - this.bootClass = bootClass; - } - - public Agent boot(final AgentOption agentOption) { - - final Class bootStrapClazz = getBootStrapClass(); - - final Object agent = executeTemplate.execute(new Callable() { - @Override - public Object call() throws Exception { - try { - Constructor constructor = bootStrapClazz.getConstructor(AgentOption.class); - return constructor.newInstance(agentOption); - } catch (InstantiationException e) { - throw new BootStrapException("boot create failed. Error:" + e.getMessage(), e); - } catch (IllegalAccessException e) { - throw new BootStrapException("boot method invoke failed. Error:" + e.getMessage(), e); - } - } - }); - - if (agent instanceof Agent) { - return (Agent) agent; - } else { - String agentClassName; - if (agent == null) { - agentClassName = "Agent is null"; - } else { - agentClassName = agent.getClass().getName(); - } - throw new BootStrapException("Invalid AgentType. boot failed. AgentClass:" + agentClassName); - } - } - - private Class getBootStrapClass() { - try { - return this.classLoader.loadClass(bootClass); - } catch (ClassNotFoundException e) { - throw new BootStrapException("boot class not found. bootClass:" + bootClass + " Error:" + e.getMessage(), e); - } - } - -} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentDirBaseClassPathResolver.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentDirBaseClassPathResolver.java deleted file mode 100644 index 3bbf6c2918ff..000000000000 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentDirBaseClassPathResolver.java +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.bootstrap; - - - -import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.jar.JarFile; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @author emeroad - */ -public class AgentDirBaseClassPathResolver implements ClassPathResolver { - - private final BootLogger logger = BootLogger.getLogger(this.getClass().getName()); - - static final String VERSION_PATTERN = "(-[0-9]+\\.[0-9]+\\.[0-9]+((\\-SNAPSHOT)|(-RC[0-9]+))?)?"; - static final Pattern DEFAULT_AGENT_PATTERN = compile("pinpoint-bootstrap" + VERSION_PATTERN + "\\.jar"); - static final Pattern DEFAULT_AGENT_COMMONS_PATTERN = compile("pinpoint-commons" + VERSION_PATTERN + "\\.jar"); - static final Pattern DEFAULT_AGENT_CORE_PATTERN = compile("pinpoint-bootstrap-core" + VERSION_PATTERN + "\\.jar"); - static final Pattern DEFAULT_AGENT_CORE_OPTIONAL_PATTERN = compile("pinpoint-bootstrap-core-optional" + VERSION_PATTERN + "\\.jar"); - static final Pattern DEFAULT_ANNOTATIONS = compile("pinpoint-annotations" + VERSION_PATTERN + "\\.jar"); - - private final Pattern agentPattern; - private final Pattern agentCommonsPattern; - private final Pattern agentCorePattern; - private final Pattern agentCoreOptionalPattern; - private final Pattern annotationsPattern; - - private String classPath; - - private String agentJarName; - private String agentJarFullPath; - private String agentDirPath; - - private List fileExtensionList; - private String pinpointCommonsJar; - private String bootStrapCoreJar; - private String bootStrapCoreOptionalJar; - private String annotationsJar; - - private BootstrapJarFile bootstrapJarFile; - - private static Pattern compile(String regex) { - return Pattern.compile(regex); - } - - public AgentDirBaseClassPathResolver() { - this(getClassPathFromSystemProperty()); - } - - - public AgentDirBaseClassPathResolver(String classPath) { - this.classPath = classPath; - this.agentPattern = DEFAULT_AGENT_PATTERN; - this.agentCommonsPattern = DEFAULT_AGENT_COMMONS_PATTERN; - this.agentCorePattern = DEFAULT_AGENT_CORE_PATTERN; - this.agentCoreOptionalPattern = DEFAULT_AGENT_CORE_OPTIONAL_PATTERN; - this.annotationsPattern = DEFAULT_ANNOTATIONS; - this.fileExtensionList = getDefaultFileExtensionList(); - } - - public List getDefaultFileExtensionList() { - List extensionList = new ArrayList(); - extensionList.add("jar"); - extensionList.add("xml"); - extensionList.add("properties"); - return extensionList; - } - - public AgentDirBaseClassPathResolver(String classPath, String agentPattern) { - this.classPath = classPath; - this.agentPattern = Pattern.compile(agentPattern); - this.agentCommonsPattern = DEFAULT_AGENT_COMMONS_PATTERN; - this.agentCorePattern = DEFAULT_AGENT_CORE_PATTERN; - this.agentCoreOptionalPattern = DEFAULT_AGENT_CORE_OPTIONAL_PATTERN; - this.annotationsPattern = DEFAULT_ANNOTATIONS; - this.fileExtensionList = getDefaultFileExtensionList(); - } - - @Override - public boolean verify() { - - final BootstrapJarFile bootstrapJarFile = new BootstrapJarFile(); - - // 1st find boot-strap.jar - final boolean agentJarNotFound = this.findAgentJar(); - if (!agentJarNotFound) { - logger.warn("pinpoint-bootstrap-x.x.x(-SNAPSHOT).jar not found."); - return false; - } - - // 2nd find pinpoint-commons.jar - final String pinpointCommonsJar = getPinpointCommonsJar(); - if (pinpointCommonsJar == null) { - logger.warn("pinpoint-commons-x.x.x(-SNAPSHOT).jar not found"); - return false; - } - final JarFile pinpointCommonsJarFile = getJarFile(pinpointCommonsJar); - if (pinpointCommonsJarFile == null) { - logger.warn("pinpoint-commons-x.x.x(-SNAPSHOT).jar not found"); - return false; - } - bootstrapJarFile.append(pinpointCommonsJarFile); - - // 3rd find bootstrap-core.jar - final String bootStrapCoreJar = getBootStrapCoreJar(); - if (bootStrapCoreJar == null) { - logger.warn("pinpoint-bootstrap-core-x.x.x(-SNAPSHOT).jar not found"); - return false; - } - JarFile bootStrapCoreJarFile = getJarFile(bootStrapCoreJar); - if (bootStrapCoreJarFile == null) { - logger.warn("pinpoint-bootstrap-core-x.x.x(-SNAPSHOT).jar not found"); - return false; - } - bootstrapJarFile.append(bootStrapCoreJarFile); - - // 4th find bootstrap-core-optional.jar - final String bootStrapCoreOptionalJar = getBootStrapCoreOptionalJar(); - if (bootStrapCoreOptionalJar == null) { - logger.info("pinpoint-bootstrap-core-optional-x.x.x(-SNAPSHOT).jar not found"); - } else { - JarFile bootStrapCoreOptionalJarFile = getJarFile(bootStrapCoreOptionalJar); - if (bootStrapCoreOptionalJarFile == null) { - logger.info("pinpoint-bootstrap-core-optional-x.x.x(-SNAPSHOT).jar not found"); - } else { - bootstrapJarFile.append(bootStrapCoreOptionalJarFile); - } - } - - // 5th find annotations.jar : optional dependency - final String annotationsJar = getAnnotationsJar(); - if (annotationsJar == null) { - logger.info("pinpoint-annotations-x.x.x(-SNAPSHOT).jar not found"); - } else { - JarFile jarFile = getJarFile(annotationsJar); - bootstrapJarFile.append(jarFile); - } - - this.bootstrapJarFile = bootstrapJarFile; - return true; - } - - public void setClassPathFromSystemProperty() { - this.classPath = getClassPathFromSystemProperty(); - } - - @Override - public BootstrapJarFile getBootstrapJarFile() { - return bootstrapJarFile; - } - - public static String getClassPathFromSystemProperty() { - return System.getProperty("java.class.path"); - } - - boolean findAgentJar() { - Matcher matcher = agentPattern.matcher(classPath); - if (!matcher.find()) { - return false; - } - this.agentJarName = parseAgentJar(matcher); - this.agentJarFullPath = parseAgentJarPath(classPath, agentJarName); - if (agentJarFullPath == null) { - return false; - } - this.agentDirPath = parseAgentDirPath(agentJarFullPath); - if (agentDirPath == null) { - return false; - } - - logger.info("Agent original-path:" + agentDirPath); - // defense alias change - this.agentDirPath = toCanonicalPath(agentDirPath); - logger.info("Agent canonical-path:" + agentDirPath); - - - this.pinpointCommonsJar = findFromBootDir("pinpoint-commons.jar", agentCommonsPattern); - this.bootStrapCoreJar = findFromBootDir("pinpoint-bootstrap-core.jar", agentCorePattern); - this.bootStrapCoreOptionalJar = findFromBootDir("pinpoint-bootstrap-core-optional.jar", agentCoreOptionalPattern); - this.annotationsJar = findFromBootDir("pinpoint-annotations.jar", annotationsPattern); - return true; - } - - private String toCanonicalPath(String path) { - final File file = new File(path); - return toCanonicalPath(file); - } - - private String toCanonicalPath(File file) { - try { - return file.getCanonicalPath(); - } catch (IOException e) { - logger.warn(file.getPath() + " getCanonicalPath() error. Error:" + e.getMessage(), e); - return file.getAbsolutePath(); - } - } - - private String findFromBootDir(final String name, final Pattern pattern) { - String bootDirPath = agentDirPath + File.separator + "boot"; - final File[] files = listFiles(name, pattern, bootDirPath); - if (isEmpty(files)) { - logger.info(name + " not found."); - return null; - } else if (files.length == 1) { - File file = files[0]; - return toCanonicalPath(file); - } else { - logger.info("too many " + name + " found. " + Arrays.toString(files)); - return null; - } - } - - private boolean isEmpty(File[] files) { - return files == null || files.length == 0; - } - - private File[] listFiles(final String name, final Pattern pattern, String bootDirPath) { - File bootDir = new File(bootDirPath); - return bootDir.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String fileName) { - Matcher matcher = pattern.matcher(fileName); - if (matcher.matches()) { - - logger.info("found " + name + ". " + dir.getAbsolutePath() + File.separator + fileName); - return true; - } - return false; - } - }); - } - - @Override - public String getPinpointCommonsJar() { - return pinpointCommonsJar; - } - - @Override - public String getBootStrapCoreJar() { - return bootStrapCoreJar; - } - - @Override - public String getBootStrapCoreOptionalJar() { - return bootStrapCoreOptionalJar; - } - - public String getAnnotationsJar() { - return annotationsJar; - } - - private String parseAgentJar(Matcher matcher) { - int start = matcher.start(); - int end = matcher.end(); - return this.classPath.substring(start, end); - } - - @Override - public String getAgentJarName() { - return this.agentJarName; - } - - private String parseAgentJarPath(String classPath, String agentJar) { - String[] classPathList = classPath.split(File.pathSeparator); - for (String findPath : classPathList) { - boolean find = findPath.contains(agentJar); - if (find) { - return findPath; - } - } - return null; - } - - @Override - public String getAgentJarFullPath() { - return agentJarFullPath; - } - - @Override - public String getAgentLibPath() { - return this.agentDirPath + File.separator + "lib"; - } - - @Override - public String getAgentLogFilePath() { - return this.agentDirPath + File.separator + "log"; - } - - @Override - public String getAgentPluginPath() { - return this.agentDirPath + File.separator + "plugin"; - } - - @Override - public List resolveLib() { - String agentLibPath = getAgentLibPath(); - File libDir = new File(agentLibPath); - if (!libDir.exists()) { - logger.warn(agentLibPath + " not found"); - return Collections.emptyList(); - } - if (!libDir.isDirectory()) { - logger.warn(agentLibPath + " not Directory"); - return Collections.emptyList(); - } - final List jarURLList = new ArrayList(); - - final File[] findJarList = findJar(libDir); - if (findJarList != null) { - for (File file : findJarList) { - URL url = toURI(file); - if (url != null) { - jarURLList.add(url); - } - } - } - - URL agentDirUri = toURI(new File(agentLibPath)); - if (agentDirUri != null) { - jarURLList.add(agentDirUri); - } - - // hot fix. boot jars not found from classPool ?? - jarURLList.add(toURI(new File(getPinpointCommonsJar()))); - jarURLList.add(toURI(new File(getBootStrapCoreJar()))); - String bootstrapCoreOptionalJar = getBootStrapCoreOptionalJar(); - // bootstrap-core-optional jar is not required and is okay to be null - if (bootstrapCoreOptionalJar != null) { - jarURLList.add(toURI(new File(bootstrapCoreOptionalJar))); - } - - return jarURLList; - } - - @Override - public URL[] resolvePlugins() { - final File file = new File(getAgentPluginPath()); - - if (!file.exists()) { - logger.warn(file + " not found"); - return new URL[0]; - } - - if (!file.isDirectory()) { - logger.warn(file + " is not a directory"); - return new URL[0]; - } - - - final File[] jars = file.listFiles(new FilenameFilter() { - - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".jar"); - } - }); - - if (isEmpty(jars)) { - return new URL[0]; - } - - final URL[] urls = new URL[jars.length]; - - - for (int i = 0; i < jars.length; i++) { - try { - urls[i] = jars[i].toURI().toURL(); - } catch (MalformedURLException e) { - // TODO have to change to PinpointException AFTER moving the exception to pinpoint-common - throw new RuntimeException("Fail to load plugin jars", e); - } - } - - for (File pluginJar : jars) { - logger.info("Found plugins: " + pluginJar.getPath()); - } - - return urls; - } - - private URL toURI(File file) { - URI uri = file.toURI(); - try { - return uri.toURL(); - } catch (MalformedURLException e) { - logger.warn(file.getName() + ".toURL() failed.", e); - return null; - } - } - - private File[] findJar(File libDir) { - return libDir.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - String path = pathname.getName(); - for (String extension : fileExtensionList) { - if (path.lastIndexOf("." + extension) != -1) { - return true; - } - } - return false; - } - }); - } - - private String parseAgentDirPath(String agentJarFullPath) { - int index1 = agentJarFullPath.lastIndexOf("/"); - int index2 = agentJarFullPath.lastIndexOf("\\"); - int max = Math.max(index1, index2); - if (max == -1) { - return null; - } - return agentJarFullPath.substring(0, max); - } - - @Override - public String getAgentDirPath() { - return agentDirPath; - } - - @Override - public String getAgentConfigPath() { - return agentDirPath + File.separator + "pinpoint.config"; - } - - - private JarFile getJarFile(String jarFilePath) { - try { - return new JarFile(jarFilePath); - } catch (IOException ioe) { - logger.warn(jarFilePath + " file not found. Error:" + ioe.getMessage(), ioe); - return null; - } - } - - -} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentOption.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentOption.java index 668d107391bd..77f12c909f6c 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentOption.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/AgentOption.java @@ -17,12 +17,9 @@ package com.navercorp.pinpoint.bootstrap; import java.lang.instrument.Instrumentation; -import java.net.URL; import java.util.List; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; /** * @author emeroad @@ -35,13 +32,12 @@ public interface AgentOption { String getApplicationName(); + boolean isContainer(); + ProfilerConfig getProfilerConfig(); - URL[] getPluginJars(); + List getPluginJars(); List getBootstrapJarPaths(); - ServiceTypeRegistryService getServiceTypeRegistryService(); - - AnnotationKeyRegistryService getAnnotationKeyRegistryService(); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/BootLogger.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/BootLogger.java index 8ce215b987c0..a70f8a358b06 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/BootLogger.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/BootLogger.java @@ -61,7 +61,7 @@ public BootLogger(String loggerName) { this.err = err; } - static BootLogger getLogger(String loggerName) { + public static BootLogger getLogger(String loggerName) { return new BootLogger(loggerName); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/BootstrapJarFile.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/BootstrapJarFile.java deleted file mode 100644 index a081264d1451..000000000000 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/BootstrapJarFile.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.navercorp.pinpoint.bootstrap; - -import java.util.ArrayList; -import java.util.List; -import java.util.jar.JarFile; - -/** - * @author Woonduk Kang(emeroad) - */ -public class BootstrapJarFile { - - private final List jarFileEntry = new ArrayList(); - - public BootstrapJarFile() { - } - - public void append(JarFile jarFile) { - if (jarFile == null) { - throw new NullPointerException("jarFile must not be null"); - } - - this.jarFileEntry.add(jarFile); - } - - public List getJarFileList() { - return jarFileEntry; - } - - public List getJarNameList() { - List bootStrapJarLIst = new ArrayList(jarFileEntry.size()); - for (JarFile jarFile : jarFileEntry) { - bootStrapJarLIst.add(jarFile.getName()); - } - return bootStrapJarLIst; - } - -} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ClassPathResolver.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ClassPathResolver.java deleted file mode 100644 index 23b14ef85fee..000000000000 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ClassPathResolver.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.navercorp.pinpoint.bootstrap; - -import java.net.URL; -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public interface ClassPathResolver { - - boolean verify(); - - BootstrapJarFile getBootstrapJarFile(); - - String getPinpointCommonsJar(); - - String getBootStrapCoreJar(); - - String getBootStrapCoreOptionalJar(); - - String getAgentJarName(); - - String getAgentJarFullPath(); - - String getAgentLibPath(); - - String getAgentLogFilePath(); - - String getAgentPluginPath(); - - List resolveLib(); - - URL[] resolvePlugins(); - - String getAgentDirPath(); - - String getAgentConfigPath(); -} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ContainerResolver.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ContainerResolver.java new file mode 100644 index 000000000000..ef17cf738204 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ContainerResolver.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap; + +import com.navercorp.pinpoint.common.util.StringUtils; + +import java.util.Properties; + +/** + * @author HyunGil Jeong + */ +public class ContainerResolver { + + public static final String CONTAINER_PROPERTY_KEY = "pinpoint.container"; + + private final BootLogger logger = BootLogger.getLogger(ContainerResolver.class.getName()); + + private final Properties properties; + + public ContainerResolver() { + this(System.getProperties()); + } + + public ContainerResolver(Properties properties) { + if (properties == null) { + throw new NullPointerException("properties must not be null"); + } + this.properties = properties; + } + + /** + * Returns true if {@value #CONTAINER_PROPERTY_KEY} property exists and has no value or is true. + * + * @return true if {@value #CONTAINER_PROPERTY_KEY} property exists and has no value or is true. + */ + public boolean isContainer() { + if (properties.containsKey(CONTAINER_PROPERTY_KEY)) { + String value = properties.getProperty(CONTAINER_PROPERTY_KEY); + if (StringUtils.isEmpty(value)) { + logger.info("-D" + CONTAINER_PROPERTY_KEY + " found."); + return true; + } + boolean isContainer = Boolean.parseBoolean(value); + logger.info("-D" + CONTAINER_PROPERTY_KEY + " found : " + value + ", resolved to " + isContainer); + return isContainer; + } + return false; + } +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ContextClassLoaderExecuteTemplate.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ContextClassLoaderExecuteTemplate.java index b12c8c9da212..d6e0ff976ed3 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ContextClassLoaderExecuteTemplate.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ContextClassLoaderExecuteTemplate.java @@ -24,12 +24,10 @@ * @author emeroad */ public class ContextClassLoaderExecuteTemplate { + // @Nullable private final ClassLoader classLoader; public ContextClassLoaderExecuteTemplate(ClassLoader classLoader) { - if (classLoader == null) { - throw new NullPointerException("classLoader must not be null"); - } this.classLoader = classLoader; } @@ -37,7 +35,8 @@ public V execute(Callable callable) throws BootStrapException { try { final Thread currentThread = Thread.currentThread(); final ClassLoader before = currentThread.getContextClassLoader(); - currentThread.setContextClassLoader(ContextClassLoaderExecuteTemplate.this.classLoader); + // ctxCl == null safe? + currentThread.setContextClassLoader(this.classLoader); try { return callable.call(); } finally { diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/DefaultAgentOption.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/DefaultAgentOption.java index 927572764243..327b03f15b40 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/DefaultAgentOption.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/DefaultAgentOption.java @@ -16,16 +16,12 @@ package com.navercorp.pinpoint.bootstrap; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + import java.lang.instrument.Instrumentation; -import java.net.URL; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; - /** * @author emeroad */ @@ -35,14 +31,13 @@ public class DefaultAgentOption implements AgentOption { private final String agentId; private final String applicationName; + private final boolean isContainer; private final ProfilerConfig profilerConfig; - private final URL[] pluginJars; + private final List pluginJars; private final List bootstrapJarPaths; - private final ServiceTypeRegistryService serviceTypeRegistryService; - private final AnnotationKeyRegistryService annotationKeyRegistryService; - public DefaultAgentOption(final Instrumentation instrumentation, String agentId, String applicationName, final ProfilerConfig profilerConfig, final URL[] pluginJars, final List bootstrapJarPaths, final ServiceTypeRegistryService serviceTypeRegistryService, final AnnotationKeyRegistryService annotationKeyRegistryService) { + public DefaultAgentOption(final Instrumentation instrumentation, String agentId, String applicationName, final boolean isContainer, final ProfilerConfig profilerConfig, final List pluginJars, final List bootstrapJarPaths) { if (instrumentation == null) { throw new NullPointerException("instrumentation must not be null"); } @@ -58,15 +53,10 @@ public DefaultAgentOption(final Instrumentation instrumentation, String agentId, if (pluginJars == null) { throw new NullPointerException("pluginJars must not be null"); } - if (annotationKeyRegistryService == null) { - throw new NullPointerException("annotationKeyRegistryService must not be null"); - } - if (serviceTypeRegistryService == null) { - throw new NullPointerException("serviceTypeRegistryService must not be null"); - } this.instrumentation = instrumentation; this.agentId = agentId; this.applicationName = applicationName; + this.isContainer = isContainer; this.profilerConfig = profilerConfig; this.pluginJars = pluginJars; if (bootstrapJarPaths == null) { @@ -74,8 +64,6 @@ public DefaultAgentOption(final Instrumentation instrumentation, String agentId, } else { this.bootstrapJarPaths = bootstrapJarPaths; } - this.serviceTypeRegistryService = serviceTypeRegistryService; - this.annotationKeyRegistryService = annotationKeyRegistryService; } @Override @@ -94,7 +82,12 @@ public String getApplicationName() { } @Override - public URL[] getPluginJars() { + public boolean isContainer() { + return isContainer; + } + + @Override + public List getPluginJars() { return this.pluginJars; } @@ -108,27 +101,16 @@ public ProfilerConfig getProfilerConfig() { return this.profilerConfig; } - @Override - public ServiceTypeRegistryService getServiceTypeRegistryService() { - return this.serviceTypeRegistryService; - } - - @Override - public AnnotationKeyRegistryService getAnnotationKeyRegistryService() { - return this.annotationKeyRegistryService; - } - @Override public String toString() { final StringBuilder sb = new StringBuilder("DefaultAgentOption{"); sb.append("instrumentation=").append(instrumentation); sb.append(", agentId='").append(agentId).append('\''); sb.append(", applicationName='").append(applicationName).append('\''); + sb.append(", isContainer=").append(isContainer); sb.append(", profilerConfig=").append(profilerConfig); - sb.append(", pluginJars=").append(Arrays.toString(pluginJars)); + sb.append(", pluginJars=").append(pluginJars); sb.append(", bootstrapJarPaths=").append(bootstrapJarPaths); - sb.append(", serviceTypeRegistryService=").append(serviceTypeRegistryService); - sb.append(", annotationKeyRegistryService=").append(annotationKeyRegistryService); sb.append('}'); return sb.toString(); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ModuleBootLoader.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ModuleBootLoader.java new file mode 100644 index 000000000000..f21e582869ce --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ModuleBootLoader.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap; + +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.URL; + +/** + * @author Woonduk Kang(emeroad) + */ +class ModuleBootLoader { + + private final Instrumentation instrumentation; + // @Nullable + private final ClassLoader parentClassLoader; + + private Object moduleSupport; + + ModuleBootLoader(Instrumentation instrumentation, ClassLoader parentClassLoader) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + this.instrumentation = instrumentation; + this.parentClassLoader = parentClassLoader; + } + + void loadModuleSupport() { + try { + Class bootStrapClass = getModuleSupportFactoryClass(parentClassLoader); + Object moduleSupportFactory = newModuleSupportFactory(bootStrapClass); + + Method newModuleSupportMethod = moduleSupportFactory.getClass().getMethod("newModuleSupport", Instrumentation.class); + this.moduleSupport = newModuleSupportMethod.invoke(moduleSupportFactory, instrumentation); + + Class moduleSupportSetup = moduleSupport.getClass(); + Method setupMethod = moduleSupportSetup.getMethod("setup"); + setupMethod.invoke(moduleSupport); + } catch (Exception e) { + throw new IllegalStateException("moduleSupport load fail Caused by:" + e.getMessage(), e); + } + } + + void defineAgentModule(ClassLoader classLoader, URL[] jarFileList) { + if (moduleSupport == null) { + throw new IllegalStateException("moduleSupport not loaded"); + } + try { + Method definePinpointPackage = this.moduleSupport.getClass().getDeclaredMethod("defineAgentModule", ClassLoader.class, URL[].class); + definePinpointPackage.invoke(moduleSupport, classLoader, jarFileList); + } catch (Exception ex) { + throw new IllegalStateException("defineAgentPackage fail: Caused by:" + ex.getMessage(), ex); + } + } + + + private Class getModuleSupportFactoryClass(ClassLoader parentClassLoader) { + try { + return Class.forName("com.navercorp.pinpoint.bootstrap.java9.module.ModuleSupportFactory", false, parentClassLoader); + } catch (ClassNotFoundException ex) { + throw new IllegalStateException("ModuleSupportFactory not found Caused by:" + ex.getMessage(), ex); + } + } + + private Object newModuleSupportFactory(Class bootStrapClass) { + try { + Constructor constructor = bootStrapClass.getDeclaredConstructor(); + return constructor.newInstance(); + } catch (Exception e) { + throw new IllegalStateException("ModuleSupportFactory() initialize fail", e); + } + } +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ModuleUtils.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ModuleUtils.java new file mode 100644 index 000000000000..dd02ae070ecf --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/ModuleUtils.java @@ -0,0 +1,22 @@ +package com.navercorp.pinpoint.bootstrap; + +/** + * @author Woonduk Kang(emeroad) + */ +final class ModuleUtils { + + private static final boolean moduleSupport = checkModuleClass(); + + private static boolean checkModuleClass() { + try { + Class.forName("java.lang.Module", false, null); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + + static boolean isModuleSupported() { + return moduleSupport; + } +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointBootStrap.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointBootStrap.java index ea6975cb95ba..95a745c6c7ab 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointBootStrap.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointBootStrap.java @@ -17,11 +17,18 @@ package com.navercorp.pinpoint.bootstrap; import java.lang.instrument.Instrumentation; +import java.net.URL; import java.util.List; import java.util.Map; import java.util.jar.JarFile; import com.navercorp.pinpoint.ProductInfo; +import com.navercorp.pinpoint.bootstrap.agentdir.AgentDirBaseClassPathResolver; +import com.navercorp.pinpoint.bootstrap.agentdir.AgentDirectory; +import com.navercorp.pinpoint.bootstrap.agentdir.BootDir; +import com.navercorp.pinpoint.bootstrap.agentdir.ClassPathResolver; +import com.navercorp.pinpoint.bootstrap.agentdir.JavaAgentPathResolver; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; /** * @author emeroad @@ -39,6 +46,14 @@ public static void premain(String agentArgs, Instrumentation instrumentation) { agentArgs = ""; } logger.info(ProductInfo.NAME + " agentArgs:" + agentArgs); + logger.info("classLoader:" + PinpointBootStrap.class.getClassLoader()); + logger.info("contextClassLoader:" + Thread.currentThread().getContextClassLoader()); + if (Object.class.getClassLoader() != PinpointBootStrap.class.getClassLoader()) { + final URL location = CodeSourceUtils.getCodeLocation(PinpointBootStrap.class); + logger.warn("Invalid pinpoint-bootstrap.jar:" + location); + return; + } + final boolean success = STATE.start(); if (!success) { @@ -47,36 +62,78 @@ public static void premain(String agentArgs, Instrumentation instrumentation) { } Map agentArgsMap = argsToMap(agentArgs); - final ClassPathResolver classPathResolver = new AgentDirBaseClassPathResolver(); - if (!classPathResolver.verify()) { + JavaAgentPathResolver javaAgentPathResolver = JavaAgentPathResolver.newJavaAgentPathResolver(); + String agentPath = javaAgentPathResolver.resolveJavaAgentPath(); + logger.info("JavaAgentPath:" + agentPath); + final ClassPathResolver classPathResolver = new AgentDirBaseClassPathResolver(agentPath); + + final AgentDirectory agentDirectory = resolveAgentDir(classPathResolver); + if (agentDirectory == null) { logger.warn("Agent Directory Verify fail. skipping agent loading."); logPinpointAgentLoadFail(); return; } + BootDir bootDir = agentDirectory.getBootDir(); + appendToBootstrapClassLoader(instrumentation, bootDir); - BootstrapJarFile bootstrapJarFile = classPathResolver.getBootstrapJarFile(); - appendToBootstrapClassLoader(instrumentation, bootstrapJarFile); - - - PinpointStarter bootStrap = new PinpointStarter(agentArgsMap, bootstrapJarFile, classPathResolver, instrumentation); + ClassLoader parentClassLoader = getParentClassLoader(); + final ModuleBootLoader moduleBootLoader = loadModuleBootLoader(instrumentation, parentClassLoader); + PinpointStarter bootStrap = new PinpointStarter(parentClassLoader, agentArgsMap, agentDirectory, instrumentation, moduleBootLoader); if (!bootStrap.start()) { logPinpointAgentLoadFail(); } } + private static ModuleBootLoader loadModuleBootLoader(Instrumentation instrumentation, ClassLoader parentClassLoader) { + if (!ModuleUtils.isModuleSupported()) { + return null; + } + logger.info("java9 module detected"); + logger.info("ModuleBootLoader start"); + ModuleBootLoader moduleBootLoader = new ModuleBootLoader(instrumentation, parentClassLoader); + moduleBootLoader.loadModuleSupport(); + return moduleBootLoader; + } + + private static AgentDirectory resolveAgentDir(ClassPathResolver classPathResolver) { + try { + AgentDirectory agentDir = classPathResolver.resolve(); + return agentDir; + } catch(Exception e) { + logger.warn("AgentDir resolve fail Caused by:" + e.getMessage(), e); + return null; + } + } + + + private static ClassLoader getParentClassLoader() { + final ClassLoader classLoader = getPinpointBootStrapClassLoader(); + if (classLoader == Object.class.getClassLoader()) { + logger.info("parentClassLoader:BootStrapClassLoader:" + classLoader ); + } else { + logger.info("parentClassLoader:" + classLoader); + } + return classLoader; + } + + private static ClassLoader getPinpointBootStrapClassLoader() { + return PinpointBootStrap.class.getClassLoader(); + } + + private static Map argsToMap(String agentArgs) { ArgsParser argsParser = new ArgsParser(); Map agentArgsMap = argsParser.parse(agentArgs); if (!agentArgsMap.isEmpty()) { - logger.info("agentParameter :" + agentArgs); + logger.info("agentParameter:" + agentArgs); } return agentArgsMap; } - private static void appendToBootstrapClassLoader(Instrumentation instrumentation, BootstrapJarFile agentJarFile) { - List jarFileList = agentJarFile.getJarFileList(); - for (JarFile jarFile : jarFileList) { + private static void appendToBootstrapClassLoader(Instrumentation instrumentation, BootDir bootDir) { + List jarFiles = bootDir.openJarFiles(); + for (JarFile jarFile : jarFiles) { logger.info("appendToBootstrapClassLoader:" + jarFile.getName()); instrumentation.appendToBootstrapClassLoaderSearch(jarFile); } diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointStarter.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointStarter.java index 15f0618d7955..497b0b99b404 100644 --- a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointStarter.java +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/PinpointStarter.java @@ -15,23 +15,20 @@ package com.navercorp.pinpoint.bootstrap; import com.navercorp.pinpoint.ProductInfo; +import com.navercorp.pinpoint.bootstrap.agentdir.AgentDirectory; +import com.navercorp.pinpoint.bootstrap.classloader.PinpointClassLoaderFactory; +import com.navercorp.pinpoint.bootstrap.classloader.ProfilerLibs; import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.common.Version; -import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; -import com.navercorp.pinpoint.common.service.DefaultTraceMetadataLoaderService; -import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; -import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; import com.navercorp.pinpoint.common.util.PinpointThreadFactory; import com.navercorp.pinpoint.common.util.SimpleProperty; import com.navercorp.pinpoint.common.util.SystemProperty; -import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; -import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; import java.lang.instrument.Instrumentation; import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -55,31 +52,37 @@ class PinpointStarter { private SimpleProperty systemProperty = SystemProperty.INSTANCE; private final Map agentArgs; - private final BootstrapJarFile bootstrapJarFile; - private final ClassPathResolver classPathResolver; + private final AgentDirectory agentDirectory; private final Instrumentation instrumentation; + private final ClassLoader parentClassLoader; + private final ModuleBootLoader moduleBootLoader; - public PinpointStarter(Map agentArgs, BootstrapJarFile bootstrapJarFile, ClassPathResolver classPathResolver, Instrumentation instrumentation) { + public PinpointStarter(ClassLoader parentClassLoader, Map agentArgs, + AgentDirectory agentDirectory, + Instrumentation instrumentation, ModuleBootLoader moduleBootLoader) { + // null == BootstrapClassLoader +// if (bootstrapClassLoader == null) { +// throw new NullPointerException("bootstrapClassLoader must not be null"); +// } if (agentArgs == null) { throw new NullPointerException("agentArgs must not be null"); } - if (bootstrapJarFile == null) { - throw new NullPointerException("bootstrapJarFile must not be null"); - } - if (classPathResolver == null) { - throw new NullPointerException("classPathResolver must not be null"); + if (agentDirectory == null) { + throw new NullPointerException("agentDirectory must not be null"); } if (instrumentation == null) { throw new NullPointerException("instrumentation must not be null"); } this.agentArgs = agentArgs; - this.bootstrapJarFile = bootstrapJarFile; - this.classPathResolver = classPathResolver; + this.parentClassLoader = parentClassLoader; + this.agentDirectory = agentDirectory; this.instrumentation = instrumentation; + this.moduleBootLoader = moduleBootLoader; } + boolean start() { final IdValidator idValidator = new IdValidator(); final String agentId = idValidator.getAgentId(); @@ -91,21 +94,17 @@ boolean start() { return false; } - URL[] pluginJars = classPathResolver.resolvePlugins(); - - // TODO using PLogger instead of CommonLogger - CommonLoggerFactory loggerFactory = StdoutCommonLoggerFactory.INSTANCE; - TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(pluginJars, loggerFactory); - ServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(typeLoaderService, loggerFactory); - AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(typeLoaderService, loggerFactory); + final ContainerResolver containerResolver = new ContainerResolver(); + final boolean isContainer = containerResolver.isContainer(); - String configPath = getConfigPath(classPathResolver); + List pluginJars = agentDirectory.getPlugins(); + String configPath = getConfigPath(agentDirectory); if (configPath == null) { return false; } // set the path of log file as a system property - saveLogFilePath(classPathResolver); + saveLogFilePath(agentDirectory); savePinpointVersion(); @@ -114,15 +113,19 @@ boolean start() { ProfilerConfig profilerConfig = DefaultProfilerConfig.load(configPath); // this is the library list that must be loaded - List libUrlList = resolveLib(classPathResolver); - AgentClassLoader agentClassLoader = new AgentClassLoader(libUrlList.toArray(new URL[libUrlList.size()])); + final URL[] urls = resolveLib(agentDirectory); + final ClassLoader agentClassLoader = createClassLoader("pinpoint.agent", urls, parentClassLoader); + if (moduleBootLoader != null) { + this.logger.info("defineAgentModule"); + moduleBootLoader.defineAgentModule(agentClassLoader, urls); + } + final String bootClass = getBootClass(); - agentClassLoader.setBootClass(bootClass); + AgentBootLoader agentBootLoader = new AgentBootLoader(bootClass, urls, agentClassLoader); logger.info("pinpoint agent [" + bootClass + "] starting..."); - - AgentOption option = createAgentOption(agentId, applicationName, profilerConfig, instrumentation, pluginJars, bootstrapJarFile, serviceTypeRegistryService, annotationKeyRegistryService); - Agent pinpointAgent = agentClassLoader.boot(option); + AgentOption option = createAgentOption(agentId, applicationName, isContainer, profilerConfig, instrumentation, pluginJars, agentDirectory); + Agent pinpointAgent = agentBootLoader.boot(option); pinpointAgent.start(); registerShutdownHook(pinpointAgent); logger.info("pinpoint agent started normally."); @@ -134,6 +137,18 @@ boolean start() { return true; } + private ClassLoader createClassLoader(final String name, final URL[] urls, final ClassLoader parentClassLoader) { + if (System.getSecurityManager() != null) { + return AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return PinpointClassLoaderFactory.createClassLoader(name, urls, parentClassLoader, ProfilerLibs.PINPOINT_PROFILER_CLASS); + } + }); + } else { + return PinpointClassLoaderFactory.createClassLoader(name, urls, parentClassLoader, ProfilerLibs.PINPOINT_PROFILER_CLASS); + } + } + private String getBootClass() { final String agentType = getAgentType().toUpperCase(); if (PLUGIN_TEST_AGENT.equals(agentType)) { @@ -151,14 +166,13 @@ private String getAgentType() { } - private AgentOption createAgentOption(String agentId, String applicationName, ProfilerConfig profilerConfig, + private AgentOption createAgentOption(String agentId, String applicationName, boolean isContainer, + ProfilerConfig profilerConfig, Instrumentation instrumentation, - URL[] pluginJars, - BootstrapJarFile bootstrapJarFile, - ServiceTypeRegistryService serviceTypeRegistryService, - AnnotationKeyRegistryService annotationKeyRegistryService) { - List bootstrapJarPaths = bootstrapJarFile.getJarNameList(); - return new DefaultAgentOption(instrumentation, agentId, applicationName, profilerConfig, pluginJars, bootstrapJarPaths, serviceTypeRegistryService, annotationKeyRegistryService); + List pluginJars, + AgentDirectory agentDirectory) { + List bootstrapJarPaths = agentDirectory.getBootDir().toList(); + return new DefaultAgentOption(instrumentation, agentId, applicationName, isContainer, profilerConfig, pluginJars, bootstrapJarPaths); } // for test @@ -179,8 +193,8 @@ public void run() { } - private void saveLogFilePath(ClassPathResolver classPathResolver) { - String agentLogFilePath = classPathResolver.getAgentLogFilePath(); + private void saveLogFilePath(AgentDirectory agentDirectory) { + String agentLogFilePath = agentDirectory.getAgentLogFilePath(); logger.info("logPath:" + agentLogFilePath); systemProperty.setProperty(ProductInfo.NAME + ".log", agentLogFilePath); @@ -191,7 +205,7 @@ private void savePinpointVersion() { systemProperty.setProperty(ProductInfo.NAME + ".version", Version.VERSION); } - private String getConfigPath(ClassPathResolver classPathResolver) { + private String getConfigPath(AgentDirectory agentDirectory) { final String configName = ProductInfo.NAME + ".config"; String pinpointConfigFormSystemProperty = systemProperty.getProperty(configName); if (pinpointConfigFormSystemProperty != null) { @@ -199,7 +213,7 @@ private String getConfigPath(ClassPathResolver classPathResolver) { return pinpointConfigFormSystemProperty; } - String classPathAgentConfigPath = classPathResolver.getAgentConfigPath(); + String classPathAgentConfigPath = agentDirectory.getAgentConfigPath(); if (classPathAgentConfigPath != null) { logger.info("classpath " + configName + " found. " + classPathAgentConfigPath); return classPathAgentConfigPath; @@ -210,11 +224,11 @@ private String getConfigPath(ClassPathResolver classPathResolver) { } - private List resolveLib(ClassPathResolver classPathResolver) { + private URL[] resolveLib(AgentDirectory classPathResolver) { // this method may handle only absolute path, need to handle relative path (./..agentlib/lib) String agentJarFullPath = classPathResolver.getAgentJarFullPath(); String agentLibPath = classPathResolver.getAgentLibPath(); - List urlList = resolveLib(classPathResolver.resolveLib()); + List urlList = resolveLib(classPathResolver.getLibs()); String agentConfigPath = classPathResolver.getAgentConfigPath(); if (logger.isInfoEnabled()) { @@ -225,12 +239,11 @@ private List resolveLib(ClassPathResolver classPathResolver) { } logger.info("agent config:" + agentConfigPath); } - - return urlList; + return urlList.toArray(new URL[0]); } private List resolveLib(List urlList) { - if (DEFAULT_AGENT.equals(getAgentType().toUpperCase())) { + if (DEFAULT_AGENT.equalsIgnoreCase(getAgentType())) { final List releaseLib = new ArrayList(urlList.size()); for (URL url : urlList) { // diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentDirBaseClassPathResolver.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentDirBaseClassPathResolver.java new file mode 100644 index 000000000000..62013baeb1ce --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentDirBaseClassPathResolver.java @@ -0,0 +1,354 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.agentdir; + + +import com.navercorp.pinpoint.bootstrap.BootLogger; + +import java.io.File; +import java.io.FileFilter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author emeroad + */ +public class AgentDirBaseClassPathResolver implements ClassPathResolver { + + private final BootLogger logger = BootLogger.getLogger(this.getClass().getName()); + + static final String VERSION_PATTERN = "(-[0-9]+\\.[0-9]+\\.[0-9]+((\\-SNAPSHOT)|(-RC[0-9]+))?)?"; + + static final Pattern DEFAULT_AGENT_BOOTSTRAP_PATTERN = compile("pinpoint-bootstrap" + VERSION_PATTERN + "\\.jar"); + static final Pattern DEFAULT_AGENT_COMMONS_PATTERN = compile("pinpoint-commons" + VERSION_PATTERN + "\\.jar"); + static final Pattern DEFAULT_AGENT_CORE_PATTERN = compile("pinpoint-bootstrap-core" + VERSION_PATTERN + "\\.jar"); + static final Pattern DEFAULT_AGENT_JAVA8_PATTERN = compile("pinpoint-bootstrap-java8" + VERSION_PATTERN + "\\.jar"); + static final Pattern DEFAULT_AGENT_JAVA9_PATTERN = compile("pinpoint-bootstrap-java9" + VERSION_PATTERN + "\\.jar"); + static final Pattern DEFAULT_AGENT_CORE_OPTIONAL_PATTERN = compile("pinpoint-bootstrap-core-optional" + VERSION_PATTERN + "\\.jar"); + static final Pattern DEFAULT_ANNOTATIONS = compile("pinpoint-annotations" + VERSION_PATTERN + "\\.jar"); + + private final Pattern agentBootstrapPattern; + private final Pattern agentCommonsPattern; + private final Pattern agentCorePattern; + private final Pattern agentJava8Pattern; + private final Pattern agentJava9Pattern; + private final Pattern agentCoreOptionalPattern; + private final Pattern annotationsPattern; + + private final String classPath; + ; + private List fileExtensionList; + + + private static Pattern compile(String regex) { + return Pattern.compile(regex); + } + + public AgentDirBaseClassPathResolver(String classPath) { + if (classPath == null) { + throw new NullPointerException("classPath must not be null"); + } + this.classPath = classPath; + this.agentBootstrapPattern = DEFAULT_AGENT_BOOTSTRAP_PATTERN; + this.agentCommonsPattern = DEFAULT_AGENT_COMMONS_PATTERN; + this.agentCorePattern = DEFAULT_AGENT_CORE_PATTERN; + this.agentJava8Pattern = DEFAULT_AGENT_JAVA8_PATTERN; + this.agentJava9Pattern = DEFAULT_AGENT_JAVA9_PATTERN; + this.agentCoreOptionalPattern = DEFAULT_AGENT_CORE_OPTIONAL_PATTERN; + this.annotationsPattern = DEFAULT_ANNOTATIONS; + this.fileExtensionList = getDefaultFileExtensionList(); + } + + static List getDefaultFileExtensionList() { + List extensionList = new ArrayList(3); + extensionList.add("jar"); + extensionList.add("xml"); + extensionList.add("properties"); + return extensionList; + } + + + @Override + public AgentDirectory resolve() { + + // find boot-strap.jar + final String bootstrapJarName = this.findBootstrapJar(this.classPath); + if (bootstrapJarName == null) { + throw new IllegalStateException("pinpoint-bootstrap-x.x.x(-SNAPSHOT).jar not found."); + } + + final String agentJarFullPath = parseAgentJarPath(classPath, bootstrapJarName); + if (agentJarFullPath == null) { + throw new IllegalStateException("pinpoint-bootstrap-x.x.x(-SNAPSHOT).jar not found. " + classPath); + } + final String agentDirPath = getAgentDirPath(agentJarFullPath); + + final BootDir bootDir = resolveBootDir(agentDirPath); + + final String agentLibPath = getAgentLibPath(agentDirPath); + final List libs = resolveLib(agentLibPath, bootDir); + + String agentPluginPath = getAgentPluginPath(agentDirPath); + final List plugins = resolvePlugins(agentPluginPath); + + final AgentDirectory agentDirectory = new AgentDirectory(bootstrapJarName, agentJarFullPath, agentDirPath, + bootDir, libs, plugins); + + return agentDirectory; + } + + private String getAgentDirPath(String agentJarFullPath) { + String agentDirPath = parseAgentDirPath(agentJarFullPath); + if (agentDirPath == null) { + throw new IllegalStateException("agentDirPath is null " + classPath); + } + + logger.info("Agent original-path:" + agentDirPath); + // defense alias change + agentDirPath = toCanonicalPath(agentDirPath); + logger.info("Agent canonical-path:" + agentDirPath); + return agentDirPath; + } + + + private BootDir resolveBootDir(String agentDirPath) { + String bootDirPath = agentDirPath + File.separator + "boot"; + String pinpointCommonsJar = find(bootDirPath, "pinpoint-commons.jar", agentCommonsPattern); + String bootStrapCoreJar = find(bootDirPath, "pinpoint-bootstrap-core.jar", agentCorePattern); + String bootStrapJava8Jar = find(bootDirPath, "pinpoint-bootstrap-java8.jar", agentJava8Pattern); + String bootStrapJava9Jar = find(bootDirPath, "pinpoint-bootstrap-java9.jar", agentJava9Pattern); + String bootStrapCoreOptionalJar = find(bootDirPath, "pinpoint-bootstrap-core-optional.jar", agentCoreOptionalPattern); + String annotationsJar = find(bootDirPath,"pinpoint-annotations.jar", annotationsPattern); + return new BootDir(pinpointCommonsJar, bootStrapCoreJar, bootStrapCoreOptionalJar, bootStrapJava8Jar, bootStrapJava9Jar, annotationsJar); + } + + + String findBootstrapJar(String classPath) { + final Matcher matcher = agentBootstrapPattern.matcher(classPath); + if (!matcher.find()) { + return null; + } + return parseAgentJar(matcher, classPath); + } + + + private String toCanonicalPath(String path) { + final File file = new File(path); + return toCanonicalPath(file); + } + + private String toCanonicalPath(File file) { + try { + return file.getCanonicalPath(); + } catch (IOException e) { + logger.warn(file.getPath() + " getCanonicalPath() error. Error:" + e.getMessage(), e); + return file.getAbsolutePath(); + } + } + + private String find(String bootDirPath, final String name, final Pattern pattern) { + final File[] files = listFiles(name, pattern, bootDirPath); + if (isEmpty(files)) { + logger.info(name + " not found."); + return null; + } else if (files.length == 1) { + File file = files[0]; + return toCanonicalPath(file); + } else { + logger.info("too many " + name + " found. " + Arrays.toString(files)); + return null; + } + } + + private boolean isEmpty(File[] files) { + return files == null || files.length == 0; + } + + private File[] listFiles(final String name, final Pattern pattern, String bootDirPath) { + File bootDir = new File(bootDirPath); + return bootDir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String fileName) { + Matcher matcher = pattern.matcher(fileName); + if (matcher.matches()) { + + logger.info("found " + name + ". " + dir.getAbsolutePath() + File.separator + fileName); + return true; + } + return false; + } + }); + } + + + private String parseAgentJar(Matcher matcher, String classpath) { + int start = matcher.start(); + int end = matcher.end(); + return classPath.substring(start, end); + } + + private String parseAgentJarPath(String classPath, String agentJar) { + String[] classPathList = classPath.split(File.pathSeparator); + for (String findPath : classPathList) { + boolean find = findPath.contains(agentJar); + if (find) { + return findPath; + } + } + return null; + } + + + private String getAgentLibPath(String agentDirPath) { + return agentDirPath + File.separator + "lib"; + } + + private String getAgentPluginPath(String agentDirPath) { + return agentDirPath + File.separator + "plugin"; + } + + private List resolveLib(String agentLibPath, BootDir bootDir) { + File libDir = new File(agentLibPath); + if (checkDirectory(libDir)) { + return Collections.emptyList(); + } + final List jarURLList = new ArrayList(); + + final File[] findJarList = findJar(libDir); + if (findJarList != null) { + for (File file : findJarList) { + URL url = toURI(file); + if (url != null) { + jarURLList.add(url); + } + } + } + + URL agentDirUri = toURI(new File(agentLibPath)); + if (agentDirUri != null) { + jarURLList.add(agentDirUri); + } + + // hot fix. boot jars not found from classPool ?? +// jarURLList.add(toURI(new File(bootDir.getCommons()))); +// jarURLList.add(toURI(new File(bootDir.getBootstrapCore()))); +// String bootstrapCoreOptionalJar = bootDir.getBootstrapCoreOptional(); +// // bootstrap-core-optional jar is not required and is okay to be null +// if (bootstrapCoreOptionalJar != null) { +// jarURLList.add(toURI(new File(bootstrapCoreOptionalJar))); +// } + return jarURLList; + } + + private List resolvePlugins(String agentPluginPath) { + final File directory = new File(agentPluginPath); + + if (checkDirectory(directory)) { + logger.warn(directory + " is not a directory"); + return Collections.emptyList(); + } + + + final File[] jars = directory.listFiles(new FilenameFilter() { + + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".jar"); + } + }); + + if (isEmpty(jars)) { + return Collections.emptyList(); + } + + List pluginFileList = filterReadPermission(jars); + for (String pluginJar : pluginFileList) { + logger.info("Found plugins:" + pluginJar); + } + return pluginFileList; + } + + private boolean checkDirectory(File file) { + if (!file.exists()) { + logger.warn(file + " not found"); + return true; + } + if (!file.isDirectory()) { + logger.warn(file + " is not a directory"); + return true; + } + return false; + } + + private List filterReadPermission(File[] jars) { + List result = new ArrayList(); + for (File pluginJar : jars) { + if (!pluginJar.canRead()) { + logger.info("File '" + pluginJar + "' cannot be read"); + continue; + } + + result.add(pluginJar.getPath()); + } + return result; + } + + private URL toURI(File file) { + URI uri = file.toURI(); + try { + return uri.toURL(); + } catch (MalformedURLException e) { + logger.warn(file.getName() + ".toURL() failed.", e); + return null; + } + } + + private File[] findJar(File libDir) { + return libDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + String path = pathname.getName(); + for (String extension : fileExtensionList) { + if (path.lastIndexOf("." + extension) != -1) { + return true; + } + } + return false; + } + }); + } + + private String parseAgentDirPath(String agentJarFullPath) { + int index1 = agentJarFullPath.lastIndexOf("/"); + int index2 = agentJarFullPath.lastIndexOf("\\"); + int max = Math.max(index1, index2); + if (max == -1) { + return null; + } + return agentJarFullPath.substring(0, max); + } + +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentDirectory.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentDirectory.java new file mode 100644 index 000000000000..9bd4bb4dbf87 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentDirectory.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.agentdir; + + +import java.io.File; +import java.net.URL; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class AgentDirectory { + + private final String agentJarName; + private final String agentJarFullPath; + private final String agentDirPath; + + private final BootDir bootDir; + private final List plugins; + private final List libs; + + + public AgentDirectory(String agentJarName, + String agentJarFullPath, String agentDirPath, + BootDir bootDir, + List libs, List plugins) { + if (bootDir == null) { + throw new NullPointerException("bootDir must not be null"); + } + + this.agentJarName = agentJarName; + this.agentJarFullPath = agentJarFullPath; + this.agentDirPath = agentDirPath; + + this.bootDir = bootDir; + this.libs = libs; + this.plugins = plugins; + } + + public BootDir getBootDir() { + return bootDir; + } + + public List getLibs() { + return libs; + } + + public List getPlugins() { + return plugins; + } + + public String getAgentJarName() { + return this.agentJarName; + } + + public String getAgentJarFullPath() { + return agentJarFullPath; + } + + public String getAgentDirPath() { + return agentDirPath; + } + + public String getAgentLibPath() { + return this.agentDirPath + File.separator + "lib"; + } + + public String getAgentLogFilePath() { + return this.agentDirPath + File.separator + "log"; + } + + public String getAgentPluginPath() { + return this.agentDirPath + File.separator + "plugin"; + } + + public String getAgentConfigPath() { + return agentDirPath + File.separator + "pinpoint.config"; + } +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/BootDir.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/BootDir.java new file mode 100644 index 000000000000..6d81b72f8055 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/BootDir.java @@ -0,0 +1,175 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.agentdir; + +import com.navercorp.pinpoint.bootstrap.BootLogger; + +import java.util.ArrayList; +import java.util.List; +import java.util.jar.JarFile; + +/** + * @author Woonduk Kang(emeroad) + */ +public class BootDir { + + private final BootLogger logger = BootLogger.getLogger(this.getClass().getName()); + + private final String commons; + private final String bootstrapCore; + private final String bootstrapCoreOptional; + private final String bootstrapJava8; + private final String bootstrapJava9; + private final String annotations; + + + public BootDir(String commons, String bootstrapCore, String bootstrapCoreOptional, String bootstrapJava8, String bootstrapJava9, String annotations) { + if (commons == null) { + throw new NullPointerException("commons must not be null"); + } + if (bootstrapCore == null) { + throw new NullPointerException("bootstrapCore must not be null"); + } + + this.commons = commons; + this.bootstrapCore = bootstrapCore; + // optional + this.bootstrapCoreOptional = bootstrapCoreOptional; + this.bootstrapJava8 = bootstrapJava8; + // optional + this.bootstrapJava9 = bootstrapJava9; + // optional + this.annotations = annotations; + + verify(); + } + + private void verify() { + // 2st find pinpoint-commons.jar + final String pinpointCommonsJar = getCommons(); + if (pinpointCommonsJar == null) { + throw new IllegalStateException("pinpoint-commons-x.x.x(-SNAPSHOT).jar not found"); + } + + // 3st find bootstrap-core.jar + final String bootStrapCoreJar = getBootstrapCore(); + if (bootStrapCoreJar == null) { + throw new IllegalStateException("pinpoint-bootstrap-core-x.x.x(-SNAPSHOT).jar not found"); + } + + // 4th find bootstrap-core-optional.jar + final String bootStrapCoreOptionalJar = getBootstrapCoreOptional(); + if (bootStrapCoreOptionalJar == null) { + // optional + logger.info("pinpoint-bootstrap-core-optional-x.x.x(-SNAPSHOT).jar not found"); + } + + final String bootStrapJava8Jar = getBootstrapJava8(); + if (bootStrapJava8Jar == null) { + // optional + logger.info("pinpoint-bootstrap-java8-x.x.x(-SNAPSHOT).jar not found"); + } + + final String bootStrapJava9Jar = getBootstrapJava9(); + if (bootStrapJava9Jar == null) { + // optional + logger.info("pinpoint-bootstrap-java9-x.x.x(-SNAPSHOT).jar not found"); + } + // 6th find annotations.jar : optional dependency + final String annotationsJar = getAnnotations(); + if (annotationsJar == null) { + logger.info("pinpoint-annotations-x.x.x(-SNAPSHOT).jar not found"); + } + } + + public String getCommons() { + return commons; + } + + public String getBootstrapCore() { + return bootstrapCore; + } + + public String getBootstrapCoreOptional() { + return bootstrapCoreOptional; + } + + public String getBootstrapJava8() { + return bootstrapJava8; + } + + public String getBootstrapJava9() { + return bootstrapJava9; + } + + public String getAnnotations() { + return annotations; + } + + public List toList() { + final List list = new ArrayList(); + + addFilePath(list, commons, true); + addFilePath(list, bootstrapCore, true); + addFilePath(list, bootstrapCoreOptional, false); + addFilePath(list, bootstrapJava8, false); + addFilePath(list, bootstrapJava9, false); + addFilePath(list, annotations, false); + + return list; + } + + private void addFilePath(List list, String filePath, boolean required) { + if (required) { + if (filePath == null) { + throw new IllegalStateException("filePath must not be null"); + } + } else { + if (filePath == null) { + return; + } + } + list.add(filePath); + } + + public List openJarFiles() { + final List jarFileList = new ArrayList(); + + addJarFile(jarFileList, commons, true); + addJarFile(jarFileList, bootstrapCore, true); + addJarFile(jarFileList, bootstrapCoreOptional, false); + addJarFile(jarFileList, bootstrapJava8, false); + addJarFile(jarFileList, bootstrapJava9, false); + addJarFile(jarFileList, annotations, false); + + return jarFileList; + } + + private void addJarFile(List list, String filePath, boolean required) { + if (required) { + if (filePath == null) { + throw new IllegalStateException("filePath must not be null"); + } + } else { + if (filePath == null) { + return; + } + } + JarFile jarFile = JarFileUtils.openJarFile(filePath); + list.add(jarFile); + } +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/ClassPathResolver.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/ClassPathResolver.java new file mode 100644 index 000000000000..f5e6f1876876 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/ClassPathResolver.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.agentdir; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface ClassPathResolver { + + AgentDirectory resolve(); + +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/JarFileUtils.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/JarFileUtils.java new file mode 100644 index 000000000000..e31b6571192a --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/JarFileUtils.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.agentdir; + +import java.io.File; +import java.io.IOException; +import java.util.jar.JarFile; + +/** + * @author Woonduk Kang(emeroad) + */ +final class JarFileUtils { + + public static JarFile openJarFile(String filePath) { + if (filePath == null) { + throw new NullPointerException("filePath must not be null"); + } + + final File file = new File(filePath); + if (!file.exists()) { + throw new IllegalArgumentException(file + " not found"); + } + if (file.isDirectory()) { + throw new IllegalArgumentException(file + " is directory"); + } + if (!(file.isFile())) { + throw new IllegalArgumentException(file + " not file"); + } + if (!file.canRead()) { + throw new IllegalArgumentException(file + " can read"); + } + try { + return new JarFile(file); + } catch (IOException e) { + throw new IllegalStateException(file + " create fail Caused by:" + e.getMessage(), e); + } + } +} diff --git a/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/JavaAgentPathResolver.java b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/JavaAgentPathResolver.java new file mode 100644 index 000000000000..cf59d266cd46 --- /dev/null +++ b/bootstrap/src/main/java/com/navercorp/pinpoint/bootstrap/agentdir/JavaAgentPathResolver.java @@ -0,0 +1,100 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.agentdir; + +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; + +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Woonduk Kang(emeroad) + */ +public class JavaAgentPathResolver { + + static final String JAVA_AGENT_OPTION = "-javaagent:"; + private final Pattern DEFAULT_AGENT_PATTERN = AgentDirBaseClassPathResolver.DEFAULT_AGENT_BOOTSTRAP_PATTERN; + + private final ResolvingType resolvingType; + + enum ResolvingType { + INPUT_ARGUMENT, + // Added for unknown bugs. + @Deprecated + SYSTEM_PROPERTY + }; + + JavaAgentPathResolver(ResolvingType resolvingType) { + if (resolvingType == null) { + throw new NullPointerException("type must not be null"); + } + this.resolvingType = resolvingType; + } + + public static JavaAgentPathResolver newJavaAgentPathResolver() { + final ResolvingType resolvingType = getResolvingType(); + return new JavaAgentPathResolver(resolvingType); + } + + private static ResolvingType getResolvingType() { + final String type = System.getProperty("pinpoint.javaagent.resolving", ""); + if (type.equalsIgnoreCase("system")) { + return ResolvingType.SYSTEM_PROPERTY; + } + return ResolvingType.INPUT_ARGUMENT; + } + + public String resolveJavaAgentPath() { + if (resolvingType == ResolvingType.SYSTEM_PROPERTY) { + return getClassPathFromSystemProperty(); + } + + RuntimeMXBean runtimeMXBean = getRuntimeMXBean(); + List inputArguments = runtimeMXBean.getInputArguments(); + for (String inputArgument : inputArguments) { + if (isPinpointAgent(inputArgument, DEFAULT_AGENT_PATTERN)) { + return removeJavaAgentPrefix(inputArgument); + } + } + throw new IllegalArgumentException(JAVA_AGENT_OPTION + " not found"); + } + + @VisibleForTesting + RuntimeMXBean getRuntimeMXBean() { + return ManagementFactory.getRuntimeMXBean(); + } + + private String removeJavaAgentPrefix(String inputArgument) { + return inputArgument.substring(JAVA_AGENT_OPTION.length(), inputArgument.length()); + } + + private boolean isPinpointAgent(String inputArgument, Pattern javaPattern) { + if (!inputArgument.startsWith(JAVA_AGENT_OPTION)) { + return false; + } + Matcher matcher = javaPattern.matcher(inputArgument); + return matcher.find(); + } + + String getClassPathFromSystemProperty() { + return System.getProperty("java.class.path"); + } + +} diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentBootLoaderTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentBootLoaderTest.java new file mode 100644 index 000000000000..d879ef7fb2d6 --- /dev/null +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentBootLoaderTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap; + + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.instrument.Instrumentation; +import java.net.URL; + +import java.util.Collections; + +import static org.mockito.Mockito.mock; + +/** + * @author emeroad + */ +public class AgentBootLoaderTest { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void boot() { + ClassLoader classLoader = AgentBootLoaderTest.class.getClassLoader(); + AgentBootLoader agentBootLoader = new AgentBootLoader("com.navercorp.pinpoint.bootstrap.DummyAgent", new URL[0], classLoader); + Instrumentation instrumentation = mock(Instrumentation.class); + AgentOption option = new DefaultAgentOption(instrumentation, "testCaseAgent", "testCaseAppName", false, new DefaultProfilerConfig(), Collections.emptyList(), null); + Agent boot = agentBootLoader.boot(option); + + boot.stop(); + } + + private String getProjectLibDir() { + // not really necessary, but useful for testing protectionDomain + URL location = CodeSourceUtils.getCodeLocation(AgentBootLoader.class); + + logger.debug("lib location:{}", location); + String path = location.getPath(); + // file:/D:/nhn_source/pinpoint_project/pinpoint-tomcat-profiler/target/classes/ + int dirPath = path.lastIndexOf("target/classes/"); + if (dirPath == -1) { + throw new RuntimeException("target/classes/ not found"); + } + String projectDir = path.substring(1, dirPath); + return projectDir + "src/test/lib"; + } +} diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentClassLoaderTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentClassLoaderTest.java deleted file mode 100644 index 4b032f02db1b..000000000000 --- a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentClassLoaderTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.bootstrap; - - -import java.io.IOException; -import java.net.URL; -import java.security.CodeSource; -import java.security.ProtectionDomain; - -import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; -import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; - -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author emeroad - */ -public class AgentClassLoaderTest { - - private Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Test - public void boot() throws IOException, ClassNotFoundException { - AgentClassLoader agentClassLoader = new AgentClassLoader(new URL[0]); - agentClassLoader.setBootClass("com.navercorp.pinpoint.bootstrap.DummyAgent"); - AgentOption option = new DefaultAgentOption(new DummyInstrumentation(), "testCaseAgent", "testCaseAppName", new DefaultProfilerConfig(), new URL[0], null, new DefaultServiceTypeRegistryService(), new DefaultAnnotationKeyRegistryService()); - agentClassLoader.boot(option); - // TODO need verification - implementation for obtaining logger changed -// PLoggerBinder loggerBinder = (PLoggerBinder) agentClassLoader.initializeLoggerBinder(); -// PLogger test = loggerBinder.getLogger("test"); -// test.info("slf4j logger test"); - - } - - private String getProjectLibDir() { - // not really necessary, but useful for testing protectionDomain - ProtectionDomain protectionDomain = AgentClassLoader.class.getProtectionDomain(); - CodeSource codeSource = protectionDomain.getCodeSource(); - URL location = codeSource.getLocation(); - - logger.debug("lib location:{}", location); - String path = location.getPath(); - // file:/D:/nhn_source/pinpoint_project/pinpoint-tomcat-profiler/target/classes/ - int dirPath = path.lastIndexOf("target/classes/"); - if (dirPath == -1) { - throw new RuntimeException("target/classes/ not found"); - } - String projectDir = path.substring(1, dirPath); - return projectDir + "src/test/lib"; - } -} diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentDirGenerator.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentDirGenerator.java index 1e904e94def2..4777278c1cde 100644 --- a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentDirGenerator.java +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentDirGenerator.java @@ -42,6 +42,7 @@ public class AgentDirGenerator { private static final String commons = "pinpoint-commons-" + Version.VERSION + ".jar"; private static final String bootStrapCoreJar = "pinpoint-bootstrap-core-" + Version.VERSION + ".jar"; + private static final String bootStrapJava9Jar = "pinpoint-bootstrap-java9-" + Version.VERSION + ".jar"; private static final String bootStrapCoreOptionalJar = "pinpoint-bootstrap-core-optional-" + Version.VERSION + ".jar"; private static final String annotations = "pinpoint-annotations-" + Version.VERSION + ".jar"; @@ -65,6 +66,7 @@ public void create() throws IOException { createJarFile(boot, commons); createJarFile(boot, bootStrapCoreJar); + createJarFile(boot, bootStrapJava9Jar); createJarFile(boot, bootStrapCoreOptionalJar); createJarFile(boot, annotations); } diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/ContainerResolverTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/ContainerResolverTest.java new file mode 100644 index 000000000000..58265a5b0bf9 --- /dev/null +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/ContainerResolverTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Properties; + +/** + * @author HyunGil Jeong + */ +public class ContainerResolverTest { + + @Test + public void noKeyShouldReturnFalse() { + Properties properties = new Properties(); + ContainerResolver containerResolver = new ContainerResolver(properties); + Assert.assertFalse(containerResolver.isContainer()); + } + + @Test + public void emptyValueShouldReturnTrue() { + Properties properties = new Properties(); + properties.put(ContainerResolver.CONTAINER_PROPERTY_KEY, ""); + ContainerResolver containerResolver = new ContainerResolver(properties); + Assert.assertTrue(containerResolver.isContainer()); + } + + @Test + public void trueValueShouldReturnTrue() { + Properties properties = new Properties(); + properties.put(ContainerResolver.CONTAINER_PROPERTY_KEY, "tRue"); + ContainerResolver containerResolver = new ContainerResolver(properties); + Assert.assertTrue(containerResolver.isContainer()); + } +} diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/DummyInstrumentation.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/DummyInstrumentation.java deleted file mode 100644 index d8a0f2ebbc42..000000000000 --- a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/DummyInstrumentation.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.bootstrap; - -import java.lang.instrument.ClassDefinition; -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.Instrumentation; -import java.lang.instrument.UnmodifiableClassException; -import java.util.jar.JarFile; - -/** - * @author emeroad - */ -public class DummyInstrumentation implements Instrumentation { - @Override - public void addTransformer(ClassFileTransformer transformer, boolean canRetransform) { - - } - - @Override - public void addTransformer(ClassFileTransformer transformer) { - - } - - @Override - public boolean removeTransformer(ClassFileTransformer transformer) { - return false; - } - - @Override - public boolean isRetransformClassesSupported() { - return false; - } - - @Override - public void retransformClasses(Class... classes) throws UnmodifiableClassException { - - } - - @Override - public boolean isRedefineClassesSupported() { - return false; - } - - @Override - public void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException { - - } - - @Override - public boolean isModifiableClass(Class theClass) { - return false; - } - - @Override - public Class[] getAllLoadedClasses() { - return new Class[0]; - } - - @Override - public Class[] getInitiatedClasses(ClassLoader loader) { - return new Class[0]; - } - - @Override - public long getObjectSize(Object objectToSize) { - return 0; - } - - @Override - public void appendToBootstrapClassLoaderSearch(JarFile jarfile) { - - } - - @Override - public void appendToSystemClassLoaderSearch(JarFile jarfile) { - - } - - @Override - public boolean isNativeMethodPrefixSupported() { - return false; - } - - @Override - public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) { - - } -} diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentDirBaseClassPathResolverTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentDirBaseClassPathResolverTest.java similarity index 76% rename from bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentDirBaseClassPathResolverTest.java rename to bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentDirBaseClassPathResolverTest.java index 4f14e1896ee1..3c0e547f3383 100644 --- a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentDirBaseClassPathResolverTest.java +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentDirBaseClassPathResolverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,9 +14,11 @@ * limitations under the License. */ -package com.navercorp.pinpoint.bootstrap; +package com.navercorp.pinpoint.bootstrap.agentdir; +import com.navercorp.pinpoint.bootstrap.AgentDirGenerator; import com.navercorp.pinpoint.common.Version; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; import org.apache.commons.io.FileUtils; import org.junit.AfterClass; import org.junit.Assert; @@ -92,31 +94,31 @@ public void testFindAgentJar() throws Exception { logger.debug("agentBootstrapPath:{}", agentBootstrapPath); AgentDirBaseClassPathResolver classPathResolver = new AgentDirBaseClassPathResolver(agentBootstrapPath); - Assert.assertTrue("verify agent directory ", classPathResolver.verify()); + AgentDirectory agentDirectory = classPathResolver.resolve(); + Assert.assertTrue("verify agent directory ", agentDirectory != null); - boolean findAgentJar = classPathResolver.findAgentJar(); - Assert.assertTrue(findAgentJar); + String findAgentJar = agentDirectory.getAgentJarName(); + Assert.assertNotNull(findAgentJar); - String agentJar = classPathResolver.getAgentJarName(); + String agentJar = agentDirectory.getAgentJarName(); Assert.assertEquals(BOOTSTRAP_JAR, agentJar); - String agentPath = classPathResolver.getAgentJarFullPath(); + String agentPath = agentDirectory.getAgentJarFullPath(); Assert.assertEquals(agentBootstrapPath, agentPath); - String agentDirPath = classPathResolver.getAgentDirPath(); + String agentDirPath = agentDirectory.getAgentDirPath(); Assert.assertEquals(agentBuildDir, agentDirPath); - String agentLibPath = classPathResolver.getAgentLibPath(); + String agentLibPath = agentDirectory.getAgentLibPath(); Assert.assertEquals(agentBuildDir + File.separator + "lib", agentLibPath); - BootstrapJarFile bootstrapJarFile = classPathResolver.getBootstrapJarFile(); + List bootstrapJarFile = agentDirectory.getBootDir().openJarFiles(); closeJarFile(bootstrapJarFile); } - private void closeJarFile(BootstrapJarFile bootstrapJarFile) { - final List jarFileList = bootstrapJarFile.getJarFileList(); - for (JarFile jarFile : jarFileList) { + private void closeJarFile(List jarFiles) { + for (JarFile jarFile : jarFiles) { try { jarFile.close(); } catch (IOException e) { @@ -126,9 +128,8 @@ private void closeJarFile(BootstrapJarFile bootstrapJarFile) { } private static String getClassLocation(Class clazz) { - CodeSource codeSource = clazz.getProtectionDomain().getCodeSource(); - URL location = codeSource.getLocation(); - logger.debug("codeSource.getLocation:{}", location); + URL location = CodeSourceUtils.getCodeLocation(clazz); + logger.debug("codeSource.getCodeLocation:{}", location); File file = FileUtils.toFile(location); return file.getPath(); } @@ -147,14 +148,14 @@ public void findAgentJar() { private void findAgentJar(String path) { AgentDirBaseClassPathResolver classPathResolver = new AgentDirBaseClassPathResolver(path); - boolean agentJar = classPathResolver.findAgentJar(); - Assert.assertTrue(agentJar); + String agentJar = classPathResolver.findBootstrapJar(path); + Assert.assertNotNull(agentJar); } private void findAgentJarAssertFail(String path) { AgentDirBaseClassPathResolver classPathResolver = new AgentDirBaseClassPathResolver(path); - boolean agentJar = classPathResolver.findAgentJar(); - Assert.assertFalse(agentJar); + String agentJar = classPathResolver.findBootstrapJar(path); + Assert.assertNull(agentJar); } } diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentVersionTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentVersionTest.java similarity index 92% rename from bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentVersionTest.java rename to bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentVersionTest.java index 21b67d65e939..869458f96693 100644 --- a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/AgentVersionTest.java +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/agentdir/AgentVersionTest.java @@ -1,21 +1,20 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ -package com.navercorp.pinpoint.bootstrap; +package com.navercorp.pinpoint.bootstrap.agentdir; import org.junit.Assert; import org.junit.Test; diff --git a/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/agentdir/JavaAgentPathResolverTest.java b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/agentdir/JavaAgentPathResolverTest.java new file mode 100644 index 000000000000..4c51aa6a801a --- /dev/null +++ b/bootstrap/src/test/java/com/navercorp/pinpoint/bootstrap/agentdir/JavaAgentPathResolverTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.bootstrap.agentdir; + +import org.junit.Test; + +import java.lang.management.RuntimeMXBean; +import java.util.Collections; +import java.util.List; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author Woonduk Kang(emeroad) + */ +public class JavaAgentPathResolverTest { + + @Test + public void testInputArgument() { + String agentPath = "/pinpoint/agent/target/pinpoint-agent-1.8.1-SNAPSHOT/pinpoint-bootstrap-1.8.1-SNAPSHOT.jar"; + final RuntimeMXBean runtimeMXBean = mock(RuntimeMXBean.class); + List inputArguments = Collections.singletonList(JavaAgentPathResolver.JAVA_AGENT_OPTION + agentPath); + when(runtimeMXBean.getInputArguments()).thenReturn(inputArguments); + + JavaAgentPathResolver javaAgentPathResolver = new JavaAgentPathResolver(JavaAgentPathResolver.ResolvingType.INPUT_ARGUMENT) { + @Override + RuntimeMXBean getRuntimeMXBean() { + return runtimeMXBean; + } + }; + String resolveJavaAgentPath = javaAgentPathResolver.resolveJavaAgentPath(); + org.junit.Assert.assertEquals(resolveJavaAgentPath, agentPath); + } + +} \ No newline at end of file diff --git a/clover.license b/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-collector @@ -15,7 +31,6 @@ 1.8 ${env.JAVA_8_HOME} java18 - 2.8.10 @@ -173,6 +188,15 @@ javax.servlet-api provided + + + com.navercorp.pinpoint + pinpoint-rpc + ${project.version} + test-jar + test + + @@ -190,57 +214,6 @@ ${basedir}/src/main/resources-${env} - - - - com.spotify - docker-maven-plugin - ${docker.maven.plugin.version} - - false - naver/${project.artifactId}:${project.version} - tomcat:8-jre8 - - ["/usr/local/bin/start-collector.sh"] - - - 9994 - 9995 - 9996 - - - - /assets/ - ${project.build.directory} - ${project.artifactId}-${project.version}.war - - - /assets/ - ${project.build.directory}/deploy/WEB-INF/classes/ - - pinpoint-collector.properties - hbase.properties - - - - /usr/local/bin/ - ${project.basedir}/ - start-collector.sh - - - - chmod a+x /usr/local/bin/start-collector.sh - rm -rf /usr/local/tomcat/webapps/* - sed -i -e 's/8005/9005/' /usr/local/tomcat/conf/server.xml - sed -i -e 's/8080/9080/' /usr/local/tomcat/conf/server.xml - sed -i -e 's/8009/9009/' /usr/local/tomcat/conf/server.xml - sed -i -e 's/8443/9443/' /usr/local/tomcat/conf/server.xml - unzip /assets/${project.artifactId}-${project.version}.war -d /usr/local/tomcat/webapps/ROOT - rm -rf /assets/${project.artifactId}-${project.version}.war - - - - diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/ClusterPointRepository.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/ClusterPointRepository.java index 88618675d61f..6e35e3a609dc 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/ClusterPointRepository.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/ClusterPointRepository.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -30,6 +30,10 @@ public class ClusterPointRepository implements ClusterPo private final CopyOnWriteArrayList clusterPointRepository = new CopyOnWriteArrayList<>(); public boolean addClusterPoint(T clusterPoint) { + if (logger.isInfoEnabled()) { + logger.info("addClusterPoint(clusterPoint = [{}])", clusterPoint); + } + boolean isAdd = clusterPointRepository.addIfAbsent(clusterPoint); if (!isAdd) { @@ -40,6 +44,10 @@ public boolean addClusterPoint(T clusterPoint) { } public boolean removeClusterPoint(T clusterPoint) { + if (logger.isInfoEnabled()) { + logger.info("addClusterPoint(clusterPoint = [{}])", clusterPoint); + } + boolean isRemove = clusterPointRepository.remove(clusterPoint); if (!isRemove) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/ClusterPointRouter.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/ClusterPointRouter.java index dafe9e92c26c..d86c8de11eec 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/ClusterPointRouter.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/ClusterPointRouter.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,6 +20,7 @@ import com.navercorp.pinpoint.collector.cluster.route.RequestEvent; import com.navercorp.pinpoint.collector.cluster.route.StreamEvent; import com.navercorp.pinpoint.collector.cluster.route.StreamRouteHandler; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.rpc.MessageListener; import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.packet.RequestPacket; @@ -64,6 +65,7 @@ public class ClusterPointRouter implements MessageListener, ServerStreamChannelM private SerializerFactory commandSerializerFactory; @Autowired + @Qualifier("commandHeaderTBaseDeserializerFactory") private DeserializerFactory commandDeserializerFactory; public ClusterPointRouter(ClusterPointRepository targetClusterPointRepository, @@ -127,11 +129,12 @@ public void handleStreamClose(ServerStreamChannelContext streamChannelContext, S } private boolean handleRouteRequest(TCommandTransfer request, RequestPacket requestPacket, PinpointSocket pinpointSocket) { - byte[] payload = ((TCommandTransfer)request).getPayload(); + byte[] payload = request.getPayload(); TBase command = deserialize(payload); - TCommandTransferResponse response = routeHandler.onRoute(new RequestEvent((TCommandTransfer) request, pinpointSocket.getRemoteAddress(), requestPacket.getRequestId(), command)); - pinpointSocket.response(requestPacket, serialize(response)); + RequestEvent event = new RequestEvent(request, pinpointSocket.getRemoteAddress(), requestPacket.getRequestId(), command); + TCommandTransferResponse response = routeHandler.onRoute(event); + pinpointSocket.response(requestPacket.getRequestId(), serialize(response)); return response.getRouteResult() == TRouteResult.OK; } @@ -140,11 +143,11 @@ private void handleRouteRequestFail(String message, RequestPacket requestPacket, TResult tResult = new TResult(false); tResult.setMessage(message); - pinpointSocket.response(requestPacket, serialize(tResult)); + pinpointSocket.response(requestPacket.getRequestId(), serialize(tResult)); } private StreamCode handleStreamRouteCreate(TCommandTransfer request, StreamCreatePacket packet, ServerStreamChannelContext streamChannelContext) { - byte[] payload = ((TCommandTransfer)request).getPayload(); + byte[] payload = request.getPayload(); TBase command = deserialize(payload); if (command == null) { return StreamCode.TYPE_UNKNOWN; @@ -169,7 +172,11 @@ private byte[] serialize(TBase result) { } private TBase deserialize(byte[] objectData) { - return SerializationUtils.deserialize(objectData, commandDeserializerFactory, null); + final Message> deserialize = SerializationUtils.deserialize(objectData, commandDeserializerFactory, null); + if (deserialize == null) { + return null; + } + return deserialize.getData(); } private StreamCode convertToStreamCode(TRouteResult routeResult) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/ClusterConnectionManager.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/ClusterConnectionManager.java index feeaf1a436d7..e752bc07573b 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/ClusterConnectionManager.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/ClusterConnectionManager.java @@ -15,8 +15,8 @@ */ package com.navercorp.pinpoint.collector.cluster.connection; -import java.net.InetSocketAddress; -import java.net.SocketAddress; +import com.navercorp.pinpoint.collector.util.Address; + import java.util.List; /** @@ -27,9 +27,9 @@ public interface ClusterConnectionManager { void stop(); - void connectPointIfAbsent(InetSocketAddress address); + void connectPointIfAbsent(Address address); - public void disconnectPoint(SocketAddress address); + void disconnectPoint(Address address); - public List getConnectedAddressList(); + List
getConnectedAddressList(); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/ClusterServerMessageListenerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/ClusterServerMessageListenerFactory.java new file mode 100644 index 000000000000..d64858afb330 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/ClusterServerMessageListenerFactory.java @@ -0,0 +1,90 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.cluster.connection; + +import com.navercorp.pinpoint.rpc.MessageListener; +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; +import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; +import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.rpc.packet.SendPacket; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.rpc.server.ServerMessageListenerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + * @author Taejin Koo + */ +class ClusterServerMessageListenerFactory implements ServerMessageListenerFactory { + + private final String clusterId; + private final MessageListener routeMessageListener; + + public ClusterServerMessageListenerFactory(String clusterId, MessageListener routeMessageListener) { + this.clusterId = clusterId; + this.routeMessageListener = routeMessageListener; + } + + @Override + public ServerMessageListener create() { + return new ClusterServerMessageListener(clusterId, routeMessageListener); + } + + + private static class ClusterServerMessageListener implements ServerMessageListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final String clusterId; + private final MessageListener routeMessageListener; + + public ClusterServerMessageListener(String clusterId, MessageListener routeMessageListener) { + this.clusterId = clusterId; + this.routeMessageListener = routeMessageListener; + } + + @Override + public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { + logger.info("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); + } + + @Override + public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { + logger.info("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); + + // TODO : need handle control message (looks like getClusterId, ..) + routeMessageListener.handleRequest(requestPacket, pinpointSocket); + } + + @Override + public HandshakeResponseCode handleHandshake(Map properties) { + logger.info("handle handShake {}", properties); + return HandshakeResponseCode.DUPLEX_COMMUNICATION; + } + + @Override + public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { + logger.info("ping received packet:{}, remote:{}", pingPacket, pinpointServer); + } + + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterAcceptor.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterAcceptor.java index 76517a514c49..f7ceb028ed7e 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterAcceptor.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterAcceptor.java @@ -17,19 +17,16 @@ package com.navercorp.pinpoint.collector.cluster.connection; -import com.navercorp.pinpoint.rpc.MessageListener; -import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.collector.util.Address; +import com.navercorp.pinpoint.collector.util.DefaultAddress; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.rpc.cluster.ClusterOption; import com.navercorp.pinpoint.rpc.cluster.Role; import com.navercorp.pinpoint.rpc.common.SocketStateCode; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; -import com.navercorp.pinpoint.rpc.packet.SendPacket; import com.navercorp.pinpoint.rpc.server.ChannelFilter; import com.navercorp.pinpoint.rpc.server.PinpointServer; import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.rpc.server.ServerOption; import com.navercorp.pinpoint.rpc.server.handler.ServerStateChangeEventHandler; import com.navercorp.pinpoint.rpc.util.ClassUtils; import org.slf4j.Logger; @@ -37,7 +34,6 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.Map; /** * @author Taejin Koo @@ -46,6 +42,7 @@ public class CollectorClusterAcceptor implements CollectorClusterConnectionProvi private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final String name; private final InetSocketAddress bindAddress; private final CollectorClusterConnectionRepository clusterSocketRepository; @@ -54,73 +51,41 @@ public class CollectorClusterAcceptor implements CollectorClusterConnectionProvi private final CollectorClusterConnectionOption option; public CollectorClusterAcceptor(CollectorClusterConnectionOption option, InetSocketAddress bindAddress, CollectorClusterConnectionRepository clusterSocketRepository) { - this.option = option; - this.bindAddress = bindAddress; - this.clusterSocketRepository = clusterSocketRepository; + this.name = ClassUtils.simpleClassName(this); + this.option = Assert.requireNonNull(option, "option must not be null"); + this.bindAddress = Assert.requireNonNull(bindAddress, "bindAddress must not be null"); + this.clusterSocketRepository = Assert.requireNonNull(clusterSocketRepository, "clusterSocketRepository must not be null"); } @Override public void start() { - logger.info("{} initialization started.", ClassUtils.simpleClassName(this)); + logger.info("{} initialization started.", name); ClusterOption clusterOption = new ClusterOption(true, option.getClusterId(), Role.ROUTER); - PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(clusterOption, ChannelFilter.BYPASS); - serverAcceptor.setMessageListener(new ClusterServerMessageListener(option.getClusterId(), option.getRouteMessageHandler())); + ServerOption.Builder serverOptionBuilder = new ServerOption.Builder(); + serverOptionBuilder.setClusterOption(clusterOption); + + PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(serverOptionBuilder.build(), ChannelFilter.BYPASS); + serverAcceptor.setMessageListenerFactory(new ClusterServerMessageListenerFactory(option.getClusterId(), option.getRouteMessageHandler())); serverAcceptor.setServerStreamChannelMessageListener(option.getRouteStreamMessageHandler()); serverAcceptor.addStateChangeEventHandler(new WebClusterServerChannelStateChangeHandler()); serverAcceptor.bind(bindAddress); this.serverAcceptor = serverAcceptor; - logger.info("{} initialization completed.", ClassUtils.simpleClassName(this)); + logger.info("{} initialization completed.", name); } @Override public void stop() { - logger.info("{} destroying started.", ClassUtils.simpleClassName(this)); + logger.info("{} destroying started.", name); if (serverAcceptor != null) { serverAcceptor.close(); } - logger.info("{} destroying completed.", ClassUtils.simpleClassName(this)); - } - - class ClusterServerMessageListener implements ServerMessageListener { - - private final String clusterId; - private final MessageListener routeMessageListener; - - public ClusterServerMessageListener(String clusterId, MessageListener routeMessageListener) { - this.clusterId = clusterId; - this.routeMessageListener = routeMessageListener; - } - - @Override - public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { - logger.info("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); - } - - @Override - public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - logger.info("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); - - // TODO : need handle control message (looks like getClusterId, ..) - routeMessageListener.handleRequest(requestPacket, pinpointSocket); - } - - @Override - public HandshakeResponseCode handleHandshake(Map properties) { - logger.info("handle handShake {}", properties); - return HandshakeResponseCode.DUPLEX_COMMUNICATION; - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - logger.info("ping received packet:{}, remote:{}", pingPacket, pinpointServer); - } - + logger.info("{} destroying completed.", name); } class WebClusterServerChannelStateChangeHandler implements ServerStateChangeEventHandler { @@ -128,16 +93,25 @@ class WebClusterServerChannelStateChangeHandler implements ServerStateChangeEven @Override public void eventPerformed(PinpointServer pinpointServer, SocketStateCode stateCode) throws Exception { if (stateCode.isRunDuplex()) { - SocketAddress remoteAddress = pinpointServer.getRemoteAddress(); - clusterSocketRepository.putIfAbsent(remoteAddress, pinpointServer); + Address address = getAddress(pinpointServer); + clusterSocketRepository.putIfAbsent(address, pinpointServer); return; } else if (stateCode.isClosed()) { - SocketAddress remoteAddress = pinpointServer.getRemoteAddress(); - clusterSocketRepository.remove(remoteAddress); + Address address = getAddress(pinpointServer); + clusterSocketRepository.remove(address); return; } } + private Address getAddress(PinpointServer pinpointServer) { + final SocketAddress remoteAddress = pinpointServer.getRemoteAddress(); + if (!(remoteAddress instanceof InetSocketAddress)) { + throw new IllegalStateException("unexpected address type:" + remoteAddress); + } + InetSocketAddress inetSocketAddress = (InetSocketAddress) remoteAddress; + return new DefaultAddress(inetSocketAddress.getHostString(), inetSocketAddress.getPort()); + } + @Override public void exceptionCaught(PinpointServer pinpointServer, SocketStateCode stateCode, Throwable e) { } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionFactory.java index 7a765e1251f0..9e225abdf46c 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionFactory.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionFactory.java @@ -17,6 +17,7 @@ package com.navercorp.pinpoint.collector.cluster.connection; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.rpc.MessageListener; import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelMessageListener; @@ -34,7 +35,7 @@ public class CollectorClusterConnectionFactory implements CollectorClusterConnec private final ServerStreamChannelMessageListener routeStreamMessageHandler; public CollectorClusterConnectionFactory(String clusterId, MessageListener routeMessageHandler, ServerStreamChannelMessageListener routeStreamMessageHandler) { - this.clusterId = clusterId; + this.clusterId = Assert.requireNonNull(clusterId, "clusterId must not be null"); this.routeMessageHandler = routeMessageHandler; this.routeStreamMessageHandler = routeStreamMessageHandler; } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionManager.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionManager.java index 1c293fe7325a..f7aad45ad678 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionManager.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionManager.java @@ -17,14 +17,13 @@ package com.navercorp.pinpoint.collector.cluster.connection; +import com.navercorp.pinpoint.collector.util.Address; import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.util.ClassUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.util.List; /** @@ -45,11 +44,9 @@ public CollectorClusterConnectionManager(String clusterId, CollectorClusterConne } public CollectorClusterConnectionManager(String clusterId, CollectorClusterConnectionRepository socketRepository, CollectorClusterConnector client, CollectorClusterAcceptor acceptor) { - Assert.requireNonNull(client, "clusterConnector must not be null."); - - this.clusterId = clusterId; + this.clusterId = Assert.requireNonNull(clusterId, "clusterId must not be null"); this.socketRepository = socketRepository; - this.clusterConnector = client; + this.clusterConnector = Assert.requireNonNull(client, "clusterConnector must not be null."); this.clusterAcceptor = acceptor; } @@ -90,7 +87,7 @@ public void stop() { } @Override - public void connectPointIfAbsent(InetSocketAddress address) { + public void connectPointIfAbsent(Address address) { logger.info("localhost -> {} connect started.", address); if (socketRepository.containsKey(address)) { @@ -98,13 +95,14 @@ public void connectPointIfAbsent(InetSocketAddress address) { return; } - socketRepository.putIfAbsent(address, clusterConnector.connect(address)); + PinpointSocket connect = clusterConnector.connect(address); + socketRepository.putIfAbsent(address, connect); logger.info("localhost -> {} connect completed.", address); } @Override - public void disconnectPoint(SocketAddress address) { + public void disconnectPoint(Address address) { logger.info("localhost -> {} disconnect started.", address); PinpointSocket socket = socketRepository.remove(address); @@ -117,7 +115,7 @@ public void disconnectPoint(SocketAddress address) { } @Override - public List getConnectedAddressList() { + public List
getConnectedAddressList() { return socketRepository.getAddressList(); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionRepository.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionRepository.java index 161b8540f146..e09e8f65dd06 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionRepository.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnectionRepository.java @@ -17,9 +17,9 @@ package com.navercorp.pinpoint.collector.cluster.connection; +import com.navercorp.pinpoint.collector.util.Address; import com.navercorp.pinpoint.rpc.PinpointSocket; -import java.net.SocketAddress; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -30,23 +30,23 @@ */ public class CollectorClusterConnectionRepository { - private final ConcurrentHashMap clusterConnectionRepository = new ConcurrentHashMap<>(); + private final ConcurrentHashMap clusterConnectionRepository = new ConcurrentHashMap<>(); - public PinpointSocket putIfAbsent(SocketAddress address, PinpointSocket pinpointSocket) { + public PinpointSocket putIfAbsent(Address address, PinpointSocket pinpointSocket) { return clusterConnectionRepository.putIfAbsent(address, pinpointSocket); } - public PinpointSocket remove(SocketAddress address) { + public PinpointSocket remove(Address address) { return clusterConnectionRepository.remove(address); } - public boolean containsKey(SocketAddress address) { + public boolean containsKey(Address address) { return clusterConnectionRepository.containsKey(address); } - public List getAddressList() { + public List
getAddressList() { // fix jdk 8 KeySetView compatibility - Set socketAddresses = clusterConnectionRepository.keySet(); + Set
socketAddresses = clusterConnectionRepository.keySet(); return new ArrayList<>(socketAddresses); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnector.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnector.java index 221c4fe87e2f..b0ed43e04fab 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnector.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/connection/CollectorClusterConnector.java @@ -17,6 +17,8 @@ package com.navercorp.pinpoint.collector.cluster.connection; +import com.navercorp.pinpoint.collector.util.Address; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; @@ -27,7 +29,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; @@ -41,7 +42,7 @@ public class CollectorClusterConnector implements CollectorClusterConnectionProv private PinpointClientFactory clientFactory; public CollectorClusterConnector(CollectorClusterConnectionOption option) { - this.option = option; + this.option = Assert.requireNonNull(option, "option must not be null"); } @Override @@ -52,7 +53,8 @@ public void start() { this.clientFactory = new DefaultPinpointClientFactory(); - this.clientFactory.setTimeoutMillis(1000 * 5); + this.clientFactory.setWriteTimeoutMillis(1000 * 3); + this.clientFactory.setRequestTimeoutMillis(1000 * 5); this.clientFactory.setMessageListener(option.getRouteMessageHandler()); this.clientFactory.setServerStreamChannelMessageListener(option.getRouteStreamMessageHandler()); this.clientFactory.setClusterOption(clusterOption); @@ -75,12 +77,12 @@ public void stop() { logger.info("{} destroying completed.", ClassUtils.simpleClassName(this)); } - PinpointSocket connect(InetSocketAddress address) { + PinpointSocket connect(Address address) { if (clientFactory == null) { throw new IllegalStateException("not started."); } - PinpointSocket socket = ClientFactoryUtils.createPinpointClient(address, clientFactory); + PinpointSocket socket = ClientFactoryUtils.createPinpointClient(address.getHost(), address.getPort(), clientFactory); return socket; } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/FlinkClusterConnectionManager.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/FlinkClusterConnectionManager.java index a40430f199b4..3dc9aaefafbe 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/FlinkClusterConnectionManager.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/FlinkClusterConnectionManager.java @@ -16,15 +16,17 @@ package com.navercorp.pinpoint.collector.cluster.flink; import com.navercorp.pinpoint.collector.cluster.connection.ClusterConnectionManager; -import com.navercorp.pinpoint.profiler.sender.TcpDataSender; +import com.navercorp.pinpoint.collector.sender.FlinkRequestFactory; +import com.navercorp.pinpoint.collector.sender.FlinkTcpDataSender; +import com.navercorp.pinpoint.collector.util.Address; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; +import com.navercorp.pinpoint.thrift.io.FlinkHeaderTBaseSerializer; import com.navercorp.pinpoint.thrift.io.FlinkHeaderTBaseSerializerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.util.List; /** @@ -35,16 +37,19 @@ public class FlinkClusterConnectionManager implements ClusterConnectionManager { private final PinpointClientFactory pinpointClientFactory; private final TcpDataSenderRepository tcpDataSenderRepository; private final FlinkHeaderTBaseSerializerFactory flinkHeaderTBaseSerializerFactory; + private final FlinkRequestFactory flinkRequestFactory; - public FlinkClusterConnectionManager(TcpDataSenderRepository tcpDataSenderRepository) { - this.tcpDataSenderRepository = tcpDataSenderRepository; + public FlinkClusterConnectionManager(TcpDataSenderRepository tcpDataSenderRepository, FlinkHeaderTBaseSerializerFactory flinkHeaderTBaseSerializerFactory, FlinkRequestFactory flinkRequestFactory) { + this.tcpDataSenderRepository = Assert.requireNonNull(tcpDataSenderRepository, "tcpDataSenderRepository must not be null"); + this.flinkHeaderTBaseSerializerFactory = Assert.requireNonNull(flinkHeaderTBaseSerializerFactory, "flinkHeaderTBaseSerializerFactory must not be null"); + this.flinkRequestFactory = Assert.requireNonNull(flinkRequestFactory, "flinkRequestFactory must not be null"); this.pinpointClientFactory = newPointClientFactory(); - this.flinkHeaderTBaseSerializerFactory = new FlinkHeaderTBaseSerializerFactory(); } private PinpointClientFactory newPointClientFactory() { PinpointClientFactory pinpointClientFactory = new DefaultPinpointClientFactory(); - pinpointClientFactory.setTimeoutMillis(1000 * 5); + pinpointClientFactory.setWriteTimeoutMillis(1000 * 3); + pinpointClientFactory.setRequestTimeoutMillis(1000 * 5); return pinpointClientFactory; } @@ -62,7 +67,7 @@ public void stop() { } @Override - public void connectPointIfAbsent(InetSocketAddress address) { + public void connectPointIfAbsent(Address address) { logger.info("localhost -> {} connect started.", address); if (tcpDataSenderRepository.containsKey(address)) { @@ -70,16 +75,14 @@ public void connectPointIfAbsent(InetSocketAddress address) { return; } - SenderContext senderContext = createTcpDataSender(address); - + final SenderContext senderContext = createTcpDataSender(address); if (senderContext == null) { return; } - SenderContext context = tcpDataSenderRepository.putIfAbsent(address, senderContext); - + final SenderContext context = tcpDataSenderRepository.putIfAbsent(address, senderContext); if (context != null) { - logger.info("TcpDataSender have already been for {}.", address); + logger.info("FlinkTcpDataSender have already been for {}.", address); senderContext.close(); } @@ -87,10 +90,10 @@ public void connectPointIfAbsent(InetSocketAddress address) { } @Override - public void disconnectPoint(SocketAddress address) { + public void disconnectPoint(Address address) { logger.info("localhost -> {} disconnect started.", address); - SenderContext context = tcpDataSenderRepository.remove(address); + final SenderContext context = tcpDataSenderRepository.remove(address); if (context != null) { context.close(); logger.info("localhost -> {} disconnect completed.", address); @@ -100,13 +103,16 @@ public void disconnectPoint(SocketAddress address) { } @Override - public List getConnectedAddressList() { + public List
getConnectedAddressList() { return tcpDataSenderRepository.getAddressList(); } - private SenderContext createTcpDataSender(InetSocketAddress address) { + private SenderContext createTcpDataSender(Address address) { try { - TcpDataSender tcpDataSender = new TcpDataSender(address, pinpointClientFactory, flinkHeaderTBaseSerializerFactory.createSerializer()); + final String host = address.getHost(); + final int port = address.getPort(); + FlinkHeaderTBaseSerializer serializer = flinkHeaderTBaseSerializerFactory.createSerializer(); + FlinkTcpDataSender tcpDataSender = new FlinkTcpDataSender("flink", host, port, pinpointClientFactory, serializer, flinkRequestFactory); return new SenderContext(tcpDataSender); } catch (Exception e) { logger.error("not create tcpDataSender for {}.", address, e); diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/FlinkClusterService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/FlinkClusterService.java index 424683812351..1834a8d860dd 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/FlinkClusterService.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/FlinkClusterService.java @@ -15,22 +15,23 @@ */ package com.navercorp.pinpoint.collector.cluster.flink; -import com.navercorp.pinpoint.collector.cluster.zookeeper.*; +import com.navercorp.pinpoint.collector.cluster.zookeeper.ZookeeperClusterManager; import com.navercorp.pinpoint.collector.config.CollectorConfiguration; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.CuratorZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperEventWatcher; import com.navercorp.pinpoint.common.server.util.concurrent.CommonState; import com.navercorp.pinpoint.common.server.util.concurrent.CommonStateContext; +import com.navercorp.pinpoint.common.util.Assert; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.proto.WatcherEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.io.IOException; -import java.util.concurrent.atomic.AtomicBoolean; /** * @author minwoo.jung @@ -48,9 +49,9 @@ public class FlinkClusterService { private ZookeeperClusterManager zookeeperClusterManager; public FlinkClusterService(CollectorConfiguration config, FlinkClusterConnectionManager clusterConnectionManager) { - this.config = config; + this.config = Assert.requireNonNull(config, "config must not be null"); this.serviceState = new CommonStateContext(); - this.clusterConnectionManager = clusterConnectionManager; + this.clusterConnectionManager = Assert.requireNonNull(clusterConnectionManager, "clusterConnectionManager must not be null"); } @PostConstruct @@ -66,7 +67,7 @@ public void setUp() throws KeeperException, IOException, InterruptedException { logger.info("{} initialization started.", this.getClass().getSimpleName()); ClusterManagerWatcher watcher = new ClusterManagerWatcher(); - this.client = new DefaultZookeeperClient(config.getFlinkClusterZookeeperAddress(), config.getFlinkClusterSessionTimeout(), watcher); + this.client = new CuratorZookeeperClient(config.getFlinkClusterZookeeperAddress(), config.getFlinkClusterSessionTimeout(), watcher); this.client.connect(); this.zookeeperClusterManager = new ZookeeperClusterManager(client, PINPOINT_FLINK_CLUSTER_PATH, clusterConnectionManager); @@ -76,9 +77,7 @@ public void setUp() throws KeeperException, IOException, InterruptedException { logger.info("{} initialization completed.", this.getClass().getSimpleName()); if (client.isConnected()) { - WatcherEvent watcherEvent = new WatcherEvent(EventType.None.getIntValue(), KeeperState.SyncConnected.getIntValue(), ""); - WatchedEvent event = new WatchedEvent(watcherEvent); - watcher.process(event); + watcher.handleConnected(); } } break; @@ -128,54 +127,41 @@ public ZookeeperClusterManager getZookeeperClusterManager() { class ClusterManagerWatcher implements ZookeeperEventWatcher { - private final AtomicBoolean connected = new AtomicBoolean(false); - @Override public void process(WatchedEvent event) { logger.debug("Process Zookeeper Event({})", event); - KeeperState state = event.getState(); EventType eventType = event.getType(); - // ephemeral node is removed on disconnect event (leave node management exclusively to zookeeper) - if (ZookeeperUtils.isDisconnectedEvent(state, eventType)) { - connected.compareAndSet(true, false); - if (state == KeeperState.Expired) { - if (client != null) { - client.reconnectWhenSessionExpired(); - } - } - return; - } - - // on connect/reconnect event - if (ZookeeperUtils.isConnectedEvent(state, eventType)) { - // could already be connected (failure to compareAndSet doesn't really matter) - boolean changed = connected.compareAndSet(false, true); - } - - if (serviceState.isStarted() && connected.get()) { + if (serviceState.isStarted() && client.isConnected()) { // duplicate event possible - but the logic does not change - if (ZookeeperUtils.isConnectedEvent(state, eventType)) { -// profilerClusterManager.initZookeeperClusterData(); - zookeeperClusterManager.handleAndRegisterWatcher(PINPOINT_FLINK_CLUSTER_PATH); - } else if (eventType == EventType.NodeChildrenChanged) { - String path = event.getPath(); - - if (PINPOINT_FLINK_CLUSTER_PATH.equals(path)) { - zookeeperClusterManager.handleAndRegisterWatcher(path); + if (eventType == EventType.NodeChildrenChanged) { + String eventPath = event.getPath(); + + if (PINPOINT_FLINK_CLUSTER_PATH.equals(eventPath)) { + zookeeperClusterManager.handleAndRegisterWatcher(eventPath); } else { - logger.warn("Unknown Path ChildrenChanged {}.", path); + logger.warn("Unknown Path ChildrenChanged {}.", eventPath); } - } } } @Override - public boolean isConnected() { - return connected.get(); + public boolean handleConnected() { + if (serviceState.isStarted()) { + zookeeperClusterManager.handleAndRegisterWatcher(PINPOINT_FLINK_CLUSTER_PATH); + return true; + } else { + return false; + } + } + + @Override + public boolean handleDisconnected() { + return true; } } + } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/SenderContext.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/SenderContext.java index 454aeacbe923..466a645134d8 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/SenderContext.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/SenderContext.java @@ -15,24 +15,25 @@ */ package com.navercorp.pinpoint.collector.cluster.flink; -import com.navercorp.pinpoint.profiler.sender.TcpDataSender; +import com.navercorp.pinpoint.collector.sender.FlinkTcpDataSender; +import com.navercorp.pinpoint.common.util.Assert; /** * @author minwoo.jung */ public class SenderContext { - private TcpDataSender tcpDataSender; + private FlinkTcpDataSender flinkTcpDataSender; - public SenderContext(TcpDataSender tcpDataSender) { - this.tcpDataSender = tcpDataSender; + public SenderContext(FlinkTcpDataSender tcpDataSender) { + this.flinkTcpDataSender = Assert.requireNonNull(tcpDataSender, "flinkTcpDataSender must not be null"); } - public TcpDataSender getTcpDataSender() { - return tcpDataSender; + public FlinkTcpDataSender getFlinkTcpDataSender() { + return flinkTcpDataSender; } public void close() { - tcpDataSender.stop(); + flinkTcpDataSender.stop(); } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/TcpDataSenderRepository.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/TcpDataSenderRepository.java index 68d189e21241..43624b114866 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/TcpDataSenderRepository.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/flink/TcpDataSenderRepository.java @@ -15,9 +15,10 @@ */ package com.navercorp.pinpoint.collector.cluster.flink; +import com.navercorp.pinpoint.collector.sender.FlinkTcpDataSender; import com.navercorp.pinpoint.collector.service.SendAgentStatService; +import com.navercorp.pinpoint.collector.util.Address; -import java.net.SocketAddress; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -28,43 +29,42 @@ * @author minwoo.jung */ public class TcpDataSenderRepository { - private final ConcurrentHashMap clusterConnectionRepository = new ConcurrentHashMap<>(); + private final ConcurrentHashMap clusterConnectionRepository = new ConcurrentHashMap<>(); private final SendAgentStatService sendAgentStatService; TcpDataSenderRepository(SendAgentStatService sendAgentStatService) { this.sendAgentStatService = sendAgentStatService; } - public SenderContext putIfAbsent(SocketAddress address, SenderContext senderContext) { + public SenderContext putIfAbsent(Address address, SenderContext senderContext) { SenderContext context = clusterConnectionRepository.putIfAbsent(address, senderContext); - replaceDataInsendAgentStatService(); + replaceDataInSendAgentStatService(); return context; } - public SenderContext remove(SocketAddress address) { + public SenderContext remove(Address address) { SenderContext senderContext = clusterConnectionRepository.remove(address); - replaceDataInsendAgentStatService(); + replaceDataInSendAgentStatService(); return senderContext; } - private void replaceDataInsendAgentStatService() { + private void replaceDataInSendAgentStatService() { Collection values = clusterConnectionRepository.values(); - List tcpDataSenderList = new ArrayList<>(values.size()); + List tcpDataSenderList = new ArrayList<>(values.size()); for (SenderContext senderContext : values) { - tcpDataSenderList.add(senderContext.getTcpDataSender()); + tcpDataSenderList.add(senderContext.getFlinkTcpDataSender()); } - sendAgentStatService.replaceFlinkServerList(tcpDataSenderList); + sendAgentStatService.replaceFlinkTcpDataSenderList(tcpDataSenderList); } - public boolean containsKey(SocketAddress address) { + public boolean containsKey(Address address) { return clusterConnectionRepository.containsKey(address); } - public List getAddressList() { - // fix jdk 8 KeySetView compatibility - Set socketAddresses = clusterConnectionRepository.keySet(); + public List
getAddressList() { + Set
socketAddresses = clusterConnectionRepository.keySet(); return new ArrayList<>(socketAddresses); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/route/filter/AgentEventHandlingFilter.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/route/filter/AgentEventHandlingFilter.java index 5c572ea94e15..0e612497d55b 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/route/filter/AgentEventHandlingFilter.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/route/filter/AgentEventHandlingFilter.java @@ -18,23 +18,100 @@ import com.navercorp.pinpoint.collector.cluster.route.ResponseEvent; import com.navercorp.pinpoint.collector.service.AgentEventService; +import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; +import com.navercorp.pinpoint.common.server.util.AgentEventType; +import com.navercorp.pinpoint.common.server.util.AgentEventTypeCategory; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.thrift.dto.command.TCommandTransfer; +import com.navercorp.pinpoint.thrift.dto.command.TCommandTransferResponse; +import com.navercorp.pinpoint.thrift.dto.command.TRouteResult; +import com.navercorp.pinpoint.thrift.io.DeserializerFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; +import com.navercorp.pinpoint.thrift.util.SerializationUtils; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Objects; +import java.util.Set; /** * @author HyunGil Jeong */ +@Service public class AgentEventHandlingFilter implements RouteFilter { + private static final Set RESPONSE_EVENT_TYPES = AgentEventType.getTypesByCategory(AgentEventTypeCategory.USER_REQUEST); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private AgentEventService agentEventService; + @Autowired + @Qualifier("commandHeaderTBaseDeserializerFactory") + private DeserializerFactory commandDeserializerFactory; + @Override public void doEvent(ResponseEvent event) { if (event == null) { return; } final long eventTimestamp = System.currentTimeMillis(); - this.agentEventService.handleResponseEvent(event, eventTimestamp); + handleResponseEvent(event, eventTimestamp); } -} + @Async("agentEventWorker") + public void handleResponseEvent(ResponseEvent responseEvent, long eventTimestamp) { + Objects.requireNonNull(responseEvent, "responseEvent must not be null"); + if (logger.isDebugEnabled()) { + logger.debug("Handle response event {}", responseEvent); + } + final TCommandTransferResponse response = responseEvent.getRouteResult(); + if (response.getRouteResult() != TRouteResult.OK) { + return; + } + insertResponseEvent(responseEvent, eventTimestamp); + } + + private void insertResponseEvent(ResponseEvent responseEvent, long eventTimestamp) { + final TCommandTransfer command = responseEvent.getDeliveryCommand(); + final String agentId = command.getAgentId(); + final long startTimestamp = command.getStartTime(); + + final TCommandTransferResponse response = responseEvent.getRouteResult(); + final byte[] payload = response.getPayload(); + + final Class payloadType = readPayload(payload); + if (payload == null) { + return; + } + + for (AgentEventType eventType : RESPONSE_EVENT_TYPES) { + if (eventType.getMessageType() == payloadType) { + final AgentEventBo agentEventBo = new AgentEventBo(agentId, startTimestamp, eventTimestamp, eventType); + agentEventBo.setEventBody(payload); + this.agentEventService.insert(agentEventBo); + } + } + } + + private Class readPayload(byte[] payload) { + if (payload == null) { + return Void.class; + } + + try { + final Message> deserialize = SerializationUtils.deserialize(payload, commandDeserializerFactory); + final TBase tBase = deserialize.getData(); + return tBase.getClass(); + } catch (TException e) { + logger.warn("Error deserializing ResponseEvent payload", e); + } + return null; + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/DefaultZookeeperClient.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/DefaultZookeeperClient.java deleted file mode 100644 index f9a8344002f2..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/DefaultZookeeperClient.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper; - -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.AuthException; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.BadOperationException; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.ConnectionException; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.NoNodeException; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.PinpointZookeeperException; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.TimeoutException; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.UnknownException; -import com.navercorp.pinpoint.common.server.util.concurrent.CommonStateContext; -import com.navercorp.pinpoint.rpc.util.TimerFactory; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.KeeperException.Code; -import org.apache.zookeeper.ZooDefs.Ids; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.data.Stat; -import org.jboss.netty.util.HashedWheelTimer; -import org.jboss.netty.util.Timeout; -import org.jboss.netty.util.TimerTask; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * - * Conditional thread safe
- * If multiple threads invokes connect, reconnect, or close concurrently; then it is possible for the object's zookeeper field to be out of sync. - * - * @author koo.taejin - */ -public class DefaultZookeeperClient implements ZookeeperClient { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final CommonStateContext stateContext; - - private final HashedWheelTimer timer; - - private final String hostPort; - private final int sessionTimeout; - private final ZookeeperEventWatcher watcher; - private final long reconnectDelayWhenSessionExpired; - - // Zookeeper clients are thread-safe - private volatile ZooKeeper zookeeper; - - public DefaultZookeeperClient(String hostPort, int sessionTimeout, ZookeeperEventWatcher watcher) { - this(hostPort, sessionTimeout, watcher, ZookeeperClusterService.DEFAULT_RECONNECT_DELAY_WHEN_SESSION_EXPIRED); - } - - public DefaultZookeeperClient(String hostPort, int sessionTimeout, ZookeeperEventWatcher watcher, long reconnectDelayWhenSessionExpired) { - this.hostPort = hostPort; - this.sessionTimeout = sessionTimeout; - this.watcher = watcher; - this.reconnectDelayWhenSessionExpired = reconnectDelayWhenSessionExpired; - - this.timer = TimerFactory.createHashedWheelTimer(this.getClass().getSimpleName(), 100, TimeUnit.MILLISECONDS, 512); - this.stateContext = new CommonStateContext(); - } - - @Override - public void connect() throws IOException { - if (stateContext.changeStateInitializing()) { - this.zookeeper = new ZooKeeper(hostPort, sessionTimeout, watcher); // server - stateContext.changeStateStarted(); - } else { - logger.warn("connect() failed. error : Illegal State. State may be {}.", stateContext.getCurrentState()); - } - } - - @Override - public void reconnectWhenSessionExpired() { - if (!stateContext.isStarted()) { - logger.warn("ZookeeperClient.reconnectWhenSessionExpired() failed. Error: Already closed."); - return; - } - - ZooKeeper zookeeper = this.zookeeper; - if (zookeeper.getState().isConnected()) { - logger.warn("ZookeeperClient.reconnect() failed. Error: session(0x{}) is connected.", Long.toHexString(zookeeper.getSessionId())); - return; - } - - logger.warn("Execute ZookeeperClient.reconnectWhenSessionExpired()(Expired session:0x{}).", Long.toHexString(zookeeper.getSessionId())); - try { - zookeeper.close(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - ZooKeeper newZookeeper = createNewZookeeper(); - if (!stateContext.isStarted()) { - logger.warn("ZookeeperClient.reconnectWhenSessionExpired() failed. Error: Already closed."); - return; - } - - if (newZookeeper == null) { - logger.warn("Failed to create new Zookeeper instance. It will be retry AFTER {}ms.", reconnectDelayWhenSessionExpired); - - timer.newTimeout(new TimerTask() { - @Override - public void run(Timeout timeout) throws Exception { - if (timeout.isCancelled()) { - return; - } - - reconnectWhenSessionExpired(); - } - }, reconnectDelayWhenSessionExpired, TimeUnit.MILLISECONDS); - } else { - this.zookeeper = newZookeeper; - } - } - - private ZooKeeper createNewZookeeper() { - try { - return new ZooKeeper(hostPort, sessionTimeout, watcher); - } catch (IOException ignore) { - // ignore - } - return null; - } - - /** - * do not create the final node in the given path. - * - * @throws PinpointZookeeperException - * @throws InterruptedException - */ - @Override - public void createPath(String path) throws PinpointZookeeperException, InterruptedException { - createPath(path, false); - } - - @Override - public void createPath(String path, boolean createEndNode) throws PinpointZookeeperException, InterruptedException { - checkState(); - - int pos = 1; - do { - pos = path.indexOf('/', pos + 1); - - if (pos == -1) { - pos = path.length(); - } - - ZooKeeper zookeeper = this.zookeeper; - try { - if (pos == path.length()) { - if (!createEndNode) { - return; - } - } - - String subPath = path.substring(0, pos); - if (zookeeper.exists(subPath, false) != null) { - continue; - } - - zookeeper.create(subPath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } catch (KeeperException exception) { - if (exception.code() != Code.NODEEXISTS) { - handleException(exception); - } - } - - } while (pos < path.length()); - } - - @Override - public String createNode(String zNodePath, byte[] data) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - if (zookeeper.exists(zNodePath, false) != null) { - return zNodePath; - } - - String pathName = zookeeper.create(zNodePath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); - return pathName; - } catch (KeeperException exception) { - handleException(exception); - } - return zNodePath; - } - - @Override - public byte[] getData(String path) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - return zookeeper.getData(path, false, null); - } catch (KeeperException exception) { - handleException(exception); - } - - throw new UnknownException("UnknownException."); - } - - @Override - public void setData(String path, byte[] data) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - if (zookeeper.exists(path, false) == null) { - return; - } - - zookeeper.setData(path, data, -1); - } catch (KeeperException exception) { - handleException(exception); - } - } - - @Override - public void delete(String path) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - zookeeper.delete(path, -1); - } catch (KeeperException exception) { - if (exception.code() != Code.NONODE) { - handleException(exception); - } - } - } - - @Override - public boolean exists(String path) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - Stat stat = zookeeper.exists(path, false); - if (stat == null) { - return false; - } - } catch (KeeperException exception) { - if (exception.code() != Code.NODEEXISTS) { - handleException(exception); - } - } - return true; - } - - private void checkState() throws PinpointZookeeperException { - if (!isConnected()) { - throw new ConnectionException("Instance must be connected."); - } - } - - @Override - public boolean isConnected() { - if (!watcher.isConnected() || !stateContext.isStarted()) { - return false; - } - - return true; - } - - @Override - public List getChildrenNode(String path, boolean watch) throws PinpointZookeeperException, InterruptedException { - checkState(); - - try { - List childNodeList = zookeeper.getChildren(path, watch, null); - - logger.info("ChildNode List = {}", childNodeList); - return childNodeList; - } catch (KeeperException exception) { - if (exception.code() != Code.NONODE) { - handleException(exception); - } - } - - return Collections.emptyList(); - } - - private void handleException(KeeperException keeperException) throws PinpointZookeeperException { - switch (keeperException.code()) { - case CONNECTIONLOSS: - case SESSIONEXPIRED: - throw new ConnectionException(keeperException.getMessage(), keeperException); - case AUTHFAILED: - case INVALIDACL: - case NOAUTH: - throw new AuthException(keeperException.getMessage(), keeperException); - case BADARGUMENTS: - case BADVERSION: - case NOCHILDRENFOREPHEMERALS: - case NOTEMPTY: - case NODEEXISTS: - throw new BadOperationException(keeperException.getMessage(), keeperException); - case NONODE: - throw new NoNodeException(keeperException.getMessage(), keeperException); - case OPERATIONTIMEOUT: - throw new TimeoutException(keeperException.getMessage(), keeperException); - default: - throw new UnknownException(keeperException.getMessage(), keeperException); - } - } - - @Override - public void close() { - if (stateContext.changeStateDestroying()) { - ZooKeeper zookeeper = this.zookeeper; - if (timer != null) { - timer.stop(); - } - - if (zookeeper != null) { - try { - zookeeper.close(); - } catch (InterruptedException ignore) { - logger.info("Interrupted zookeeper.close(). Caused:" + ignore.getMessage(), ignore); - Thread.currentThread().interrupt(); - } - } - stateContext.changeStateStopped(); - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClient.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClient.java deleted file mode 100644 index 6d849399d17b..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClient.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper; - -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.PinpointZookeeperException; - -import java.io.IOException; -import java.util.List; - -/** - * @author Taejin Koo - */ -public interface ZookeeperClient { - - void connect() throws IOException; - - void reconnectWhenSessionExpired(); - - void createPath(String path) throws PinpointZookeeperException, InterruptedException; - - void createPath(String path, boolean createEndNode) throws PinpointZookeeperException, InterruptedException; - - String createNode(String zNodePath, byte[] data) throws PinpointZookeeperException, InterruptedException; - - byte[] getData(String path) throws PinpointZookeeperException, InterruptedException; - - void setData(String path, byte[] data) throws PinpointZookeeperException, InterruptedException; - - void delete(String path) throws PinpointZookeeperException, InterruptedException; - - boolean exists(String path) throws PinpointZookeeperException, InterruptedException; - - boolean isConnected(); - - List getChildrenNode(String path, boolean watch) throws PinpointZookeeperException, InterruptedException; - - void close(); - - } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClusterManager.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClusterManager.java index d552dc138b81..9b0a86952c71 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClusterManager.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClusterManager.java @@ -17,16 +17,19 @@ package com.navercorp.pinpoint.collector.cluster.zookeeper; import com.navercorp.pinpoint.collector.cluster.connection.ClusterConnectionManager; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.ConnectionException; -import com.navercorp.pinpoint.common.util.NetUtils; -import com.navercorp.pinpoint.common.util.PinpointThreadFactory; +import com.navercorp.pinpoint.collector.util.Address; +import com.navercorp.pinpoint.collector.util.AddressParser; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperConstants; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.ConnectionException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.PinpointZookeeperException; import com.navercorp.pinpoint.common.server.util.concurrent.CommonState; import com.navercorp.pinpoint.common.server.util.concurrent.CommonStateContext; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.PinpointThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -48,15 +51,16 @@ public class ZookeeperClusterManager { private final GetAndRegisterTask getAndRegisterTask = new GetAndRegisterTask(); private final StopTask stopTask = new StopTask(); + private final CommonStateContext workerState = new CommonStateContext(); + private final ZookeeperClient client; private final ClusterConnectionManager clusterConnectionManager; - private final String zNodePath; + private final String parentPath; private final AtomicBoolean retryMode = new AtomicBoolean(false); private final BlockingQueue queue = new LinkedBlockingQueue<>(1); - private final CommonStateContext workerState; private final Thread workerThread; // private final Timer timer; @@ -65,12 +69,15 @@ public class ZookeeperClusterManager { // synchronize current status with Zookeeper when an event(job) is triggered. // (the number of events does not matter as long as a single event is triggered - subsequent events may be ignored) public ZookeeperClusterManager(ZookeeperClient client, String zookeeperClusterPath, ClusterConnectionManager clusterConnectionManager) { - this.client = client; + this.client = Assert.requireNonNull(client, "client must not be null"); + Assert.requireNonNull(zookeeperClusterPath, "client must not be null"); + this.clusterConnectionManager = Assert.requireNonNull(clusterConnectionManager, "clusterConnectionManager must not be null"); - this.clusterConnectionManager = clusterConnectionManager; - this.zNodePath = zookeeperClusterPath; - - this.workerState = new CommonStateContext(); + if (!zookeeperClusterPath.endsWith("/")) { + this.parentPath = zookeeperClusterPath + ZookeeperConstants.PATH_SEPARATOR; + } else { + this.parentPath = zookeeperClusterPath; + } final ThreadFactory threadFactory = new PinpointThreadFactory(this.getClass().getSimpleName(), true); this.workerThread = threadFactory.newThread(new Worker()); @@ -142,7 +149,7 @@ public void stop() { public void handleAndRegisterWatcher(String path) { if (workerState.isStarted()) { - if (zNodePath.equals(path)) { + if (parentPath.equals(path) || parentPath.equals(path + ZookeeperConstants.PATH_SEPARATOR)) { final boolean offerSuccess = queue.offer(getAndRegisterTask); if (!offerSuccess) { logger.info("Message Queue is Full."); @@ -209,28 +216,23 @@ class GetAndRegisterTask implements Task { private boolean handleAndRegisterWatcher0() { boolean needNotRetry = false; try { + client.createPath(parentPath); - if (!client.exists(zNodePath)) { - client.createPath(zNodePath, true); - } - - List childNodeList = client.getChildrenNode(zNodePath, true); - List clusterAddressList = NetUtils.toInetSocketAddressLIst(childNodeList); - - List addressList = clusterConnectionManager.getConnectedAddressList(); + List
targetAddressList = getTargetAddressList(parentPath); + List
connectedAddressList = clusterConnectionManager.getConnectedAddressList(); - logger.info("Handle register and remove Task. Current Address List = {}, Cluster Address List = {}", addressList, clusterAddressList); + logger.info("Handle register and remove Task. Current Address List = {}, Cluster Address List = {}", connectedAddressList, targetAddressList); - for (InetSocketAddress clusterAddress : clusterAddressList) { - if (!addressList.contains(clusterAddress)) { - clusterConnectionManager.connectPointIfAbsent(clusterAddress); + for (Address targetAddress : targetAddressList) { + if (!connectedAddressList.contains(targetAddress)) { + clusterConnectionManager.connectPointIfAbsent(targetAddress); } } - for (SocketAddress address : addressList) { + for (Address connectedAddress : connectedAddressList) { //noinspection SuspiciousMethodCalls,SuspiciousMethodCalls - if (!clusterAddressList.contains(address)) { - clusterConnectionManager.disconnectPoint(address); + if (!targetAddressList.contains(connectedAddress)) { + clusterConnectionManager.disconnectPoint(connectedAddress); } } @@ -244,6 +246,12 @@ private boolean handleAndRegisterWatcher0() { return needNotRetry; } + + private List
getTargetAddressList(String parentPath) throws PinpointZookeeperException, InterruptedException { + List childNodeList = client.getChildNodeList(parentPath, true); + return AddressParser.parseAddressLIst(childNodeList); + } + } static class StopTask implements Task { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClusterService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClusterService.java index 4f739af1da0e..679ed1a3a899 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClusterService.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperClusterService.java @@ -18,18 +18,24 @@ import com.navercorp.pinpoint.collector.cluster.AbstractClusterService; import com.navercorp.pinpoint.collector.cluster.ClusterPointRouter; -import com.navercorp.pinpoint.common.server.util.concurrent.CommonState; -import com.navercorp.pinpoint.common.server.util.concurrent.CommonStateContext; -import com.navercorp.pinpoint.collector.cluster.connection.*; +import com.navercorp.pinpoint.collector.cluster.connection.CollectorClusterAcceptor; +import com.navercorp.pinpoint.collector.cluster.connection.CollectorClusterConnectionFactory; +import com.navercorp.pinpoint.collector.cluster.connection.CollectorClusterConnectionManager; +import com.navercorp.pinpoint.collector.cluster.connection.CollectorClusterConnectionRepository; +import com.navercorp.pinpoint.collector.cluster.connection.CollectorClusterConnector; import com.navercorp.pinpoint.collector.config.CollectorConfiguration; import com.navercorp.pinpoint.collector.util.CollectorUtils; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.CuratorZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperConstants; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperEventWatcher; +import com.navercorp.pinpoint.common.server.util.concurrent.CommonState; +import com.navercorp.pinpoint.common.server.util.concurrent.CommonStateContext; import com.navercorp.pinpoint.rpc.server.handler.ServerStateChangeEventHandler; import org.apache.commons.lang3.StringUtils; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; -import org.apache.zookeeper.proto.WatcherEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,26 +43,19 @@ import javax.annotation.PreDestroy; import java.io.IOException; import java.net.InetSocketAddress; -import java.util.concurrent.atomic.AtomicBoolean; /** * @author koo.taejin */ public class ZookeeperClusterService extends AbstractClusterService { - static final long DEFAULT_RECONNECT_DELAY_WHEN_SESSION_EXPIRED = 30000; - - private static final String PINPOINT_CLUSTER_PATH = "/pinpoint-cluster"; - private static final String PINPOINT_WEB_CLUSTER_PATH = PINPOINT_CLUSTER_PATH + "/web"; - private static final String PINPOINT_PROFILER_CLUSTER_PATH = PINPOINT_CLUSTER_PATH + "/profiler"; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); // represented as pid@hostname (identifiers may overlap for services hosted on localhost if pids are identical) // shouldn't be too big of a problem, but will change to MAC or IP if it becomes problematic. private final String serverIdentifier = CollectorUtils.getServerIdentifier(); - private final CommonStateContext serviceState; + private final CommonStateContext serviceState = new CommonStateContext(); private CollectorClusterConnectionManager clusterConnectionManager; @@ -71,7 +70,6 @@ public class ZookeeperClusterService extends AbstractClusterService { public ZookeeperClusterService(CollectorConfiguration config, ClusterPointRouter clusterPointRouter) { super(config, clusterPointRouter); - this.serviceState = new CommonStateContext(); if (config.isClusterEnable()) { CollectorClusterConnectionRepository clusterRepository = new CollectorClusterConnectionRepository(); CollectorClusterConnectionFactory clusterConnectionFactory = new CollectorClusterConnectionFactory(serverIdentifier, clusterPointRouter, clusterPointRouter); @@ -102,23 +100,20 @@ public void setUp() throws KeeperException, IOException, InterruptedException { logger.info("{} initialization started.", this.getClass().getSimpleName()); ClusterManagerWatcher watcher = new ClusterManagerWatcher(); - this.client = new DefaultZookeeperClient(config.getClusterAddress(), config.getClusterSessionTimeout(), watcher); + this.client = new CuratorZookeeperClient(config.getClusterAddress(), config.getClusterSessionTimeout(), watcher); this.client.connect(); this.profilerClusterManager = new ZookeeperProfilerClusterManager(client, serverIdentifier, clusterPointRouter.getTargetClusterPointRepository()); this.profilerClusterManager.start(); - this.webClusterManager = new ZookeeperClusterManager(client, PINPOINT_WEB_CLUSTER_PATH, clusterConnectionManager); + this.webClusterManager = new ZookeeperClusterManager(client, ZookeeperConstants.PINPOINT_WEB_CLUSTER_PATH, clusterConnectionManager); this.webClusterManager.start(); this.serviceState.changeStateStarted(); logger.info("{} initialization completed.", this.getClass().getSimpleName()); if (client.isConnected()) { - WatcherEvent watcherEvent = new WatcherEvent(EventType.None.getIntValue(), KeeperState.SyncConnected.getIntValue(), ""); - WatchedEvent event = new WatchedEvent(watcherEvent); - - watcher.process(event); + watcher.handleConnected(); } } break; @@ -193,53 +188,40 @@ public ZookeeperClusterManager getWebClusterManager() { class ClusterManagerWatcher implements ZookeeperEventWatcher { - private final AtomicBoolean connected = new AtomicBoolean(false); - @Override public void process(WatchedEvent event) { logger.debug("Process Zookeeper Event({})", event); - KeeperState state = event.getState(); EventType eventType = event.getType(); - - // ephemeral node is removed on disconnect event (leave node management exclusively to zookeeper) - if (ZookeeperUtils.isDisconnectedEvent(state, eventType)) { - connected.compareAndSet(true, false); - if (state == KeeperState.Expired) { - if (client != null) { - client.reconnectWhenSessionExpired(); - } - } - return; - } - - // on connect/reconnect event - if (ZookeeperUtils.isConnectedEvent(state, eventType)) { - // could already be connected (failure to compareAndSet doesn't really matter) - boolean changed = connected.compareAndSet(false, true); - } - if (serviceState.isStarted() && connected.get()) { + if (serviceState.isStarted() && client.isConnected()) { // duplicate event possible - but the logic does not change - if (ZookeeperUtils.isConnectedEvent(state, eventType)) { - profilerClusterManager.initZookeeperClusterData(); - webClusterManager.handleAndRegisterWatcher(PINPOINT_WEB_CLUSTER_PATH); - } else if (eventType == EventType.NodeChildrenChanged) { + if (eventType == EventType.NodeChildrenChanged) { String path = event.getPath(); - if (PINPOINT_WEB_CLUSTER_PATH.equals(path)) { + if (ZookeeperConstants.PINPOINT_WEB_CLUSTER_PATH.equals(path)) { webClusterManager.handleAndRegisterWatcher(path); } else { logger.warn("Unknown Path ChildrenChanged {}.", path); } - } } } @Override - public boolean isConnected() { - return connected.get(); + public boolean handleConnected() { + if (serviceState.isStarted()) { + profilerClusterManager.initZookeeperClusterData(); + webClusterManager.handleAndRegisterWatcher(ZookeeperConstants.PINPOINT_WEB_CLUSTER_PATH); + return true; + } else { + return false; + } + } + + @Override + public boolean handleDisconnected() { + return true; } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperEventWatcher.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperEventWatcher.java deleted file mode 100644 index 35f222b71a11..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperEventWatcher.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper; - -import org.apache.zookeeper.Watcher; - -/** - * @author koo.taejin - */ -public interface ZookeeperEventWatcher extends Watcher { - - boolean isConnected(); - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperJobWorker.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperJobWorker.java index b366d61ae208..9694750e7324 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperJobWorker.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperJobWorker.java @@ -16,8 +16,10 @@ package com.navercorp.pinpoint.collector.cluster.zookeeper; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.PinpointZookeeperException; import com.navercorp.pinpoint.collector.cluster.zookeeper.job.ZookeeperJob; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperConstants; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.PinpointZookeeperException; import com.navercorp.pinpoint.common.server.util.concurrent.CommonStateContext; import com.navercorp.pinpoint.common.util.BytesUtils; import com.navercorp.pinpoint.common.util.CollectionUtils; @@ -28,6 +30,7 @@ import com.navercorp.pinpoint.rpc.util.ListUtils; import com.navercorp.pinpoint.rpc.util.MapUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.curator.utils.ZKPaths; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,10 +47,6 @@ */ public class ZookeeperJobWorker implements Runnable { - private static final String PINPOINT_CLUSTER_PATH = "/pinpoint-cluster"; - private static final String PINPOINT_COLLECTOR_CLUSTER_PATH = PINPOINT_CLUSTER_PATH + "/collector"; - - private static final String PATH_SEPARATOR = "/"; private static final String PROFILER_SEPARATOR = "\r\n"; private final Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -68,7 +67,7 @@ public ZookeeperJobWorker(ZookeeperClient zookeeperClient, String serverIdentifi this.workerState = new CommonStateContext(); - this.collectorUniqPath = bindingPathAndZNode(PINPOINT_COLLECTOR_CLUSTER_PATH, serverIdentifier); + this.collectorUniqPath = ZKPaths.makePath(ZookeeperConstants.PINPOINT_COLLECTOR_CLUSTER_PATH, serverIdentifier); } public void start() { @@ -122,18 +121,6 @@ public void stop() { logger.info("stop() completed."); } - private String bindingPathAndZNode(String path, String zNodeName) { - StringBuilder fullPath = new StringBuilder(StringUtils.length(path) + StringUtils.length(zNodeName) + 1); - - fullPath.append(path); - if (!path.endsWith(PATH_SEPARATOR)) { - fullPath.append(PATH_SEPARATOR); - } - fullPath.append(zNodeName); - - return fullPath.toString(); - } - public void addPinpointServer(PinpointServer pinpointServer) { if (logger.isDebugEnabled()) { logger.debug("addPinpointServer server:{}, properties:{}", pinpointServer, pinpointServer.getChannelProperties()); @@ -160,16 +147,23 @@ public List getClusterList() { } private String getClusterData() throws PinpointZookeeperException, InterruptedException { - final byte[] clusterBytes = zookeeperClient.getData(collectorUniqPath); - return BytesUtils.toString(clusterBytes); + try { + final byte[] result = zookeeperClient.getData(collectorUniqPath); + if (result == null) { + return StringUtils.EMPTY; + } + return BytesUtils.toString(result); + } catch (Exception e) { + logger.warn("getClusterData failed. message:{}", e.getMessage(), e); + } + return StringUtils.EMPTY; } - private void setClusterData(String clusterString) throws PinpointZookeeperException, InterruptedException { - final byte[] clusterBytes = BytesUtils.toBytes(clusterString); - zookeeperClient.setData(collectorUniqPath, clusterBytes); + private void setClusterData(String value) throws Exception { + final byte[] payload = BytesUtils.toBytes(value); + zookeeperClient.createOrSetNode(collectorUniqPath, payload); } - public void removePinpointServer(PinpointServer pinpointServer) { if (logger.isDebugEnabled()) { logger.debug("removePinpointServer server:{}, properties:{}", pinpointServer, pinpointServer.getChannelProperties()); @@ -338,19 +332,12 @@ private boolean handleUpdate(List zookeeperJobList) { final List addContentCandidateList = getZookeeperKeyList(zookeeperJobList); try { - if (zookeeperClient.exists(collectorUniqPath)) { - final String currentClusterData = getClusterData(); - - final String updateCluster = addIfAbsentContents(currentClusterData, addContentCandidateList); - setClusterData(updateCluster); - } else { - zookeeperClient.createPath(collectorUniqPath); - - // should return error even if NODE exists if the data is important - final String newClusterData = addIfAbsentContents("", addContentCandidateList); - final byte[] newClusterDataBytes = BytesUtils.toBytes(newClusterData); - zookeeperClient.createNode(collectorUniqPath, newClusterDataBytes); - } + zookeeperClient.createPath(collectorUniqPath); + + String currentData = getClusterData(); + final String newData = addIfAbsentContents(currentData, addContentCandidateList); + + setClusterData(newData); return true; } catch (Exception e) { logger.warn("handleUpdate failed. caused:{}, jobSize:{}", e.getMessage(), zookeeperJobList.size(), e); @@ -366,12 +353,12 @@ private boolean handleDelete(List zookeeperJobList) { final List removeContentCandidateList = getZookeeperKeyList(zookeeperJobList); try { - if (zookeeperClient.exists(collectorUniqPath)) { - final String currentClusterData = getClusterData(); + zookeeperClient.createPath(collectorUniqPath); - final String remainCluster = removeIfExistContents(currentClusterData, removeContentCandidateList); - setClusterData(remainCluster); - } + final String currentData = getClusterData(); + final String newData = removeIfExistContents(currentData, removeContentCandidateList); + + setClusterData(newData); return true; } catch (Exception e) { logger.warn("handleDelete failed. caused:{}, jobSize:{}", e.getMessage(), zookeeperJobList.size(), e); @@ -397,14 +384,8 @@ private boolean handleClear(List zookeeperJobList) { } try { - if (zookeeperClient.exists(collectorUniqPath)) { - zookeeperClient.setData(collectorUniqPath, EMPTY_DATA_BYTES); - } else { - zookeeperClient.createPath(collectorUniqPath); - - // should return error even if NODE exists if the data is important - zookeeperClient.createNode(collectorUniqPath, EMPTY_DATA_BYTES); - } + zookeeperClient.createPath(collectorUniqPath); + zookeeperClient.createOrSetNode(collectorUniqPath, EMPTY_DATA_BYTES); return true; } catch (Exception e) { logger.warn("handleClear failed. caused:{}, jobSize:{}", e.getMessage(), zookeeperJobList.size(), e); @@ -464,6 +445,10 @@ private List getChangeList(List originalList, List chang } private List tokenize(String str) { + if (StringUtils.isEmpty(str)) { + return Collections.emptyList(); + } + final String[] tokenArray = org.springframework.util.StringUtils.tokenizeToStringArray(str, PROFILER_SEPARATOR); return Arrays.asList(tokenArray); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperProfilerClusterManager.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperProfilerClusterManager.java index 4648b8f9b32f..1e79b39020e8 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperProfilerClusterManager.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperProfilerClusterManager.java @@ -18,7 +18,9 @@ import com.navercorp.pinpoint.collector.cluster.ClusterPointRepository; import com.navercorp.pinpoint.collector.cluster.PinpointServerClusterPoint; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperClient; import com.navercorp.pinpoint.common.server.util.concurrent.CommonStateContext; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.rpc.common.SocketStateCode; import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; import com.navercorp.pinpoint.rpc.server.PinpointServer; @@ -40,7 +42,7 @@ public class ZookeeperProfilerClusterManager implements ServerStateChangeEventHa private final ZookeeperJobWorker worker; - private final CommonStateContext workerState; + private final CommonStateContext workerState = new CommonStateContext(); private final ClusterPointRepository profileCluster; @@ -49,8 +51,7 @@ public class ZookeeperProfilerClusterManager implements ServerStateChangeEventHa // keep it simple - register on RUN, remove on FINISHED, skip otherwise // should only be instantiated when cluster is enabled. public ZookeeperProfilerClusterManager(ZookeeperClient client, String serverIdentifier, ClusterPointRepository profileCluster) { - this.workerState = new CommonStateContext(); - this.profileCluster = profileCluster; + this.profileCluster = Assert.requireNonNull(profileCluster, "profileCluster must not be null"); this.worker = new ZookeeperJobWorker(client, serverIdentifier); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperUtils.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperUtils.java deleted file mode 100644 index 5ee80d9dea64..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperUtils.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper; - -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; - -/** - * @author koo.taejin - */ -public final class ZookeeperUtils { - - // would be a good idea to move to commons-hbase (if implemented) in the future - private ZookeeperUtils() { - } - - public static boolean isConnectedEvent(WatchedEvent event) { - KeeperState state = event.getState(); - EventType eventType = event.getType(); - - return isConnectedEvent(state, eventType); - } - - public static boolean isConnectedEvent(KeeperState state, EventType eventType) { - if ((state == KeeperState.SyncConnected || state == KeeperState.NoSyncConnected) && eventType == EventType.None) { - return true; - } else { - return false; - } - } - - - public static boolean isDisconnectedEvent(WatchedEvent event) { - KeeperState state = event.getState(); - EventType eventType = event.getType(); - - return isDisconnectedEvent(state, eventType); - } - - public static boolean isDisconnectedEvent(KeeperState state, EventType eventType) { - if ((state == KeeperState.Disconnected || state == KeeperState.Expired) && eventType == eventType.None) { - return true; - } else { - return false; - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/AuthException.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/AuthException.java deleted file mode 100644 index 2af5f3ceaceb..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/AuthException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class AuthException extends PinpointZookeeperException { - - public AuthException() { - } - - public AuthException(String message) { - super(message); - } - - public AuthException(String message, Throwable cause) { - super(message, cause); - } - - public AuthException(Throwable cause) { - super(cause); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/BadOperationException.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/BadOperationException.java deleted file mode 100644 index 53011447be1e..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/BadOperationException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class BadOperationException extends PinpointZookeeperException { - - public BadOperationException() { - } - - public BadOperationException(String message) { - super(message); - } - - public BadOperationException(String message, Throwable cause) { - super(message, cause); - } - - public BadOperationException(Throwable cause) { - super(cause); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/ConnectionException.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/ConnectionException.java deleted file mode 100644 index fea8ecf96767..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/ConnectionException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class ConnectionException extends PinpointZookeeperException { - - public ConnectionException() { - } - - public ConnectionException(String message) { - super(message); - } - - public ConnectionException(String message, Throwable cause) { - super(message, cause); - } - - public ConnectionException(Throwable cause) { - super(cause); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/NoNodeException.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/NoNodeException.java deleted file mode 100644 index 0fd714142427..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/NoNodeException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class NoNodeException extends PinpointZookeeperException { - - public NoNodeException() { - } - - public NoNodeException(String message) { - super(message); - } - - public NoNodeException(String message, Throwable cause) { - super(message, cause); - } - - public NoNodeException(Throwable cause) { - super(cause); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/PinpointZookeeperException.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/PinpointZookeeperException.java deleted file mode 100644 index c8f9b7f0338d..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/PinpointZookeeperException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class PinpointZookeeperException extends Exception { - - public PinpointZookeeperException() { - } - - public PinpointZookeeperException(String message) { - super(message); - } - - public PinpointZookeeperException(String message, Throwable cause) { - super(message, cause); - } - - public PinpointZookeeperException(Throwable cause) { - super(cause); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/TimeoutException.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/TimeoutException.java deleted file mode 100644 index d49ccc38a78a..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/TimeoutException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class TimeoutException extends PinpointZookeeperException { - - public TimeoutException() { - } - - public TimeoutException(String message) { - super(message); - } - - public TimeoutException(String message, Throwable cause) { - super(message, cause); - } - - public TimeoutException(Throwable cause) { - super(cause); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/UnknownException.java b/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/UnknownException.java deleted file mode 100644 index d7eb026402d7..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/cluster/zookeeper/exception/UnknownException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class UnknownException extends PinpointZookeeperException { - - public UnknownException() { - } - - public UnknownException(String message) { - super(message); - } - - public UnknownException(String message, Throwable cause) { - super(message, cause); - } - - public UnknownException(Throwable cause) { - super(cause); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/controller/ServerTimeController.java b/collector/src/main/java/com/navercorp/pinpoint/collector/controller/ServerTimeController.java new file mode 100644 index 000000000000..459c01b166bf --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/controller/ServerTimeController.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.controller; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * @author Taejin Koo + */ +@Controller +public class ServerTimeController { + + @RequestMapping(value = "/serverTime", method = RequestMethod.GET) + @ResponseBody + public ServerTime getServerTime() { + return new ServerTime(); + } + + + private static class ServerTime { + + private final long currentServerTime; + + public ServerTime() { + this.currentServerTime = System.currentTimeMillis(); + } + + @JsonProperty("currentServerTime") + public long getCurrentServerTime() { + return currentServerTime; + } + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/AgentInfoDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/AgentInfoDao.java index 01f21e339acc..b73e58a4f7c8 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/AgentInfoDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/AgentInfoDao.java @@ -16,11 +16,11 @@ package com.navercorp.pinpoint.collector.dao; -import com.navercorp.pinpoint.thrift.dto.TAgentInfo; +import com.navercorp.pinpoint.common.server.bo.AgentInfoBo; /** * @author emeroad */ public interface AgentInfoDao { - void insert(TAgentInfo agentInfo); + void insert(AgentInfoBo agentInfo); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApiMetaDataDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApiMetaDataDao.java index 96d1bd27ccd0..c64c43c4dda0 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApiMetaDataDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApiMetaDataDao.java @@ -16,12 +16,11 @@ package com.navercorp.pinpoint.collector.dao; -import com.navercorp.pinpoint.thrift.dto.TApiMetaData; +import com.navercorp.pinpoint.common.server.bo.ApiMetaDataBo; /** * @author emeroad */ public interface ApiMetaDataDao { - - void insert(TApiMetaData apiMetaData); + void insert(ApiMetaDataBo apiMetaData); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApplicationIndexDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApplicationIndexDao.java index 523190adfac9..b9d2acbc493f 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApplicationIndexDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApplicationIndexDao.java @@ -16,11 +16,11 @@ package com.navercorp.pinpoint.collector.dao; -import com.navercorp.pinpoint.thrift.dto.TAgentInfo; +import com.navercorp.pinpoint.common.server.bo.AgentInfoBo; /** * @author emeroad */ public interface ApplicationIndexDao { - void insert(final TAgentInfo agentInfo); + void insert(final AgentInfoBo agentInfo); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApplicationTraceIndexDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApplicationTraceIndexDao.java index 9846ff0ecca6..73f0c3753a39 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApplicationTraceIndexDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/ApplicationTraceIndexDao.java @@ -16,11 +16,11 @@ package com.navercorp.pinpoint.collector.dao; -import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.common.server.bo.SpanBo; /** * @author emeroad */ public interface ApplicationTraceIndexDao { - void insert(TSpan span); + void insert(SpanBo span); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/SqlMetaDataDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/SqlMetaDataDao.java index 8bf3cbbff3f9..7e525b811c8c 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/SqlMetaDataDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/SqlMetaDataDao.java @@ -16,11 +16,11 @@ package com.navercorp.pinpoint.collector.dao; -import com.navercorp.pinpoint.thrift.dto.TSqlMetaData; +import com.navercorp.pinpoint.common.server.bo.SqlMetaDataBo; /** * @author emeroad */ public interface SqlMetaDataDao { - void insert(TSqlMetaData sqlMetaData); + void insert(SqlMetaDataBo sqlMetaData); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/StringMetaDataDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/StringMetaDataDao.java index e5b685044adf..34ffe0ebebcb 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/StringMetaDataDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/StringMetaDataDao.java @@ -16,12 +16,11 @@ package com.navercorp.pinpoint.collector.dao; -import com.navercorp.pinpoint.thrift.dto.TStringMetaData; +import com.navercorp.pinpoint.common.server.bo.StringMetaDataBo; /** * @author emeroad */ public interface StringMetaDataDao { - - void insert(TStringMetaData stringMetaData); + void insert(StringMetaDataBo stringMetaData); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentEventDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentEventDao.java index 584c4c302579..84707cabd56b 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentEventDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentEventDao.java @@ -16,6 +16,8 @@ package com.navercorp.pinpoint.collector.dao.hbase; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,6 +45,9 @@ public class HbaseAgentEventDao implements AgentEventDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentEventValueMapper valueMapper; @@ -64,7 +69,8 @@ public void insert(AgentEventBo agentEventBo) { final AgentEventType eventType = agentEventBo.getEventType(); byte[] qualifier = Bytes.toBytes(eventType.getCode()); - this.hbaseTemplate.put(HBaseTables.AGENT_EVENT, rowKey, HBaseTables.AGENT_EVENT_CF_EVENTS, qualifier, agentEventBo, this.valueMapper); + TableName agentEventTableName = tableNameProvider.getTableName(HBaseTables.AGENT_EVENT_STR); + this.hbaseTemplate.put(agentEventTableName, rowKey, HBaseTables.AGENT_EVENT_CF_EVENTS, qualifier, agentEventBo, this.valueMapper); } byte[] createRowKey(String agentId, long eventTimestamp) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentInfoDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentInfoDao.java index d166a4970fee..553c29094f55 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentInfoDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentInfoDao.java @@ -17,24 +17,19 @@ package com.navercorp.pinpoint.collector.dao.hbase; import com.navercorp.pinpoint.collector.dao.AgentInfoDao; -import com.navercorp.pinpoint.collector.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.AgentInfoBo; -import com.navercorp.pinpoint.common.server.bo.JvmInfoBo; -import com.navercorp.pinpoint.common.server.bo.ServerMetaDataBo; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.server.util.RowKeyUtils; import com.navercorp.pinpoint.common.util.TimeUtils; -import com.navercorp.pinpoint.thrift.dto.TAgentInfo; -import com.navercorp.pinpoint.thrift.dto.TJvmInfo; -import com.navercorp.pinpoint.thrift.dto.TServerMetaData; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Repository; /** @@ -49,20 +44,10 @@ public class HbaseAgentInfoDao implements AgentInfoDao { private HbaseOperations2 hbaseTemplate; @Autowired - @Qualifier("agentInfoBoMapper") - private ThriftBoMapper agentInfoBoMapper; - - @Autowired - @Qualifier("serverMetaDataBoMapper") - private ThriftBoMapper serverMetaDataBoMapper; - - @Autowired - @Qualifier("jvmInfoBoMapper") - private ThriftBoMapper jvmInfoBoMapper; + private TableNameProvider tableNameProvider; @Override - public void insert(TAgentInfo agentInfo) { - + public void insert(AgentInfoBo agentInfo) { if (agentInfo == null) { throw new NullPointerException("agentInfo must not be null"); } @@ -71,28 +56,26 @@ public void insert(TAgentInfo agentInfo) { logger.debug("insert agent info. {}", agentInfo); } - byte[] agentId = Bytes.toBytes(agentInfo.getAgentId()); - long reverseKey = TimeUtils.reverseTimeMillis(agentInfo.getStartTimestamp()); - byte[] rowKey = RowKeyUtils.concatFixedByteAndLong(agentId, HBaseTables.AGENT_NAME_MAX_LEN, reverseKey); - Put put = new Put(rowKey); + final byte[] agentId = Bytes.toBytes(agentInfo.getAgentId()); + final long reverseKey = TimeUtils.reverseTimeMillis(agentInfo.getStartTime()); + final byte[] rowKey = RowKeyUtils.concatFixedByteAndLong(agentId, HBaseTables.AGENT_NAME_MAX_LEN, reverseKey); + final Put put = new Put(rowKey); // should add additional agent informations. for now added only starttime for sqlMetaData - AgentInfoBo agentInfoBo = this.agentInfoBoMapper.map(agentInfo); - byte[] agentInfoBoValue = agentInfoBo.writeValue(); + final byte[] agentInfoBoValue = agentInfo.writeValue(); put.addColumn(HBaseTables.AGENTINFO_CF_INFO, HBaseTables.AGENTINFO_CF_INFO_IDENTIFIER, agentInfoBoValue); - if (agentInfo.isSetServerMetaData()) { - ServerMetaDataBo serverMetaDataBo = this.serverMetaDataBoMapper.map(agentInfo.getServerMetaData()); - byte[] serverMetaDataBoValue = serverMetaDataBo.writeValue(); + if (agentInfo.getServerMetaData() != null) { + final byte[] serverMetaDataBoValue = agentInfo.getServerMetaData().writeValue(); put.addColumn(HBaseTables.AGENTINFO_CF_INFO, HBaseTables.AGENTINFO_CF_INFO_SERVER_META_DATA, serverMetaDataBoValue); } - if (agentInfo.isSetJvmInfo()) { - JvmInfoBo jvmInfoBo = this.jvmInfoBoMapper.map(agentInfo.getJvmInfo()); - byte[] jvmInfoBoValue = jvmInfoBo.writeValue(); + if (agentInfo.getJvmInfo() != null) { + final byte[] jvmInfoBoValue = agentInfo.getJvmInfo().writeValue(); put.addColumn(HBaseTables.AGENTINFO_CF_INFO, HBaseTables.AGENTINFO_CF_INFO_JVM, jvmInfoBoValue); } - hbaseTemplate.put(HBaseTables.AGENTINFO, put); + final TableName agentInfoTableName = tableNameProvider.getTableName(HBaseTables.AGENTINFO_STR); + hbaseTemplate.put(agentInfoTableName, put); } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentLifeCycleDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentLifeCycleDao.java index 6890013d7788..0568381fe196 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentLifeCycleDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseAgentLifeCycleDao.java @@ -16,6 +16,8 @@ package com.navercorp.pinpoint.collector.dao.hbase; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +43,9 @@ public class HbaseAgentLifeCycleDao implements AgentLifeCycleDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentLifeCycleValueMapper valueMapper; @@ -60,7 +65,8 @@ public void insert(AgentLifeCycleBo agentLifeCycleBo) { byte[] rowKey = createRowKey(agentId, startTimestamp, eventIdentifier); - this.hbaseTemplate.put(HBaseTables.AGENT_LIFECYCLE, rowKey, HBaseTables.AGENT_LIFECYCLE_CF_STATUS, HBaseTables.AGENT_LIFECYCLE_CF_STATUS_QUALI_STATES, + TableName agentLifeCycleTableName = tableNameProvider.getTableName(HBaseTables.AGENT_LIFECYCLE_STR); + this.hbaseTemplate.put(agentLifeCycleTableName, rowKey, HBaseTables.AGENT_LIFECYCLE_CF_STATUS, HBaseTables.AGENT_LIFECYCLE_CF_STATUS_QUALI_STATES, agentLifeCycleBo, this.valueMapper); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApiMetaDataDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApiMetaDataDao.java index 00e9a0d62ddf..a9c45555fa9c 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApiMetaDataDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApiMetaDataDao.java @@ -17,14 +17,15 @@ package com.navercorp.pinpoint.collector.dao.hbase; import com.navercorp.pinpoint.collector.dao.ApiMetaDataDao; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.ApiMetaDataBo; import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; import com.navercorp.pinpoint.common.buffer.Buffer; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; -import com.navercorp.pinpoint.thrift.dto.TApiMetaData; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,43 +45,35 @@ public class HbaseApiMetaDataDao implements ApiMetaDataDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("metadataRowKeyDistributor") private RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix; @Override - public void insert(TApiMetaData apiMetaData) { + public void insert(ApiMetaDataBo apiMetaData) { if (logger.isDebugEnabled()) { logger.debug("insert:{}", apiMetaData); } - - ApiMetaDataBo apiMetaDataBo = new ApiMetaDataBo(apiMetaData.getAgentId(), apiMetaData.getAgentStartTime(), apiMetaData.getApiId()); - byte[] rowKey = getDistributedKey(apiMetaDataBo.toRowKey()); - + final byte[] rowKey = getDistributedKey(apiMetaData.toRowKey()); final Put put = new Put(rowKey); - final Buffer buffer = new AutomaticBuffer(64); - String api = apiMetaData.getApiInfo(); + final String api = apiMetaData.getApiInfo(); buffer.putPrefixedString(api); - if (apiMetaData.isSetLine()) { - buffer.putInt(apiMetaData.getLine()); - } else { - buffer.putInt(-1); - } - if(apiMetaData.isSetType()) { - buffer.putInt(apiMetaData.getType()); - } else { - buffer.putInt(0); - } - + buffer.putInt(apiMetaData.getLineNumber()); + buffer.putInt(apiMetaData.getMethodTypeEnum().getCode()); + final byte[] apiMetaDataBytes = buffer.getBuffer(); put.addColumn(HBaseTables.API_METADATA_CF_API, HBaseTables.API_METADATA_CF_API_QUALI_SIGNATURE, apiMetaDataBytes); - hbaseTemplate.put(HBaseTables.API_METADATA, put); + final TableName apiMetaDataTableName = tableNameProvider.getTableName(HBaseTables.API_METADATA_STR); + hbaseTemplate.put(apiMetaDataTableName, put); } private byte[] getDistributedKey(byte[] rowKey) { return rowKeyDistributorByHashPrefix.getDistributedKey(rowKey); } -} +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApplicationIndexDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApplicationIndexDao.java index 247dc2f91a0a..59be4c33c345 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApplicationIndexDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApplicationIndexDao.java @@ -20,8 +20,10 @@ import com.navercorp.pinpoint.collector.dao.ApplicationIndexDao; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; -import com.navercorp.pinpoint.thrift.dto.TAgentInfo; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; +import com.navercorp.pinpoint.common.server.bo.AgentInfoBo; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; @@ -43,19 +45,22 @@ public class HbaseApplicationIndexDao implements ApplicationIndexDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Override - public void insert(final TAgentInfo agentInfo) { + public void insert(final AgentInfoBo agentInfo) { if (agentInfo == null) { throw new NullPointerException("agentInfo must not be null"); } - Put put = new Put(Bytes.toBytes(agentInfo.getApplicationName())); - byte[] qualifier = Bytes.toBytes(agentInfo.getAgentId()); - byte[] value = Bytes.toBytes(agentInfo.getServiceType()); - + final Put put = new Put(Bytes.toBytes(agentInfo.getApplicationName())); + final byte[] qualifier = Bytes.toBytes(agentInfo.getAgentId()); + final byte[] value = Bytes.toBytes(agentInfo.getServiceTypeCode()); put.addColumn(APPLICATION_INDEX_CF_AGENTS, qualifier, value); - - hbaseTemplate.put(APPLICATION_INDEX, put); + + final TableName applicationIndexTableName = tableNameProvider.getTableName(APPLICATION_INDEX_STR); + hbaseTemplate.put(applicationIndexTableName, put); logger.debug("Insert agentInfo. {}", agentInfo); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApplicationTraceIndexDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApplicationTraceIndexDao.java index d4acd739716a..d2493f5bf9ce 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApplicationTraceIndexDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseApplicationTraceIndexDao.java @@ -19,14 +19,16 @@ import static com.navercorp.pinpoint.common.hbase.HBaseTables.*; import com.navercorp.pinpoint.collector.dao.ApplicationTraceIndexDao; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; +import com.navercorp.pinpoint.common.server.bo.SpanBo; import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; import com.navercorp.pinpoint.common.buffer.Buffer; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.server.util.SpanUtils; -import com.navercorp.pinpoint.thrift.dto.TSpan; import com.sematext.hbase.wd.AbstractRowKeyDistributor; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -44,6 +46,9 @@ public class HbaseApplicationTraceIndexDao implements ApplicationTraceIndexDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AcceptedTimeService acceptedTimeService; @@ -52,38 +57,38 @@ public class HbaseApplicationTraceIndexDao implements ApplicationTraceIndexDao { private AbstractRowKeyDistributor rowKeyDistributor; @Override - public void insert(final TSpan span) { + public void insert(final SpanBo span) { if (span == null) { throw new NullPointerException("span must not be null"); } final Buffer buffer = new AutomaticBuffer(10 + AGENT_NAME_MAX_LEN); buffer.putVInt(span.getElapsed()); - buffer.putSVInt(span.getErr()); + buffer.putSVInt(span.getErrCode()); buffer.putPrefixedString(span.getAgentId()); final byte[] value = buffer.getBuffer(); - long acceptedTime = acceptedTimeService.getAcceptedTime(); + final long acceptedTime = acceptedTimeService.getAcceptedTime(); final byte[] distributedKey = createRowKey(span, acceptedTime); - Put put = new Put(distributedKey); + final Put put = new Put(distributedKey); put.addColumn(APPLICATION_TRACE_INDEX_CF_TRACE, makeQualifier(span) , acceptedTime, value); - boolean success = hbaseTemplate.asyncPut(APPLICATION_TRACE_INDEX, put); + final TableName applicationTraceIndexTableName = tableNameProvider.getTableName(APPLICATION_TRACE_INDEX_STR); + boolean success = hbaseTemplate.asyncPut(applicationTraceIndexTableName, put); if (!success) { - hbaseTemplate.put(APPLICATION_TRACE_INDEX, put); + hbaseTemplate.put(applicationTraceIndexTableName, put); } } - private byte[] makeQualifier(final TSpan span) { - byte[] qualifier = SpanUtils.getVarTransactionId(span); - + private byte[] makeQualifier(final SpanBo span) { + final byte[] qualifier = SpanUtils.getVarTransactionId(span); return qualifier; } - private byte[] createRowKey(TSpan span, long acceptedTime) { + private byte[] createRowKey(SpanBo span, long acceptedTime) { // distribute key evenly - byte[] applicationTraceIndexRowKey = SpanUtils.getApplicationTraceIndexRowKey(span.getApplicationName(), acceptedTime); + final byte[] applicationTraceIndexRowKey = SpanUtils.getApplicationTraceIndexRowKey(span.getApplicationId(), acceptedTime); return rowKeyDistributor.getDistributedKey(applicationTraceIndexRowKey); } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseHostApplicationMapDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseHostApplicationMapDao.java index 28f04e10242d..cdb87dd32fa2 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseHostApplicationMapDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseHostApplicationMapDao.java @@ -17,6 +17,7 @@ package com.navercorp.pinpoint.collector.dao.hbase; import com.navercorp.pinpoint.collector.dao.HostApplicationMapDao; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; import com.navercorp.pinpoint.collector.util.AtomicLongUpdateMap; import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; @@ -26,6 +27,7 @@ import com.navercorp.pinpoint.common.util.TimeSlot; import com.navercorp.pinpoint.common.util.TimeUtils; import com.sematext.hbase.wd.AbstractRowKeyDistributor; +import org.apache.hadoop.hbase.TableName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -45,6 +47,9 @@ public class HbaseHostApplicationMapDao implements HostApplicationMapDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AcceptedTimeService acceptedTimeService; @@ -98,11 +103,12 @@ private void insertHostVer2(String host, String bindApplicationName, short bindS byte[] columnName = createColumnName(host, bindApplicationName, bindServiceType); + TableName hostApplicationMapTableName = tableNameProvider.getTableName(HBaseTables.HOST_APPLICATION_MAP_VER2_STR); try { - hbaseTemplate.put(HBaseTables.HOST_APPLICATION_MAP_VER2, rowKey, HBaseTables.HOST_APPLICATION_MAP_VER2_CF_MAP, columnName, null); + hbaseTemplate.put(hostApplicationMapTableName, rowKey, HBaseTables.HOST_APPLICATION_MAP_VER2_CF_MAP, columnName, null); } catch (Exception ex) { logger.warn("retry one. Caused:{}", ex.getCause(), ex); - hbaseTemplate.put(HBaseTables.HOST_APPLICATION_MAP_VER2, rowKey, HBaseTables.HOST_APPLICATION_MAP_VER2_CF_MAP, columnName, null); + hbaseTemplate.put(hostApplicationMapTableName, rowKey, HBaseTables.HOST_APPLICATION_MAP_VER2_CF_MAP, columnName, null); } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapResponseTimeDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapResponseTimeDao.java index df4b01665612..5e02f266ae9b 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapResponseTimeDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapResponseTimeDao.java @@ -16,10 +16,9 @@ package com.navercorp.pinpoint.collector.dao.hbase; -import com.google.common.util.concurrent.AtomicLongMap; import com.navercorp.pinpoint.collector.dao.MapResponseTimeDao; import com.navercorp.pinpoint.collector.dao.hbase.statistics.*; -import com.navercorp.pinpoint.collector.util.AtomicLongMapUtils; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.trace.ServiceType; @@ -27,6 +26,7 @@ import com.navercorp.pinpoint.common.util.TimeSlot; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Increment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,6 +45,7 @@ * @author netspider * @author emeroad * @author jaehong.kim + * @author HyunGil Jeong */ @Repository public class HbaseMapResponseTimeDao implements MapResponseTimeDao { @@ -54,6 +55,9 @@ public class HbaseMapResponseTimeDao implements MapResponseTimeDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AcceptedTimeService acceptedTimeService; @@ -61,8 +65,8 @@ public class HbaseMapResponseTimeDao implements MapResponseTimeDao { private TimeSlot timeSlot; @Autowired - @Qualifier("selfMerge") - private RowKeyMerge rowKeyMerge; + @Qualifier("selfBulkIncrementer") + private BulkIncrementer bulkIncrementer; @Autowired @Qualifier("statisticsSelfRowKeyDistributor") @@ -70,8 +74,6 @@ public class HbaseMapResponseTimeDao implements MapResponseTimeDao { private final boolean useBulk; - private final AtomicLongMap counter = AtomicLongMap.create(); - public HbaseMapResponseTimeDao() { this(true); } @@ -101,8 +103,8 @@ public void received(String applicationName, ServiceType applicationServiceType, final short slotNumber = ApplicationMapStatisticsUtils.getSlotNumber(applicationServiceType, elapsed, isError); final ColumnName selfColumnName = new ResponseColumnName(agentId, slotNumber); if (useBulk) { - RowInfo rowInfo = new DefaultRowInfo(selfRowKey, selfColumnName); - this.counter.incrementAndGet(rowInfo); + TableName mapStatisticsSelfTableName = tableNameProvider.getTableName(MAP_STATISTICS_SELF_VER2_STR); + bulkIncrementer.increment(mapStatisticsSelfTableName, selfRowKey, selfColumnName); } else { final byte[] rowKey = getDistributedKey(selfRowKey.getRowKey()); // column name is the name of caller app. @@ -118,7 +120,8 @@ private void increment(byte[] rowKey, byte[] columnName, long increment) { if (columnName == null) { throw new NullPointerException("columnName must not be null"); } - hbaseTemplate.incrementColumnValue(MAP_STATISTICS_SELF_VER2, rowKey, MAP_STATISTICS_SELF_VER2_CF_COUNTER, columnName, increment); + TableName mapStatisticsSelfTableName = tableNameProvider.getTableName(MAP_STATISTICS_SELF_VER2_STR); + hbaseTemplate.incrementColumnValue(mapStatisticsSelfTableName, rowKey, MAP_STATISTICS_SELF_VER2_CF_COUNTER, columnName, increment); } @@ -128,18 +131,15 @@ public void flushAll() { throw new IllegalStateException("useBulk is " + useBulk); } - // update statistics by rowkey and column for now. need to update it by rowkey later. - final Map remove = AtomicLongMapUtils.remove(this.counter); - - final List merge = rowKeyMerge.createBulkIncrement(remove, rowKeyDistributorByHashPrefix); - if (merge.isEmpty()) { - return; - } - - if (logger.isDebugEnabled()) { - logger.debug("flush {} Increment:{}", this.getClass().getSimpleName(), merge.size()); + Map> incrementMap = bulkIncrementer.getIncrements(rowKeyDistributorByHashPrefix); + for (Map.Entry> e : incrementMap.entrySet()) { + TableName tableName = e.getKey(); + List increments = e.getValue(); + if (logger.isDebugEnabled()) { + logger.debug("flush {} to [{}] Increment:{}", this.getClass().getSimpleName(), tableName.getNameAsString(), increments.size()); + } + hbaseTemplate.increment(tableName, increments); } - hbaseTemplate.increment(MAP_STATISTICS_SELF_VER2, merge); } private byte[] getDistributedKey(byte[] rowKey) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapStatisticsCalleeDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapStatisticsCalleeDao.java index ac9662ddf232..e25fa2c17869 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapStatisticsCalleeDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapStatisticsCalleeDao.java @@ -18,10 +18,9 @@ import static com.navercorp.pinpoint.common.hbase.HBaseTables.*; -import com.google.common.util.concurrent.AtomicLongMap; import com.navercorp.pinpoint.collector.dao.MapStatisticsCalleeDao; import com.navercorp.pinpoint.collector.dao.hbase.statistics.*; -import com.navercorp.pinpoint.collector.util.AtomicLongMapUtils; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.trace.ServiceType; @@ -30,6 +29,7 @@ import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Increment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,6 +45,7 @@ * * @author netspider * @author emeroad + * @author HyunGil Jeong */ @Repository public class HbaseMapStatisticsCalleeDao implements MapStatisticsCalleeDao { @@ -54,6 +55,9 @@ public class HbaseMapStatisticsCalleeDao implements MapStatisticsCalleeDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AcceptedTimeService acceptedTimeService; @@ -61,8 +65,8 @@ public class HbaseMapStatisticsCalleeDao implements MapStatisticsCalleeDao { private TimeSlot timeSlot; @Autowired - @Qualifier("calleeMerge") - private RowKeyMerge rowKeyMerge; + @Qualifier("calleeBulkIncrementer") + private BulkIncrementer bulkIncrementer; @Autowired @Qualifier("statisticsCalleeRowKeyDistributor") @@ -70,8 +74,6 @@ public class HbaseMapStatisticsCalleeDao implements MapStatisticsCalleeDao { private final boolean useBulk; - private final AtomicLongMap counter = AtomicLongMap.create(); - public HbaseMapStatisticsCalleeDao() { this(true); } @@ -80,7 +82,6 @@ public HbaseMapStatisticsCalleeDao(boolean useBulk) { this.useBulk = useBulk; } - @Override public void update(String calleeApplicationName, ServiceType calleeServiceType, String callerApplicationName, ServiceType callerServiceType, String callerHost, int elapsed, boolean isError) { if (callerApplicationName == null) { @@ -107,8 +108,8 @@ public void update(String calleeApplicationName, ServiceType calleeServiceType, final ColumnName callerColumnName = new CallerColumnName(callerServiceType.getCode(), callerApplicationName, callerHost, callerSlotNumber); if (useBulk) { - RowInfo rowInfo = new DefaultRowInfo(calleeRowKey, callerColumnName); - counter.incrementAndGet(rowInfo); + TableName mapStatisticsCallerTableName = tableNameProvider.getTableName(MAP_STATISTICS_CALLER_VER2_STR); + bulkIncrementer.increment(mapStatisticsCallerTableName, calleeRowKey, callerColumnName); } else { final byte[] rowKey = getDistributedKey(calleeRowKey.getRowKey()); @@ -125,7 +126,8 @@ private void increment(byte[] rowKey, byte[] columnName, long increment) { if (columnName == null) { throw new NullPointerException("columnName must not be null"); } - hbaseTemplate.incrementColumnValue(MAP_STATISTICS_CALLER_VER2, rowKey, MAP_STATISTICS_CALLER_VER2_CF_COUNTER, columnName, increment); + TableName mapStatisticsCallerTableName = tableNameProvider.getTableName(MAP_STATISTICS_CALLER_VER2_STR); + hbaseTemplate.incrementColumnValue(mapStatisticsCallerTableName, rowKey, MAP_STATISTICS_CALLER_VER2_CF_COUNTER, columnName, increment); } @Override @@ -134,17 +136,16 @@ public void flushAll() { throw new IllegalStateException(); } - final Map remove = AtomicLongMapUtils.remove(this.counter); + Map> incrementMap = bulkIncrementer.getIncrements(rowKeyDistributorByHashPrefix); - final List merge = rowKeyMerge.createBulkIncrement(remove, rowKeyDistributorByHashPrefix); - if (merge.isEmpty()) { - return; - } - - if (logger.isDebugEnabled()) { - logger.debug("flush {} Increment:{}", this.getClass().getSimpleName(), merge.size()); + for (Map.Entry> e : incrementMap.entrySet()) { + TableName tableName = e.getKey(); + List increments = e.getValue(); + if (logger.isDebugEnabled()) { + logger.debug("flush {} to [{}] Increment:{}", this.getClass().getSimpleName(), tableName.getNameAsString(), increments.size()); + } + hbaseTemplate.increment(tableName, increments); } - hbaseTemplate.increment(MAP_STATISTICS_CALLER_VER2, merge); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapStatisticsCallerDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapStatisticsCallerDao.java index 033beab9bb11..e798c2746609 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapStatisticsCallerDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseMapStatisticsCallerDao.java @@ -18,10 +18,9 @@ import static com.navercorp.pinpoint.common.hbase.HBaseTables.*; -import com.google.common.util.concurrent.AtomicLongMap; import com.navercorp.pinpoint.collector.dao.MapStatisticsCallerDao; import com.navercorp.pinpoint.collector.dao.hbase.statistics.*; -import com.navercorp.pinpoint.collector.util.AtomicLongMapUtils; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.trace.ServiceType; @@ -30,6 +29,7 @@ import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Increment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,6 +45,7 @@ * * @author netspider * @author emeroad + * @author HyunGil Jeong */ @Repository public class HbaseMapStatisticsCallerDao implements MapStatisticsCallerDao { @@ -54,24 +55,25 @@ public class HbaseMapStatisticsCallerDao implements MapStatisticsCallerDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AcceptedTimeService acceptedTimeService; @Autowired - @Qualifier("callerMerge") - private RowKeyMerge rowKeyMerge; + private TimeSlot timeSlot; @Autowired - @Qualifier("statisticsCallerRowKeyDistributor") - private RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix; + @Qualifier("callerBulkIncrementer") + private BulkIncrementer bulkIncrementer; @Autowired - private TimeSlot timeSlot; + @Qualifier("statisticsCallerRowKeyDistributor") + private RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix; private final boolean useBulk; - private final AtomicLongMap counter = AtomicLongMap.create(); - public HbaseMapStatisticsCallerDao() { this(true); } @@ -105,8 +107,8 @@ public void update(String callerApplicationName, ServiceType callerServiceType, final short calleeSlotNumber = ApplicationMapStatisticsUtils.getSlotNumber(calleeServiceType, elapsed, isError); final ColumnName calleeColumnName = new CalleeColumnName(callerAgentid, calleeServiceType.getCode(), calleeApplicationName, calleeHost, calleeSlotNumber); if (useBulk) { - RowInfo rowInfo = new DefaultRowInfo(callerRowKey, calleeColumnName); - this.counter.incrementAndGet(rowInfo); + TableName mapStatisticsCalleeTableName = tableNameProvider.getTableName(MAP_STATISTICS_CALLEE_VER2_STR); + bulkIncrementer.increment(mapStatisticsCalleeTableName, callerRowKey, calleeColumnName); } else { final byte[] rowKey = getDistributedKey(callerRowKey.getRowKey()); // column name is the name of caller app. @@ -122,7 +124,8 @@ private void increment(byte[] rowKey, byte[] columnName, long increment) { if (columnName == null) { throw new NullPointerException("columnName must not be null"); } - hbaseTemplate.incrementColumnValue(MAP_STATISTICS_CALLEE_VER2, rowKey, MAP_STATISTICS_CALLEE_VER2_CF_COUNTER, columnName, increment); + TableName mapStatisticsCalleeTableName = tableNameProvider.getTableName(MAP_STATISTICS_CALLEE_VER2_STR); + hbaseTemplate.incrementColumnValue(mapStatisticsCalleeTableName, rowKey, MAP_STATISTICS_CALLEE_VER2_CF_COUNTER, columnName, increment); } @Override @@ -131,17 +134,16 @@ public void flushAll() { throw new IllegalStateException(); } // update statistics by rowkey and column for now. need to update it by rowkey later. - final Map remove = AtomicLongMapUtils.remove(this.counter); - - final List merge = rowKeyMerge.createBulkIncrement(remove, rowKeyDistributorByHashPrefix); - if (merge.isEmpty()) { - return; - } - - if (logger.isDebugEnabled()) { - logger.debug("flush {} Increment:{}", this.getClass().getSimpleName(), merge.size()); + Map> incrementMap = bulkIncrementer.getIncrements(rowKeyDistributorByHashPrefix); + + for (Map.Entry> e : incrementMap.entrySet()) { + TableName tableName = e.getKey(); + List increments = e.getValue(); + if (logger.isDebugEnabled()) { + logger.debug("flush {} to [{}] Increment:{}", this.getClass().getSimpleName(), tableName.getNameAsString(), increments.size()); + } + hbaseTemplate.increment(tableName, increments); } - hbaseTemplate.increment(MAP_STATISTICS_CALLEE_VER2, merge); } private byte[] getDistributedKey(byte[] rowKey) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseSqlMetaDataDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseSqlMetaDataDao.java index 1ff7c1a91819..2080d32e058c 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseSqlMetaDataDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseSqlMetaDataDao.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,23 +17,25 @@ package com.navercorp.pinpoint.collector.dao.hbase; import com.navercorp.pinpoint.collector.dao.SqlMetaDataDao; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.SqlMetaDataBo; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; -import com.navercorp.pinpoint.thrift.dto.TSqlMetaData; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Repository; /** * @author minwoo.jung */ -//@Repository +@Repository public class HbaseSqlMetaDataDao implements SqlMetaDataDao { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -41,12 +43,15 @@ public class HbaseSqlMetaDataDao implements SqlMetaDataDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("metadataRowKeyDistributor2") private RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix; @Override - public void insert(TSqlMetaData sqlMetaData) { + public void insert(SqlMetaDataBo sqlMetaData) { if (sqlMetaData == null) { throw new NullPointerException("sqlMetaData must not be null"); } @@ -54,17 +59,14 @@ public void insert(TSqlMetaData sqlMetaData) { logger.debug("insert:{}", sqlMetaData); } - SqlMetaDataBo sqlMetaDataBo = new SqlMetaDataBo(sqlMetaData.getAgentId(), sqlMetaData.getAgentStartTime(), sqlMetaData.getSqlId()); - final byte[] rowKey = getDistributedKey(sqlMetaDataBo.toRowKey()); - - - Put put = new Put(rowKey); - String sql = sqlMetaData.getSql(); - byte[] sqlBytes = Bytes.toBytes(sql); - + final byte[] rowKey = getDistributedKey(sqlMetaData.toRowKey()); + final Put put = new Put(rowKey); + final String sql = sqlMetaData.getSql(); + final byte[] sqlBytes = Bytes.toBytes(sql); put.addColumn(HBaseTables.SQL_METADATA_VER2_CF_SQL, HBaseTables.SQL_METADATA_VER2_CF_SQL_QUALI_SQLSTATEMENT, sqlBytes); - hbaseTemplate.put(HBaseTables.SQL_METADATA_VER2, put); + final TableName sqlMetaDataTableName = tableNameProvider.getTableName(HBaseTables.SQL_METADATA_VER2_STR); + hbaseTemplate.put(sqlMetaDataTableName, put); } private byte[] getDistributedKey(byte[] rowKey) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseStringMetaDataDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseStringMetaDataDao.java index ce9dd0987666..1a5c600bdb56 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseStringMetaDataDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseStringMetaDataDao.java @@ -17,12 +17,13 @@ package com.navercorp.pinpoint.collector.dao.hbase; import com.navercorp.pinpoint.collector.dao.StringMetaDataDao; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.StringMetaDataBo; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; -import com.navercorp.pinpoint.thrift.dto.TStringMetaData; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; @@ -43,12 +44,15 @@ public class HbaseStringMetaDataDao implements StringMetaDataDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("metadataRowKeyDistributor") private RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix; @Override - public void insert(TStringMetaData stringMetaData) { + public void insert(StringMetaDataBo stringMetaData) { if (stringMetaData == null) { throw new NullPointerException("stringMetaData must not be null"); } @@ -56,16 +60,14 @@ public void insert(TStringMetaData stringMetaData) { logger.debug("insert:{}", stringMetaData); } - final StringMetaDataBo stringMetaDataBo = new StringMetaDataBo(stringMetaData.getAgentId(), stringMetaData.getAgentStartTime(), stringMetaData.getStringId()); - final byte[] rowKey = getDistributedKey(stringMetaDataBo.toRowKey()); - - - Put put = new Put(rowKey); - String stringValue = stringMetaData.getStringValue(); - byte[] sqlBytes = Bytes.toBytes(stringValue); + final byte[] rowKey = getDistributedKey(stringMetaData.toRowKey()); + final Put put = new Put(rowKey); + final String stringValue = stringMetaData.getStringValue(); + final byte[] sqlBytes = Bytes.toBytes(stringValue); put.addColumn(HBaseTables.STRING_METADATA_CF_STR, HBaseTables.STRING_METADATA_CF_STR_QUALI_STRING, sqlBytes); - hbaseTemplate.put(HBaseTables.STRING_METADATA, put); + final TableName stringMetaDataTableName = tableNameProvider.getTableName(HBaseTables.STRING_METADATA_STR); + hbaseTemplate.put(stringMetaDataTableName, put); } private byte[] getDistributedKey(byte[] rowKey) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseTraceDaoV2.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseTraceDaoV2.java index bdb85d80b201..bc2ed504fd00 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseTraceDaoV2.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/HbaseTraceDaoV2.java @@ -2,6 +2,7 @@ import com.navercorp.pinpoint.collector.dao.TraceDao; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.SpanBo; import com.navercorp.pinpoint.common.server.bo.SpanChunkBo; import com.navercorp.pinpoint.common.server.bo.SpanEventBo; @@ -10,6 +11,7 @@ import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.SpanSerializerV2; import com.navercorp.pinpoint.common.util.TransactionId; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,7 +21,7 @@ import java.util.List; -import static com.navercorp.pinpoint.common.hbase.HBaseTables.TRACE_V2; +import static com.navercorp.pinpoint.common.hbase.HBaseTables.TRACE_V2_STR; /** * @author Woonduk Kang(emeroad) @@ -32,6 +34,8 @@ public class HbaseTraceDaoV2 implements TraceDao { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; @Autowired private SpanSerializerV2 spanSerializer; @@ -59,10 +63,10 @@ public void insert(final SpanBo spanBo) { this.spanSerializer.serialize(spanBo, put, null); - - boolean success = hbaseTemplate.asyncPut(TRACE_V2, put); + TableName traceTableName = tableNameProvider.getTableName(TRACE_V2_STR); + boolean success = hbaseTemplate.asyncPut(traceTableName, put); if (!success) { - hbaseTemplate.put(TRACE_V2, put); + hbaseTemplate.put(traceTableName, put); } } @@ -86,9 +90,10 @@ public void insertSpanChunk(SpanChunkBo spanChunkBo) { this.spanChunkSerializer.serialize(spanChunkBo, put, null); if (!put.isEmpty()) { - boolean success = hbaseTemplate.asyncPut(TRACE_V2, put); + TableName traceTableName = tableNameProvider.getTableName(TRACE_V2_STR); + boolean success = hbaseTemplate.asyncPut(traceTableName, put); if (!success) { - hbaseTemplate.put(TRACE_V2, put); + hbaseTemplate.put(traceTableName, put); } } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseActiveTraceDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseActiveTraceDao.java index f5d23da8c19f..c541cf324b92 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseActiveTraceDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseActiveTraceDao.java @@ -19,11 +19,13 @@ import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.ActiveTraceSerializer; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.stat.ActiveTraceBo; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -39,6 +41,9 @@ public class HbaseActiveTraceDao implements AgentStatDaoV2 { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; @@ -55,9 +60,10 @@ public void insert(String agentId, List agentStatDataPoints) { } List activeTracePuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.ACTIVE_TRACE, agentStatDataPoints, this.activeTraceSerializer); if (!activeTracePuts.isEmpty()) { - List rejectedPuts = this.hbaseTemplate.asyncPut(HBaseTables.AGENT_STAT_VER2, activeTracePuts); + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, activeTracePuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - this.hbaseTemplate.put(HBaseTables.AGENT_STAT_VER2, rejectedPuts); + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); } } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseCpuLoadDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseCpuLoadDao.java index 3a8e15c297e9..849e08aa5486 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseCpuLoadDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseCpuLoadDao.java @@ -19,11 +19,13 @@ import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.CpuLoadSerializer; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -39,6 +41,9 @@ public class HbaseCpuLoadDao implements AgentStatDaoV2 { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; @@ -55,9 +60,10 @@ public void insert(String agentId, List cpuLoadBos) { } List cpuLoadPuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.CPU_LOAD, cpuLoadBos, this.cpuLoadSerializer); if (!cpuLoadPuts.isEmpty()) { - List rejectedPuts = this.hbaseTemplate.asyncPut(HBaseTables.AGENT_STAT_VER2, cpuLoadPuts); + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, cpuLoadPuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - this.hbaseTemplate.put(HBaseTables.AGENT_STAT_VER2, rejectedPuts); + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); } } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDataSourceListDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDataSourceListDao.java index bce4b631dd9b..ed6d6fd014d2 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDataSourceListDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDataSourceListDao.java @@ -19,6 +19,7 @@ import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatUtils; import com.navercorp.pinpoint.common.server.bo.serializer.stat.DataSourceSerializer; @@ -27,6 +28,7 @@ import com.navercorp.pinpoint.common.server.bo.stat.DataSourceListBo; import com.navercorp.pinpoint.common.util.CollectionUtils; import org.apache.commons.collections.map.MultiKeyMap; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,6 +50,9 @@ public class HbaseDataSourceListDao implements AgentStatDaoV2 @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; @@ -66,9 +71,10 @@ public void insert(String agentId, List dataSourceListBos) { List reorderedDataSourceListBos = reorderDataSourceListBos(dataSourceListBos); List activeTracePuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.DATASOURCE, reorderedDataSourceListBos, dataSourceSerializer); if (!activeTracePuts.isEmpty()) { - List rejectedPuts = this.hbaseTemplate.asyncPut(HBaseTables.AGENT_STAT_VER2, activeTracePuts); + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, activeTracePuts); if (CollectionUtils.hasLength(rejectedPuts)) { - this.hbaseTemplate.put(HBaseTables.AGENT_STAT_VER2, rejectedPuts); + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); } } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDeadlockDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDeadlockDao.java deleted file mode 100644 index e4a34e827492..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDeadlockDao.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.dao.hbase.stat; - -import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; -import com.navercorp.pinpoint.common.hbase.HBaseTables; -import com.navercorp.pinpoint.common.hbase.HbaseOperations2; -import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; -import com.navercorp.pinpoint.common.server.bo.serializer.stat.DeadlockSerializer; -import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; -import org.apache.commons.collections.CollectionUtils; -import org.apache.hadoop.hbase.client.Put; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Repository; - -import java.util.List; - -/** - * @author Taejin Koo - */ -@Repository -public class HbaseDeadlockDao implements AgentStatDaoV2 { - - @Autowired - private HbaseOperations2 hbaseTemplate; - - @Autowired - private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; - - @Autowired - private DeadlockSerializer deadlockSerializer; - - @Override - public void insert(String agentId, List deadlockBos) { - if (agentId == null) { - throw new NullPointerException("agentId must not be null"); - } - if (CollectionUtils.isEmpty(deadlockBos)) { - return; - } - List deadlockPuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.DEADLOCK, deadlockBos, this.deadlockSerializer); - if (!deadlockPuts.isEmpty()) { - List rejectedPuts = this.hbaseTemplate.asyncPut(HBaseTables.AGENT_STAT_VER2, deadlockPuts); - if (CollectionUtils.isNotEmpty(rejectedPuts)) { - this.hbaseTemplate.put(HBaseTables.AGENT_STAT_VER2, rejectedPuts); - } - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDeadlockThreadCountDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDeadlockThreadCountDao.java new file mode 100644 index 000000000000..08b39194a17b --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDeadlockThreadCountDao.java @@ -0,0 +1,71 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.dao.hbase.stat; + +import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; +import com.navercorp.pinpoint.common.hbase.HBaseTables; +import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.DeadlockThreadCountSerializer; +import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Put; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author Taejin Koo + */ +@Repository +public class HbaseDeadlockThreadCountDao implements AgentStatDaoV2 { + + @Autowired + private HbaseOperations2 hbaseTemplate; + + @Autowired + private TableNameProvider tableNameProvider; + + @Autowired + private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; + + @Autowired + private DeadlockThreadCountSerializer deadlockThreadCountSerializer; + + @Override + public void insert(String agentId, List deadlockThreadCountBos) { + if (agentId == null) { + throw new NullPointerException("agentId must not be null"); + } + if (CollectionUtils.isEmpty(deadlockThreadCountBos)) { + return; + } + List deadlockPuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.DEADLOCK, deadlockThreadCountBos, this.deadlockThreadCountSerializer); + if (!deadlockPuts.isEmpty()) { + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, deadlockPuts); + if (CollectionUtils.isNotEmpty(rejectedPuts)) { + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); + } + } + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDirectBufferDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDirectBufferDao.java new file mode 100644 index 000000000000..949be04483b4 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseDirectBufferDao.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.dao.hbase.stat; + +import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; +import com.navercorp.pinpoint.common.hbase.HBaseTables; +import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.DirectBufferSerializer; +import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Put; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Repository +public class HbaseDirectBufferDao implements AgentStatDaoV2 { + + @Autowired + private HbaseOperations2 hbaseTemplate; + + @Autowired + private TableNameProvider tableNameProvider; + + @Autowired + private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; + + @Autowired + private DirectBufferSerializer directBufferSerializer; + + @Override + public void insert(String agentId, List directBufferBos) { + if (agentId == null) { + throw new NullPointerException("agentId must not be null"); + } + if (CollectionUtils.isEmpty(directBufferBos)) { + return; + } + List directBufferPuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.DIRECT_BUFFER, directBufferBos, this.directBufferSerializer); + if (!directBufferPuts.isEmpty()) { + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, directBufferPuts); + if (CollectionUtils.isNotEmpty(rejectedPuts)) { + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); + } + } + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseFileDescriptorDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseFileDescriptorDao.java new file mode 100644 index 000000000000..29d267605d7a --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseFileDescriptorDao.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.dao.hbase.stat; + +import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; +import com.navercorp.pinpoint.common.hbase.HBaseTables; +import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.FileDescriptorSerializer; +import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Put; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Repository +public class HbaseFileDescriptorDao implements AgentStatDaoV2 { + + @Autowired + private HbaseOperations2 hbaseTemplate; + + @Autowired + private TableNameProvider tableNameProvider; + + @Autowired + private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; + + @Autowired + private FileDescriptorSerializer fileDescriptorSerializer; + + @Override + public void insert(String agentId, List fileDescriptorBos) { + if (agentId == null) { + throw new NullPointerException("agentId must not be null"); + } + if (CollectionUtils.isEmpty(fileDescriptorBos)) { + return; + } + List fileDescriptorPuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.FILE_DESCRIPTOR, fileDescriptorBos, this.fileDescriptorSerializer); + if (!fileDescriptorPuts.isEmpty()) { + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, fileDescriptorPuts); + if (CollectionUtils.isNotEmpty(rejectedPuts)) { + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); + } + } + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseJvmGcDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseJvmGcDao.java index 801d52b5facf..1010adc28080 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseJvmGcDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseJvmGcDao.java @@ -19,11 +19,13 @@ import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.JvmGcSerializer; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcBo; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -39,6 +41,9 @@ public class HbaseJvmGcDao implements AgentStatDaoV2 { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; @@ -55,9 +60,10 @@ public void insert(String agentId, List jvmGcBos) { } List jvmGcBoPuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.JVM_GC, jvmGcBos, this.jvmGcSerializer); if (!jvmGcBoPuts.isEmpty()) { - List rejectedPuts = this.hbaseTemplate.asyncPut(HBaseTables.AGENT_STAT_VER2, jvmGcBoPuts); + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, jvmGcBoPuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - this.hbaseTemplate.put(HBaseTables.AGENT_STAT_VER2, rejectedPuts); + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); } } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseJvmGcDetailedDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseJvmGcDetailedDao.java index 62265691fb22..5649d59725ca 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseJvmGcDetailedDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseJvmGcDetailedDao.java @@ -19,11 +19,13 @@ import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.JvmGcDetailedSerializer; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcDetailedBo; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -39,6 +41,9 @@ public class HbaseJvmGcDetailedDao implements AgentStatDaoV2 { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; @@ -55,9 +60,10 @@ public void insert(String agentId, List jvmGcDetailedBos) { } List jvmGcDetailedPuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.JVM_GC_DETAILED, jvmGcDetailedBos, this.jvmGcDetailedSerializer); if (!jvmGcDetailedPuts.isEmpty()) { - List rejectedPuts = this.hbaseTemplate.asyncPut(HBaseTables.AGENT_STAT_VER2, jvmGcDetailedPuts); + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, jvmGcDetailedPuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - this.hbaseTemplate.put(HBaseTables.AGENT_STAT_VER2, rejectedPuts); + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); } } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseResponseTimeDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseResponseTimeDao.java index f55f8e90378e..10bb272976b5 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseResponseTimeDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseResponseTimeDao.java @@ -19,11 +19,13 @@ import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.ResponseTimeSerializer; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; import com.navercorp.pinpoint.common.server.bo.stat.ResponseTimeBo; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -39,6 +41,9 @@ public class HbaseResponseTimeDao implements AgentStatDaoV2 { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; @@ -55,9 +60,10 @@ public void insert(String agentId, List responseTimeBos) { } List responseTimePuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.RESPONSE_TIME, responseTimeBos, this.responseTimeSerializer); if (!responseTimePuts.isEmpty()) { - List rejectedPuts = this.hbaseTemplate.asyncPut(HBaseTables.AGENT_STAT_VER2, responseTimePuts); + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, responseTimePuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - this.hbaseTemplate.put(HBaseTables.AGENT_STAT_VER2, rejectedPuts); + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); } } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseTransactionDao.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseTransactionDao.java index 63597cb1279f..1a54a2df79dc 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseTransactionDao.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/stat/HbaseTransactionDao.java @@ -19,11 +19,13 @@ import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.TransactionSerializer; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; import com.navercorp.pinpoint.common.server.bo.stat.TransactionBo; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Put; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -39,6 +41,9 @@ public class HbaseTransactionDao implements AgentStatDaoV2 { @Autowired private HbaseOperations2 hbaseTemplate; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentStatHbaseOperationFactory agentStatHbaseOperationFactory; @@ -55,9 +60,10 @@ public void insert(String agentId, List transactionBos) { } List transactionPuts = this.agentStatHbaseOperationFactory.createPuts(agentId, AgentStatType.TRANSACTION, transactionBos, this.transactionSerializer); if (!transactionPuts.isEmpty()) { - List rejectedPuts = this.hbaseTemplate.asyncPut(HBaseTables.AGENT_STAT_VER2, transactionPuts); + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List rejectedPuts = this.hbaseTemplate.asyncPut(agentStatTableName, transactionPuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - this.hbaseTemplate.put(HBaseTables.AGENT_STAT_VER2, rejectedPuts); + this.hbaseTemplate.put(agentStatTableName, rejectedPuts); } } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/BulkIncrementer.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/BulkIncrementer.java new file mode 100644 index 000000000000..13d7a7d4c3a9 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/BulkIncrementer.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.dao.hbase.statistics; + +import com.google.common.util.concurrent.AtomicLongMap; +import com.navercorp.pinpoint.collector.util.AtomicLongMapUtils; +import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Increment; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * @author HyunGil Jeong + */ +public class BulkIncrementer { + + private final RowKeyMerge rowKeyMerge; + + private final AtomicLongMap counter = AtomicLongMap.create(); + + public BulkIncrementer(RowKeyMerge rowKeyMerge) { + this.rowKeyMerge = Objects.requireNonNull(rowKeyMerge, "rowKeyMerge must not be null"); + } + + public void increment(TableName tableName, RowKey rowKey, ColumnName columnName) { + RowInfo rowInfo = new DefaultRowInfo(tableName, rowKey, columnName); + counter.incrementAndGet(rowInfo); + } + + public Map> getIncrements(RowKeyDistributorByHashPrefix rowKeyDistributor) { + final Map snapshot = AtomicLongMapUtils.remove(counter); + return rowKeyMerge.createBulkIncrement(snapshot, rowKeyDistributor); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/DefaultRowInfo.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/DefaultRowInfo.java index 4e07fec94f66..a2cdd19131e8 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/DefaultRowInfo.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/DefaultRowInfo.java @@ -16,30 +16,37 @@ package com.navercorp.pinpoint.collector.dao.hbase.statistics; +import org.apache.hadoop.hbase.TableName; + +import java.util.Objects; + /** * @author emeroad + * @author HyunGil Jeong */ public class DefaultRowInfo implements RowInfo { - private RowKey rowKey; - private ColumnName columnName; + private final TableName tableName; + private final RowKey rowKey; + private final ColumnName columnName; - public DefaultRowInfo(RowKey rowKey, ColumnName columnName) { - if (rowKey == null) { - throw new NullPointerException("rowKey must not be null"); - } - if (columnName == null) { - throw new NullPointerException("columnName must not be null"); - } + public DefaultRowInfo(TableName tableName, RowKey rowKey, ColumnName columnName) { + this.tableName = Objects.requireNonNull(tableName, "tableName must not be null"); + this.rowKey = Objects.requireNonNull(rowKey, "rowKey must not be null"); + this.columnName = Objects.requireNonNull(columnName, "columnName must not be null"); + } - this.rowKey = rowKey; - this.columnName = columnName; + @Override + public TableName getTableName() { + return tableName; } + @Override public RowKey getRowKey() { return rowKey; } + @Override public ColumnName getColumnName() { return columnName; } @@ -51,15 +58,15 @@ public boolean equals(Object o) { DefaultRowInfo that = (DefaultRowInfo) o; - if (!columnName.equals(that.columnName)) return false; + if (!tableName.equals(that.tableName)) return false; if (!rowKey.equals(that.rowKey)) return false; - - return true; + return columnName.equals(that.columnName); } @Override public int hashCode() { - int result = rowKey.hashCode(); + int result = tableName.hashCode(); + result = 31 * result + rowKey.hashCode(); result = 31 * result + columnName.hashCode(); return result; } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/RowInfo.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/RowInfo.java index 312be2e46fb4..6effee0d51c4 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/RowInfo.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/RowInfo.java @@ -16,11 +16,15 @@ package com.navercorp.pinpoint.collector.dao.hbase.statistics; +import org.apache.hadoop.hbase.TableName; + /** * @author emeroad */ public interface RowInfo { + TableName getTableName(); + RowKey getRowKey(); ColumnName getColumnName(); diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/RowKeyMerge.java b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/RowKeyMerge.java index e43442c837f0..8dc0b7a7d662 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/RowKeyMerge.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/RowKeyMerge.java @@ -17,14 +17,21 @@ package com.navercorp.pinpoint.collector.dao.hbase.statistics; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Increment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * @author emeroad + * @author HyunGil Jeong */ public class RowKeyMerge { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -37,19 +44,24 @@ public RowKeyMerge(byte[] family) { this.family = Arrays.copyOf(family, family.length); } - public List createBulkIncrement(Map data, RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix) { + public Map> createBulkIncrement(Map data, RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix) { if (data.isEmpty()) { - return Collections.emptyList(); + return Collections.emptyMap(); } - final Map> rowkeyMerge = rowKeyBaseMerge(data); + final Map> tableIncrementMap = new HashMap<>(); + final Map>> tableRowKeyMap = mergeRowKeys(data); - List incrementList = new ArrayList<>(); - for (Map.Entry> rowKeyEntry : rowkeyMerge.entrySet()) { - Increment increment = createIncrement(rowKeyEntry, rowKeyDistributorByHashPrefix); - incrementList.add(increment); + for (Map.Entry>> tableRowKeys : tableRowKeyMap.entrySet()) { + final TableName tableName = tableRowKeys.getKey(); + final List incrementList = new ArrayList<>(); + for (Map.Entry> rowKeyEntry : tableRowKeys.getValue().entrySet()) { + Increment increment = createIncrement(rowKeyEntry, rowKeyDistributorByHashPrefix); + incrementList.add(increment); + } + tableIncrementMap.put(tableName, incrementList); } - return incrementList; + return tableIncrementMap; } private Increment createIncrement(Map.Entry> rowKeyEntry, RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix) { @@ -68,8 +80,8 @@ private Increment createIncrement(Map.Entry> rowKeyEntr return increment; } - private Map> rowKeyBaseMerge(Map data) { - final Map> merge = new HashMap<>(); + private Map>> mergeRowKeys(Map data) { + final Map>> tables = new HashMap<>(); for (Map.Entry entry : data.entrySet()) { final RowInfo rowInfo = entry.getKey(); @@ -77,16 +89,13 @@ private Map> rowKeyBaseMerge(Map data) { long callCount = entry.getValue(); rowInfo.getColumnName().setCallCount(callCount); - RowKey rowKey = rowInfo.getRowKey(); - List oldList = merge.get(rowKey); - if (oldList == null) { - List newList = new ArrayList<>(); - newList.add(rowInfo.getColumnName()); - merge.put(rowKey, newList); - } else { - oldList.add(rowInfo.getColumnName()); - } + final TableName tableName = rowInfo.getTableName(); + final RowKey rowKey = rowInfo.getRowKey(); + + Map> rows = tables.computeIfAbsent(tableName, k -> new HashMap<>()); + List columnNames = rows.computeIfAbsent(rowKey, k -> new ArrayList<>()); + columnNames.add(rowInfo.getColumnName()); } - return merge; + return tables; } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/AgentEventHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/AgentEventHandler.java deleted file mode 100644 index 1f7e7c1e5684..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/AgentEventHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import com.navercorp.pinpoint.collector.mapper.thrift.event.AgentEventBatchMapper; -import com.navercorp.pinpoint.collector.mapper.thrift.event.AgentEventMapper; -import com.navercorp.pinpoint.collector.service.AgentEventService; -import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; -import com.navercorp.pinpoint.common.util.CollectionUtils; -import com.navercorp.pinpoint.thrift.dto.TAgentStat; -import com.navercorp.pinpoint.thrift.dto.TAgentStatBatch; -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * @author Taejin Koo - */ -@Service("agentEventHandler") -public class AgentEventHandler implements SimpleHandler { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Autowired - private AgentEventMapper agentEventMapper; - - @Autowired - private AgentEventBatchMapper agentEventBatchMapper; - - @Autowired - private AgentEventService agentEventService; - - @Override - public void handleSimple(TBase tBase) { - // FIXME (2014.08) Legacy - TAgentStat should not be sent over the wire. - if (tBase instanceof TAgentStat) { - TAgentStat tAgentStat = (TAgentStat)tBase; - this.handleAgentStat(tAgentStat); - } else if (tBase instanceof TAgentStatBatch) { - TAgentStatBatch tAgentStatBatch = (TAgentStatBatch) tBase; - this.handleAgentStatBatch(tAgentStatBatch); - } else { - throw new IllegalArgumentException("unexpected tbase:" + tBase + " expected:" + TAgentStat.class.getName() + " or " + TAgentStatBatch.class.getName()); - } - } - - private void handleAgentStat(TAgentStat tAgentStat) { - if (logger.isDebugEnabled()) { - logger.debug("Received TAgentStat={}", tAgentStat); - } - - AgentEventBo agentEventBo = this.agentEventMapper.map(tAgentStat); - if (agentEventBo == null) { - return; - } - - agentEventService.service(agentEventBo); - } - - private void handleAgentStatBatch(TAgentStatBatch tAgentStatBatch) { - if (logger.isDebugEnabled()) { - logger.debug("Received TAgentStatBatch={}", tAgentStatBatch); - } - - List agentEventBoList = this.agentEventBatchMapper.map(tAgentStatBatch); - if (CollectionUtils.isEmpty(agentEventBoList)) { - return; - } - - for (AgentEventBo agentEventBo : agentEventBoList) { - agentEventService.service(agentEventBo); - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/AgentInfoHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/AgentInfoHandler.java deleted file mode 100644 index 4269d4396cc9..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/AgentInfoHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.navercorp.pinpoint.collector.dao.AgentInfoDao; -import com.navercorp.pinpoint.collector.dao.ApplicationIndexDao; -import com.navercorp.pinpoint.thrift.dto.TAgentInfo; -import com.navercorp.pinpoint.thrift.dto.TResult; - -/** - * @author emeroad - * @author koo.taejin - */ -@Service("agentInfoHandler") -public class AgentInfoHandler implements SimpleHandler, RequestResponseHandler { - - private final Logger logger = LoggerFactory.getLogger(AgentInfoHandler.class.getName()); - - @Autowired - private AgentInfoDao agentInfoDao; - - @Autowired - private ApplicationIndexDao applicationIndexDao; - - public void handleSimple(TBase tbase) { - handleRequest(tbase); - } - - @Override - public TBase handleRequest(TBase tbase) { - if (!(tbase instanceof TAgentInfo)) { - logger.warn("invalid tbase:{}", tbase); - // it happens to return null not only at this BO(Business Object) but also at other BOs. - - return null; - } - - try { - TAgentInfo agentInfo = (TAgentInfo) tbase; - - logger.debug("Received AgentInfo={}", agentInfo); - - // agent info - agentInfoDao.insert(agentInfo); - - // for querying agentid using applicationname - applicationIndexDao.insert(agentInfo); - - return new TResult(true); - } catch (Exception e) { - logger.warn("AgentInfo handle error. Caused:{}", e.getMessage(), e); - TResult result = new TResult(false); - result.setMessage(e.getMessage()); - return result; - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/AgentStatHandlerV2.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/AgentStatHandlerV2.java deleted file mode 100644 index b7ef1aae3d3b..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/AgentStatHandlerV2.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import com.navercorp.pinpoint.collector.mapper.thrift.stat.AgentStatBatchMapper; -import com.navercorp.pinpoint.collector.mapper.thrift.stat.AgentStatMapper; -import com.navercorp.pinpoint.collector.service.AgentStatService; -import com.navercorp.pinpoint.common.server.bo.stat.AgentStatBo; -import com.navercorp.pinpoint.thrift.dto.TAgentStat; -import com.navercorp.pinpoint.thrift.dto.TAgentStatBatch; -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.Collections; -import java.util.List; - -/** - * @author emeroad - * @author HyunGil Jeong - */ -@Service("agentStatHandlerV2") -public class AgentStatHandlerV2 implements SimpleHandler { - - private final Logger logger = LoggerFactory.getLogger(AgentStatHandlerV2.class.getName()); - - @Autowired - private AgentStatMapper agentStatMapper; - - @Autowired - private AgentStatBatchMapper agentStatBatchMapper; - - @Autowired(required = false) - private List agentStatServiceList = Collections.emptyList(); - - @Override - public void handleSimple(TBase tBase) { - // FIXME (2014.08) Legacy - TAgentStat should not be sent over the wire. - if (tBase instanceof TAgentStat) { - TAgentStat tAgentStat = (TAgentStat)tBase; - this.handleAgentStat(tAgentStat); - } else if (tBase instanceof TAgentStatBatch) { - TAgentStatBatch tAgentStatBatch = (TAgentStatBatch) tBase; - this.handleAgentStatBatch(tAgentStatBatch); - } else { - throw new IllegalArgumentException("unexpected tbase:" + tBase + " expected:" + TAgentStat.class.getName() + " or " + TAgentStatBatch.class.getName()); - } - } - - private void handleAgentStat(TAgentStat tAgentStat) { - if (logger.isDebugEnabled()) { - logger.debug("Received TAgentStat={}", tAgentStat); - } - - AgentStatBo agentStatBo = this.agentStatMapper.map(tAgentStat); - - if (agentStatBo == null) { - return; - } - for (AgentStatService agentStatService : agentStatServiceList) { - agentStatService.save(agentStatBo); - } - } - - private void handleAgentStatBatch(TAgentStatBatch tAgentStatBatch) { - if (logger.isDebugEnabled()) { - logger.debug("Received TAgentStatBatch={}", tAgentStatBatch); - } - - AgentStatBo agentStatBo = this.agentStatBatchMapper.map(tAgentStatBatch); - - if (agentStatBo == null) { - return; - } - for (AgentStatService agentStatService : agentStatServiceList) { - agentStatService.save(agentStatBo); - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/ApiMetaDataHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/ApiMetaDataHandler.java deleted file mode 100644 index 328f0941429c..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/ApiMetaDataHandler.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import com.navercorp.pinpoint.collector.dao.ApiMetaDataDao; -import com.navercorp.pinpoint.thrift.dto.TApiMetaData; -import com.navercorp.pinpoint.thrift.dto.TResult; - -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * @author emeroad - */ -@Service -public class ApiMetaDataHandler implements RequestResponseHandler { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Autowired - private ApiMetaDataDao sqlMetaDataDao; - - @Override - public TBase handleRequest(TBase tbase) { - if (!(tbase instanceof TApiMetaData)) { - logger.error("invalid tbase:{}", tbase); - return null; - } - - TApiMetaData apiMetaData = (TApiMetaData) tbase; - - // Because api meta data is important , logging it at info level. - if (logger.isInfoEnabled()) { - logger.info("Received ApiMetaData={}", apiMetaData); - } - - try { - sqlMetaDataDao.insert(apiMetaData); - } catch (Exception e) { - logger.warn("{} handler error. Caused:{}", this.getClass(), e.getMessage(), e); - TResult result = new TResult(false); - result.setMessage(e.getMessage()); - return result; - } - return new TResult(true); - } -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/RequestResponseHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/RequestResponseHandler.java index 2ffb5b666f99..3c9611d26283 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/RequestResponseHandler.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/RequestResponseHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,8 @@ package com.navercorp.pinpoint.collector.handler; -import org.apache.thrift.TBase; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; import org.springframework.stereotype.Service; /** @@ -26,6 +27,5 @@ @Service public interface RequestResponseHandler { - TBase handleRequest(TBase tbase); - + void handleRequest(ServerRequest serverRequest, ServerResponse serverResponse); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SimpleDualHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SimpleDualHandler.java new file mode 100644 index 000000000000..7005cada3237 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SimpleDualHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler; + +import com.navercorp.pinpoint.io.request.ServerRequest; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class SimpleDualHandler implements SimpleHandler { + private final SimpleHandler one; + private final SimpleHandler two; + + public SimpleDualHandler(SimpleHandler one, SimpleHandler two) { + if (one == null) { + throw new NullPointerException("one must not be null"); + } + if (two == null) { + throw new NullPointerException("two must not be null"); + } + this.one = one; + this.two = two; + + } + + @Override + public void handleSimple(ServerRequest serverRequest) { + one.handleSimple(serverRequest); + two.handleSimple(serverRequest); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SimpleHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SimpleHandler.java index 6e620ee751ed..b662a093458a 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SimpleHandler.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SimpleHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.collector.handler; -import org.apache.thrift.TBase; +import com.navercorp.pinpoint.io.request.ServerRequest; /** * @author emeroad @@ -24,6 +24,6 @@ */ public interface SimpleHandler { - void handleSimple(TBase tBase); + void handleSimple(ServerRequest serverRequest); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SpanChunkHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SpanChunkHandler.java deleted file mode 100644 index 4762e3eb1846..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SpanChunkHandler.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import java.util.List; - -import com.navercorp.pinpoint.collector.dao.TraceDao; -import com.navercorp.pinpoint.common.server.bo.SpanChunkBo; -import com.navercorp.pinpoint.common.server.bo.SpanEventBo; -import com.navercorp.pinpoint.common.server.bo.SpanFactory; -import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; -import com.navercorp.pinpoint.common.trace.ServiceType; - -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import com.navercorp.pinpoint.thrift.dto.TSpanChunk; - -import org.springframework.stereotype.Service; - -/** - * @author emeroad - */ -@Service -public class SpanChunkHandler implements SimpleHandler { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Autowired - private TraceDao traceDao; - - @Autowired - private StatisticsHandler statisticsHandler; - - @Autowired - private ServiceTypeRegistryService registry; - - @Autowired - private SpanFactory spanFactory; - - @Override - public void handleSimple(TBase tbase) { - - try { - final SpanChunkBo spanChunkBo = newSpanChunkBo(tbase); - - traceDao.insertSpanChunk(spanChunkBo); - - final ServiceType applicationServiceType = getApplicationServiceType(spanChunkBo); - List spanEventList = spanChunkBo.getSpanEventBoList(); - if (spanEventList != null) { - if (logger.isDebugEnabled()) { - logger.debug("SpanChunk Size:{}", spanEventList.size()); - } - // TODO need to batch update later. - for (SpanEventBo spanEvent : spanEventList) { - final ServiceType spanEventType = registry.findServiceType(spanEvent.getServiceType()); - - if (!spanEventType.isRecordStatistics()) { - continue; - } - - // if terminal update statistics - final int elapsed = spanEvent.getEndElapsed(); - final boolean hasException = spanEvent.hasException(); - - /* - * save information to draw a server map based on statistics - */ - // save the information of caller (the spanevent that span called) - statisticsHandler.updateCaller(spanChunkBo.getApplicationId(), applicationServiceType, spanChunkBo.getAgentId(), spanEvent.getDestinationId(), spanEventType, spanEvent.getEndPoint(), elapsed, hasException); - - // save the information of callee (the span that called spanevent) - statisticsHandler.updateCallee(spanEvent.getDestinationId(), spanEventType, spanChunkBo.getApplicationId(), applicationServiceType, spanChunkBo.getEndPoint(), elapsed, hasException); - } - } - } catch (Exception e) { - logger.warn("SpanChunk handle error Caused:{}", e.getMessage(), e); - } - } - - private SpanChunkBo newSpanChunkBo(TBase tbase) { - if (!(tbase instanceof TSpanChunk)) { - throw new IllegalArgumentException("unexpected tbase:" + tbase + " expected:" + this.getClass().getName()); - } - - final TSpanChunk tSpanChunk = (TSpanChunk) tbase; - if (logger.isDebugEnabled()) { - logger.debug("Received SpanChunk={}", tbase); - } - - return this.spanFactory.buildSpanChunkBo(tSpanChunk); - } - - private ServiceType getApplicationServiceType(SpanChunkBo spanChunk) { - final short applicationServiceTypeCode = spanChunk.getApplicationServiceType(); - return registry.findServiceType(applicationServiceTypeCode); - } -} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SpanHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SpanHandler.java deleted file mode 100644 index bfeccc1d23ff..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SpanHandler.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import java.util.List; - -import com.navercorp.pinpoint.collector.dao.TraceDao; -import com.navercorp.pinpoint.common.server.bo.SpanBo; -import com.navercorp.pinpoint.common.server.bo.SpanEventBo; -import com.navercorp.pinpoint.common.server.bo.SpanFactory; -import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; -import com.navercorp.pinpoint.common.trace.ServiceType; - -import org.apache.commons.collections.CollectionUtils; -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import com.navercorp.pinpoint.collector.dao.ApplicationTraceIndexDao; -import com.navercorp.pinpoint.collector.dao.HostApplicationMapDao; -import com.navercorp.pinpoint.thrift.dto.TSpan; - -import org.springframework.stereotype.Service; - -/** - * @author emeroad - * @author netspider - */ -@Service -public class SpanHandler implements SimpleHandler { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Autowired - private TraceDao traceDao; - - @Autowired - private ApplicationTraceIndexDao applicationTraceIndexDao; - - @Autowired - private StatisticsHandler statisticsHandler; - - @Autowired - private HostApplicationMapDao hostApplicationMapDao; - - @Autowired - private ServiceTypeRegistryService registry; - - @Autowired - private SpanFactory spanFactory; - - public void handleSimple(TBase tbase) { - - if (!(tbase instanceof TSpan)) { - throw new IllegalArgumentException("unexpected tbase:" + tbase + " expected:" + this.getClass().getName()); - } - - try { - final TSpan tSpan = (TSpan) tbase; - if (logger.isDebugEnabled()) { - logger.debug("Received SPAN={}", tSpan); - } - - - final SpanBo spanBo = spanFactory.buildSpanBo(tSpan); - - traceDao.insert(spanBo); - applicationTraceIndexDao.insert(tSpan); - - // insert statistics info for server map - insertAcceptorHost(spanBo); - insertSpanStat(spanBo); - insertSpanEventStat(spanBo); - } catch (Exception e) { - logger.warn("Span handle error. Caused:{}. Span:{}",e.getMessage(), tbase, e); - } - } - - - private void insertSpanStat(SpanBo span) { - final ServiceType applicationServiceType = getApplicationServiceType(span); - final ServiceType spanServiceType = registry.findServiceType(span.getServiceType()); - - final boolean isError = span.getErrCode() != 0; - int bugCheck = 0; - if (span.getParentSpanId() == -1) { - if (spanServiceType.isQueue()) { - // create virtual queue node - statisticsHandler.updateCaller(span.getAcceptorHost(), spanServiceType, span.getRemoteAddr(), span.getApplicationId(), applicationServiceType, span.getEndPoint(), span.getElapsed(), isError); - - statisticsHandler.updateCallee(span.getApplicationId(), applicationServiceType, span.getAcceptorHost(), spanServiceType, span.getAgentId(), span.getElapsed(), isError); - } else { - // create virtual user - statisticsHandler.updateCaller(span.getApplicationId(), ServiceType.USER, span.getAgentId(), span.getApplicationId(), applicationServiceType, span.getAgentId(), span.getElapsed(), isError); - - // update the span information of the current node (self) - statisticsHandler.updateCallee(span.getApplicationId(), applicationServiceType, span.getApplicationId(), ServiceType.USER, span.getAgentId(), span.getElapsed(), isError); - } - bugCheck++; - } - - // save statistics info only when parentApplicationContext exists - // when drawing server map based on statistics info, you must know the application name of the previous node. - if (span.getParentApplicationId() != null) { - String parentApplicationName = span.getParentApplicationId(); - logger.debug("Received parent application name. {}", parentApplicationName); - - ServiceType parentApplicationType = registry.findServiceType(span.getParentApplicationServiceType()); - - // create virtual queue node if current' span's service type is a queue AND : - // 1. parent node's application service type is not a queue (it may have come from a queue that is traced) - // 2. current node's application service type is not a queue (current node may be a queue that is traced) - if (spanServiceType.isQueue()) { - if (!applicationServiceType.isQueue() && !parentApplicationType.isQueue()) { - // emulate virtual queue node's accept Span and record it's acceptor host - hostApplicationMapDao.insert(span.getRemoteAddr(), span.getAcceptorHost(), spanServiceType.getCode(), parentApplicationName, parentApplicationType.getCode()); - // emulate virtual queue node's send SpanEvent - statisticsHandler.updateCaller(span.getAcceptorHost(), spanServiceType, span.getRemoteAddr(), span.getApplicationId(), applicationServiceType, span.getEndPoint(), span.getElapsed(), isError); - - parentApplicationName = span.getAcceptorHost(); - parentApplicationType = spanServiceType; - } - } - - statisticsHandler.updateCallee(span.getApplicationId(), applicationServiceType, parentApplicationName, parentApplicationType, span.getAgentId(), span.getElapsed(), isError); - bugCheck++; - } - - // record the response time of the current node (self). - // blow code may be conflict of idea above callee key. - // it is odd to record reversely, because of already recording the caller data at previous node. - // the data may be different due to timeout or network error. - - statisticsHandler.updateResponseTime(span.getApplicationId(), applicationServiceType, span.getAgentId(), span.getElapsed(), isError); - - if (bugCheck != 1) { - logger.warn("ambiguous span found(bug). span:{}", span); - } - } - - private void insertSpanEventStat(SpanBo span) { - - final List spanEventList = span.getSpanEventBoList(); - if (CollectionUtils.isEmpty(spanEventList)) { - return; - } - - final ServiceType applicationServiceType = getApplicationServiceType(span); - - logger.debug("handle spanEvent size:{}", spanEventList.size()); - // TODO need to batch update later. - for (SpanEventBo spanEvent : spanEventList) { - final ServiceType spanEventType = registry.findServiceType(spanEvent.getServiceType()); - if (!spanEventType.isRecordStatistics()) { - continue; - } - - // if terminal update statistics - final int elapsed = spanEvent.getEndElapsed(); - final boolean hasException = spanEvent.hasException(); - - /* - * save information to draw a server map based on statistics - */ - // save the information of caller (the spanevent that called span) - statisticsHandler.updateCaller(span.getApplicationId(), applicationServiceType, span.getAgentId(), spanEvent.getDestinationId(), spanEventType, spanEvent.getEndPoint(), elapsed, hasException); - - // save the information of callee (the span that spanevent called) - statisticsHandler.updateCallee(spanEvent.getDestinationId(), spanEventType, span.getApplicationId(), applicationServiceType, span.getEndPoint(), elapsed, hasException); - } - } - - private void insertAcceptorHost(SpanBo span) { - // save host application map - // acceptor host is set at profiler module only when the span is not the kind of root span - final String acceptorHost = span.getAcceptorHost(); - if (acceptorHost == null) { - return; - } - final String spanApplicationName = span.getApplicationId(); - final short applicationServiceTypeCode = getApplicationServiceType(span).getCode(); - - final String parentApplicationName = span.getParentApplicationId(); - final short parentServiceType = span.getParentApplicationServiceType(); - - final ServiceType spanServiceType = registry.findServiceType(span.getServiceType()); - if (spanServiceType.isQueue()) { - hostApplicationMapDao.insert(span.getEndPoint(), spanApplicationName, applicationServiceTypeCode, parentApplicationName, parentServiceType); - } else { - hostApplicationMapDao.insert(acceptorHost, spanApplicationName, applicationServiceTypeCode, parentApplicationName, parentServiceType); - } - } - - private ServiceType getApplicationServiceType(SpanBo span) { - // Check if applicationServiceType is set. If not, use span's service type. - final short applicationServiceTypeCode = span.getApplicationServiceType(); - return registry.findServiceType(applicationServiceTypeCode); - } -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SqlMetaDataHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SqlMetaDataHandler.java deleted file mode 100644 index 0f2a2de7251a..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/SqlMetaDataHandler.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import com.navercorp.pinpoint.collector.dao.SqlMetaDataDao; -import com.navercorp.pinpoint.thrift.dto.TResult; -import com.navercorp.pinpoint.thrift.dto.TSqlMetaData; - -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author emeroad - */ -//@Service -public class SqlMetaDataHandler implements RequestResponseHandler { - private final Logger logger = LoggerFactory.getLogger(getClass()); - -// @Autowired - private SqlMetaDataDao sqlMetaDataDao; - - @Override - public TBase handleRequest(TBase tbase) { - if (!(tbase instanceof TSqlMetaData)) { - logger.error("invalid tbase:{}", tbase); - return null; - } - - final TSqlMetaData sqlMetaData = (TSqlMetaData) tbase; - - if (logger.isDebugEnabled()) { - logger.debug("Received SqlMetaData:{}", sqlMetaData); - } - - - try { - sqlMetaDataDao.insert(sqlMetaData); - } catch (Exception e) { - logger.warn("{} handler error. Caused:{}", this.getClass(), e.getMessage(), e); - TResult result = new TResult(false); - result.setMessage(e.getMessage()); - return result; - } - return new TResult(true); - } - - public void setSqlMetaDataDao(SqlMetaDataDao sqlMetaDataDao) { - this.sqlMetaDataDao = sqlMetaDataDao; - } -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/StatisticsHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/StatisticsHandler.java deleted file mode 100644 index ef1ba3bbaa77..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/StatisticsHandler.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import com.navercorp.pinpoint.collector.dao.MapResponseTimeDao; -import com.navercorp.pinpoint.collector.dao.MapStatisticsCalleeDao; -import com.navercorp.pinpoint.collector.dao.MapStatisticsCallerDao; -import com.navercorp.pinpoint.common.trace.ServiceType; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * - * @author netspider - * - */ -@Service -public class StatisticsHandler { - - @Autowired - private MapStatisticsCalleeDao mapStatisticsCalleeDao; - - @Autowired - private MapStatisticsCallerDao mapStatisticsCallerDao; - - @Autowired - private MapResponseTimeDao mapResponseTimeDao; - - /** - * Calling MySQL from Tomcat generates the following message for the caller(Tomcat) :
- * emeroad-app (TOMCAT) -> MySQL_DB_ID (MYSQL)[10.25.141.69:3306]
- *
- * The following message is generated for the callee(MySQL) :
- * MySQL (MYSQL) <- emeroad-app (TOMCAT)[localhost:8080] - * @param callerApplicationName - * @param callerServiceType - * @param calleeApplicationName - * @param calleeServiceType - * @param calleeHost - * @param elapsed - * @param isError - */ - public void updateCaller(String callerApplicationName, ServiceType callerServiceType, String callerAgentId, String calleeApplicationName, ServiceType calleeServiceType, String calleeHost, int elapsed, boolean isError) { - mapStatisticsCallerDao.update(callerApplicationName, callerServiceType, callerAgentId, calleeApplicationName, calleeServiceType, calleeHost, elapsed, isError); - } - - /** - * Calling MySQL from Tomcat generates the following message for the callee(MySQL) :
- * MySQL_DB_ID (MYSQL) <- emeroad-app (TOMCAT)[localhost:8080]
- *

- * The following message is generated for the caller(Tomcat) :
- * emeroad-app (TOMCAT) -> MySQL (MYSQL)[10.25.141.69:3306] - * @param callerApplicationName - * @param callerServiceType - * @param calleeApplicationName - * @param calleeServiceType - * @param callerHost - * @param elapsed - * @param isError - */ - public void updateCallee(String calleeApplicationName, ServiceType calleeServiceType, String callerApplicationName, ServiceType callerServiceType, String callerHost, int elapsed, boolean isError) { - mapStatisticsCalleeDao.update(calleeApplicationName, calleeServiceType, callerApplicationName, callerServiceType, callerHost, elapsed, isError); - } - - public void updateResponseTime(String applicationName, ServiceType serviceType, String agentId, int elapsed, boolean isError) { - mapResponseTimeDao.received(applicationName, serviceType, agentId, elapsed, isError); - } -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/StringMetaDataHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/StringMetaDataHandler.java deleted file mode 100644 index 08372496dca3..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/StringMetaDataHandler.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import com.navercorp.pinpoint.collector.dao.StringMetaDataDao; -import com.navercorp.pinpoint.thrift.dto.TResult; -import com.navercorp.pinpoint.thrift.dto.TStringMetaData; - -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * @author emeroad - */ -@Service -public class StringMetaDataHandler implements RequestResponseHandler { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Autowired - private StringMetaDataDao stringMetaDataDao; - - @Override - public TBase handleRequest(TBase tbase) { - if (!(tbase instanceof TStringMetaData)) { - logger.error("invalid tbase:{}", tbase); - return null; - } - - TStringMetaData stringMetaData = (TStringMetaData) tbase; - // because api data is important, logging it at info level - if (logger.isInfoEnabled()) { - logger.info("Received StringMetaData={}", stringMetaData); - } - - try { - stringMetaDataDao.insert(stringMetaData); - } catch (Exception e) { - logger.warn("{} handler error. Caused:{}", this.getClass(), e.getMessage(), e); - TResult result = new TResult(false); - result.setMessage(e.getMessage()); - return result; - } - return new TResult(true); - } -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentEventHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentEventHandler.java new file mode 100644 index 000000000000..07671a9813ef --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentEventHandler.java @@ -0,0 +1,126 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler.thrift; + +import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.collector.mapper.thrift.event.AgentEventBatchMapper; +import com.navercorp.pinpoint.collector.mapper.thrift.event.AgentEventMapper; +import com.navercorp.pinpoint.collector.service.AgentEventService; +import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; +import com.navercorp.pinpoint.common.server.bo.event.DeadlockEventBo; +import com.navercorp.pinpoint.common.server.util.AgentEventMessageSerializerV1; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.thrift.dto.TAgentStat; +import com.navercorp.pinpoint.thrift.dto.TAgentStatBatch; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author Taejin Koo + * @author jaehong.kim - Add AgentEventMessageSerializerV1 + */ +@Service +public class ThriftAgentEventHandler implements SimpleHandler { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private AgentEventMapper agentEventMapper; + + @Autowired + private AgentEventBatchMapper agentEventBatchMapper; + + @Autowired + private AgentEventMessageSerializerV1 agentEventMessageSerializerV1; + + @Autowired + private AgentEventService agentEventService; + + @Override + public void handleSimple(ServerRequest serverRequest) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + handleSimple((TBase) data); + } else { + throw new UnsupportedOperationException("data is not support type : " + data); + } + } + + private void handleSimple(TBase tBase) { + // FIXME (2014.08) Legacy - TAgentStat should not be sent over the wire. + if (tBase instanceof TAgentStat) { + final TAgentStat tAgentStat = (TAgentStat) tBase; + this.handleAgentStat(tAgentStat); + } else if (tBase instanceof TAgentStatBatch) { + final TAgentStatBatch tAgentStatBatch = (TAgentStatBatch) tBase; + this.handleAgentStatBatch(tAgentStatBatch); + } else { + throw new IllegalArgumentException("unexpected tbase:" + tBase + " expected:" + TAgentStat.class.getName() + " or " + TAgentStatBatch.class.getName()); + } + } + + private void handleAgentStat(TAgentStat tAgentStat) { + if (logger.isDebugEnabled()) { + logger.debug("Received TAgentStat={}", tAgentStat); + } + + final AgentEventBo agentEventBo = this.agentEventMapper.map(tAgentStat); + if (agentEventBo == null) { + return; + } + insert(agentEventBo); + } + + private void handleAgentStatBatch(TAgentStatBatch tAgentStatBatch) { + if (logger.isDebugEnabled()) { + logger.debug("Received TAgentStatBatch={}", tAgentStatBatch); + } + + final List agentEventBoList = this.agentEventBatchMapper.map(tAgentStatBatch); + if (CollectionUtils.isEmpty(agentEventBoList)) { + return; + } + + for (AgentEventBo agentEventBo : agentEventBoList) { + insert(agentEventBo); + } + } + + private void insert(final AgentEventBo agentEventBo) { + try { + final Object eventMessage = getEventMessage(agentEventBo); + final byte[] eventBody = agentEventMessageSerializerV1.serialize(agentEventBo.getEventType(), eventMessage); + agentEventBo.setEventBody(eventBody); + } catch (Exception e) { + logger.warn("error handling agent event", e); + return; + } + this.agentEventService.insert(agentEventBo); + } + + private Object getEventMessage(AgentEventBo agentEventBo) { + if (agentEventBo instanceof DeadlockEventBo) { + return ((DeadlockEventBo) agentEventBo).getDeadlockBo(); + } + throw new IllegalArgumentException("unsupported message " + agentEventBo); + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentInfoHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentInfoHandler.java new file mode 100644 index 000000000000..5a01eddc6ad5 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentInfoHandler.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler.thrift; + +import com.navercorp.pinpoint.collector.handler.RequestResponseHandler; +import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.collector.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.collector.service.AgentInfoService; +import com.navercorp.pinpoint.common.server.bo.AgentInfoBo; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.dto.TAgentInfo; +import com.navercorp.pinpoint.thrift.dto.TResult; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +/** + * @author emeroad + * @author koo.taejin + */ +@Service +public class ThriftAgentInfoHandler implements SimpleHandler, RequestResponseHandler { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Autowired + private AgentInfoService agentInfoService; + + @Autowired + @Qualifier("agentInfoBoMapper") + private ThriftBoMapper agentInfoBoMapper; + + @Override + public void handleSimple(ServerRequest serverRequest) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + handleRequest((TBase) data); + } else { + throw new UnsupportedOperationException("data is not support type : " + data); + } + } + + + @Override + public void handleRequest(ServerRequest serverRequest, ServerResponse serverResponse) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + final TBase tBase = handleRequest((TBase) data); + serverResponse.write(tBase); + } else { + logger.warn("invalid serverRequest:{}", serverRequest); + } + } + + private TBase handleRequest(TBase tbase) { + if (!(tbase instanceof TAgentInfo)) { + logger.warn("invalid tbase:{}", tbase); + // it happens to return null not only at this BO(Business Object) but also at other BOs. + return null; + } + + try { + final TAgentInfo agentInfo = (TAgentInfo) tbase; + logger.debug("Received AgentInfo={}", agentInfo); + + // agent info + final AgentInfoBo agentInfoBo = this.agentInfoBoMapper.map(agentInfo); + this.agentInfoService.insert(agentInfoBo); + return new TResult(true); + } catch (Exception e) { + logger.warn("AgentInfo handle error. Caused:{}", e.getMessage(), e); + final TResult result = new TResult(false); + result.setMessage(e.getMessage()); + return result; + } + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentStatHandlerV2.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentStatHandlerV2.java new file mode 100644 index 000000000000..0a1072230af6 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentStatHandlerV2.java @@ -0,0 +1,106 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler.thrift; + +import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.collector.mapper.thrift.stat.AgentStatBatchMapper; +import com.navercorp.pinpoint.collector.mapper.thrift.stat.AgentStatMapper; +import com.navercorp.pinpoint.collector.service.AgentStatService; +import com.navercorp.pinpoint.common.server.bo.stat.AgentStatBo; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.thrift.dto.TAgentStat; +import com.navercorp.pinpoint.thrift.dto.TAgentStatBatch; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +/** + * @author emeroad + * @author HyunGil Jeong + */ +@Service +public class ThriftAgentStatHandlerV2 implements SimpleHandler { + + private final Logger logger = LoggerFactory.getLogger(ThriftAgentStatHandlerV2.class.getName()); + + @Autowired + private AgentStatMapper agentStatMapper; + + @Autowired + private AgentStatBatchMapper agentStatBatchMapper; + + @Autowired(required = false) + private List agentStatServiceList = Collections.emptyList(); + + @Override + public void handleSimple(ServerRequest serverRequest) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + handleSimple((TBase) data); + } else { + throw new UnsupportedOperationException("data is not support type : " + data); + } + } + + void handleSimple(TBase tBase) { + // FIXME (2014.08) Legacy - TAgentStat should not be sent over the wire. + if (tBase instanceof TAgentStat) { + TAgentStat tAgentStat = (TAgentStat)tBase; + this.handleAgentStat(tAgentStat); + } else if (tBase instanceof TAgentStatBatch) { + TAgentStatBatch tAgentStatBatch = (TAgentStatBatch) tBase; + this.handleAgentStatBatch(tAgentStatBatch); + } else { + throw new IllegalArgumentException("unexpected tbase:" + tBase + " expected:" + TAgentStat.class.getName() + " or " + TAgentStatBatch.class.getName()); + } + } + + private void handleAgentStat(TAgentStat tAgentStat) { + if (logger.isDebugEnabled()) { + logger.debug("Received TAgentStat={}", tAgentStat); + } + + final AgentStatBo agentStatBo = this.agentStatMapper.map(tAgentStat); + if (agentStatBo == null) { + return; + } + + for (AgentStatService agentStatService : agentStatServiceList) { + agentStatService.save(agentStatBo); + } + } + + private void handleAgentStatBatch(TAgentStatBatch tAgentStatBatch) { + if (logger.isDebugEnabled()) { + logger.debug("Received TAgentStatBatch={}", tAgentStatBatch); + } + + final AgentStatBo agentStatBo = this.agentStatBatchMapper.map(tAgentStatBatch); + if (agentStatBo == null) { + return; + } + + for (AgentStatService agentStatService : agentStatServiceList) { + agentStatService.save(agentStatBo); + } + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftApiMetaDataHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftApiMetaDataHandler.java new file mode 100644 index 000000000000..4ce9ddb167c5 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftApiMetaDataHandler.java @@ -0,0 +1,87 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler.thrift; + +import com.navercorp.pinpoint.collector.handler.RequestResponseHandler; +import com.navercorp.pinpoint.collector.service.ApiMetaDataService; +import com.navercorp.pinpoint.common.server.bo.ApiMetaDataBo; +import com.navercorp.pinpoint.common.server.bo.MethodTypeEnum; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.dto.TApiMetaData; +import com.navercorp.pinpoint.thrift.dto.TResult; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author emeroad + */ +@Service +public class ThriftApiMetaDataHandler implements RequestResponseHandler { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private ApiMetaDataService apiMetaDataService; + + @Override + public void handleRequest(ServerRequest serverRequest, ServerResponse serverResponse) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + TBase tBase = handleRequest((TBase) data); + serverResponse.write(tBase); + } else { + logger.warn("invalid serverRequest:{}", serverRequest); + } + } + + private TBase handleRequest(TBase tbase) { + if (!(tbase instanceof TApiMetaData)) { + logger.error("invalid tbase:{}", tbase); + return null; + } + + final TApiMetaData apiMetaData = (TApiMetaData) tbase; + // Because api meta data is important , logging it at info level. + if (logger.isInfoEnabled()) { + logger.info("Received ApiMetaData={}", apiMetaData); + } + + try { + final ApiMetaDataBo apiMetaDataBo = new ApiMetaDataBo(apiMetaData.getAgentId(), apiMetaData.getAgentStartTime(), apiMetaData.getApiId()); + apiMetaDataBo.setApiInfo(apiMetaData.getApiInfo()); + if (apiMetaData.isSetLine()) { + apiMetaDataBo.setLineNumber(apiMetaData.getLine()); + } + + if (apiMetaData.isSetType()) { + apiMetaDataBo.setMethodTypeEnum(MethodTypeEnum.valueOf(apiMetaData.getType())); + } + + this.apiMetaDataService.insert(apiMetaDataBo); + } catch (Exception e) { + logger.warn("{} handler error. Caused:{}", this.getClass(), e.getMessage(), e); + final TResult result = new TResult(false); + result.setMessage(e.getMessage()); + return result; + } + return new TResult(true); + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftSpanChunkHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftSpanChunkHandler.java new file mode 100644 index 000000000000..2ea4bee374e8 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftSpanChunkHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler.thrift; + +import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.collector.service.TraceService; +import com.navercorp.pinpoint.common.server.bo.SpanChunkBo; +import com.navercorp.pinpoint.common.server.bo.SpanFactory; + +import com.navercorp.pinpoint.io.request.ServerRequest; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; + +import org.springframework.stereotype.Service; + +/** + * @author emeroad + */ +@Service +public class ThriftSpanChunkHandler implements SimpleHandler { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private TraceService traceService; + + @Autowired + private SpanFactory spanFactory; + + @Override + public void handleSimple(ServerRequest serverRequest) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + handleSimple((TBase) data); + } else { + throw new UnsupportedOperationException("data is not support type : " + data); + } + } + + private void handleSimple(TBase tbase) { + + try { + final SpanChunkBo spanChunkBo = newSpanChunkBo(tbase); + this.traceService.insertSpanChunk(spanChunkBo); + } catch (Exception e) { + logger.warn("SpanChunk handle error Caused:{}", e.getMessage(), e); + } + } + + private SpanChunkBo newSpanChunkBo(TBase tbase) { + if (!(tbase instanceof TSpanChunk)) { + throw new IllegalArgumentException("unexpected tbase:" + tbase + " expected:" + this.getClass().getName()); + } + + final TSpanChunk tSpanChunk = (TSpanChunk) tbase; + if (logger.isDebugEnabled()) { + logger.debug("Received SpanChunk={}", tbase); + } + + return this.spanFactory.buildSpanChunkBo(tSpanChunk); + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftSpanHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftSpanHandler.java new file mode 100644 index 000000000000..db0d837d1ecb --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftSpanHandler.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler.thrift; + +import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.collector.service.TraceService; +import com.navercorp.pinpoint.common.server.bo.SpanBo; +import com.navercorp.pinpoint.common.server.bo.SpanFactory; + +import com.navercorp.pinpoint.io.request.ServerRequest; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.navercorp.pinpoint.thrift.dto.TSpan; + +import org.springframework.stereotype.Service; + +/** + * @author emeroad + * @author netspider + */ +@Service +public class ThriftSpanHandler implements SimpleHandler { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private TraceService traceService; + + @Autowired + private SpanFactory spanFactory; + + @Override + public void handleSimple(ServerRequest serverRequest) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + handleSimple((TBase) data); + } else { + throw new UnsupportedOperationException("data is not support type : " + data); + } + } + + private void handleSimple(TBase tbase) { + if (!(tbase instanceof TSpan)) { + throw new IllegalArgumentException("unexpected tbase:" + tbase + " expected:" + this.getClass().getName()); + } + + try { + final TSpan tSpan = (TSpan) tbase; + if (logger.isDebugEnabled()) { + logger.debug("Received SPAN={}", tSpan); + } + + final SpanBo spanBo = spanFactory.buildSpanBo(tSpan); + traceService.insertSpan(spanBo); + } catch (Exception e) { + logger.warn("Span handle error. Caused:{}. Span:{}", e.getMessage(), tbase, e); + } + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftSqlMetaDataHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftSqlMetaDataHandler.java new file mode 100644 index 000000000000..39ac8edf32be --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftSqlMetaDataHandler.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler.thrift; + +import com.navercorp.pinpoint.collector.handler.RequestResponseHandler; +import com.navercorp.pinpoint.collector.service.SqlMetaDataService; +import com.navercorp.pinpoint.common.server.bo.SqlMetaDataBo; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.dto.TResult; +import com.navercorp.pinpoint.thrift.dto.TSqlMetaData; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author emeroad + */ +@Service +public class ThriftSqlMetaDataHandler implements RequestResponseHandler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private SqlMetaDataService sqlMetaDataService; + + public ThriftSqlMetaDataHandler() { + } + + @Override + public void handleRequest(ServerRequest serverRequest, ServerResponse serverResponse) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + TBase tBase = handleRequest((TBase) data); + serverResponse.write(tBase); + return; + } + + logger.warn("invalid serverRequest:{}", serverRequest); + } + + private TBase handleRequest(TBase tbase) { + if (!(tbase instanceof TSqlMetaData)) { + logger.error("invalid tbase:{}", tbase); + return null; + } + + final TSqlMetaData sqlMetaData = (TSqlMetaData) tbase; + if (logger.isDebugEnabled()) { + logger.debug("Received SqlMetaData:{}", sqlMetaData); + } + + try { + final SqlMetaDataBo sqlMetaDataBo = new SqlMetaDataBo(sqlMetaData.getAgentId(), sqlMetaData.getAgentStartTime(), sqlMetaData.getSqlId()); + sqlMetaDataBo.setSql(sqlMetaData.getSql()); + sqlMetaDataService.insert(sqlMetaDataBo); + } catch (Exception e) { + logger.warn("{} handler error. Caused:{}", this.getClass(), e.getMessage(), e); + final TResult result = new TResult(false); + result.setMessage(e.getMessage()); + return result; + } + return new TResult(true); + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftStringMetaDataHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftStringMetaDataHandler.java new file mode 100644 index 000000000000..ea70faca94f6 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftStringMetaDataHandler.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler.thrift; + +import com.navercorp.pinpoint.collector.handler.RequestResponseHandler; +import com.navercorp.pinpoint.collector.service.StringMetaDataService; +import com.navercorp.pinpoint.common.server.bo.StringMetaDataBo; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.dto.TResult; +import com.navercorp.pinpoint.thrift.dto.TStringMetaData; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author emeroad + */ +@Service +public class ThriftStringMetaDataHandler implements RequestResponseHandler { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private StringMetaDataService stringMetaDataService; + + @Override + public void handleRequest(ServerRequest serverRequest, ServerResponse serverResponse) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + TBase tBase = handleRequest((TBase) data); + serverResponse.write(tBase); + } else { + logger.warn("invalid serverRequest:{}", serverRequest); + return; + } + } + + private TBase handleRequest(TBase tbase) { + if (!(tbase instanceof TStringMetaData)) { + logger.error("invalid tbase:{}", tbase); + return null; + } + + TStringMetaData stringMetaData = (TStringMetaData) tbase; + // because api data is important, logging it at info level + if (logger.isInfoEnabled()) { + logger.info("Received StringMetaData={}", stringMetaData); + } + + try { + final StringMetaDataBo stringMetaDataBo = new StringMetaDataBo(stringMetaData.getAgentId(), stringMetaData.getAgentStartTime(), stringMetaData.getStringId()); + stringMetaDataBo.setStringValue(stringMetaData.getStringValue()); + stringMetaDataService.insert(stringMetaDataBo); + } catch (Exception e) { + logger.warn("{} handler error. Caused:{}", this.getClass(), e.getMessage(), e); + final TResult result = new TResult(false); + result.setMessage(e.getMessage()); + return result; + } + return new TResult(true); + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/AgentInfoBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/AgentInfoBoMapper.java index d340ff6c6f96..0e1464b6baba 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/AgentInfoBoMapper.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/AgentInfoBoMapper.java @@ -17,8 +17,14 @@ package com.navercorp.pinpoint.collector.mapper.thrift; import com.navercorp.pinpoint.common.server.bo.AgentInfoBo; +import com.navercorp.pinpoint.common.server.bo.JvmInfoBo; +import com.navercorp.pinpoint.common.server.bo.ServerMetaDataBo; import com.navercorp.pinpoint.thrift.dto.TAgentInfo; +import com.navercorp.pinpoint.thrift.dto.TJvmInfo; +import com.navercorp.pinpoint.thrift.dto.TServerMetaData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; /** @@ -26,6 +32,13 @@ */ @Component public class AgentInfoBoMapper implements ThriftBoMapper { + @Autowired + @Qualifier("serverMetaDataBoMapper") + private ThriftBoMapper serverMetaDataBoMapper; + + @Autowired + @Qualifier("jvmInfoBoMapper") + private ThriftBoMapper jvmInfoBoMapper; @Override public AgentInfoBo map(TAgentInfo thriftObject) { @@ -41,8 +54,9 @@ public AgentInfoBo map(TAgentInfo thriftObject) { final long startTime = thriftObject.getStartTimestamp(); final long endTimeStamp = thriftObject.getEndTimestamp(); final int endStatus = thriftObject.getEndStatus(); - - AgentInfoBo.Builder builder = new AgentInfoBo.Builder(); + final boolean container = thriftObject.isContainer(); + + final AgentInfoBo.Builder builder = new AgentInfoBo.Builder(); builder.setHostName(hostName); builder.setIp(ip); builder.setPorts(ports); @@ -55,8 +69,16 @@ public AgentInfoBo map(TAgentInfo thriftObject) { builder.setStartTime(startTime); builder.setEndTimeStamp(endTimeStamp); builder.setEndStatus(endStatus); + builder.isContainer(container); + + if (thriftObject.isSetServerMetaData()) { + builder.setServerMetaData(this.serverMetaDataBoMapper.map(thriftObject.getServerMetaData())); + } + + if (thriftObject.isSetJvmInfo()) { + builder.setJvmInfo(this.jvmInfoBoMapper.map(thriftObject.getJvmInfo())); + } return builder.build(); } - } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventBatchMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventBatchMapper.java index fee041ead7f7..f8ce94aa82ff 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventBatchMapper.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventBatchMapper.java @@ -36,7 +36,7 @@ public class AgentEventBatchMapper implements ThriftBoMapper, TAgentStatBatch> { @Autowired - DeadlockEventBoMapper deadlockEventBoMapper; + private DeadlockEventBoMapper deadlockEventBoMapper; @Override public List map(TAgentStatBatch tAgentStatBatch) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventMapper.java index f906e7e18a98..6b7de55ba3b8 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventMapper.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventMapper.java @@ -30,7 +30,7 @@ public class AgentEventMapper implements ThriftBoMapper { @Autowired - DeadlockEventBoMapper deadlockEventBoMapper; + private DeadlockEventBoMapper deadlockEventBoMapper; @Override public AgentEventBo map(TAgentStat tAgentStat) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/DeadlockBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/DeadlockBoMapper.java new file mode 100644 index 000000000000..86a6de95e4ea --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/DeadlockBoMapper.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.event; + +import com.navercorp.pinpoint.collector.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.common.server.bo.event.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadDumpBo; +import com.navercorp.pinpoint.thrift.dto.TDeadlock; +import com.navercorp.pinpoint.thrift.dto.command.TThreadDump; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author jaehong.kim + */ +@Component +public class DeadlockBoMapper implements ThriftBoMapper { + + @Autowired + private ThreadDumpBoMapper threadDumpBoMapper; + + public DeadlockBo map(final TDeadlock tDeadlock) { + final DeadlockBo deadlockBo = new DeadlockBo(); + deadlockBo.setDeadlockedThreadCount(tDeadlock.getDeadlockedThreadCount()); + + if (tDeadlock.isSetDeadlockedThreadList()) { + final List threadDumpBoList = new ArrayList<>(); + for (TThreadDump threadDump : tDeadlock.getDeadlockedThreadList()) { + final ThreadDumpBo threadDumpBo = this.threadDumpBoMapper.map(threadDump); + threadDumpBoList.add(threadDumpBo); + } + deadlockBo.setThreadDumpBoList(threadDumpBoList); + } + + return deadlockBo; + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/DeadlockEventBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/DeadlockEventBoMapper.java index ff1e792fe0d9..39ea0a322ae5 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/DeadlockEventBoMapper.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/DeadlockEventBoMapper.java @@ -16,21 +16,26 @@ package com.navercorp.pinpoint.collector.mapper.thrift.event; +import com.navercorp.pinpoint.common.server.bo.event.DeadlockBo; import com.navercorp.pinpoint.common.server.bo.event.DeadlockEventBo; import com.navercorp.pinpoint.common.server.util.AgentEventType; import com.navercorp.pinpoint.thrift.dto.TDeadlock; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * @author Taejin Koo + * @author jaehong.kim - Add DeadlockBoMapper */ @Component public class DeadlockEventBoMapper implements AgentEventBoMapper { + @Autowired + private DeadlockBoMapper deadlockBoMapper; + @Override public DeadlockEventBo map(String agentId, long startTimeStamp, long eventTimestamp, TDeadlock tDeadlock) { - DeadlockEventBo deadlockEventBo = new DeadlockEventBo(agentId, startTimeStamp, eventTimestamp, AgentEventType.AGENT_DEADLOCK_DETECTED, tDeadlock); - return deadlockEventBo; + final DeadlockBo deadlockBo = this.deadlockBoMapper.map(tDeadlock); + return new DeadlockEventBo(agentId, startTimeStamp, eventTimestamp, AgentEventType.AGENT_DEADLOCK_DETECTED, deadlockBo); } - } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/MonitorInfoBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/MonitorInfoBoMapper.java new file mode 100644 index 000000000000..4c2a070e4539 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/MonitorInfoBoMapper.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.event; + +import com.navercorp.pinpoint.collector.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.common.server.bo.event.MonitorInfoBo; +import com.navercorp.pinpoint.thrift.dto.command.TMonitorInfo; +import org.springframework.stereotype.Component; + +/** + * @author jaehong.kim + */ +@Component +public class MonitorInfoBoMapper implements ThriftBoMapper { + + public MonitorInfoBo map(final TMonitorInfo monitorInfo) { + final MonitorInfoBo monitorInfoBo = new MonitorInfoBo(); + monitorInfoBo.setStackDepth(monitorInfo.getStackDepth()); + monitorInfoBo.setStackFrame(monitorInfo.getStackFrame()); + return monitorInfoBo; + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/ThreadDumpBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/ThreadDumpBoMapper.java new file mode 100644 index 000000000000..d6d98fce9835 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/event/ThreadDumpBoMapper.java @@ -0,0 +1,71 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.event; + +import com.navercorp.pinpoint.collector.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.common.server.bo.event.MonitorInfoBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadDumpBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadState; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.thrift.dto.command.TMonitorInfo; +import com.navercorp.pinpoint.thrift.dto.command.TThreadDump; +import com.navercorp.pinpoint.thrift.dto.command.TThreadState; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author jaehong.kim + */ +@Component +public class ThreadDumpBoMapper implements ThriftBoMapper { + @Autowired + private MonitorInfoBoMapper monitorInfoBoMapper; + + public ThreadDumpBo map(final TThreadDump threadDump) { + final ThreadDumpBo threadDumpBo = new ThreadDumpBo(); + threadDumpBo.setThreadName(threadDump.getThreadName()); + threadDumpBo.setThreadId(threadDump.getThreadId()); + threadDumpBo.setBlockedTime(threadDump.getBlockedTime()); + threadDumpBo.setBlockedCount(threadDump.getBlockedCount()); + threadDumpBo.setWaitedTime(threadDump.getWaitedTime()); + threadDumpBo.setWaitedCount(threadDump.getWaitedCount()); + threadDumpBo.setLockName(threadDump.getLockName()); + threadDumpBo.setLockOwnerId(threadDump.getLockOwnerId()); + threadDumpBo.setLockOwnerName(threadDump.getLockOwnerName()); + threadDumpBo.setInNative(threadDump.isInNative()); + threadDumpBo.setSuspended(threadDump.isSuspended()); + + final TThreadState threadState = threadDump.getThreadState(); + threadDumpBo.setThreadState(ThreadState.findByValue(threadState.getValue())); + threadDumpBo.setStackTraceList(threadDump.getStackTrace()); + + if (!CollectionUtils.isEmpty(threadDump.getLockedMonitors())) { + final List monitorInfoBoList = new ArrayList<>(); + for (TMonitorInfo monitorInfo : threadDump.getLockedMonitors()) { + final MonitorInfoBo monitorInfoBo = this.monitorInfoBoMapper.map(monitorInfo); + monitorInfoBoList.add(monitorInfoBo); + } + threadDumpBo.setLockedMonitorInfoList(monitorInfoBoList); + } + + threadDumpBo.setLockedSynchronizerList(threadDump.getLockedSynchronizers()); + return threadDumpBo; + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/AgentStatBatchMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/AgentStatBatchMapper.java index 8f535d03f223..412b39a91626 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/AgentStatBatchMapper.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/AgentStatBatchMapper.java @@ -23,7 +23,9 @@ import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; import com.navercorp.pinpoint.common.server.bo.stat.DataSourceBo; import com.navercorp.pinpoint.common.server.bo.stat.DataSourceListBo; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcDetailedBo; import com.navercorp.pinpoint.common.server.bo.stat.ResponseTimeBo; @@ -66,7 +68,13 @@ public class AgentStatBatchMapper implements ThriftBoMapper activeTraceBos = new ArrayList<>(agentStatsSize); List dataSourceListBos = new ArrayList(agentStatsSize); List responseTimeBos = new ArrayList<>(agentStatsSize); - List deadlockBos = new ArrayList<>(agentStatsSize); + List deadlockThreadCountBos = new ArrayList<>(agentStatsSize); + List fileDescriptorBos = new ArrayList<>(agentStatsSize); + List directBufferBos = new ArrayList<>(agentStatsSize); for (TAgentStat tAgentStat : tAgentStatBatch.getAgentStats()) { final long timestamp = tAgentStat.getTimestamp(); @@ -152,9 +162,23 @@ public AgentStatBo map(TAgentStatBatch tAgentStatBatch) { // deadlock if (tAgentStat.isSetDeadlock()) { - DeadlockBo deadlockBo = this.deadlockBoMapper.map(tAgentStat.getDeadlock()); - setBaseData(deadlockBo, agentId, startTimestamp, timestamp); - deadlockBos.add(deadlockBo); + DeadlockThreadCountBo deadlockThreadCountBo = this.deadlockThreadCountBoMapper.map(tAgentStat.getDeadlock()); + setBaseData(deadlockThreadCountBo, agentId, startTimestamp, timestamp); + deadlockThreadCountBos.add(deadlockThreadCountBo); + } + + // fileDescriptor + if (tAgentStat.isSetFileDescriptor()) { + FileDescriptorBo fileDescriptorBo = this.fileDescriptorBoMapper.map(tAgentStat.getFileDescriptor()); + setBaseData(fileDescriptorBo, agentId, startTimestamp, timestamp); + fileDescriptorBos.add(fileDescriptorBo); + } + + // directBuffer + if (tAgentStat.isSetDirectBuffer()) { + DirectBufferBo directBufferBo = this.directBufferBoMapper.map(tAgentStat.getDirectBuffer()); + setBaseData(directBufferBo, agentId, startTimestamp, timestamp); + directBufferBos.add(directBufferBo); } } @@ -165,7 +189,9 @@ public AgentStatBo map(TAgentStatBatch tAgentStatBatch) { agentStatBo.setActiveTraceBos(activeTraceBos); agentStatBo.setDataSourceListBos(dataSourceListBos); agentStatBo.setResponseTimeBos(responseTimeBos); - agentStatBo.setDeadlockBos(deadlockBos); + agentStatBo.setDeadlockThreadCountBos(deadlockThreadCountBos); + agentStatBo.setFileDescriptorBos(fileDescriptorBos); + agentStatBo.setDirectBufferBos(directBufferBos); return agentStatBo; } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/AgentStatMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/AgentStatMapper.java index a5604b719422..8750faee6cd5 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/AgentStatMapper.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/AgentStatMapper.java @@ -23,7 +23,9 @@ import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; import com.navercorp.pinpoint.common.server.bo.stat.DataSourceBo; import com.navercorp.pinpoint.common.server.bo.stat.DataSourceListBo; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcDetailedBo; import com.navercorp.pinpoint.common.server.bo.stat.ResponseTimeBo; @@ -64,7 +66,13 @@ public class AgentStatMapper implements ThriftBoMapper private ResponseTimeBoMapper responseTimeBoMapper; @Autowired - private DeadlockBoMapper deadlockBoMapper; + private DeadlockThreadCountBoMapper deadlockThreadCountBoMapper; + + @Autowired + private FileDescriptorBoMapper fileDescriptorBoMapper; + + @Autowired + private DirectBufferBoMapper directBufferBoMapper; @Override public AgentStatBo map(TAgentStat tAgentStat) { @@ -130,9 +138,21 @@ public AgentStatBo map(TAgentStat tAgentStat) { } // deadlock if (tAgentStat.isSetDeadlock()) { - DeadlockBo deadlockBo = this.deadlockBoMapper.map(tAgentStat.getDeadlock()); - setBaseData(deadlockBo, agentId, startTimestamp, timestamp); - agentStatBo.setDeadlockBos(Arrays.asList(deadlockBo)); + DeadlockThreadCountBo deadlockThreadCountBo = this.deadlockThreadCountBoMapper.map(tAgentStat.getDeadlock()); + setBaseData(deadlockThreadCountBo, agentId, startTimestamp, timestamp); + agentStatBo.setDeadlockThreadCountBos(Arrays.asList(deadlockThreadCountBo)); + } + // fileDescriptor + if (tAgentStat.isSetFileDescriptor()) { + FileDescriptorBo fileDescriptorBo = this.fileDescriptorBoMapper.map(tAgentStat.getFileDescriptor()); + setBaseData(fileDescriptorBo, agentId, startTimestamp, timestamp); + agentStatBo.setFileDescriptorBos(Arrays.asList(fileDescriptorBo)); + } + // directBuffer + if (tAgentStat.isSetDirectBuffer()) { + DirectBufferBo directBufferBo = this.directBufferBoMapper.map(tAgentStat.getDirectBuffer()); + setBaseData(directBufferBo, agentId, startTimestamp, timestamp); + agentStatBo.setDirectBufferBos(Arrays.asList(directBufferBo)); } return agentStatBo; diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockBoMapper.java deleted file mode 100644 index a8e83e6977df..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockBoMapper.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.mapper.thrift.stat; - -import com.navercorp.pinpoint.collector.mapper.thrift.ThriftBoMapper; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; -import com.navercorp.pinpoint.thrift.dto.TDeadlock; -import org.springframework.stereotype.Component; - -/** - * @author Taejin Koo - */ -@Component -public class DeadlockBoMapper implements ThriftBoMapper { - - @Override - public DeadlockBo map(TDeadlock tDeadlock) { - DeadlockBo deadlockBo = new DeadlockBo(); - deadlockBo.setDeadlockedThreadCount(tDeadlock.getDeadlockedThreadCount()); - deadlockBo.setThreadDumpList(tDeadlock.getDeadlockedThreadList()); - return deadlockBo; - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockThreadCountBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockThreadCountBoMapper.java new file mode 100644 index 000000000000..f828fc19ec8b --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockThreadCountBoMapper.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.collector.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import com.navercorp.pinpoint.thrift.dto.TDeadlock; +import org.springframework.stereotype.Component; + +/** + * @author Taejin Koo + */ +@Component +public class DeadlockThreadCountBoMapper implements ThriftBoMapper { + + @Override + public DeadlockThreadCountBo map(TDeadlock tDeadlock) { + DeadlockThreadCountBo deadlockThreadCountBo = new DeadlockThreadCountBo(); + deadlockThreadCountBo.setDeadlockedThreadCount(tDeadlock.getDeadlockedThreadCount()); + return deadlockThreadCountBo; + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DirectBufferBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DirectBufferBoMapper.java new file mode 100644 index 000000000000..263488f8f682 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DirectBufferBoMapper.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.collector.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.thrift.dto.TDirectBuffer; +import org.springframework.stereotype.Component; + +/** + * @author Roy Kim + */ +@Component +public class DirectBufferBoMapper implements ThriftBoMapper { + + @Override + public DirectBufferBo map(TDirectBuffer tOpenDirectBuffer) { + DirectBufferBo directBufferBo = new DirectBufferBo(); + directBufferBo.setDirectCount(tOpenDirectBuffer.getDirectCount()); + directBufferBo.setDirectMemoryUsed(tOpenDirectBuffer.getDirectMemoryUsed()); + directBufferBo.setMappedCount(tOpenDirectBuffer.getMappedCount()); + directBufferBo.setMappedMemoryUsed(tOpenDirectBuffer.getMappedMemoryUsed()); + return directBufferBo; + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/FileDescriptorBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/FileDescriptorBoMapper.java new file mode 100644 index 000000000000..d3f2109f8d55 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/FileDescriptorBoMapper.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.collector.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import com.navercorp.pinpoint.thrift.dto.TFileDescriptor; +import org.springframework.stereotype.Component; + +/** + * @author Roy Kim + */ +@Component +public class FileDescriptorBoMapper implements ThriftBoMapper { + + @Override + public FileDescriptorBo map(TFileDescriptor tOpenFileDescriptor) { + FileDescriptorBo fileDescriptorBo = new FileDescriptorBo(); + fileDescriptorBo.setOpenFileDescriptorCount(tOpenFileDescriptor.getOpenFileDescriptorCount()); + return fileDescriptorBo; + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/JvmGcDetailedBoMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/JvmGcDetailedBoMapper.java index 06ea407d0869..2d5616624abb 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/JvmGcDetailedBoMapper.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/JvmGcDetailedBoMapper.java @@ -31,7 +31,7 @@ public class JvmGcDetailedBoMapper implements ThriftBoMapper map(AgentStatBo agentStatBo) { final TreeMap tFAgentStatMap = new TreeMap<>(); @@ -44,6 +44,8 @@ public List map(AgentStatBo agentStatBo) { insertTFActiveTrace(tFAgentStatMap, agentStatBo.getActiveTraceBos(), agentId, startTimestamp); insertTFResponseTime(tFAgentStatMap, agentStatBo.getResponseTimeBos(), agentId, startTimestamp); insertTFDataSourceList(tFAgentStatMap, agentStatBo.getDataSourceListBos(), agentId, startTimestamp); + insertTFileDescriptorList(tFAgentStatMap, agentStatBo.getFileDescriptorBos(), agentId, startTimestamp); + insertTDirectBufferList(tFAgentStatMap, agentStatBo.getDirectBufferBos(), agentId, startTimestamp); return new ArrayList<>(tFAgentStatMap.values()); } @@ -114,6 +116,28 @@ private void insertTFCpuLoad(Map tFAgentStatMap, List tFAgentStatMap, List fileDescriptorBoList, String agentId, long startTimestamp) { + if (fileDescriptorBoList == null) { + return; + } + + for (FileDescriptorBo fileDescriptorBo : fileDescriptorBoList) { + TFAgentStat tFAgentStat = getOrCreateTFAgentStat(tFAgentStatMap, fileDescriptorBo.getTimestamp(), agentId, startTimestamp); + tFAgentStat.setFileDescriptor(tFFileDescriptorBoMapper.map(fileDescriptorBo)); + } + } + + private void insertTDirectBufferList(Map tFAgentStatMap, List directBufferBoList, String agentId, long startTimestamp) { + if (directBufferBoList == null) { + return; + } + + for (DirectBufferBo directBufferBo : directBufferBoList) { + TFAgentStat tFAgentStat = getOrCreateTFAgentStat(tFAgentStatMap, directBufferBo.getTimestamp(), agentId, startTimestamp); + tFAgentStat.setDirectBuffer(tFDirectBufferMapper.map(directBufferBo)); + } + } + private TFAgentStat getOrCreateTFAgentStat(Map tFAgentStatMap, long timestamp, String agentId, long startTimestamp) { TFAgentStat tFAgentStat = tFAgentStatMap.get(timestamp); diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFDirectBufferMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFDirectBufferMapper.java new file mode 100644 index 000000000000..d14aed0865f7 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFDirectBufferMapper.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.thrift.dto.flink.TFDirectBuffer; + +/** + * @author Roy Kim + */ +public class TFDirectBufferMapper { + + public TFDirectBuffer map(DirectBufferBo directBufferBo) { + TFDirectBuffer tfFDirectBuffer = new TFDirectBuffer(); + tfFDirectBuffer.setDirectCount(directBufferBo.getDirectCount()); + tfFDirectBuffer.setDirectMemoryUsed(directBufferBo.getDirectMemoryUsed()); + tfFDirectBuffer.setMappedCount(directBufferBo.getMappedCount()); + tfFDirectBuffer.setMappedMemoryUsed(directBufferBo.getMappedMemoryUsed()); + return tfFDirectBuffer; + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFFileDescriptorMapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFFileDescriptorMapper.java new file mode 100644 index 000000000000..e2bcd3d29bf9 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFFileDescriptorMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import com.navercorp.pinpoint.thrift.dto.flink.TFFileDescriptor; + +/** + * @author Roy Kim + */ +public class TFFileDescriptorMapper { + + public TFFileDescriptor map(FileDescriptorBo fileDescriptorBo) { + TFFileDescriptor tfFFileDescriptor = new TFFileDescriptor(); + tfFFileDescriptor.setOpenFileDescriptorCount(fileDescriptorBo.getOpenFileDescriptorCount()); + return tfFFileDescriptor; + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/CountingRejectedExecutionHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/CountingRejectedExecutionHandler.java new file mode 100644 index 000000000000..fcc1097b1144 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/CountingRejectedExecutionHandler.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.monitor; + +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricRegistry; + +import java.util.Objects; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @author Woonduk Kang(emeroad) + */ +public class CountingRejectedExecutionHandler implements RejectedExecutionHandler { + + private final Meter rejected; + + public CountingRejectedExecutionHandler(String executorName, MetricRegistry registry) { + Objects.requireNonNull(executorName, "executorName must not be null"); + Objects.requireNonNull(registry, "registry must not be null"); + + this.rejected = registry.meter(MetricRegistry.name(executorName, "rejected")); + } + + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + rejected.mark(); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/LoggingRejectedExecutionHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/LoggingRejectedExecutionHandler.java new file mode 100644 index 000000000000..915abefefdc8 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/LoggingRejectedExecutionHandler.java @@ -0,0 +1,51 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.monitor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author Woonduk Kang(emeroad) + */ +public class LoggingRejectedExecutionHandler implements RejectedExecutionHandler { + + private final AtomicLong rejectedCount = new AtomicLong(0); + + private final Logger logger; + private final int logRate; + + public LoggingRejectedExecutionHandler(String executorName, int logRate) { + Objects.requireNonNull(executorName, "executorName must not be null"); + + this.logger = LoggerFactory.getLogger(executorName); + this.logRate = logRate; + } + + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + final long error = rejectedCount.incrementAndGet(); + if ((error % logRate) == 0) { + logger.warn("RejectedExecutionCount={}", error); + } + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/MonitoredExecutorService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/MonitoredExecutorService.java deleted file mode 100644 index ceac2aa941f4..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/MonitoredExecutorService.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.navercorp.pinpoint.collector.monitor; - -import com.codahale.metrics.Counter; -import com.codahale.metrics.Meter; -import com.codahale.metrics.MetricRegistry; -import com.codahale.metrics.Timer; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** - * - * refer to dropwizard metrics - * https://github.com/dropwizard/metrics/blob/3.2-development/metrics-core/src/main/java/com/codahale/metrics/InstrumentedExecutorService.java - * - * Caution : If using multiple method (like invokeAny, invokeAll), then rejected count can be incorrect. - * - * @author Taejin Koo - */ -public class MonitoredExecutorService implements ExecutorService { - - private final Meter submitted; - private final Meter rejected; - private final Counter running; - private final Meter completed; - private final Timer dispatchDurationTimer; - private final Timer durationTimer; - - private final ExecutorService delegate; - - public MonitoredExecutorService(ExecutorService delegate, MetricRegistry registry, String name) { - this.delegate = delegate; - - this.submitted = registry.meter(MetricRegistry.name(name, "submitted")); - this.rejected = registry.meter(MetricRegistry.name(name, "rejected")); - this.running = registry.counter(MetricRegistry.name(name, "running")); - this.completed = registry.meter(MetricRegistry.name(name, "completed")); - - this.dispatchDurationTimer = registry.timer(MetricRegistry.name(name, "dispatchDuration")); - this.durationTimer = registry.timer(MetricRegistry.name(name, "duration")); - } - - @Override - public void execute(Runnable runnable) { - submitted.mark(); - try { - delegate.execute(new InstrumentedRunnable(runnable)); - } catch (RejectedExecutionException ree) { - rejected.mark(); - throw ree; - } - } - - @Override - public Future submit(Runnable runnable) { - submitted.mark(); - try { - return delegate.submit(new InstrumentedRunnable(runnable)); - } catch (RejectedExecutionException ree) { - rejected.mark(); - throw ree; - } - } - - @Override - public Future submit(Runnable runnable, T result) { - submitted.mark(); - try { - return delegate.submit(new InstrumentedRunnable(runnable), result); - } catch (RejectedExecutionException ree) { - rejected.mark(); - throw ree; - } - } - - @Override - public Future submit(Callable callable) { - submitted.mark(); - try { - return delegate.submit(new InstrumentedCallable(callable)); - } catch (RejectedExecutionException ree) { - rejected.mark(); - throw ree; - } - } - - @Override - public List> invokeAll(Collection> callables) throws InterruptedException { - submitted.mark(callables.size()); - Collection> instrumented = instrument(callables); - try { - return delegate.invokeAll(instrumented); - } catch (RejectedExecutionException ree) { - rejected.mark(callables.size()); - throw ree; - } - } - - @Override - public List> invokeAll(Collection> callables, long timeout, TimeUnit unit) throws InterruptedException { - submitted.mark(callables.size()); - Collection> instrumented = instrument(callables); - try { - return delegate.invokeAll(instrumented, timeout, unit); - } catch (RejectedExecutionException ree) { - rejected.mark(callables.size()); - throw ree; - } - } - - @Override - public T invokeAny(Collection> callables) throws ExecutionException, InterruptedException { - submitted.mark(callables.size()); - Collection> instrumented = instrument(callables); - try { - return delegate.invokeAny(instrumented); - } catch (RejectedExecutionException ree) { - rejected.mark(callables.size()); - throw ree; - } - } - - @Override - public T invokeAny(Collection> callables, long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException { - submitted.mark(callables.size()); - Collection> instrumented = instrument(callables); - try { - return delegate.invokeAny(instrumented, timeout, unit); - } catch (RejectedExecutionException ree) { - rejected.mark(callables.size()); - throw ree; - } - } - - private Collection> instrument(Collection> callables) { - final List> instrumented = new ArrayList>(callables.size()); - for (Callable callable : callables) { - instrumented.add(new InstrumentedCallable(callable)); - } - return instrumented; - } - - @Override - public void shutdown() { - delegate.shutdown(); - } - - @Override - public List shutdownNow() { - return delegate.shutdownNow(); - } - - @Override - public boolean isShutdown() { - return delegate.isShutdown(); - } - - @Override - public boolean isTerminated() { - return delegate.isTerminated(); - } - - @Override - public boolean awaitTermination(long timeout, TimeUnit timeUnit) throws InterruptedException { - return delegate.awaitTermination(timeout, timeUnit); - } - - private class InstrumentedRunnable implements Runnable { - private final Runnable runnable; - private final Timer.Context dispatchDuration; - - InstrumentedRunnable(Runnable runnable) { - this.runnable = runnable; - this.dispatchDuration = dispatchDurationTimer.time(); - } - - @Override - public void run() { - dispatchDuration.stop(); - - running.inc(); - final Timer.Context context = durationTimer.time(); - try { - runnable.run(); - } finally { - context.stop(); - running.dec(); - completed.mark(); - } - } - } - - private class InstrumentedCallable implements Callable { - private final Callable callable; - private final Timer.Context dispatchDuration; - - InstrumentedCallable(Callable callable) { - this.callable = callable; - this.dispatchDuration = dispatchDurationTimer.time(); - } - - @Override - public T call() throws Exception { - dispatchDuration.stop(); - - running.inc(); - final Timer.Context context = durationTimer.time(); - try { - return callable.call(); - } finally { - context.stop(); - running.dec(); - completed.mark(); - } - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/MonitoredRunnableDecorator.java b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/MonitoredRunnableDecorator.java new file mode 100644 index 000000000000..0d87bb96203a --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/MonitoredRunnableDecorator.java @@ -0,0 +1,153 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.monitor; + +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Callable; +/** + * @author Woonduk Kang(emeroad) + */ +public class MonitoredRunnableDecorator implements RunnableDecorator { + + @SuppressWarnings("unused") // for debug + private final String executorName; + private final Meter submitted; + + private final Timer dispatchDurationTimer; + private final Timer durationTimer; + private final MetricRegistry registry; + + public MonitoredRunnableDecorator(String executorName, MetricRegistry registry) { + this.registry = registry; + this.executorName = Objects.requireNonNull(executorName, "name must not be null"); + + this.submitted = registry.meter(MetricRegistry.name(executorName, "submitted")); + + this.dispatchDurationTimer = registry.timer(MetricRegistry.name(executorName, "dispatchDuration")); + this.durationTimer = registry.timer(MetricRegistry.name(executorName, "duration")); + } + + @Override + public Runnable decorate(Runnable runnable) { + if (runnable == null) { + throw new NullPointerException(); + } + submitted.mark(); + return instrument(runnable); + } + + private Runnable instrument(Runnable runnable) { + return new InstrumentedRunnable(runnable); + } + + + @Override + public Callable decorate(Callable task) { + if (task == null) { + throw new NullPointerException(); + } + + submitted.mark(); + return instrument(task); + } + + private Callable instrument(Callable runnable) { + return new InstrumentedCallable<>(runnable); + } + + + @Override + public Collection> decorate(Collection> tasks) { + if (tasks == null) { + throw new NullPointerException(); + } + submitted.mark(tasks.size()); + return instrument(tasks); + } + + private Collection> instrument(Collection> tasks) { + final List> instrumented = new ArrayList>(tasks.size()); + for (Callable callable : tasks) { + instrumented.add(instrument(callable)); + } + return instrumented; + } + + + private class InstrumentedRunnable implements Runnable { + private final Runnable runnable; + private final Timer.Context dispatchDuration; + + InstrumentedRunnable(Runnable runnable) { + this.runnable = Objects.requireNonNull(runnable, "runnable must not be null"); + this.dispatchDuration = dispatchDurationTimer.time(); + } + + @Override + public void run() { + dispatchDuration.stop(); + + final Timer.Context context = durationTimer.time(); + try { + runnable.run(); + } finally { + context.stop(); + } + } + + @Override + public String toString() { + return runnable.toString(); + } + } + + + private class InstrumentedCallable implements Callable { + private final Callable callable; + private final Timer.Context dispatchDuration; + + InstrumentedCallable(Callable callable) { + this.callable = Objects.requireNonNull(callable, "callable must not be null"); + this.dispatchDuration = dispatchDurationTimer.time(); + } + + @Override + public T call() throws Exception { + dispatchDuration.stop(); + + final Timer.Context context = durationTimer.time(); + try { + return callable.call(); + } finally { + context.stop(); + } + } + + @Override + public String toString() { + return callable.toString(); + } + } +} + diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/MonitoredThreadPoolExecutor.java b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/MonitoredThreadPoolExecutor.java new file mode 100644 index 000000000000..4b99720ebe02 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/MonitoredThreadPoolExecutor.java @@ -0,0 +1,109 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.monitor; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * @author Woonduk Kang(emeroad) + */ +public class MonitoredThreadPoolExecutor extends ThreadPoolExecutor { + + private final RunnableDecorator runnableDecorator; + + public MonitoredThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, + RunnableDecorator runnableDecorator) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); + this.runnableDecorator = Objects.requireNonNull(runnableDecorator, "executeListener must not be null"); + + } + + + public MonitoredThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, + ThreadFactory threadFactory, RunnableDecorator runnableDecorator) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); + this.runnableDecorator = Objects.requireNonNull(runnableDecorator, "runnableDecorator must not be null"); + } + + public MonitoredThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, + RejectedExecutionHandler handler, RunnableDecorator runnableDecorator) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); + this.runnableDecorator = Objects.requireNonNull(runnableDecorator, "runnableDecorator must not be null"); + + } + + public MonitoredThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, + ThreadFactory threadFactory, RejectedExecutionHandler handler, RunnableDecorator runnableDecorator) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); + this.runnableDecorator = Objects.requireNonNull(runnableDecorator, "runnableDecorator must not be null"); + } + + + + @Override + public void execute(Runnable command) { + super.execute(runnableDecorator.decorate(command)); + } + + @Override + public Future submit(Runnable task) { + return super.submit(runnableDecorator.decorate(task)); + } + + @Override + public Future submit(Callable task) { + return super.submit(runnableDecorator.decorate(task)); + } + + @Override + public Future submit(Runnable task, T result) { + return super.submit(runnableDecorator.decorate(task), result); + } + + @Override + public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { + return super.invokeAny(runnableDecorator.decorate(tasks)); + } + + @Override + public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return super.invokeAny(runnableDecorator.decorate(tasks), timeout, unit); + } + + @Override + public List> invokeAll(Collection> tasks) throws InterruptedException { + return super.invokeAll(runnableDecorator.decorate(tasks)); + } + + @Override + public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { + return super.invokeAll(runnableDecorator.decorate(tasks), timeout, unit); + } + +} + diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/RejectedExecutionHandlerChain.java b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/RejectedExecutionHandlerChain.java new file mode 100644 index 000000000000..f35f3ebd5a3a --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/RejectedExecutionHandlerChain.java @@ -0,0 +1,46 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.monitor; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RejectedExecutionHandlerChain implements RejectedExecutionHandler { + private final RejectedExecutionHandler[] handlerChain; + + public static RejectedExecutionHandler build(List chain) { + Objects.requireNonNull(chain, "handlerChain must not be null"); + RejectedExecutionHandler[] handlerChain = chain.toArray(new RejectedExecutionHandler[0]); + return new RejectedExecutionHandlerChain(handlerChain); + } + + private RejectedExecutionHandlerChain(RejectedExecutionHandler[] handlerChain) { + this.handlerChain = Objects.requireNonNull(handlerChain, "handlerChain must not be null"); + } + + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + for (RejectedExecutionHandler rejectedExecutionHandler : handlerChain) { + rejectedExecutionHandler.rejectedExecution(r, executor); + } + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/RunnableDecorator.java b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/RunnableDecorator.java new file mode 100644 index 000000000000..d5db48229636 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/monitor/RunnableDecorator.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.monitor; + +import java.util.Collection; +import java.util.concurrent.Callable; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface RunnableDecorator { + Runnable decorate(Runnable runnable); + + Callable decorate(Callable task); + + Collection> decorate(Collection> tasks); +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/AbstractDispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/AbstractDispatchHandler.java deleted file mode 100644 index 198958a3654c..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/AbstractDispatchHandler.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import com.navercorp.pinpoint.collector.handler.RequestResponseHandler; -import com.navercorp.pinpoint.collector.handler.SimpleHandler; -import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; -import com.navercorp.pinpoint.common.util.CollectionUtils; -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.Collections; -import java.util.List; - -/** - * @author emeroad - * @author Taejin Koo - */ -public abstract class AbstractDispatchHandler implements DispatchHandler { - - protected Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Autowired - private AcceptedTimeService acceptedTimeService; - - public AbstractDispatchHandler() { - } - - @Override - public void dispatchSendMessage(TBase tBase) { - - // mark accepted time - acceptedTimeService.accept(); - - // TODO consider to change dispatch table automatically - List simpleHandlerList = getSimpleHandler(tBase); - if (!CollectionUtils.isEmpty(simpleHandlerList)) { - for (SimpleHandler simpleHandler : simpleHandlerList) { - if (logger.isTraceEnabled()) { - logger.trace("simpleHandler name:{}", simpleHandler.getClass().getName()); - } - simpleHandler.handleSimple(tBase); - } - } - - if (CollectionUtils.isEmpty(simpleHandlerList)) { - throw new UnsupportedOperationException("Handler not found. Unknown type of data received. tBase=" + tBase); - } - } - - public TBase dispatchRequestMessage(TBase tBase) { - // mark accepted time - acceptedTimeService.accept(); - - RequestResponseHandler requestResponseHandler = getRequestResponseHandler(tBase); - if (requestResponseHandler != null) { - if (logger.isTraceEnabled()) { - logger.trace("requestResponseHandler name:{}", requestResponseHandler.getClass().getName()); - } - return requestResponseHandler.handleRequest(tBase); - } - - throw new UnsupportedOperationException("Handler not found. Unknown type of data received. tBase=" + tBase); - } - - protected List getSimpleHandler(TBase tBase) { - return Collections.emptyList(); - } - - protected RequestResponseHandler getRequestResponseHandler(TBase tBase) { - return null; - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/AddressFilterAdaptor.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/AddressFilterAdaptor.java deleted file mode 100644 index d2b6fe0c9d48..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/AddressFilterAdaptor.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import com.navercorp.pinpoint.common.server.util.AddressFilter; -import com.navercorp.pinpoint.rpc.server.ChannelFilter; -import org.jboss.netty.channel.Channel; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Objects; - -/** - * @author Woonduk Kang(emeroad) - */ -public class AddressFilterAdaptor implements ChannelFilter { - private final AddressFilter filter; - - public AddressFilterAdaptor(AddressFilter filter) { - this.filter = Objects.requireNonNull(filter, "filter must not be null"); - } - - @Override - public boolean accept(Channel channel) { - final InetSocketAddress remoteAddress = (InetSocketAddress) channel.getRemoteAddress(); - if (remoteAddress == null) { - return true; - } - InetAddress address = remoteAddress.getAddress(); - return filter.accept(address); - } -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DataReceiver.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DataReceiver.java deleted file mode 100644 index 85bfbd62ad53..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DataReceiver.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -/** - * @author emeroad - */ -public interface DataReceiver { - void start(); - - void shutdown(); -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DataReceiverGroup.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DataReceiverGroup.java deleted file mode 100644 index 86ce7a7020d0..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DataReceiverGroup.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import com.codahale.metrics.MetricRegistry; -import com.navercorp.pinpoint.collector.config.DataReceiverGroupConfiguration; -import com.navercorp.pinpoint.collector.receiver.tcp.TCPReceiver; -import com.navercorp.pinpoint.collector.receiver.udp.BaseUDPHandlerFactory; -import com.navercorp.pinpoint.collector.receiver.udp.NetworkAvailabilityCheckPacketFilter; -import com.navercorp.pinpoint.collector.receiver.udp.PacketHandlerFactory; -import com.navercorp.pinpoint.collector.receiver.udp.TBaseFilterChain; -import com.navercorp.pinpoint.collector.receiver.udp.UDPReceiver; -import com.navercorp.pinpoint.common.server.util.AddressFilter; -import com.navercorp.pinpoint.common.util.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import javax.annotation.PostConstruct; -import java.net.DatagramPacket; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** - * DataReceiverGroup can have a TCP Receiver and a UDP Receiver with the same behavior - * - * @author Taejin Koo - */ -public class DataReceiverGroup implements DataReceiver { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final DispatchWorker worker; - private final List receiverList; - - @Autowired - private MetricRegistry metricRegistry; - - public DataReceiverGroup(String name, DataReceiverGroupConfiguration configuration, AddressFilter ignoreAddressFilter, DispatchHandler dispatchHandler) { - Objects.requireNonNull(configuration, "configuration must not be null"); - Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); - - String workerName = String.format("Pinpoint-%s-Worker", name); - DispatchWorkerOption dispatchWorkerOption = new DispatchWorkerOption(workerName, configuration.getWorkerThreadSize(), configuration.getWorkerQueueSize(), 100, configuration.isWorkerMonitorEnable()); - this.worker = new DispatchWorker(dispatchWorkerOption); - - List receiverList = new ArrayList<>(); - - if (configuration.isUdpEnable()) { - DataReceiver udpReceiver = createUdpReceiver(name, configuration, dispatchHandler, ignoreAddressFilter); - receiverList.add(udpReceiver); - } - - if (configuration.isTcpEnable()) { - DataReceiver tcpReceiver = createTcpReceiver(name, configuration, dispatchHandler, ignoreAddressFilter); - receiverList.add(tcpReceiver); - } - - Assert.isTrue(receiverList.size() > 0, "receiver must be greater than 0"); - - this.receiverList = Collections.unmodifiableList(receiverList); - } - - private UDPReceiver createUdpReceiver(String name, DataReceiverGroupConfiguration configuration, DispatchHandler dispatchHandler, AddressFilter ignoreAddressFilter) { - String udpReceiverName = String.format("Pinpoint-UDP-%s-Receiver", name); - TBaseFilterChain filterChain = new TBaseFilterChain(Arrays.asList(new NetworkAvailabilityCheckPacketFilter())); - PacketHandlerFactory packetHandlerFactory = new BaseUDPHandlerFactory(dispatchHandler, filterChain, ignoreAddressFilter); - InetSocketAddress bindAddress = new InetSocketAddress(configuration.getUdpBindIp(), configuration.getUdpBindPort()); - return new UDPReceiver(udpReceiverName, packetHandlerFactory, worker, configuration.getUdpReceiveBufferSize(), bindAddress); - } - - public TCPReceiver createTcpReceiver(String name, DataReceiverGroupConfiguration configuration, DispatchHandler dispatchHandler, AddressFilter ignoreAddressFilter) { - String tcpReceiverName = String.format("Pinpoint-TCP-%s-Receiver", name); - InetSocketAddress bindAddress = new InetSocketAddress(configuration.getTcpBindIp(), configuration.getTcpBindPort()); - - return new TCPReceiver(tcpReceiverName, dispatchHandler, worker, bindAddress, ignoreAddressFilter); - } - - @PostConstruct - @Override - public void start() { - logger.info("start() started"); - - worker.setMetricRegistry(metricRegistry); - worker.start(); - - for (DataReceiver receiver : receiverList) { - receiver.start(); - } - - logger.info("start() completed"); - } - - @Override - public void shutdown() { - logger.info("shutdown() started"); - - for (DataReceiver receiver : receiverList) { - receiver.shutdown(); - } - - worker.shutdown(); - - logger.info("shutdown() completed"); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchHandler.java deleted file mode 100644 index 26cdd24d7692..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import org.apache.thrift.TBase; - -/** - * @author emeroad - * @author koo.taejin - */ -public interface DispatchHandler { - - // Separating Send and Request. That dose not be satisfied but try to change that later. - - void dispatchSendMessage(TBase tBase); - - TBase dispatchRequestMessage(TBase tBase); - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchHandlerWrapper.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchHandlerWrapper.java deleted file mode 100644 index ccdd181b4937..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchHandlerWrapper.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import com.navercorp.pinpoint.collector.manage.HandlerManager; -import com.navercorp.pinpoint.thrift.dto.TResult; - -/** - * @author Taejin Koo - */ -public class DispatchHandlerWrapper implements DispatchHandler { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final DispatchHandler delegate; - - @Autowired - private HandlerManager handlerManager; - - public DispatchHandlerWrapper(DispatchHandler dispatchHandler) { - if (dispatchHandler == null) { - throw new NullPointerException("dispatchHandler may note be null."); - } - this.delegate = dispatchHandler; - } - - @Override - public void dispatchSendMessage(TBase tBase) { - if (checkAvailable()) { - this.delegate.dispatchSendMessage(tBase); - return; - } - - logger.debug("Handler is disabled. Skipping send message {}.", tBase); - return; - } - - @Override - public TBase dispatchRequestMessage(TBase tBase) { - if (checkAvailable()) { - return this.delegate.dispatchRequestMessage(tBase); - } - - logger.debug("Handler is disabled. Skipping request message {}.", tBase); - - TResult result = new TResult(false); - result.setMessage("Handler is disabled. Skipping request message."); - return result; - } - - private boolean checkAvailable() { - if (handlerManager == null) { - return true; - } - - if (handlerManager.isEnable()) { - return true; - } - - return false; - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchWorker.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchWorker.java deleted file mode 100644 index ad1e33138bca..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchWorker.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import com.codahale.metrics.MetricRegistry; -import com.navercorp.pinpoint.collector.monitor.MonitoredExecutorService; -import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.common.util.ExecutorFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * @author Taejin Koo - */ -public class DispatchWorker { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final DispatchWorkerOption option; - private final AtomicInteger rejectedCount = new AtomicInteger(0); - - private MetricRegistry metricRegistry; - - private ExecutorService worker; - - public DispatchWorker(DispatchWorkerOption option) { - Assert.requireNonNull(option, "option may not be null"); - - this.option = option; - } - - public MetricRegistry getMetricRegistry() { - return metricRegistry; - } - - public void setMetricRegistry(MetricRegistry metricRegistry) { - this.metricRegistry = metricRegistry; - } - - public void start() { - logger.info("{} start.", getName()); - ExecutorService worker = createWorker(getName(), getThreadSize(), getQueueSize()); - if (option.isEnableCollectMetric()) { - if (metricRegistry == null) { - logger.warn("metricRegistry not autowired. Can't enable monitoring."); - this.worker = worker; - } else { - this.worker = new MonitoredExecutorService(worker, metricRegistry, getName()); - } - } else { - this.worker = worker; - } - } - - private ExecutorService createWorker(String workerName, int threadSize, int queueSize) { - return ExecutorFactory.newFixedThreadPool(threadSize, queueSize, workerName, true); - } - - public void shutdown() { - logger.info("{} shutdown.", getName()); - worker.shutdown(); - try { - worker.awaitTermination(1000 * 10, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - logger.info("{}.shutdown() Interrupted", getName(), e); - Thread.currentThread().interrupt(); - } - } - - public void execute(Runnable runnable) { - execute(runnable, false); - } - - public void execute(Runnable runnable, boolean throwWhenExceptionOccurs) { - try { - worker.execute(runnable); - } catch (RejectedExecutionException exception) { - handleRejectedExecutionException(exception, throwWhenExceptionOccurs); - } - } - - private void handleRejectedExecutionException(RejectedExecutionException exception, boolean throwWhenExceptionOccurs) { - final int error = rejectedCount.incrementAndGet(); - if (throwWhenExceptionOccurs) { - throw exception; - } else { - if ((error % option.getRecordLogRate()) == 0) { - logger.warn("RejectedExecutionCount={}", error); - } - } - } - - public String getName() { - return option.getName(); - } - - public int getThreadSize() { - return option.getThreadSize(); - } - - public int getQueueSize() { - return option.getQueueSize(); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchWorkerOption.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchWorkerOption.java deleted file mode 100644 index 21c4b38b59a8..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/DispatchWorkerOption.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -/** - * @author Taejin Koo - */ -public class DispatchWorkerOption { - - private final String name; - - private final int threadSize; - private final int queueSize; - private final int recordLogRate; - - private final boolean enableCollectMetric; - - public DispatchWorkerOption(String name, int threadSize, int queueSize) { - this(name, threadSize, queueSize, 100); - } - - public DispatchWorkerOption(String name, int threadSize, int queueSize, boolean enableCollectMetric) { - this(name, threadSize, queueSize, 100, enableCollectMetric); - } - - public DispatchWorkerOption(String name, int threadSize, int queueSize, int recordLogRate) { - this(name, threadSize, queueSize, recordLogRate, false); - } - - public DispatchWorkerOption(String name, int threadSize, int queueSize, int recordLogRate, boolean enableCollectMetric) { - if (threadSize <= 0) { - throw new IllegalArgumentException("threadSize must be greater than 0"); - } - - if (queueSize <= 0) { - throw new IllegalArgumentException("queueSize must be greater than 0"); - } - - if (recordLogRate <= 0) { - throw new IllegalArgumentException("recordLogRate must be greater than 0"); - } - - this.name = name; - this.threadSize = threadSize; - this.queueSize = queueSize; - this.recordLogRate = recordLogRate; - this.enableCollectMetric = enableCollectMetric; - } - - public String getName() { - return name; - } - - public int getThreadSize() { - return threadSize; - } - - public int getQueueSize() { - return queueSize; - } - - public int getRecordLogRate() { - return recordLogRate; - } - - public boolean isEnableCollectMetric() { - return enableCollectMetric; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("DispatchWorkerOption{"); - sb.append("name='").append(name).append('\''); - sb.append(", threadSize=").append(threadSize); - sb.append(", queueSize=").append(queueSize); - sb.append(", recordLogRate=").append(recordLogRate); - sb.append(", enableCollectMetric=").append(enableCollectMetric); - sb.append('}'); - return sb.toString(); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/SpanDispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/SpanDispatchHandler.java deleted file mode 100644 index 4cc9fd34136e..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/SpanDispatchHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import com.navercorp.pinpoint.collector.handler.SimpleHandler; -import com.navercorp.pinpoint.thrift.dto.TSpan; -import com.navercorp.pinpoint.thrift.dto.TSpanChunk; -import org.apache.thrift.TBase; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author emeroad - */ -public class SpanDispatchHandler extends AbstractDispatchHandler { - - @Autowired() - @Qualifier("spanHandler") - private SimpleHandler spanDataHandler; - - @Autowired() - @Qualifier("spanChunkHandler") - private SimpleHandler spanChunkHandler; - - public SpanDispatchHandler() { - this.logger = LoggerFactory.getLogger(this.getClass()); - } - - - @Override - protected List getSimpleHandler(TBase tBase) { - List simpleHandlerList = new ArrayList<>(); - - if (tBase instanceof TSpan) { - simpleHandlerList.add(spanDataHandler); - } - if (tBase instanceof TSpanChunk) { - simpleHandlerList.add(spanChunkHandler); - } - - return simpleHandlerList; - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/SpanReceiver.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/SpanReceiver.java deleted file mode 100644 index 53fda916672d..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/SpanReceiver.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import com.navercorp.pinpoint.collector.config.DataReceiverGroupConfiguration; -import com.navercorp.pinpoint.common.server.util.AddressFilter; - -/** - * @author Taejin Koo - */ -public class SpanReceiver extends DataReceiverGroup { - - public SpanReceiver(DataReceiverGroupConfiguration config, AddressFilter filter, DispatchHandler dispatchHandler) { - super("Span", config, filter, dispatchHandler); - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/StatDispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/StatDispatchHandler.java deleted file mode 100644 index e9c8279e2052..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/StatDispatchHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import com.navercorp.pinpoint.collector.handler.AgentEventHandler; -import com.navercorp.pinpoint.collector.handler.AgentStatHandlerV2; -import com.navercorp.pinpoint.collector.handler.SimpleHandler; -import com.navercorp.pinpoint.thrift.dto.TAgentStat; -import com.navercorp.pinpoint.thrift.dto.TAgentStatBatch; -import org.apache.thrift.TBase; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author emeroad - * @author hyungil.jeong - */ -public class StatDispatchHandler extends AbstractDispatchHandler { - - @Autowired - private AgentStatHandlerV2 agentStatHandler; - - @Autowired - private AgentEventHandler agentEventHandler; - - public StatDispatchHandler() { - this.logger = LoggerFactory.getLogger(this.getClass()); - } - - @Override - protected List getSimpleHandler(TBase tBase) { - List simpleHandlerList = new ArrayList<>(); - - // To change below code to switch table make it a little bit faster. - // FIXME (2014.08) Legacy - TAgentStats should not be sent over the wire. - if (tBase instanceof TAgentStat || tBase instanceof TAgentStatBatch) { - simpleHandlerList.add(agentStatHandler); - simpleHandlerList.add(agentEventHandler); - } - - return simpleHandlerList; - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/StatReceiver.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/StatReceiver.java deleted file mode 100644 index d4ff557f6cee..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/StatReceiver.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import com.navercorp.pinpoint.collector.config.DataReceiverGroupConfiguration; -import com.navercorp.pinpoint.common.server.util.AddressFilter; - -/** - * @author Taejin Koo - */ -public class StatReceiver extends DataReceiverGroup { - - public StatReceiver(DataReceiverGroupConfiguration config, AddressFilter filter, DispatchHandler dispatchHandler) { - super("Stat", config, filter, dispatchHandler); - } - -} - diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/TcpDispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/TcpDispatchHandler.java deleted file mode 100644 index 55e8a2f10fb3..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/TcpDispatchHandler.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import com.navercorp.pinpoint.collector.handler.AgentInfoHandler; -import com.navercorp.pinpoint.collector.handler.RequestResponseHandler; -import com.navercorp.pinpoint.collector.handler.SimpleHandler; -import com.navercorp.pinpoint.thrift.dto.TAgentInfo; -import com.navercorp.pinpoint.thrift.dto.TApiMetaData; -import com.navercorp.pinpoint.thrift.dto.TSqlMetaData; -import com.navercorp.pinpoint.thrift.dto.TStringMetaData; -import org.apache.thrift.TBase; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author emeroad - * @author koo.taejin - */ -public class TcpDispatchHandler extends AbstractDispatchHandler { - - @Autowired() - @Qualifier("agentInfoHandler") - private AgentInfoHandler agentInfoHandler; - - @Autowired() - @Qualifier("sqlMetaDataHandler") - private RequestResponseHandler sqlMetaDataHandler; - - @Autowired() - @Qualifier("apiMetaDataHandler") - private RequestResponseHandler apiMetaDataHandler; - - @Autowired() - @Qualifier("stringMetaDataHandler") - private RequestResponseHandler stringMetaDataHandler; - - - - public TcpDispatchHandler() { - this.logger = LoggerFactory.getLogger(this.getClass()); - } - - - @Override - protected RequestResponseHandler getRequestResponseHandler(TBase tBase) { - if (tBase instanceof TSqlMetaData) { - return sqlMetaDataHandler; - } - if (tBase instanceof TApiMetaData) { - return apiMetaDataHandler; - } - if (tBase instanceof TStringMetaData) { - return stringMetaDataHandler; - } - if (tBase instanceof TAgentInfo) { - return agentInfoHandler; - } - return null; - } - - @Override - protected List getSimpleHandler(TBase tBase) { - List simpleHandlerList = new ArrayList<>(); - if (tBase instanceof TAgentInfo) { - simpleHandlerList.add(agentInfoHandler); - } - - return simpleHandlerList; - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/AgentBaseDataReceiver.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/AgentBaseDataReceiver.java deleted file mode 100644 index a4d8dae1ea8a..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/AgentBaseDataReceiver.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.tcp; - -import com.codahale.metrics.MetricRegistry; -import com.navercorp.pinpoint.collector.cluster.zookeeper.ZookeeperClusterService; -import com.navercorp.pinpoint.collector.config.AgentBaseDataReceiverConfiguration; -import com.navercorp.pinpoint.collector.receiver.DispatchHandler; -import com.navercorp.pinpoint.collector.receiver.DispatchWorker; -import com.navercorp.pinpoint.collector.receiver.DispatchWorkerOption; -import com.navercorp.pinpoint.collector.receiver.AddressFilterAdaptor; -import com.navercorp.pinpoint.common.server.util.AddressFilter; -import com.navercorp.pinpoint.collector.rpc.handler.AgentLifeCycleHandler; -import com.navercorp.pinpoint.collector.service.AgentEventService; -import com.navercorp.pinpoint.common.server.util.AgentEventType; -import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; -import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; -import com.navercorp.pinpoint.rpc.packet.SendPacket; -import com.navercorp.pinpoint.rpc.server.ChannelFilter; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.ServerMessageListener; -import com.navercorp.pinpoint.rpc.server.handler.ServerStateChangeEventHandler; -import com.navercorp.pinpoint.rpc.util.MapUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.annotation.Resource; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * @author emeroad - * @author koo.taejin - */ -public class AgentBaseDataReceiver { - - private final Logger logger = LoggerFactory.getLogger(AgentBaseDataReceiver.class); - - private PinpointServerAcceptor serverAcceptor; - - private final AgentBaseDataReceiverConfiguration configuration; - private final AddressFilter addressFilter; - - private final ZookeeperClusterService clusterService; - - @Autowired - private MetricRegistry metricRegistry; - - private DispatchWorker worker; - - private final SendPacketHandler sendPacketHandler; - private final RequestPacketHandler requestPacketHandler; - - - @Resource(name = "agentEventService") - private AgentEventService agentEventService; - - @Resource(name = "agentLifeCycleHandler") - private AgentLifeCycleHandler agentLifeCycleHandler; - - @Resource(name = "channelStateChangeEventHandlers") - private List channelStateChangeEventHandlers = Collections.emptyList(); - - public AgentBaseDataReceiver(AgentBaseDataReceiverConfiguration configuration, AddressFilter addressFilter, DispatchHandler dispatchHandler) { - this(configuration, addressFilter, dispatchHandler, null); - } - - public AgentBaseDataReceiver(AgentBaseDataReceiverConfiguration configuration, AddressFilter addressFilter, DispatchHandler dispatchHandler, ZookeeperClusterService service) { - Assert.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); - this.configuration = Assert.requireNonNull(configuration, "config must not be null"); - - this.addressFilter = Objects.requireNonNull(addressFilter, "addressFilter must not be null"); - - DispatchWorkerOption dispatchWorkerOption = new DispatchWorkerOption("Pinpoint-AgentBaseDataReceiver-Worker", configuration.getWorkerThreadSize(), configuration.getWorkerQueueSize(), 1, configuration.isWorkerMonitorEnable()); - this.worker = new DispatchWorker(dispatchWorkerOption); - - this.sendPacketHandler = new SendPacketHandler(dispatchHandler); - this.requestPacketHandler = new RequestPacketHandler(dispatchHandler); - - this.clusterService = service; - } - - @PostConstruct - public void start() { - if (logger.isInfoEnabled()) { - logger.info("start() started"); - } - ChannelFilter connectedFilter = new AddressFilterAdaptor(addressFilter); - PinpointServerAcceptor acceptor = new PinpointServerAcceptor(connectedFilter); - prepare(acceptor); - - worker.setMetricRegistry(metricRegistry); - worker.start(); - - // take care when attaching message handlers as events are generated from the IO thread. - // pass them to a separate queue and handle them in a different thread. - acceptor.setMessageListener(new ServerMessageListener() { - - @Override - public HandshakeResponseCode handleHandshake(Map properties) { - if (properties == null) { - return HandshakeResponseType.ProtocolError.PROTOCOL_ERROR; - } - - boolean hasRequiredKeys = HandshakePropertyType.hasRequiredKeys(properties); - if (!hasRequiredKeys) { - return HandshakeResponseType.PropertyError.PROPERTY_ERROR; - } - - boolean supportServer = MapUtils.getBoolean(properties, HandshakePropertyType.SUPPORT_SERVER.getName(), true); - if (supportServer) { - return HandshakeResponseType.Success.DUPLEX_COMMUNICATION; - } else { - return HandshakeResponseType.Success.SIMPLEX_COMMUNICATION; - } - } - - @Override - public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { - receive(sendPacket, pinpointSocket); - } - - @Override - public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - requestResponse(requestPacket, pinpointSocket); - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - recordPing(pingPacket, pinpointServer); - } - }); - acceptor.bind(configuration.getBindIp(), configuration.getBindPort()); - - this.serverAcceptor = acceptor; - - if (logger.isInfoEnabled()) { - logger.info("start() completed"); - } - } - - private void prepare(PinpointServerAcceptor acceptor) { - if (clusterService != null && clusterService.isEnable()) { - acceptor.addStateChangeEventHandler(clusterService.getChannelStateChangeEventHandler()); - } - - for (ServerStateChangeEventHandler channelStateChangeEventHandler : this.channelStateChangeEventHandlers) { - acceptor.addStateChangeEventHandler(channelStateChangeEventHandler); - } - } - - private void receive(SendPacket sendPacket, PinpointSocket pinpointSocket) { - worker.execute(new Runnable() { - @Override - public void run() { - sendPacketHandler.handle(sendPacket, pinpointSocket); - } - }); - } - - private void requestResponse(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - worker.execute(new Runnable() { - @Override - public void run() { - requestPacketHandler.handle(requestPacket, pinpointSocket); - } - }); - } - - private void recordPing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - final int eventCounter = pingPacket.getPingId(); - long pingTimestamp = System.currentTimeMillis(); - try { - if (!(eventCounter < 0)) { - agentLifeCycleHandler.handleLifeCycleEvent(pinpointServer, pingTimestamp, AgentLifeCycleState.RUNNING, eventCounter); - } - agentEventService.handleEvent(pinpointServer, pingTimestamp, AgentEventType.AGENT_PING); - } catch (Exception e) { - logger.warn("Error handling ping event", e); - } - } - - @PreDestroy - public void stop() { - if (logger.isInfoEnabled()) { - logger.info("stop() started"); - } - - if (serverAcceptor != null) { - serverAcceptor.close(); - } - - if (worker != null) { - worker.shutdown(); - } - - if (logger.isInfoEnabled()) { - logger.info("stop() completed"); - } - } - - - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/PinpointPacketHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/PinpointPacketHandler.java deleted file mode 100644 index 4b537e6dfb26..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/PinpointPacketHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.tcp; - -import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.packet.BasicPacket; - -/** - * @author Taejin Koo - */ -public interface PinpointPacketHandler

{ - - void handle(P packet, PinpointSocket pinpointSocket); - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/RequestPacketHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/RequestPacketHandler.java deleted file mode 100644 index 034ffbe5ecf2..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/RequestPacketHandler.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.tcp; - -import com.navercorp.pinpoint.collector.receiver.DispatchHandler; -import com.navercorp.pinpoint.collector.util.PacketUtils; -import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; -import com.navercorp.pinpoint.thrift.io.DeserializerFactory; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; -import com.navercorp.pinpoint.thrift.io.SerializerFactory; -import com.navercorp.pinpoint.thrift.io.ThreadLocalHeaderTBaseDeserializerFactory; -import com.navercorp.pinpoint.thrift.io.ThreadLocalHeaderTBaseSerializerFactory; -import com.navercorp.pinpoint.thrift.util.SerializationUtils; -import org.apache.thrift.TBase; -import org.apache.thrift.TException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.SocketAddress; -import java.util.Objects; - -/** - * @author Taejin Koo - */ -public class RequestPacketHandler implements PinpointPacketHandler { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - - private final DispatchHandler dispatchHandler; - - private final SerializerFactory serializerFactory; - private final DeserializerFactory deserializerFactory; - - public RequestPacketHandler(DispatchHandler dispatchHandler) { - this(dispatchHandler, new ThreadLocalHeaderTBaseSerializerFactory<>(new HeaderTBaseSerializerFactory(true, HeaderTBaseSerializerFactory.DEFAULT_UDP_STREAM_MAX_SIZE))); - } - - public RequestPacketHandler(DispatchHandler dispatchHandler, SerializerFactory serializerFactory) { - this(dispatchHandler, serializerFactory, new ThreadLocalHeaderTBaseDeserializerFactory<>(new HeaderTBaseDeserializerFactory())); - } - - public RequestPacketHandler(DispatchHandler dispatchHandler, DeserializerFactory deserializerFactory) { - this(dispatchHandler, new ThreadLocalHeaderTBaseSerializerFactory<>(new HeaderTBaseSerializerFactory(true, HeaderTBaseSerializerFactory.DEFAULT_UDP_STREAM_MAX_SIZE)), deserializerFactory); - } - - public RequestPacketHandler(DispatchHandler dispatchHandler, SerializerFactory serializerFactory, DeserializerFactory deserializerFactory) { - this.dispatchHandler = Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); - this.serializerFactory = Objects.requireNonNull(serializerFactory, "serializerFactory must not be null"); - this.deserializerFactory = Objects.requireNonNull(deserializerFactory, "deserializerFactory must not be null"); - } - - @Override - public void handle(RequestPacket packet, PinpointSocket pinpointSocket) { - Objects.requireNonNull(packet, "packet must not be null"); - Objects.requireNonNull(pinpointSocket, "pinpointSocket must not be null"); - - byte[] payload = packet.getPayload(); - Objects.requireNonNull(payload, "payload must not be null"); - - SocketAddress remoteAddress = pinpointSocket.getRemoteAddress(); - try { - TBase tBase = SerializationUtils.deserialize(payload, deserializerFactory); - TBase result = dispatchHandler.dispatchRequestMessage(tBase); - if (result != null) { - byte[] resultBytes = SerializationUtils.serialize(result, serializerFactory); - pinpointSocket.response(packet, resultBytes); - } - } catch (TException e) { - if (logger.isWarnEnabled()) { - logger.warn("packet serialize error. remote:{} cause:{}", remoteAddress, e.getMessage(), e); - } - if (isDebug) { - logger.debug("packet dump hex:{}", PacketUtils.dumpByteArray(payload)); - } - } catch (Exception e) { - // there are cases where invalid headers are received - if (logger.isWarnEnabled()) { - logger.warn("Unexpected error. remote:{} cause:{}", remoteAddress, e.getMessage(), e); - } - if (isDebug) { - logger.debug("packet dump hex:{}", PacketUtils.dumpByteArray(payload)); - } - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/SendPacketHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/SendPacketHandler.java deleted file mode 100644 index 0d5f4aba852e..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/SendPacketHandler.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.tcp; - -import com.navercorp.pinpoint.collector.receiver.DispatchHandler; -import com.navercorp.pinpoint.collector.util.PacketUtils; -import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.packet.SendPacket; -import com.navercorp.pinpoint.thrift.io.DeserializerFactory; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; -import com.navercorp.pinpoint.thrift.io.ThreadLocalHeaderTBaseDeserializerFactory; -import com.navercorp.pinpoint.thrift.util.SerializationUtils; -import org.apache.thrift.TBase; -import org.apache.thrift.TException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.SocketAddress; -import java.util.Objects; - -/** - * @author Taejin Koo - */ -public class SendPacketHandler implements PinpointPacketHandler { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - - private final DispatchHandler dispatchHandler; - - private final DeserializerFactory deserializerFactory; - - public SendPacketHandler(DispatchHandler dispatchHandler) { - this(dispatchHandler, new ThreadLocalHeaderTBaseDeserializerFactory<>(new HeaderTBaseDeserializerFactory())); - } - - public SendPacketHandler(DispatchHandler dispatchHandler, DeserializerFactory deserializerFactory) { - this.dispatchHandler = Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); - this.deserializerFactory = Objects.requireNonNull(deserializerFactory, "deserializerFactory must not be null"); - } - - @Override - public void handle(SendPacket packet, PinpointSocket pinpointSocket) { - Objects.requireNonNull(packet, "packet must not be null"); - Objects.requireNonNull(pinpointSocket, "pinpointSocket must not be null"); - - byte[] payload = packet.getPayload(); - Objects.requireNonNull(payload, "payload must not be null"); - - SocketAddress remoteAddress = pinpointSocket.getRemoteAddress(); - try { - TBase tBase = SerializationUtils.deserialize(payload, deserializerFactory); - dispatchHandler.dispatchSendMessage(tBase); - } catch (TException e) { - if (logger.isWarnEnabled()) { - logger.warn("packet serialize error. remote:{} cause:{}", remoteAddress, e.getMessage(), e); - } - if (isDebug) { - logger.debug("packet dump hex:{}", PacketUtils.dumpByteArray(payload)); - } - } catch (Exception e) { - // there are cases where invalid headers are received - if (logger.isWarnEnabled()) { - logger.warn("Unexpected error. remote:{} cause:{}", remoteAddress, e.getMessage(), e); - } - if (isDebug) { - logger.debug("packet dump hex:{}", PacketUtils.dumpByteArray(payload)); - } - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/TCPReceiver.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/TCPReceiver.java deleted file mode 100644 index 9c26f7a416be..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/tcp/TCPReceiver.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.tcp; - -import com.navercorp.pinpoint.collector.receiver.DataReceiver; -import com.navercorp.pinpoint.collector.receiver.DispatchHandler; -import com.navercorp.pinpoint.collector.receiver.DispatchWorker; -import com.navercorp.pinpoint.collector.receiver.AddressFilterAdaptor; -import com.navercorp.pinpoint.common.server.util.AddressFilter; -import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; -import com.navercorp.pinpoint.rpc.packet.SendPacket; -import com.navercorp.pinpoint.rpc.server.ChannelFilter; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.ServerMessageListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.Objects; - -/** - * @author Taejin Koo - */ -public class TCPReceiver implements DataReceiver { - - private final Logger logger; - - private final String name; - - private final InetSocketAddress bindAddress; - private final AddressFilter ignoreAddressFilter; - - private PinpointServerAcceptor serverAcceptor; - - private final DispatchWorker worker; - - private final SendPacketHandler sendPacketHandler; - private final RequestPacketHandler requestPacketHandler; - - - public TCPReceiver(String name, DispatchHandler dispatchHandler, DispatchWorker worker, InetSocketAddress bindAddress, AddressFilter ignoreAddressFilter) { - this.name = Objects.requireNonNull(name, "name must not be null"); - logger = LoggerFactory.getLogger(name); - - this.bindAddress = Objects.requireNonNull(bindAddress, "bindAddress must not be null"); - - this.ignoreAddressFilter = Objects.requireNonNull(ignoreAddressFilter, "ignoreAddressFilter must not be null"); - this.worker = Objects.requireNonNull(worker, "worker must not be null"); - - Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); - this.sendPacketHandler = new SendPacketHandler(dispatchHandler); - this.requestPacketHandler = new RequestPacketHandler(dispatchHandler); - } - - @Override - public void start() { - if (logger.isInfoEnabled()) { - logger.info("{} start() started", name); - } - - ChannelFilter connectedFilter = new AddressFilterAdaptor(ignoreAddressFilter); - PinpointServerAcceptor acceptor = new PinpointServerAcceptor(connectedFilter); - - // take care when attaching message handlers as events are generated from the IO thread. - // pass them to a separate queue and handle them in a different thread. - acceptor.setMessageListener(new ServerMessageListener() { - - @Override - public HandshakeResponseCode handleHandshake(Map properties) { - return HandshakeResponseCode.SIMPLEX_COMMUNICATION; - } - - @Override - public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { - receive(sendPacket, pinpointSocket); - } - - @Override - public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - requestResponse(requestPacket, pinpointSocket); - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - } - - }); - acceptor.bind(bindAddress); - - this.serverAcceptor = acceptor; - - if (logger.isInfoEnabled()) { - logger.info("{} start() completed", name); - } - } - - private void receive(SendPacket sendPacket, PinpointSocket pinpointSocket) { - worker.execute(new Runnable() { - @Override - public void run() { - sendPacketHandler.handle(sendPacket, pinpointSocket); - } - }); - } - - private void requestResponse(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - worker.execute(new Runnable() { - @Override - public void run() { - requestPacketHandler.handle(requestPacket, pinpointSocket); - } - }); - } - - @Override - public void shutdown() { - if (logger.isInfoEnabled()) { - logger.info("{} shutdown() started", name); - } - - if (serverAcceptor != null) { - serverAcceptor.close(); - } - - if (logger.isInfoEnabled()) { - logger.info("{} shutdown() completed", name); - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/AddressFilterAdaptor.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/AddressFilterAdaptor.java new file mode 100644 index 000000000000..02dcc14fe92e --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/AddressFilterAdaptor.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.common.server.util.AddressFilter; +import com.navercorp.pinpoint.rpc.server.ChannelFilter; +import org.jboss.netty.channel.Channel; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Objects; + +/** + * @author Woonduk Kang(emeroad) + */ +public class AddressFilterAdaptor implements ChannelFilter { + private final AddressFilter filter; + + public AddressFilterAdaptor(AddressFilter filter) { + this.filter = Objects.requireNonNull(filter, "filter must not be null"); + } + + @Override + public boolean accept(Channel channel) { + final InetSocketAddress remoteAddress = (InetSocketAddress) channel.getRemoteAddress(); + if (remoteAddress == null) { + return true; + } + InetAddress address = remoteAddress.getAddress(); + return filter.accept(address); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/DelegateDispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/DelegateDispatchHandler.java new file mode 100644 index 000000000000..231797396752 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/DelegateDispatchHandler.java @@ -0,0 +1,84 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.collector.manage.HandlerManager; +import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.dto.TResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DelegateDispatchHandler implements DispatchHandler { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private AcceptedTimeService acceptedTimeService; + private final DispatchHandler delegate; + + private final HandlerManager handlerManager; + + public DelegateDispatchHandler(AcceptedTimeService acceptedTimeService, DispatchHandler delegate, HandlerManager handlerManager) { + this.acceptedTimeService = Objects.requireNonNull(acceptedTimeService, "acceptedTimeService must not be null"); + this.delegate = Objects.requireNonNull(delegate, "delegate must not be null"); + this.handlerManager = Objects.requireNonNull(handlerManager, "handlerManager must not be null"); + } + + + @Override + public void dispatchSendMessage(ServerRequest serverRequest) { + acceptedTimeService.accept(); + + if (!checkAvailable()) { + logger.debug("Handler is disabled. Skipping send message {}.", serverRequest); + return; + } + + this.delegate.dispatchSendMessage(serverRequest); + } + + + @Override + public void dispatchRequestMessage(ServerRequest serverRequest, ServerResponse serverResponse) { + acceptedTimeService.accept(); + + if (!checkAvailable()) { + logger.debug("Handler is disabled. Skipping request message {}.", serverRequest); + TResult result = new TResult(false); + result.setMessage("Handler is disabled. Skipping request message."); + serverResponse.write(result); + return; + } + + delegate.dispatchRequestMessage(serverRequest, serverResponse); + + } + + + private boolean checkAvailable() { + if (handlerManager.isEnable()) { + return true; + } + + return false; + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/DispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/DispatchHandler.java new file mode 100644 index 000000000000..2880d5db2509 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/DispatchHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import org.apache.thrift.TBase; + +/** + * @author emeroad + * @author koo.taejin + */ +public interface DispatchHandler { + + // Separating Send and Request. That dose not be satisfied but try to change that later. + void dispatchSendMessage(ServerRequest serverRequest); + + void dispatchRequestMessage(ServerRequest serverRequest, ServerResponse serverResponse); + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/DispatchHandlerFactoryBean.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/DispatchHandlerFactoryBean.java new file mode 100644 index 000000000000..c0b9a99f13c6 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/DispatchHandlerFactoryBean.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; + +import com.navercorp.pinpoint.collector.manage.HandlerManager; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Objects; + +/** + * @author Taejin Koo + */ +public class DispatchHandlerFactoryBean implements FactoryBean { + + @Autowired + private AcceptedTimeService acceptedTimeService; + private final DispatchHandler delegate; + + private final HandlerManager handlerManager; + + public DispatchHandlerFactoryBean(DispatchHandler delegate, HandlerManager handlerManager) { + this.delegate = Objects.requireNonNull(delegate, "delegate must not be null"); + this.handlerManager = Objects.requireNonNull(handlerManager, "handlerManager must not be null"); + } + + + + + @Override + public DispatchHandler getObject() throws Exception { + return new DelegateDispatchHandler(acceptedTimeService, delegate, handlerManager); + } + + @Override + public Class getObjectType() { + return DispatchHandler.class; + } + + @Override + public boolean isSingleton() { + return true; + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/ExecutorFactoryBean.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/ExecutorFactoryBean.java new file mode 100644 index 000000000000..760a90444bfd --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/ExecutorFactoryBean.java @@ -0,0 +1,132 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.codahale.metrics.Gauge; +import com.codahale.metrics.MetricRegistry; +import com.navercorp.pinpoint.collector.monitor.CountingRejectedExecutionHandler; +import com.navercorp.pinpoint.collector.monitor.MonitoredThreadPoolExecutor; +import com.navercorp.pinpoint.collector.monitor.LoggingRejectedExecutionHandler; +import com.navercorp.pinpoint.collector.monitor.RejectedExecutionHandlerChain; +import com.navercorp.pinpoint.collector.monitor.MonitoredRunnableDecorator; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ExecutorFactoryBean extends org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean { + + private int logRate = 100; + private String beanName; + + private MetricRegistry registry; + private boolean preStartAllCoreThreads; + + public ExecutorFactoryBean() { + } + + + @Override + public void setBeanName(String name) { + super.setBeanName(name); + this.beanName = name; + } + + + + @Override + protected ThreadPoolExecutor createExecutor( + int corePoolSize, int maxPoolSize, int keepAliveSeconds, BlockingQueue queue, + ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + + final ThreadPoolExecutor threadPoolExecutor = newThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveSeconds, queue, threadFactory, rejectedExecutionHandler); + if (preStartAllCoreThreads) { + threadPoolExecutor.prestartAllCoreThreads(); + } + return threadPoolExecutor; + } + + private ThreadPoolExecutor newThreadPoolExecutor(int corePoolSize, int maxPoolSize, int keepAliveSeconds, BlockingQueue queue, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + if (registry != null) { + return newMonitoredExecutorService(corePoolSize, maxPoolSize, keepAliveSeconds, queue, threadFactory, rejectedExecutionHandler); + } + + return new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveSeconds, TimeUnit.MILLISECONDS, queue, threadFactory, rejectedExecutionHandler); + } + + private ThreadPoolExecutor newMonitoredExecutorService(int corePoolSize, int maxPoolSize, int keepAliveSeconds, BlockingQueue queue, + ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + + rejectedExecutionHandler = wrapHandlerChain(rejectedExecutionHandler); + MonitoredRunnableDecorator monitoredRunnableDecorator = new MonitoredRunnableDecorator(beanName, registry); + + MonitoredThreadPoolExecutor monitoredThreadPoolExecutor = new MonitoredThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveSeconds, TimeUnit.MILLISECONDS, + queue, threadFactory, rejectedExecutionHandler, monitoredRunnableDecorator); + + + Gauge runningGauge = () -> (long) monitoredThreadPoolExecutor.getActiveCount(); + this.registry.register(MetricRegistry.name(beanName, "running"), runningGauge); + + Gauge completedTaskGauge = () -> (long) monitoredThreadPoolExecutor.getCompletedTaskCount(); + this.registry.register(MetricRegistry.name(beanName, "completed"), completedTaskGauge); + + return monitoredThreadPoolExecutor; + } + + private RejectedExecutionHandler wrapHandlerChain(RejectedExecutionHandler rejectedExecutionHandler) { + + final List handlerList = new ArrayList<>(); + if (registry != null) { + RejectedExecutionHandler countingHandler = new CountingRejectedExecutionHandler(beanName, registry); + handlerList.add(countingHandler); + } + + if (logRate > -1) { + RejectedExecutionHandler loggingHandler = new LoggingRejectedExecutionHandler(beanName, logRate); + handlerList.add(loggingHandler); + } + + // original exception policy + handlerList.add(rejectedExecutionHandler); + + if (handlerList.isEmpty()) { + return rejectedExecutionHandler; + } + return RejectedExecutionHandlerChain.build(handlerList); + } + + + public void setPreStartAllCoreThreads(boolean preStartAllCoreThreads) { + this.preStartAllCoreThreads = preStartAllCoreThreads; + } + + public void setRegistry(MetricRegistry registry) { + this.registry = registry; + } + + public void setLogRate(int logRate) { + this.logRate = logRate; + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/PinpointServerAcceptorProvider.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/PinpointServerAcceptorProvider.java new file mode 100644 index 000000000000..efaecef1b5dd --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/PinpointServerAcceptorProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.PipelineFactory; +import com.navercorp.pinpoint.rpc.cluster.ClusterOption; +import com.navercorp.pinpoint.rpc.server.ChannelFilter; +import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; +import com.navercorp.pinpoint.rpc.server.ServerCodecPipelineFactory; +import com.navercorp.pinpoint.rpc.server.ServerOption; + +/** + * @author Taejin Koo + */ +public class PinpointServerAcceptorProvider { + + private ServerOption serverOption = ServerOption.getDefaultServerOption(); + private ChannelFilter channelFilter = ChannelFilter.BYPASS; + private PipelineFactory pipelineFactory = new ServerCodecPipelineFactory(); + + public PinpointServerAcceptor get() { + return new PinpointServerAcceptor(serverOption, channelFilter, pipelineFactory); + } + + public void setServerOption(ServerOption serverOption) { + this.serverOption = Assert.requireNonNull(serverOption, "serverOption must not be null"); + } + + public void setChannelFilter(ChannelFilter channelFilter) { + this.channelFilter = Assert.requireNonNull(channelFilter, "channelFilter must not be null"); + } + + public void setPipelineFactory(PipelineFactory pipelineFactory) { + this.pipelineFactory = Assert.requireNonNull(pipelineFactory, "pipelineFactory must not be null"); + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/SpanDispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/SpanDispatchHandler.java new file mode 100644 index 000000000000..cceb11d97126 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/SpanDispatchHandler.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.collector.handler.thrift.ThriftSpanChunkHandler; +import com.navercorp.pinpoint.collector.handler.thrift.ThriftSpanHandler; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.io.DefaultTBaseLocator; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author emeroad + */ +public class SpanDispatchHandler implements DispatchHandler { + + @Autowired() + private ThriftSpanHandler spanDataHandler; + + @Autowired() + private ThriftSpanChunkHandler thriftSpanChunkHandler; + + public SpanDispatchHandler() { + } + + + private SimpleHandler getSimpleHandler(Header header) { + final short type = header.getType(); + if (type == DefaultTBaseLocator.SPAN) { + return spanDataHandler; + } + if (type == DefaultTBaseLocator.SPANCHUNK) { + return thriftSpanChunkHandler; + } + + throw new UnsupportedOperationException("unsupported header:" + header); + } + + @Override + public void dispatchSendMessage(ServerRequest serverRequest) { + SimpleHandler simpleHandler = getSimpleHandler(serverRequest.getHeader()); + simpleHandler.handleSimple(serverRequest); + } + + + @Override + public void dispatchRequestMessage(ServerRequest serverRequest, ServerResponse serverResponse) { + + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/StatDispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/StatDispatchHandler.java new file mode 100644 index 000000000000..d3d54327b998 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/StatDispatchHandler.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.collector.handler.thrift.ThriftAgentEventHandler; +import com.navercorp.pinpoint.collector.handler.thrift.ThriftAgentStatHandlerV2; +import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.collector.handler.SimpleDualHandler; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.io.DefaultTBaseLocator; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author emeroad + * @author hyungil.jeong + */ +public class StatDispatchHandler implements DispatchHandler { + + @Autowired + private ThriftAgentStatHandlerV2 thriftAgentStatHandler; + + @Autowired + private ThriftAgentEventHandler thriftAgentEventHandler; + + + public StatDispatchHandler() { + + } + + private SimpleHandler getSimpleHandler(Header header) { + // To change below code to switch table make it a little bit faster. + // FIXME (2014.08) Legacy - TAgentStats should not be sent over the wire. + final short type = header.getType(); + if (type == DefaultTBaseLocator.AGENT_STAT || type == DefaultTBaseLocator.AGENT_STAT_BATCH) { + return new SimpleDualHandler(thriftAgentStatHandler, thriftAgentEventHandler); + } + + throw new UnsupportedOperationException("unsupported header:" + header); + } + + @Override + public void dispatchSendMessage(ServerRequest serverRequest) { + SimpleHandler simpleHandler = getSimpleHandler(serverRequest.getHeader()); + simpleHandler.handleSimple(serverRequest); + } + + @Override + public void dispatchRequestMessage(ServerRequest serverRequest, ServerResponse serverResponse) { + + } + + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/TCPReceiverBean.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/TCPReceiverBean.java new file mode 100644 index 000000000000..a1f4d54268fe --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/TCPReceiverBean.java @@ -0,0 +1,128 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.collector.receiver.thrift.tcp.DefaultTCPPacketHandlerFactory; +import com.navercorp.pinpoint.collector.receiver.thrift.tcp.TCPPacketHandler; +import com.navercorp.pinpoint.collector.receiver.thrift.tcp.TCPPacketHandlerFactory; +import com.navercorp.pinpoint.collector.receiver.thrift.tcp.DefaultTCPReceiver; +import com.navercorp.pinpoint.collector.receiver.thrift.tcp.TCPReceiver; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; + +import java.net.InetSocketAddress; +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * @author Woonduk Kang(emeroad) + */ +public class TCPReceiverBean implements InitializingBean, DisposableBean, BeanNameAware { + private String beanName; + + private boolean enable = true; + + private String bindIp; + private int bindPort; + + private TCPReceiver tcpReceiver; + private Executor executor; + + private PinpointServerAcceptorProvider acceptorProvider; + + private DispatchHandler dispatchHandler; + + private TCPPacketHandlerFactory tcpPacketHandlerFactory; + + @Override + public void afterPropertiesSet() throws Exception { + if (!enable) { + return; + } + Objects.requireNonNull(beanName, "beanName must not be null"); + Objects.requireNonNull(bindIp, "bindIp must not be null"); + Objects.requireNonNull(executor, "executor must not be null"); + Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); + Objects.requireNonNull(acceptorProvider, "acceptorProvider must not be null"); + + tcpReceiver = createTcpReceiver(beanName, this.bindIp, bindPort, executor, dispatchHandler, this.tcpPacketHandlerFactory, acceptorProvider); + tcpReceiver.start(); + } + + protected TCPReceiver createTcpReceiver(String beanName, String bindIp, int port, Executor executor, + DispatchHandler dispatchHandler, TCPPacketHandlerFactory tcpPacketHandlerFactory, PinpointServerAcceptorProvider acceptorProvider) { + InetSocketAddress bindAddress = new InetSocketAddress(bindIp, port); + TCPPacketHandler tcpPacketHandler = wrapDispatchHandler(dispatchHandler, tcpPacketHandlerFactory); + + return new DefaultTCPReceiver(beanName, tcpPacketHandler, executor, bindAddress, acceptorProvider); + } + + private TCPPacketHandler wrapDispatchHandler(DispatchHandler dispatchHandler, TCPPacketHandlerFactory tcpPacketHandlerFactory) { + if (tcpPacketHandlerFactory == null) { + // using default Factory + tcpPacketHandlerFactory = new DefaultTCPPacketHandlerFactory(); + } + return tcpPacketHandlerFactory.build(dispatchHandler); + } + + + @Override + public void destroy() throws Exception { + if (!enable) { + return; + } + if (tcpReceiver != null) { + tcpReceiver.shutdown(); + } + } + + public void setExecutor(Executor executor) { + this.executor = Objects.requireNonNull(executor, "executor must not be null"); + } + + public void setDispatchHandler(DispatchHandler dispatchHandler) { + this.dispatchHandler = dispatchHandler; + } + + public void setTcpPacketHandlerFactory(TCPPacketHandlerFactory tcpPacketHandlerFactory) { + this.tcpPacketHandlerFactory = tcpPacketHandlerFactory; + } + + public void setBindIp(String bindIp) { + this.bindIp = Objects.requireNonNull(bindIp, "bindIp must not be null"); + } + + public void setBindPort(int bindPort) { + this.bindPort = bindPort; + } + + + @Override + public void setBeanName(String name) { + this.beanName = name; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public void setAcceptorProvider(PinpointServerAcceptorProvider acceptorProvider) { + this.acceptorProvider = acceptorProvider; + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/TcpDispatchHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/TcpDispatchHandler.java new file mode 100644 index 000000000000..c000d21ce61d --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/TcpDispatchHandler.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.collector.handler.thrift.ThriftAgentInfoHandler; +import com.navercorp.pinpoint.collector.handler.RequestResponseHandler; +import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.collector.handler.thrift.ThriftApiMetaDataHandler; +import com.navercorp.pinpoint.collector.handler.thrift.ThriftSqlMetaDataHandler; +import com.navercorp.pinpoint.collector.handler.thrift.ThriftStringMetaDataHandler; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.io.DefaultTBaseLocator; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author emeroad + * @author koo.taejin + */ +public class TcpDispatchHandler implements DispatchHandler { + + @Autowired + private ThriftAgentInfoHandler thriftAgentInfoHandler; + + @Autowired + private ThriftSqlMetaDataHandler thriftSqlMetaDataHandler; + + @Autowired + private ThriftApiMetaDataHandler thriftApiMetaDataHandler; + + @Autowired + private ThriftStringMetaDataHandler thriftStringMetaDataHandler; + + public TcpDispatchHandler() { + } + + protected RequestResponseHandler getRequestResponseHandler(ServerRequest serverRequest) { + final Header header = serverRequest.getHeader(); + final short type = header.getType(); + if (type == DefaultTBaseLocator.SQLMETADATA) { + return thriftSqlMetaDataHandler; + } + if (type == DefaultTBaseLocator.APIMETADATA) { + return thriftApiMetaDataHandler; + } + if (type == DefaultTBaseLocator.STRINGMETADATA) { + return thriftStringMetaDataHandler; + } + if (type == DefaultTBaseLocator.AGENT_INFO) { + return thriftAgentInfoHandler; + } + throw new UnsupportedOperationException("unsupported header:" + header); + } + + private SimpleHandler getSimpleHandler(Header header) { + final short type = header.getType(); + if (type == DefaultTBaseLocator.AGENT_INFO) { + return thriftAgentInfoHandler; + } + + throw new UnsupportedOperationException("unsupported header:" + header); + } + + @Override + public void dispatchSendMessage(ServerRequest serverRequest) { + final Header header = serverRequest.getHeader(); + SimpleHandler simpleHandler = getSimpleHandler(header); + simpleHandler.handleSimple(serverRequest); + } + + @Override + public void dispatchRequestMessage(ServerRequest serverRequest, ServerResponse serverResponse) { + RequestResponseHandler requestResponseHandler = getRequestResponseHandler(serverRequest); + requestResponseHandler.handleRequest(serverRequest, serverResponse); + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/UDPReceiverBean.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/UDPReceiverBean.java new file mode 100644 index 000000000000..c7d5c4e3d7a6 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/UDPReceiverBean.java @@ -0,0 +1,144 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift; + +import com.navercorp.pinpoint.collector.receiver.thrift.udp.BaseUDPHandlerFactory; +import com.navercorp.pinpoint.collector.receiver.thrift.udp.NetworkAvailabilityCheckPacketFilter; +import com.navercorp.pinpoint.collector.receiver.thrift.udp.PacketHandlerFactory; +import com.navercorp.pinpoint.collector.receiver.thrift.udp.TBaseFilter; +import com.navercorp.pinpoint.collector.receiver.thrift.udp.TBaseFilterChain; +import com.navercorp.pinpoint.collector.receiver.thrift.udp.UDPReceiver; +import com.navercorp.pinpoint.collector.util.DatagramPacketFactory; +import com.navercorp.pinpoint.collector.util.DefaultObjectPool; +import com.navercorp.pinpoint.collector.util.ObjectPool; +import com.navercorp.pinpoint.collector.util.ObjectPoolFactory; +import com.navercorp.pinpoint.common.server.util.AddressFilter; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; + +import java.net.DatagramPacket; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * @author Woonduk Kang(emeroad) + */ +public class UDPReceiverBean implements InitializingBean, DisposableBean, BeanNameAware { + + private String beanName; + + private boolean enable = true; + + private String bindIp; + private int bindPort; + private int udpBufferSize; + + private UDPReceiver udpReceiver; + private Executor executor; + + private DispatchHandler dispatchHandler; + private AddressFilter addressFilter; + private int datagramPoolSize = 1024*4; + + + @Override + public void afterPropertiesSet() throws Exception { + if (!enable) { + return; + } + Objects.requireNonNull(beanName, "beanName must not be null"); + Objects.requireNonNull(bindIp, "bindIp must not be null"); + Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); + Objects.requireNonNull(addressFilter, "addressFilter must not be null"); + Objects.requireNonNull(executor, "executor must not be null"); + + udpReceiver = createUdpReceiver(beanName, this.bindIp, bindPort, udpBufferSize, executor, dispatchHandler, addressFilter); + udpReceiver.start(); + } + + + private UDPReceiver createUdpReceiver(String name, String bindIp, int port, int udpBufferSize, Executor executor, DispatchHandler dispatchHandler, AddressFilter ignoreAddressFilter) { + TBaseFilterChain filterChain = newTBaseFilterChain(); + @SuppressWarnings("unchecked") + PacketHandlerFactory packetHandlerFactory = new BaseUDPHandlerFactory(dispatchHandler, filterChain, ignoreAddressFilter); + + InetSocketAddress bindAddress = new InetSocketAddress(bindIp, port); + + ObjectPoolFactory packetFactory = new DatagramPacketFactory(); + ObjectPool pool = new DefaultObjectPool<>(packetFactory, datagramPoolSize); + return new UDPReceiver(name, packetHandlerFactory, executor, udpBufferSize, bindAddress, pool); + } + + + private TBaseFilterChain newTBaseFilterChain() { + List tBaseFilters = Collections.singletonList(new NetworkAvailabilityCheckPacketFilter()); + @SuppressWarnings("unchecked") + TBaseFilterChain tBaseFilterChain = new TBaseFilterChain(tBaseFilters); + return tBaseFilterChain; + } + + @Override + public void destroy() throws Exception { + if (!enable) { + return; + } + if (udpReceiver != null) { + udpReceiver.shutdown(); + } + } + + public void setExecutor(Executor executor) { + this.executor = Objects.requireNonNull(executor, "executor must not be null"); + } + + public void setDispatchHandler(DispatchHandler dispatchHandler) { + this.dispatchHandler = Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); + } + + public void setAddressFilter(AddressFilter addressFilter) { + this.addressFilter = Objects.requireNonNull(addressFilter, "addressFilter must not be null"); + } + + public void setBindIp(String bindIp) { + this.bindIp = Objects.requireNonNull(bindIp, "bindIp must not be null"); + } + + public void setBindPort(int bindPort) { + this.bindPort = bindPort; + } + + public void setUdpBufferSize(int udpBufferSize) { + this.udpBufferSize = udpBufferSize; + } + + public void setDatagramPoolSize(int datagramPoolSize) { + this.datagramPoolSize = datagramPoolSize; + } + + @Override + public void setBeanName(String name) { + this.beanName = name; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentBaseDataReceiver.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentBaseDataReceiver.java new file mode 100644 index 000000000000..cfd93b509173 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentBaseDataReceiver.java @@ -0,0 +1,136 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.cluster.zookeeper.ZookeeperClusterService; +import com.navercorp.pinpoint.collector.config.AgentBaseDataReceiverConfiguration; +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; +import com.navercorp.pinpoint.rpc.server.handler.ServerStateChangeEventHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * @author emeroad + * @author koo.taejin + */ +public class AgentBaseDataReceiver { + + private final Logger logger = LoggerFactory.getLogger(AgentBaseDataReceiver.class); + + private PinpointServerAcceptor acceptor; + + private final AgentBaseDataReceiverConfiguration configuration; + + private final ZookeeperClusterService clusterService; + + private final Executor executor; + + private final TCPPacketHandlerFactory tcpPacketHandlerFactory; + + private final TCPPacketHandler tcpPacketHandler; + + @Autowired + private AgentEventHandler agentEventHandler; + + @Autowired + private AgentLifeCycleEventHandler agentLifeCycleEventHandler; + + @Resource(name = "channelStateChangeEventHandlers") + private List channelStateChangeEventHandlers = Collections.emptyList(); + + public AgentBaseDataReceiver(AgentBaseDataReceiverConfiguration configuration, Executor executor, PinpointServerAcceptor acceptor, DispatchHandler dispatchHandler) { + this(configuration, executor, acceptor, dispatchHandler, null); + } + + public AgentBaseDataReceiver(AgentBaseDataReceiverConfiguration configuration, Executor executor, PinpointServerAcceptor acceptor, DispatchHandler dispatchHandler, ZookeeperClusterService service) { + this(configuration, executor, acceptor, new DefaultTCPPacketHandlerFactory(), dispatchHandler, service); + } + + public AgentBaseDataReceiver(AgentBaseDataReceiverConfiguration configuration, Executor executor, PinpointServerAcceptor acceptor, TCPPacketHandlerFactory tcpPacketHandlerFactory, DispatchHandler dispatchHandler, ZookeeperClusterService service) { + this.configuration = Assert.requireNonNull(configuration, "config must not be null"); + this.executor = Objects.requireNonNull(executor, "executor must not be null"); + this.acceptor = Objects.requireNonNull(acceptor, "acceptor must not be null"); + + this.tcpPacketHandlerFactory = Assert.requireNonNull(tcpPacketHandlerFactory, "tcpPacketHandlerFactory must not be null"); + this.tcpPacketHandler = wrapDispatchHandler(dispatchHandler); + this.clusterService = service; + } + + private TCPPacketHandler wrapDispatchHandler(DispatchHandler dispatchHandler) { + Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); + return tcpPacketHandlerFactory.build(dispatchHandler); + } + + @PostConstruct + public void start() { + if (logger.isInfoEnabled()) { + logger.info("start() started"); + } + + prepare(acceptor); + + // take care when attaching message handlers as events are generated from the IO thread. + // pass them to a separate queue and handle them in a different thread. + acceptor.setMessageListenerFactory(new AgentBaseDataReceiverServerMessageListenerFactory(executor, tcpPacketHandler, agentEventHandler, agentLifeCycleEventHandler)); + acceptor.bind(configuration.getBindIp(), configuration.getBindPort()); + + if (logger.isInfoEnabled()) { + logger.info("start() completed"); + } + } + + private void prepare(PinpointServerAcceptor acceptor) { + if (clusterService != null && clusterService.isEnable()) { + final ServerStateChangeEventHandler channelStateChangeEventHandler = clusterService.getChannelStateChangeEventHandler(); + logger.info("Add Cluster channel state change event handlers {}", channelStateChangeEventHandler); + acceptor.addStateChangeEventHandler(channelStateChangeEventHandler); + } else { + logger.info("clusterService is disabled"); + } + + for (ServerStateChangeEventHandler channelStateChangeEventHandler : this.channelStateChangeEventHandlers) { + logger.info("Add channel state change event handlers {}", channelStateChangeEventHandler); + acceptor.addStateChangeEventHandler(channelStateChangeEventHandler); + } + } + + @PreDestroy + public void stop() { + if (logger.isInfoEnabled()) { + logger.info("stop() started"); + } + + if (acceptor != null) { + acceptor.close(); + } + + if (logger.isInfoEnabled()) { + logger.info("stop() completed"); + } + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentBaseDataReceiverServerMessageListenerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentBaseDataReceiverServerMessageListenerFactory.java new file mode 100644 index 000000000000..4f67cf251397 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentBaseDataReceiverServerMessageListenerFactory.java @@ -0,0 +1,133 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.common.server.util.AgentEventType; +import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; +import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; +import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.rpc.packet.SendPacket; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.rpc.server.ServerMessageListenerFactory; +import com.navercorp.pinpoint.rpc.util.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * @author Taejin Koo + */ +class AgentBaseDataReceiverServerMessageListenerFactory implements ServerMessageListenerFactory { + + private final Executor executor; + private final TCPPacketHandler tcpPacketHandler; + private final AgentEventHandler agentEventHandler; + private final AgentLifeCycleEventHandler agentLifeCycleEventHandler; + + public AgentBaseDataReceiverServerMessageListenerFactory(Executor executor, TCPPacketHandler tcpPacketHandler, AgentEventHandler agentEventHandler, AgentLifeCycleEventHandler agentLifeCycleEventHandler) { + this.executor = Assert.requireNonNull(executor, "executor must not be null"); + this.tcpPacketHandler = Assert.requireNonNull(tcpPacketHandler, "tcpPacketHandler must not be null"); + this.agentEventHandler = Assert.requireNonNull(agentEventHandler, "agentEventTask must not be null"); + this.agentLifeCycleEventHandler = Assert.requireNonNull(agentLifeCycleEventHandler, "agentLifeCycleTask must not be null"); + } + + @Override + public ServerMessageListener create() { + return new AgentBaseDataReceiverServerMessageListener(executor, tcpPacketHandler, agentEventHandler, agentLifeCycleEventHandler); + } + + + private static class AgentBaseDataReceiverServerMessageListener implements ServerMessageListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final Executor executor; + private final TCPPacketHandler tcpPacketHandler; + private final AgentEventHandler agentEventHandler; + private final AgentLifeCycleEventHandler agentLifeCycleEventHandler; + + private AgentBaseDataReceiverServerMessageListener(Executor executor, TCPPacketHandler tcpPacketHandler, AgentEventHandler agentEventHandler, AgentLifeCycleEventHandler agentLifeCycleEventHandler) { + this.executor = Assert.requireNonNull(executor, "executor must not be null"); + this.tcpPacketHandler = Assert.requireNonNull(tcpPacketHandler, "tcpPacketHandler must not be null"); + this.agentEventHandler = Assert.requireNonNull(agentEventHandler, "agentEventTask must not be null"); + this.agentLifeCycleEventHandler = Assert.requireNonNull(agentLifeCycleEventHandler, "agentLifeCycleTask must not be null"); + } + + @Override + public HandshakeResponseCode handleHandshake(Map properties) { + if (properties == null) { + return HandshakeResponseType.ProtocolError.PROTOCOL_ERROR; + } + + boolean hasRequiredKeys = HandshakePropertyType.hasRequiredKeys(properties); + if (!hasRequiredKeys) { + return HandshakeResponseType.PropertyError.PROPERTY_ERROR; + } + + boolean supportServer = MapUtils.getBoolean(properties, HandshakePropertyType.SUPPORT_SERVER.getName(), true); + if (supportServer) { + return HandshakeResponseType.Success.DUPLEX_COMMUNICATION; + } else { + return HandshakeResponseType.Success.SIMPLEX_COMMUNICATION; + } + } + + @Override + public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { + executor.execute(new Runnable() { + @Override + public void run() { + tcpPacketHandler.handleSend(sendPacket, pinpointSocket); + } + }); + } + + @Override + public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { + executor.execute(new Runnable() { + @Override + public void run() { + tcpPacketHandler.handleRequest(requestPacket, pinpointSocket); + } + }); + } + + @Override + public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { + final int eventCounter = pingPacket.getPingId(); + long pingTimestamp = System.currentTimeMillis(); + try { + if (!(eventCounter < 0)) { + agentLifeCycleEventHandler.handleLifeCycleEvent(pinpointServer, pingTimestamp, AgentLifeCycleState.RUNNING, eventCounter); + } + agentEventHandler.handleEvent(pinpointServer, pingTimestamp, AgentEventType.AGENT_PING); + } catch (Exception e) { + logger.warn("Error handling ping event", e); + } + } + + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentEventHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentEventHandler.java new file mode 100644 index 000000000000..4e488f0a3fd0 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentEventHandler.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.service.AgentEventService; +import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; +import com.navercorp.pinpoint.common.server.util.AgentEventType; +import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import org.apache.commons.collections.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.Objects; + +/** + * @author HyunGil Jeong + * @author jaehong.kim - Remove AgentEventMessageSerializer + */ +@Service +public class AgentEventHandler { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private AgentEventService agentEventService; + + @Async("agentEventWorker") + public void handleEvent(PinpointServer pinpointServer, long eventTimestamp, AgentEventType eventType) { + Objects.requireNonNull(pinpointServer, "pinpointServer must not be null"); + Objects.requireNonNull(eventType, "pinpointServer must not be null"); + + final Map channelProperties = pinpointServer.getChannelProperties(); + if (MapUtils.isEmpty(channelProperties)) { + // It can occurs CONNECTED -> RUN_WITHOUT_HANDSHAKE -> CLOSED(UNEXPECTED_CLOSE_BY_CLIENT, ERROR_UNKNOWN) + logger.warn("maybe not yet received the handshake data - pinpointServer:{}", pinpointServer); + return; + } + + final String agentId = MapUtils.getString(channelProperties, HandshakePropertyType.AGENT_ID.getName()); + final long startTimestamp = MapUtils.getLong(channelProperties, HandshakePropertyType.START_TIMESTAMP.getName()); + final AgentEventBo agentEventBo = newAgentEventBo(agentId, startTimestamp, eventTimestamp, eventType); + this.agentEventService.insert(agentEventBo); + } + + private AgentEventBo newAgentEventBo(String agentId, long startTimestamp, long eventTimestamp, AgentEventType eventType) { + final AgentEventBo agentEventBo = new AgentEventBo(agentId, startTimestamp, eventTimestamp, eventType); + agentEventBo.setEventBody(new byte[0]); + return agentEventBo; + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleChangeEventHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleChangeEventHandler.java similarity index 77% rename from collector/src/main/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleChangeEventHandler.java rename to collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleChangeEventHandler.java index d491a0deb5e9..464b1a71e55c 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleChangeEventHandler.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleChangeEventHandler.java @@ -1,69 +1,65 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.rpc.handler; - -import com.navercorp.pinpoint.collector.service.AgentEventService; -import com.navercorp.pinpoint.collector.util.ManagedAgentLifeCycle; -import com.navercorp.pinpoint.common.server.util.AgentEventType; -import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; -import com.navercorp.pinpoint.rpc.common.SocketStateCode; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.handler.ServerStateChangeEventHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -/** - * @author HyunGil Jeong - */ -public class AgentLifeCycleChangeEventHandler implements ServerStateChangeEventHandler { - - public static final ManagedAgentLifeCycle STATE_NOT_MANAGED = null; - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Autowired - private AgentLifeCycleHandler agentLifeCycleHandler; - - @Autowired - private AgentEventService agentEventService; - - @Override - public void eventPerformed(PinpointServer pinpointServer, SocketStateCode stateCode) throws Exception { - ManagedAgentLifeCycle managedAgentLifeCycle = ManagedAgentLifeCycle.getManagedAgentLifeCycleByStateCode(stateCode); - if (managedAgentLifeCycle == STATE_NOT_MANAGED) { - return; - } else { - logger.info("{} eventPerformed(). pinpointServer:{}, code:{}", this.getClass().getSimpleName(), pinpointServer, stateCode); - - long eventTimestamp = System.currentTimeMillis(); - - AgentLifeCycleState agentLifeCycleState = managedAgentLifeCycle.getMappedState(); - this.agentLifeCycleHandler.handleLifeCycleEvent(pinpointServer, eventTimestamp, agentLifeCycleState, managedAgentLifeCycle.getEventCounter()); - - AgentEventType agentEventType = managedAgentLifeCycle.getMappedEvent(); - this.agentEventService.handleEvent(pinpointServer, eventTimestamp, agentEventType); - } - } - - @Override - public void exceptionCaught(PinpointServer pinpointServer, SocketStateCode stateCode, Throwable e) { - logger.warn("{} exceptionCaught(). pinpointServer:{}, code:{}. error: {}.", - this.getClass().getSimpleName(), pinpointServer, stateCode, e.getMessage(), e); - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.util.ManagedAgentLifeCycle; +import com.navercorp.pinpoint.common.server.util.AgentEventType; +import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; +import com.navercorp.pinpoint.rpc.common.SocketStateCode; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import com.navercorp.pinpoint.rpc.server.handler.ServerStateChangeEventHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author HyunGil Jeong + */ +public class AgentLifeCycleChangeEventHandler implements ServerStateChangeEventHandler { + + public static final ManagedAgentLifeCycle STATE_NOT_MANAGED = null; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private AgentLifeCycleEventHandler agentLifeCycleEventHandler; + + @Autowired + private AgentEventHandler agentEventHandler; + + @Override + public void eventPerformed(PinpointServer pinpointServer, SocketStateCode stateCode) throws Exception { + ManagedAgentLifeCycle managedAgentLifeCycle = ManagedAgentLifeCycle.getManagedAgentLifeCycleByStateCode(stateCode); + if (managedAgentLifeCycle == STATE_NOT_MANAGED) { + return; + } else { + logger.info("{} eventPerformed(). pinpointServer:{}, code:{}", this.getClass().getSimpleName(), pinpointServer, stateCode); + + long eventTimestamp = System.currentTimeMillis(); + + AgentLifeCycleState agentLifeCycleState = managedAgentLifeCycle.getMappedState(); + this.agentLifeCycleEventHandler.handleLifeCycleEvent(pinpointServer, eventTimestamp, agentLifeCycleState, managedAgentLifeCycle.getEventCounter()); + AgentEventType agentEventType = managedAgentLifeCycle.getMappedEvent(); + this.agentEventHandler.handleEvent(pinpointServer, eventTimestamp, agentEventType); + } + } + + @Override + public void exceptionCaught(PinpointServer pinpointServer, SocketStateCode stateCode, Throwable e) { + logger.warn("{} exceptionCaught(). pinpointServer:{}, code:{}. error: {}.", this.getClass().getSimpleName(), pinpointServer, stateCode, e.getMessage(), e); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleEventHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleEventHandler.java new file mode 100644 index 000000000000..9dfdbce8bec2 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleEventHandler.java @@ -0,0 +1,86 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.service.AgentLifeCycleService; +import com.navercorp.pinpoint.common.server.bo.AgentLifeCycleBo; +import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; +import com.navercorp.pinpoint.common.util.BytesUtils; +import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import org.apache.commons.collections.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.Objects; + +/** + * @author HyunGil Jeong + */ +@Service +public class AgentLifeCycleEventHandler { + + public static final String SOCKET_ID_KEY = "socketId"; + + private static final int INTEGER_BIT_COUNT = BytesUtils.INT_BYTE_LENGTH * 8; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private AgentLifeCycleService agentLifeCycleService; + + @Async("agentEventWorker") + public void handleLifeCycleEvent(PinpointServer pinpointServer, long eventTimestamp, AgentLifeCycleState agentLifeCycleState, int eventCounter) { + Objects.requireNonNull(pinpointServer, "pinpointServer must not be null"); + Objects.requireNonNull(agentLifeCycleState, "agentLifeCycleState must not be null"); + if (eventCounter < 0) { + throw new IllegalArgumentException("eventCounter may not be negative"); + } + logger.info("Handle lifecycle event - pinpointServer:{}, state:{}", pinpointServer, agentLifeCycleState); + + // TODO + Map channelProperties = pinpointServer.getChannelProperties(); + final Integer socketId = MapUtils.getInteger(channelProperties, SOCKET_ID_KEY); + if (socketId == null) { + logger.debug("socketId not found, agent does not support life cycle management - pinpointServer:{}", + pinpointServer); + return; + } + + final String agentId = MapUtils.getString(channelProperties, HandshakePropertyType.AGENT_ID.getName()); + final long startTimestamp = MapUtils.getLong(channelProperties, HandshakePropertyType.START_TIMESTAMP.getName()); + final long eventIdentifier = createEventIdentifier(socketId, eventCounter); + final AgentLifeCycleBo agentLifeCycleBo = new AgentLifeCycleBo(agentId, startTimestamp, eventTimestamp, + eventIdentifier, agentLifeCycleState); + + agentLifeCycleService.insert(agentLifeCycleBo); + } + + long createEventIdentifier(int socketId, int eventCounter) { + if (socketId < 0) { + throw new IllegalArgumentException("socketId may not be less than 0"); + } + if (eventCounter < 0) { + throw new IllegalArgumentException("eventCounter may not be less than 0"); + } + return ((long) socketId << INTEGER_BIT_COUNT) | eventCounter; + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/DefaultTCPPacketHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/DefaultTCPPacketHandler.java new file mode 100644 index 000000000000..f58767a31df7 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/DefaultTCPPacketHandler.java @@ -0,0 +1,133 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.collector.util.PacketUtils; +import com.navercorp.pinpoint.io.request.DefaultServerRequest; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.packet.BasicPacket; +import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.rpc.packet.SendPacket; +import com.navercorp.pinpoint.thrift.io.DeserializerFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; +import com.navercorp.pinpoint.thrift.io.SerializerFactory; +import com.navercorp.pinpoint.thrift.util.SerializationUtils; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Objects; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultTCPPacketHandler implements TCPPacketHandler { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final DispatchHandler dispatchHandler; + + private final SerializerFactory serializerFactory; + private final DeserializerFactory deserializerFactory; + + + public DefaultTCPPacketHandler(DispatchHandler dispatchHandler, SerializerFactory serializerFactory, DeserializerFactory deserializerFactory) { + this.dispatchHandler = Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); + this.serializerFactory = Objects.requireNonNull(serializerFactory, "serializerFactory must not be null"); + this.deserializerFactory = Objects.requireNonNull(deserializerFactory, "deserializerFactory must not be null"); + } + + @Override + public void handleSend(SendPacket packet, PinpointSocket pinpointSocket) { + Objects.requireNonNull(packet, "packet must not be null"); + Objects.requireNonNull(pinpointSocket, "pinpointSocket must not be null"); + + final byte[] payload = getPayload(packet); + final InetSocketAddress remoteAddress = (InetSocketAddress) pinpointSocket.getRemoteAddress(); + try { + Message> message = SerializationUtils.deserialize(payload, deserializerFactory); + ServerRequest> serverRequest = newServerRequest(message, remoteAddress); + dispatchHandler.dispatchSendMessage(serverRequest); + } catch (TException e) { + handleTException(payload, remoteAddress, e); + } catch (Exception e) { + // there are cases where invalid headers are received + handleException(payload, remoteAddress, e); + } + } + + private ServerRequest> newServerRequest(Message> message, InetSocketAddress remoteSocketAddress) { + final String remoteAddress = remoteSocketAddress.getAddress().getHostAddress(); + final int remotePort = remoteSocketAddress.getPort(); + return new DefaultServerRequest>(message, remoteAddress, remotePort); + } + + public byte[] getPayload(BasicPacket packet) { + final byte[] payload = packet.getPayload(); + Objects.requireNonNull(payload, "payload must not be null"); + return payload; + } + + @Override + public void handleRequest(RequestPacket packet, PinpointSocket pinpointSocket) { + Objects.requireNonNull(packet, "packet must not be null"); + Objects.requireNonNull(pinpointSocket, "pinpointSocket must not be null"); + + final byte[] payload = getPayload(packet); + final InetSocketAddress remoteAddress = (InetSocketAddress) pinpointSocket.getRemoteAddress(); + + try { + Message> message = SerializationUtils.deserialize(payload, deserializerFactory); + ServerRequest> request = newServerRequest(message, remoteAddress); + ServerResponse> response = new TCPServerResponse(serializerFactory, pinpointSocket, packet.getRequestId()); + dispatchHandler.dispatchRequestMessage(request, response); + } catch (TException e) { + handleTException(payload, remoteAddress, e); + } catch (Exception e) { + handleException(payload, remoteAddress, e); + } + } + + private void handleTException(byte[] payload, SocketAddress remoteAddress, TException e) { + if (logger.isWarnEnabled()) { + logger.warn("packet deserialize error. remote:{} cause:{}", remoteAddress, e.getMessage(), e); + } + if (isDebug) { + logger.debug("packet dump hex:{}", PacketUtils.dumpByteArray(payload)); + } + throw new RuntimeException("serialized fail ", e); + } + + private void handleException(byte[] payload, SocketAddress remoteAddress, Exception e) { + // there are cases where invalid headers are received + if (logger.isWarnEnabled()) { + logger.warn("Unexpected error. remote:{} cause:{}", remoteAddress, e.getMessage(), e); + } + if (isDebug) { + logger.debug("packet dump hex:{}", PacketUtils.dumpByteArray(payload)); + } + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/DefaultTCPPacketHandlerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/DefaultTCPPacketHandlerFactory.java new file mode 100644 index 000000000000..e9b017029dd0 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/DefaultTCPPacketHandlerFactory.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.thrift.io.DeserializerFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; +import com.navercorp.pinpoint.thrift.io.SerializerFactory; +import com.navercorp.pinpoint.thrift.io.ThreadLocalHeaderTBaseDeserializerFactory; +import com.navercorp.pinpoint.thrift.io.ThreadLocalHeaderTBaseSerializerFactory; + +import java.util.Objects; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultTCPPacketHandlerFactory implements TCPPacketHandlerFactory { + + private static final int DEFAULT_UDP_STREAM_MAX_SIZE = HeaderTBaseSerializerFactory.DEFAULT_UDP_STREAM_MAX_SIZE; + + private SerializerFactory serializerFactory; + private DeserializerFactory deserializerFactory; + + + public DefaultTCPPacketHandlerFactory() { + } + + + public void setSerializerFactory(SerializerFactory serializerFactory) { + this.serializerFactory = serializerFactory; + } + + public void setDeserializerFactory(DeserializerFactory deserializerFactory) { + this.deserializerFactory = deserializerFactory; + } + + private DeserializerFactory defaultDeserializerFactory() { + final DeserializerFactory deserializerFactory = new HeaderTBaseDeserializerFactory(); + return new ThreadLocalHeaderTBaseDeserializerFactory<>(deserializerFactory); + } + + private SerializerFactory defaultSerializerFactory() { + final SerializerFactory serializerFactory = new HeaderTBaseSerializerFactory(true, DEFAULT_UDP_STREAM_MAX_SIZE); + return new ThreadLocalHeaderTBaseSerializerFactory<>(serializerFactory); + } + + + @Override + public TCPPacketHandler build(DispatchHandler dispatchHandler) { + + Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); + + SerializerFactory serializerFactory = this.serializerFactory; + if (serializerFactory == null) { + serializerFactory = defaultSerializerFactory(); + } + DeserializerFactory deserializerFactory = this.deserializerFactory; + if (deserializerFactory == null) { + deserializerFactory = defaultDeserializerFactory(); + } + return new DefaultTCPPacketHandler(dispatchHandler, serializerFactory, deserializerFactory); + } + + + + + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/DefaultTCPReceiver.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/DefaultTCPReceiver.java new file mode 100644 index 000000000000..50736d215d9f --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/DefaultTCPReceiver.java @@ -0,0 +1,97 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.receiver.thrift.PinpointServerAcceptorProvider; +import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetSocketAddress; +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * @author Taejin Koo + */ +public class DefaultTCPReceiver implements TCPReceiver { + + private final Logger logger; + + private final String name; + + private final InetSocketAddress bindAddress; + private final PinpointServerAcceptorProvider acceptorProvider; + + private PinpointServerAcceptor serverAcceptor; + + private final Executor executor; + + private final TCPPacketHandler tcpPacketHandler; + + + public DefaultTCPReceiver(String name, TCPPacketHandler tcpPacketHandler, Executor executor, InetSocketAddress bindAddress, PinpointServerAcceptorProvider acceptorProvider) { + this.name = Objects.requireNonNull(name, "name must not be null"); + this.logger = LoggerFactory.getLogger(name); + + this.bindAddress = Objects.requireNonNull(bindAddress, "bindAddress must not be null"); + + this.acceptorProvider = Objects.requireNonNull(acceptorProvider, "acceptorProvider must not be null"); + this.executor = Objects.requireNonNull(executor, "executor must not be null"); + + this.tcpPacketHandler = Objects.requireNonNull(tcpPacketHandler, "tcpPacketHandler must not be null"); + + } + + @Override + public void start() { + if (logger.isInfoEnabled()) { + logger.info("{} start() started", name); + } + final PinpointServerAcceptor acceptor = newAcceptor(); + acceptor.bind(bindAddress); + this.serverAcceptor = acceptor; + if (logger.isInfoEnabled()) { + logger.info("{} start() completed", name); + } + } + + private PinpointServerAcceptor newAcceptor() { + PinpointServerAcceptor acceptor = acceptorProvider.get(); + + // take care when attaching message handlers as events are generated from the IO thread. + // pass them to a separate queue and handle them in a different thread. + acceptor.setMessageListenerFactory(new TCPReceiverServerMessageListenerFactory(executor, tcpPacketHandler)); + return acceptor; + } + + @Override + public void shutdown() { + if (logger.isInfoEnabled()) { + logger.info("{} shutdown() started", name); + } + + if (serverAcceptor != null) { + serverAcceptor.close(); + } + + if (logger.isInfoEnabled()) { + logger.info("{} shutdown() completed", name); + } + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPPacketHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPPacketHandler.java new file mode 100644 index 000000000000..9b48855933b5 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPPacketHandler.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.rpc.packet.SendPacket; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface TCPPacketHandler { + + void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket); + + void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket); +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPPacketHandlerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPPacketHandlerFactory.java new file mode 100644 index 000000000000..e128b0b95355 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPPacketHandlerFactory.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface TCPPacketHandlerFactory { + TCPPacketHandler build(DispatchHandler dispatchHandler); +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPReceiver.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPReceiver.java new file mode 100644 index 000000000000..da605c95b41d --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPReceiver.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +/** + * @author Taejin Koo + */ +public interface TCPReceiver { + + void start(); + + void shutdown(); + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPReceiverServerMessageListenerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPReceiverServerMessageListenerFactory.java new file mode 100644 index 000000000000..cf006e78c1e4 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPReceiverServerMessageListenerFactory.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; +import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; +import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.rpc.packet.SendPacket; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.rpc.server.ServerMessageListenerFactory; + +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * @author Taejin Koo + */ +class TCPReceiverServerMessageListenerFactory implements ServerMessageListenerFactory { + + private final Executor executor; + private final TCPPacketHandler tcpPacketHandler; + + TCPReceiverServerMessageListenerFactory(Executor executor, TCPPacketHandler tcpPacketHandler) { + this.executor = Assert.requireNonNull(executor, "executor must not be null"); + this.tcpPacketHandler = Assert.requireNonNull(tcpPacketHandler, "tcpPacketHandler must not be null"); + } + + @Override + public ServerMessageListener create() { + return new TCPReceiverServerMessageListener(executor, tcpPacketHandler); + } + + + private static class TCPReceiverServerMessageListener implements ServerMessageListener { + + private final Executor executor; + private final TCPPacketHandler tcpPacketHandler; + + public TCPReceiverServerMessageListener(Executor executor, TCPPacketHandler tcpPacketHandler) { + this.executor = Assert.requireNonNull(executor, "executor must not be null"); + this.tcpPacketHandler = Assert.requireNonNull(tcpPacketHandler, "tcpPacketHandler must not be null"); + } + + @Override + public HandshakeResponseCode handleHandshake(Map properties) { + return HandshakeResponseCode.SIMPLEX_COMMUNICATION; + } + + @Override + public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { + executor.execute(new Runnable() { + @Override + public void run() { + tcpPacketHandler.handleSend(sendPacket, pinpointSocket); + } + }); + } + + @Override + public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { + executor.execute(new Runnable() { + @Override + public void run() { + tcpPacketHandler.handleRequest(requestPacket, pinpointSocket); + } + }); + } + + @Override + public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { + } + + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPServerResponse.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPServerResponse.java new file mode 100644 index 000000000000..79f25c14faca --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPServerResponse.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; +import com.navercorp.pinpoint.thrift.io.SerializerFactory; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class TCPServerResponse implements ServerResponse> { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final SerializerFactory serializerFactory; + private final PinpointSocket pinpointSocket; + private final int requestId; + + private boolean closed = false; + + public TCPServerResponse(SerializerFactory serializerFactory, PinpointSocket pinpointSocket, int requestId) { + this.serializerFactory = Objects.requireNonNull(serializerFactory, "serializerFactory must not be null"); + this.pinpointSocket = Objects.requireNonNull(pinpointSocket, "pinpointSocket must not be null"); + this.requestId = requestId; + } + + @Override + public void write(TBase message) { + if (message == null) { + throw new NullPointerException("message must not be null"); + } + if (closed) { + throw new IllegalStateException("ServerResponse is closed"); + } + closed = true; + try { + HeaderTBaseSerializer serializer = serializerFactory.createSerializer(); + byte[] resultBytes = serializer.serialize(message); + pinpointSocket.response(requestId, resultBytes); + } catch (TException e) { + handleTException(message, e); + } + } + + private void handleTException(TBase message, TException e) { + if (logger.isWarnEnabled()) { + logger.warn("packet serialize error. message:{} cause:{}", message, e.getMessage(), e); + } + // TODO + throw new RuntimeException("message serialize fail", e); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/BaseUDPHandlerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/BaseUDPHandlerFactory.java new file mode 100644 index 000000000000..3d505030a1c4 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/BaseUDPHandlerFactory.java @@ -0,0 +1,137 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.udp; + +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.collector.util.PacketUtils; +import com.navercorp.pinpoint.common.server.util.AddressFilter; +import com.navercorp.pinpoint.io.request.DefaultServerRequest; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.thrift.io.DeserializerFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.thrift.io.ThreadLocalHeaderTBaseDeserializerFactory; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Objects; + +/** + * @author emeroad + * @author netspider + * @author minwoo.jung + */ +public class BaseUDPHandlerFactory implements PacketHandlerFactory { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final DeserializerFactory deserializerFactory = new ThreadLocalHeaderTBaseDeserializerFactory<>(new HeaderTBaseDeserializerFactory()); + + private final DispatchHandler dispatchHandler; + + private final TBaseFilter filter; + + private final PacketHandler dispatchPacket = new DispatchPacket(); + + private final AddressFilter ignoreAddressFilter; + + public BaseUDPHandlerFactory(DispatchHandler dispatchHandler, TBaseFilter filter, AddressFilter ignoreAddressFilter) { + this.dispatchHandler = Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); + this.filter = Objects.requireNonNull(filter, "filter must not be null"); + this.ignoreAddressFilter = Objects.requireNonNull(ignoreAddressFilter, "ignoreAddressFilter must not be null"); + } + + @Override + public PacketHandler createPacketHandler() { + return this.dispatchPacket; + } + + // stateless + private class DispatchPacket implements PacketHandler { + + private DispatchPacket() { + } + + @Override + public void receive(DatagramSocket localSocket, T packet) { + final InetSocketAddress remoteSocketAddress = (InetSocketAddress) packet.getSocketAddress(); + final InetAddress remoteAddress = remoteSocketAddress.getAddress(); + if (isIgnoreAddress(remoteAddress)) { + return; + } + + final HeaderTBaseDeserializer deserializer = deserializerFactory.createDeserializer(); + + Message> message = null; + try { + message = deserializer.deserialize(packet.getData()); + TBase data = message.getData(); + + if (filter.filter(localSocket, data, remoteSocketAddress) == TBaseFilter.BREAK) { + return; + } + ServerRequest> request = newServerRequest(message, remoteSocketAddress); + // dispatch signifies business logic execution + dispatchHandler.dispatchSendMessage(request); + } catch (TException e) { + if (logger.isWarnEnabled()) { + logger.warn("packet serialize error. SendSocketAddress:{} Cause:{}", remoteSocketAddress, e.getMessage(), e); + } + if (logger.isDebugEnabled()) { + logger.debug("packet dump hex:{}", PacketUtils.dumpDatagramPacket(packet)); + } + } catch (Exception e) { + // there are cases where invalid headers are received + if (logger.isWarnEnabled()) { + logger.warn("Unexpected error. SendSocketAddress:{} Cause:{} message:{}", remoteAddress, e.getMessage(), message, e); + } + if (logger.isDebugEnabled()) { + logger.debug("packet dump hex:{}", PacketUtils.dumpDatagramPacket(packet)); + } + } + } + + private boolean isIgnoreAddress(InetAddress remoteAddress) { + if (remoteAddress == null) { + return false; + } + if (!ignoreAddressFilter.accept(remoteAddress)) { + if (logger.isDebugEnabled()) { + logger.debug("UDP Connected ignore address. IP : " + remoteAddress.getHostAddress()); + } + return true; + } + return false; + } + } + + private ServerRequest> newServerRequest(Message> message, InetSocketAddress remoteSocketAddress) { + final String remoteAddress = remoteSocketAddress.getAddress().getHostAddress(); + final int remotePort = remoteSocketAddress.getPort(); + + return new DefaultServerRequest<>(message, remoteAddress, remotePort); + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/ChunkedUDPPacketHandlerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/ChunkedUDPPacketHandlerFactory.java new file mode 100644 index 000000000000..10a6204aed71 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/ChunkedUDPPacketHandlerFactory.java @@ -0,0 +1,114 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.udp; + +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.collector.util.PacketUtils; +import com.navercorp.pinpoint.io.request.DefaultServerRequest; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.thrift.io.*; + +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.*; +import java.util.List; + +/** + * Chunked UDP packet receiver + * + * @author jaehong.kim + */ +public class ChunkedUDPPacketHandlerFactory implements PacketHandlerFactory { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final DeserializerFactory deserializerFactory = new ThreadLocalHeaderTBaseDeserializerFactory<>(new ChunkHeaderTBaseDeserializerFactory()); + + private final DispatchHandler dispatchHandler; + private final TBaseFilter filter; + + private final PacketHandler dispatchPacket = new DispatchPacket(); + + public ChunkedUDPPacketHandlerFactory(DispatchHandler dispatchHandler, TBaseFilter filter) { + if (dispatchHandler == null) { + throw new NullPointerException("dispatchHandler must not be null"); + } + this.dispatchHandler = dispatchHandler; + this.filter = filter; + } + + @Override + public PacketHandler createPacketHandler() { + return this.dispatchPacket; + } + + // stateless + private class DispatchPacket implements PacketHandler { + + private DispatchPacket() { + } + + @Override + public void receive(DatagramSocket localSocket, T packet) { + final ChunkHeaderTBaseDeserializer deserializer = deserializerFactory.createDeserializer(); + try { + List>> list = deserializer.deserialize(packet.getData(), packet.getOffset(), packet.getLength()); + if (list == null) { + return; + } + + final InetSocketAddress remoteAddress = (InetSocketAddress) packet.getSocketAddress(); + for (Message> message : list) { + if (filter.filter(localSocket, message.getData(), remoteAddress) == TBaseFilter.BREAK) { + return; + } + ServerRequest> request = newServerRequest(message, remoteAddress);; + // dispatch signifies business logic execution + dispatchHandler.dispatchSendMessage(request); + } + } catch (TException e) { + if (logger.isWarnEnabled()) { + logger.warn("packet serialize error. SendSocketAddress:{} Cause:{}", packet.getSocketAddress(), e.getMessage(), e); + } + if (logger.isDebugEnabled()) { + logger.debug("packet dump hex:{}", PacketUtils.dumpDatagramPacket(packet)); + } + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unexpected error. SendSocketAddress:{} Cause:{} ", packet.getSocketAddress(), e.getMessage(), e); + } + if (logger.isDebugEnabled()) { + logger.debug("packet dump hex:{}", PacketUtils.dumpDatagramPacket(packet)); + } + } + } + } + + private ServerRequest> newServerRequest(Message> message, InetSocketAddress remoteSocketAddress) { + final String remoteAddress = remoteSocketAddress.getAddress().getHostAddress(); + final int remotePort = remoteSocketAddress.getPort(); + + ServerRequest> tBaseDefaultServerRequest = new DefaultServerRequest<>(message, remoteAddress, remotePort); + return tBaseDefaultServerRequest; + } + + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/NetworkAvailabilityCheckPacketFilter.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/NetworkAvailabilityCheckPacketFilter.java similarity index 89% rename from collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/NetworkAvailabilityCheckPacketFilter.java rename to collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/NetworkAvailabilityCheckPacketFilter.java index aebf1c3fff8c..159ff1491ee6 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/NetworkAvailabilityCheckPacketFilter.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/NetworkAvailabilityCheckPacketFilter.java @@ -14,13 +14,12 @@ * limitations under the License. */ -package com.navercorp.pinpoint.collector.receiver.udp; +package com.navercorp.pinpoint.collector.receiver.thrift.udp; import com.navercorp.pinpoint.thrift.io.NetworkAvailabilityCheckPacket; import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; import java.io.IOException; import java.net.*; @@ -28,7 +27,7 @@ /** * @author emeroad */ -public class NetworkAvailabilityCheckPacketFilter implements TBaseFilter, DisposableBean { +public class NetworkAvailabilityCheckPacketFilter implements TBaseFilter { private final Logger logger = LoggerFactory.getLogger(this.getClass()); public NetworkAvailabilityCheckPacketFilter() { @@ -60,8 +59,5 @@ private void responseOK(DatagramSocket socket, T remoteHostAddress) { } - @Override - public void destroy() throws Exception { - } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/PacketHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/PacketHandler.java similarity index 92% rename from collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/PacketHandler.java rename to collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/PacketHandler.java index 5bb26a0f557c..906b3ce3d2bc 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/PacketHandler.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/PacketHandler.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.navercorp.pinpoint.collector.receiver.udp; +package com.navercorp.pinpoint.collector.receiver.thrift.udp; import java.net.DatagramSocket; diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/PacketHandlerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/PacketHandlerFactory.java similarity index 92% rename from collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/PacketHandlerFactory.java rename to collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/PacketHandlerFactory.java index 527f1d2a26d8..edd226b20278 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/PacketHandlerFactory.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/PacketHandlerFactory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.navercorp.pinpoint.collector.receiver.udp; +package com.navercorp.pinpoint.collector.receiver.thrift.udp; /** * @author emeroad diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/SpanStreamUDPPacketHandlerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/SpanStreamUDPPacketHandlerFactory.java new file mode 100644 index 000000000000..7355d2926dc4 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/SpanStreamUDPPacketHandlerFactory.java @@ -0,0 +1,189 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.udp; + +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.io.request.DefaultMessage; +import com.navercorp.pinpoint.io.request.DefaultServerRequest; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; +import com.navercorp.pinpoint.thrift.dto.TSpanEvent; +import com.navercorp.pinpoint.thrift.io.*; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Taejin Koo + */ +public class SpanStreamUDPPacketHandlerFactory implements PacketHandlerFactory { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final DeserializerFactory deserializerFactory = new ThreadLocalHeaderTBaseDeserializerFactory<>(new HeaderTBaseDeserializerFactory()); + private final DispatchHandler dispatchHandler; + + @SuppressWarnings("unused") + private final TBaseFilter filter; + private final PacketHandler dispatchPacket = new DispatchPacket(); + + public SpanStreamUDPPacketHandlerFactory(DispatchHandler dispatchHandler, TBaseFilter filter) { + if (dispatchHandler == null) { + throw new NullPointerException("dispatchHandler must not be null"); + } + if (filter == null) { + throw new NullPointerException("filter must not be null"); + } + this.dispatchHandler = dispatchHandler; + this.filter = filter; + } + + + @Override + public PacketHandler createPacketHandler() { + return this.dispatchPacket; + } + + // stateless + private class DispatchPacket implements PacketHandler { + private ServerResponse fake = new ServerResponse() { + @Override + public void write(Object data) { + + } + }; + + private DispatchPacket() { + } + + @Override + public void receive(DatagramSocket localSocket, DatagramPacket packet) { + final HeaderTBaseDeserializer deserializer = deserializerFactory.createDeserializer(); + + ByteBuffer requestBuffer = ByteBuffer.wrap(packet.getData()); + if (requestBuffer.remaining() < SpanStreamConstants.START_PROTOCOL_BUFFER_SIZE) { + return; + } + + byte signature = requestBuffer.get(); + if (signature != SpanStreamConstants.Protocol.SPAN_STREAM_SIGNATURE) { + logger.warn("Wrong signature: 0x" + Integer.toHexString(signature & 0xFF) + " (expected: 0x" + + Integer.toHexString(SpanStreamConstants.Protocol.SPAN_STREAM_SIGNATURE & 0xFF) + ')'); + return; + } + + byte version = requestBuffer.get(); + int chunkSize = 0xff & requestBuffer.get(); + InetSocketAddress remoteSocketAddress = (InetSocketAddress) packet.getSocketAddress(); + + try { + for (int i = 0; i < chunkSize; i++) { + byte[] componentData = getComponentData(requestBuffer, deserializer); + if (componentData == null) { + logger.warn("Buffer Wrong signature: 0x{} (expected: 0x{})", Integer.toHexString(signature & 0xFF), + Integer.toHexString(SpanStreamConstants.Protocol.SPAN_STREAM_SIGNATURE & 0xFF)); + break; + } + + List>> requestList = deserializer.deserializeList(componentData); + if (CollectionUtils.isEmpty(requestList)) { + continue; + } + + if (requestList.size() == 1) { + if (filter.filter(localSocket, requestList.get(0).getData(), remoteSocketAddress) == TBaseFilter.BREAK) { + continue; + } + } + + List spanEventList = getSpanEventList(requestList); + + Message> lastMessage = requestList.get(requestList.size() - 1); + TBase tBase = lastMessage.getData(); + if (tBase instanceof TSpan) { + ((TSpan) tBase).setSpanEventList(spanEventList); + } else if (tBase instanceof TSpanChunk) { + ((TSpanChunk) tBase).setSpanEventList(spanEventList); + } + Message> message = new DefaultMessage<>(lastMessage.getHeader(), lastMessage.getHeaderEntity(), tBase); + ServerRequest> mergedRequest = newServerRequest(message, remoteSocketAddress); + + dispatchHandler.dispatchRequestMessage(mergedRequest, fake); + } + } catch (Exception e) { + logger.warn("Failed to handle receive packet.", e); + } + } + } + + private ServerRequest> newServerRequest(Message> message, InetSocketAddress remoteSocketAddress) { + final String remoteAddress = remoteSocketAddress.getAddress().getHostAddress(); + final int remotePort = remoteSocketAddress.getPort(); + + return new DefaultServerRequest<>(message, remoteAddress, remotePort); + } + + private byte[] getComponentData(ByteBuffer buffer, HeaderTBaseDeserializer deserializer) { + if (buffer.remaining() < 2) { + logger.warn("Can't available {} fixed buffer.", 2); + return null; + } + + int componentSize = 0xffff & buffer.getShort(); + if (buffer.remaining() < componentSize) { + logger.warn("Can't available {} fixed buffer.", buffer.remaining()); + return null; + } + + byte[] componentData = new byte[componentSize]; + buffer.get(componentData); + + return componentData; + } + + private List getSpanEventList(List>> tbaseList) { + if (CollectionUtils.isEmpty(tbaseList)) { + return new ArrayList<>(0); + } + + int spanEventListSize = tbaseList.size() - 1; + List spanEventList = new ArrayList<>(spanEventListSize); + for (int i = 0; i < spanEventListSize; i++) { + Message> request = tbaseList.get(i); + TBase tBase = request.getData(); + if (tBase instanceof TSpanEvent) { + spanEventList.add((TSpanEvent) tBase); + } + } + + return spanEventList; + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/TBaseFilter.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/TBaseFilter.java similarity index 95% rename from collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/TBaseFilter.java rename to collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/TBaseFilter.java index 82125213f5f8..6ed4574ed566 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/TBaseFilter.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/TBaseFilter.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.navercorp.pinpoint.collector.receiver.udp; +package com.navercorp.pinpoint.collector.receiver.thrift.udp; import org.apache.thrift.TBase; diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/TBaseFilterChain.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/TBaseFilterChain.java new file mode 100644 index 000000000000..7adb8d22411e --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/TBaseFilterChain.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.udp; + +import org.apache.thrift.TBase; + +import java.net.DatagramSocket; +import java.util.List; + +/** + * @author emeroad + */ +public class TBaseFilterChain implements TBaseFilter { + + private final TBaseFilter[] filterChain; + + + public TBaseFilterChain(List> tBaseFilter) { + if (tBaseFilter == null) { + throw new NullPointerException("tBaseFilter must not be null"); + } + + @SuppressWarnings("unchecked") + final TBaseFilter[] newArray = (TBaseFilter[]) new TBaseFilter[0]; + this.filterChain = tBaseFilter.toArray(newArray); + } + + + @Override + public boolean filter(DatagramSocket localSocket, TBase tBase, T remoteHostAddress) { + for (TBaseFilter tBaseFilter : filterChain) { + @SuppressWarnings("unchecked") + final boolean filter = tBaseFilter.filter(localSocket, tBase, remoteHostAddress); + if (filter == TBaseFilter.BREAK) { + return BREAK; + } + } + return TBaseFilter.CONTINUE; + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/Task.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/Task.java new file mode 100644 index 000000000000..1a33fe116694 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/Task.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.udp; + +import com.navercorp.pinpoint.collector.util.PooledObject; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.util.Objects; + +/** + * @author emeroad + */ +public class Task implements Runnable { + private final DatagramSocket localSocket; + private final PacketHandlerFactory packetHandlerFactory; + private final PooledObject pooledObject; + + public Task(DatagramSocket localSocket, PacketHandlerFactory packetHandlerFactory, PooledObject pooledObject) { + this.localSocket = Objects.requireNonNull(localSocket, "localSocket must not be null"); + this.packetHandlerFactory = Objects.requireNonNull(packetHandlerFactory, "packetHandlerFactory must not be null"); + this.pooledObject = Objects.requireNonNull(pooledObject, "pooledObject must not be null"); + } + + @Override + public void run() { + PacketHandler packetHandler = packetHandlerFactory.createPacketHandler(); + final DatagramPacket packet = pooledObject.getObject(); + try { + packetHandler.receive(localSocket, packet); + } finally { + pooledObject.returnObject(); + } + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/UDPReceiver.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/UDPReceiver.java similarity index 78% rename from collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/UDPReceiver.java rename to collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/UDPReceiver.java index 1bb8242b66c4..9d305f3909a7 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/UDPReceiver.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/UDPReceiver.java @@ -14,12 +14,8 @@ * limitations under the License. */ -package com.navercorp.pinpoint.collector.receiver.udp; +package com.navercorp.pinpoint.collector.receiver.thrift.udp; -import com.navercorp.pinpoint.collector.receiver.DataReceiver; -import com.navercorp.pinpoint.collector.receiver.DispatchWorker; -import com.navercorp.pinpoint.collector.util.DatagramPacketFactory; -import com.navercorp.pinpoint.collector.util.DefaultObjectPool; import com.navercorp.pinpoint.collector.util.ObjectPool; import com.navercorp.pinpoint.collector.util.PacketUtils; import com.navercorp.pinpoint.collector.util.PooledObject; @@ -30,10 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.core.task.TaskExecutor; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; @@ -45,7 +38,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -54,7 +47,7 @@ * @author netspider * @author jaehong.kim */ -public class UDPReceiver implements DataReceiver { +public class UDPReceiver { private final Logger logger; @@ -66,13 +59,12 @@ public class UDPReceiver implements DataReceiver { private final int ioThreadSize = CpuUtils.cpuCount(); private ExecutorService ioExecutor; - // modify thread pool size appropriately when modifying queue capacity - private DispatchWorker worker; + private final Executor worker; // can't really allocate memory as max udp packet sizes are unknown. // not allocating memory in advance as I am unsure of the max udp packet size. // packet cache is necessary as the JVM does not last long if they are dynamically created with the maximum size. - private ObjectPool datagramPacketPool; + private final ObjectPool datagramPacketPool; private final DatagramSocket socket; @@ -80,7 +72,8 @@ public class UDPReceiver implements DataReceiver { private final AtomicBoolean state = new AtomicBoolean(true); - public UDPReceiver(String name, PacketHandlerFactory packetHandlerFactory, DispatchWorker worker, int receiverBufferSize, InetSocketAddress bindAddress) { + public UDPReceiver(String name, PacketHandlerFactory packetHandlerFactory, + @Qualifier("udpWorker") Executor worker, int receiverBufferSize, InetSocketAddress bindAddress, ObjectPool datagramPacketPool) { this.name = Objects.requireNonNull(name); this.logger = LoggerFactory.getLogger(name); @@ -90,20 +83,11 @@ public UDPReceiver(String name, PacketHandlerFactory packetHandl Assert.isTrue(receiverBufferSize > 0, "receiverBufferSize must be greater than 0"); this.socket = createSocket(receiverBufferSize); - } - - private void prepare() { - Objects.requireNonNull(packetHandlerFactory, "packetHandlerFactory must not be null"); - this.datagramPacketPool = newDatagramPacketPool(); - - this.ioExecutor = Executors.newCachedThreadPool(new PinpointThreadFactory(name + "-Io", true)); + this.datagramPacketPool = Objects.requireNonNull(datagramPacketPool, "datagramPacketPool must not be null"); } - private ObjectPool newDatagramPacketPool() { - final int packetPoolSize = getPacketPoolSize(); - return new DefaultObjectPool<>(new DatagramPacketFactory(), packetPoolSize); - } + private void receive(final DatagramSocket socket) { if (logger.isInfoEnabled()) { @@ -116,8 +100,8 @@ private void receive(final DatagramSocket socket) { if (pooledPacket == null) { continue; } - Runnable dispatchTask = wrapDispatchTask(pooledPacket); - worker.execute(dispatchTask); + Runnable task = wrapTask(pooledPacket); + worker.execute(task); } if (logger.isInfoEnabled()) { @@ -126,17 +110,9 @@ private void receive(final DatagramSocket socket) { } } - private Runnable wrapDispatchTask(final PooledObject pooledPacket) { - final Runnable lazyExecution = new Runnable() { - @Override - public void run() { - PacketHandler dispatchPacket = packetHandlerFactory.createPacketHandler(); - PooledPacketWrap pooledPacketWrap = new PooledPacketWrap(socket, dispatchPacket, pooledPacket); - Runnable execution = pooledPacketWrap; - execution.run(); - } - }; - return lazyExecution; + private Runnable wrapTask(final PooledObject pooledPacket) { + return new + Task(socket, packetHandlerFactory, pooledPacket); } @@ -220,21 +196,17 @@ private void bindSocket(DatagramSocket socket, InetSocketAddress bindAddress) { } } - private int getPacketPoolSize() { - int threadSize = worker.getThreadSize(); - int queueSize = worker.getQueueSize(); - - return threadSize + queueSize + ioThreadSize; + private ExecutorService newThreadPoolExecutor() { + final ThreadFactory threadFactory = new PinpointThreadFactory(name + "-Io", true); + return Executors.newCachedThreadPool(threadFactory); } - @PostConstruct - @Override public void start() { if (logger.isInfoEnabled()) { logger.info("{} start() started", name); } - prepare(); + this.ioExecutor = newThreadPoolExecutor(); final DatagramSocket socket = this.socket; if (socket == null) { throw new IllegalStateException("socket is null."); @@ -256,8 +228,6 @@ public void run() { } } - @PreDestroy - @Override public void shutdown() { if (logger.isInfoEnabled()) { logger.info("{} shutdown() started", this.name); @@ -269,7 +239,7 @@ public void shutdown() { socket.close(); } if (ioExecutor != null) { - shutdownExecutor(ioExecutor, "IoExecutor"); + shutdownExecutor(ioExecutor, name); } if (logger.isInfoEnabled()) { diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/BaseUDPHandlerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/BaseUDPHandlerFactory.java deleted file mode 100644 index bcaef978f380..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/BaseUDPHandlerFactory.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.udp; - -import com.navercorp.pinpoint.collector.receiver.DispatchHandler; -import com.navercorp.pinpoint.collector.util.PacketUtils; -import com.navercorp.pinpoint.common.server.util.AddressFilter; -import com.navercorp.pinpoint.thrift.io.DeserializerFactory; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; -import com.navercorp.pinpoint.thrift.io.ThreadLocalHeaderTBaseDeserializerFactory; -import org.apache.thrift.TBase; -import org.apache.thrift.TException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketAddress; -import java.util.Objects; - -/** - * @author emeroad - * @author netspider - * @author minwoo.jung - */ -public class BaseUDPHandlerFactory implements PacketHandlerFactory { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final DeserializerFactory deserializerFactory = new ThreadLocalHeaderTBaseDeserializerFactory<>(new HeaderTBaseDeserializerFactory()); - - private final DispatchHandler dispatchHandler; - - private final TBaseFilter filter; - - private final PacketHandler dispatchPacket = new DispatchPacket(); - - private final AddressFilter ignoreAddressFilter; - - public BaseUDPHandlerFactory(DispatchHandler dispatchHandler, TBaseFilter filter, AddressFilter ignoreAddressFilter) { - this.dispatchHandler = Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); - this.filter = Objects.requireNonNull(filter, "filter must not be null"); - this.ignoreAddressFilter = Objects.requireNonNull(ignoreAddressFilter, "ignoreAddressFilter must not be null"); - } - - @Override - public PacketHandler createPacketHandler() { - return this.dispatchPacket; - } - - // stateless - private class DispatchPacket implements PacketHandler { - - private DispatchPacket() { - } - - @Override - public void receive(DatagramSocket localSocket, T packet) { - if (isIgnoreAddress(packet.getAddress())) { - return; - } - - final HeaderTBaseDeserializer deserializer = deserializerFactory.createDeserializer(); - SocketAddress socketAddress = packet.getSocketAddress(); - TBase tBase = null; - - try { - tBase = deserializer.deserialize(packet.getData()); - if (filter.filter(localSocket, tBase, socketAddress) == TBaseFilter.BREAK) { - return; - } - // dispatch signifies business logic execution - dispatchHandler.dispatchSendMessage(tBase); - } catch (TException e) { - if (logger.isWarnEnabled()) { - logger.warn("packet serialize error. SendSocketAddress:{} Cause:{}", socketAddress, e.getMessage(), e); - } - if (logger.isDebugEnabled()) { - logger.debug("packet dump hex:{}", PacketUtils.dumpDatagramPacket(packet)); - } - } catch (Exception e) { - // there are cases where invalid headers are received - if (logger.isWarnEnabled()) { - logger.warn("Unexpected error. SendSocketAddress:{} Cause:{} tBase:{}", socketAddress, e.getMessage(), tBase, e); - } - if (logger.isDebugEnabled()) { - logger.debug("packet dump hex:{}", PacketUtils.dumpDatagramPacket(packet)); - } - } - } - - private boolean isIgnoreAddress(InetAddress remoteAddress) { - if (remoteAddress == null) { - return false; - } - if (!ignoreAddressFilter.accept(remoteAddress)) { - if (logger.isDebugEnabled()) { - logger.debug("UDP Connected ignore address. IP : " + remoteAddress.getHostAddress()); - } - return true; - } - return false; - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/ChunkedUDPPacketHandlerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/ChunkedUDPPacketHandlerFactory.java deleted file mode 100644 index db96f377e57a..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/ChunkedUDPPacketHandlerFactory.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.udp; - -import com.navercorp.pinpoint.collector.receiver.DispatchHandler; -import com.navercorp.pinpoint.collector.util.PacketUtils; -import com.navercorp.pinpoint.thrift.io.*; - -import org.apache.thrift.TBase; -import org.apache.thrift.TException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.*; -import java.util.List; - -/** - * Chunked UDP packet receiver - * - * @author jaehong.kim - */ -public class ChunkedUDPPacketHandlerFactory implements PacketHandlerFactory { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final DeserializerFactory deserializerFactory = new ThreadLocalHeaderTBaseDeserializerFactory<>(new ChunkHeaderTBaseDeserializerFactory()); - - private final DispatchHandler dispatchHandler; - private final TBaseFilter filter; - - private final PacketHandler dispatchPacket = new DispatchPacket(); - - public ChunkedUDPPacketHandlerFactory(DispatchHandler dispatchHandler, TBaseFilter filter) { - if (dispatchHandler == null) { - throw new NullPointerException("dispatchHandler must not be null"); - } - this.dispatchHandler = dispatchHandler; - this.filter = filter; - } - - @Override - public PacketHandler createPacketHandler() { - return this.dispatchPacket; - } - - // stateless - private class DispatchPacket implements PacketHandler { - - private DispatchPacket() { - } - - @Override - public void receive(DatagramSocket localSocket, T packet) { - final ChunkHeaderTBaseDeserializer deserializer = deserializerFactory.createDeserializer(); - try { - List> list = deserializer.deserialize(packet.getData(), packet.getOffset(), packet.getLength()); - if (list == null) { - return; - } - - for (TBase tBase : list) { - if (filter.filter(localSocket, tBase, packet.getSocketAddress()) == TBaseFilter.BREAK) { - return; - } - // dispatch signifies business logic execution - dispatchHandler.dispatchSendMessage(tBase); - } - } catch (TException e) { - if (logger.isWarnEnabled()) { - logger.warn("packet serialize error. SendSocketAddress:{} Cause:{}", packet.getSocketAddress(), e.getMessage(), e); - } - if (logger.isDebugEnabled()) { - logger.debug("packet dump hex:{}", PacketUtils.dumpDatagramPacket(packet)); - } - } catch (Exception e) { - if (logger.isWarnEnabled()) { - logger.warn("Unexpected error. SendSocketAddress:{} Cause:{} ", packet.getSocketAddress(), e.getMessage(), e); - } - if (logger.isDebugEnabled()) { - logger.debug("packet dump hex:{}", PacketUtils.dumpDatagramPacket(packet)); - } - } - } - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/PooledPacketWrap.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/PooledPacketWrap.java deleted file mode 100644 index 763a5ab3a2cd..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/PooledPacketWrap.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.udp; - -import com.navercorp.pinpoint.collector.util.PooledObject; - -import java.net.DatagramPacket; -import java.net.DatagramSocket; - -/** - * @author emeroad - */ -public class PooledPacketWrap implements Runnable { - private final DatagramSocket localSocket; - private final PacketHandler packetHandler; - private final PooledObject pooledObject; - - public PooledPacketWrap(DatagramSocket localSocket, PacketHandler packetHandler, PooledObject pooledObject) { - if (localSocket == null) { - throw new NullPointerException("localSocket must not be null"); - } - if (packetHandler == null) { - throw new NullPointerException("packetReceiveHandler must not be null"); - } - if (pooledObject == null) { - throw new NullPointerException("pooledObject must not be null"); - } - this.localSocket = localSocket; - this.packetHandler = packetHandler; - this.pooledObject = pooledObject; - } - - @Override - public void run() { - final DatagramPacket packet = pooledObject.getObject(); - try { - packetHandler.receive(localSocket, packet); - } finally { - pooledObject.returnObject(); - } - } -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/SpanStreamUDPPacketHandlerFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/SpanStreamUDPPacketHandlerFactory.java deleted file mode 100644 index 9da15d8d9b3a..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/SpanStreamUDPPacketHandlerFactory.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.udp; - -import com.navercorp.pinpoint.collector.receiver.DispatchHandler; -import com.navercorp.pinpoint.thrift.dto.TSpan; -import com.navercorp.pinpoint.thrift.dto.TSpanChunk; -import com.navercorp.pinpoint.thrift.dto.TSpanEvent; -import com.navercorp.pinpoint.thrift.io.*; - -import org.apache.commons.collections.CollectionUtils; -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Taejin Koo - */ -public class SpanStreamUDPPacketHandlerFactory implements PacketHandlerFactory { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final DeserializerFactory deserializerFactory = new ThreadLocalHeaderTBaseDeserializerFactory<>(new HeaderTBaseDeserializerFactory()); - private final DispatchHandler dispatchHandler; - - @SuppressWarnings("unused") - private final TBaseFilter filter; - private final PacketHandler dispatchPacket = new DispatchPacket(); - - public SpanStreamUDPPacketHandlerFactory(DispatchHandler dispatchHandler, TBaseFilter filter) { - if (dispatchHandler == null) { - throw new NullPointerException("dispatchHandler must not be null"); - } - if (filter == null) { - throw new NullPointerException("filter must not be null"); - } - this.dispatchHandler = dispatchHandler; - this.filter = filter; - } - - - @Override - public PacketHandler createPacketHandler() { - return this.dispatchPacket; - } - - // stateless - private class DispatchPacket implements PacketHandler { - - private DispatchPacket() { - } - - @Override - public void receive(DatagramSocket localSocket, DatagramPacket packet) { - final HeaderTBaseDeserializer deserializer = deserializerFactory.createDeserializer(); - - ByteBuffer requestBuffer = ByteBuffer.wrap(packet.getData()); - if (requestBuffer.remaining() < SpanStreamConstants.START_PROTOCOL_BUFFER_SIZE) { - return; - } - - byte signature = requestBuffer.get(); - if (signature != SpanStreamConstants.Protocol.SPAN_STREAM_SIGNATURE) { - logger.warn("Wrong signature: 0x" + Integer.toHexString(signature & 0xFF) + " (expected: 0x" - + Integer.toHexString(SpanStreamConstants.Protocol.SPAN_STREAM_SIGNATURE & 0xFF) + ')'); - return; - } - - byte version = requestBuffer.get(); - int chunkSize = 0xff & requestBuffer.get(); - SocketAddress socketAddress = packet.getSocketAddress(); - - try { - for (int i = 0; i < chunkSize; i++) { - byte[] componentData = getComponentData(requestBuffer, deserializer); - if (componentData == null) { - logger.warn("Buffer Wrong signature: 0x{} (expected: 0x{})", Integer.toHexString(signature & 0xFF), - Integer.toHexString(SpanStreamConstants.Protocol.SPAN_STREAM_SIGNATURE & 0xFF)); - break; - } - - List> tbaseList = deserializer.deserializeList(componentData); - if (CollectionUtils.isEmpty(tbaseList)) { - continue; - } - - if (tbaseList.size() == 1) { - if (filter.filter(localSocket, tbaseList.get(0), socketAddress) == TBaseFilter.BREAK) { - continue; - } - } - - List spanEventList = getSpanEventList(tbaseList); - - TBase tBase = tbaseList.get(tbaseList.size() - 1); - if (tBase instanceof TSpan) { - ((TSpan) tBase).setSpanEventList(spanEventList); - } else if (tBase instanceof TSpanChunk) { - ((TSpanChunk) tBase).setSpanEventList(spanEventList); - } - - dispatchHandler.dispatchRequestMessage(tBase); - } - } catch (Exception e) { - logger.warn("Failed to handle receive packet.", e); - } - } - } - - private byte[] getComponentData(ByteBuffer buffer, HeaderTBaseDeserializer deserializer) { - if (buffer.remaining() < 2) { - logger.warn("Can't available {} fixed buffer.", 2); - return null; - } - - int componentSize = 0xffff & buffer.getShort(); - if (buffer.remaining() < componentSize) { - logger.warn("Can't available {} fixed buffer.", buffer.remaining()); - return null; - } - - byte[] componentData = new byte[componentSize]; - buffer.get(componentData); - - return componentData; - } - - private List getSpanEventList(List> tbaseList) { - if (CollectionUtils.isEmpty(tbaseList)) { - return new ArrayList<>(0); - } - - int spanEventListSize = tbaseList.size() - 1; - List spanEventList = new ArrayList<>(spanEventListSize); - for (int i = 0; i < spanEventListSize; i++) { - TBase tBase = tbaseList.get(i); - if (tBase instanceof TSpanEvent) { - spanEventList.add((TSpanEvent) tBase); - } - } - - return spanEventList; - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/TBaseFilterChain.java b/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/TBaseFilterChain.java deleted file mode 100644 index a7ebef410210..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/receiver/udp/TBaseFilterChain.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.udp; - -import org.apache.thrift.TBase; - -import java.net.DatagramSocket; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.List; - -/** - * @author emeroad - */ -public class TBaseFilterChain implements TBaseFilter { - - private final List> filterChain; - - public TBaseFilterChain(List> tBaseFilter) { - if (tBaseFilter == null) { - throw new NullPointerException("tBaseFilter must not be null"); - } - this.filterChain = new ArrayList<>(tBaseFilter); - } - - @Override - public boolean filter(DatagramSocket localSocket, TBase tBase, T remoteHostAddress) { - for (TBaseFilter tBaseFilter : filterChain) { - if (tBaseFilter.filter(localSocket, tBase, remoteHostAddress) == TBaseFilter.BREAK) { - return BREAK; - } - } - return TBaseFilter.CONTINUE; - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleHandler.java b/collector/src/main/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleHandler.java deleted file mode 100644 index 370770b11767..000000000000 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleHandler.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.rpc.handler; - -import com.navercorp.pinpoint.collector.dao.AgentLifeCycleDao; -import com.navercorp.pinpoint.common.server.bo.AgentLifeCycleBo; -import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; -import com.navercorp.pinpoint.common.util.BytesUtils; -import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import org.apache.commons.collections.MapUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Async; - -import java.util.Map; -import java.util.Objects; - -/** - * @author HyunGil Jeong - */ -public class AgentLifeCycleHandler { - - public static final String SOCKET_ID_KEY = "socketId"; - - private static final int INTEGER_BIT_COUNT = BytesUtils.INT_BYTE_LENGTH * 8; - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Autowired - private AgentLifeCycleDao agentLifeCycleDao; - - @Async("agentEventWorker") - public void handleLifeCycleEvent(PinpointServer pinpointServer, long eventTimestamp, - AgentLifeCycleState agentLifeCycleState, int eventCounter) { - Objects.requireNonNull(pinpointServer, "pinpointServer must not be null"); - Objects.requireNonNull(agentLifeCycleState, "agentLifeCycleState must not be null"); - if (eventCounter < 0) { - throw new IllegalArgumentException("eventCounter may not be negative"); - } - logger.info("handle lifecycle event - pinpointServer:{}, state:{}", pinpointServer, agentLifeCycleState); - - Map channelProperties = pinpointServer.getChannelProperties(); - final Integer socketId = MapUtils.getInteger(channelProperties, SOCKET_ID_KEY); - if (socketId == null) { - logger.debug("socketId not found, agent does not support life cycle management - pinpointServer:{}", - pinpointServer); - return; - } - - final String agentId = MapUtils.getString(channelProperties, HandshakePropertyType.AGENT_ID.getName()); - final long startTimestamp = MapUtils.getLong(channelProperties, HandshakePropertyType.START_TIMESTAMP.getName()); - final long eventIdentifier = createEventIdentifier(socketId, eventCounter); - - final AgentLifeCycleBo agentLifeCycleBo = new AgentLifeCycleBo(agentId, startTimestamp, eventTimestamp, - eventIdentifier, agentLifeCycleState); - - agentLifeCycleDao.insert(agentLifeCycleBo); - } - - long createEventIdentifier(int socketId, int eventCounter) { - if (socketId < 0) { - throw new IllegalArgumentException("socketId may not be less than 0"); - } - if (eventCounter < 0) { - throw new IllegalArgumentException("eventCounter may not be less than 0"); - } - return ((long)socketId << INTEGER_BIT_COUNT) | eventCounter; - } - -} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/sender/FlinkRequestFactory.java b/collector/src/main/java/com/navercorp/pinpoint/collector/sender/FlinkRequestFactory.java new file mode 100644 index 000000000000..76ee774ff5aa --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/sender/FlinkRequestFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.collector.sender; + +import com.navercorp.pinpoint.io.header.HeaderEntity; +import com.navercorp.pinpoint.io.request.FlinkRequest; + +import org.apache.thrift.TBase; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author minwoo.jung + */ +public class FlinkRequestFactory { + + public FlinkRequest createFlinkRequest(TBase data, Map headerEntity) { + return new FlinkRequest(new HeaderEntity(headerEntity), data); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/sender/FlinkTcpDataSender.java b/collector/src/main/java/com/navercorp/pinpoint/collector/sender/FlinkTcpDataSender.java new file mode 100644 index 000000000000..351664306d29 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/sender/FlinkTcpDataSender.java @@ -0,0 +1,84 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.collector.sender; + +import com.navercorp.pinpoint.io.request.FlinkRequest; +import com.navercorp.pinpoint.profiler.sender.TcpDataSender; +import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; +import com.navercorp.pinpoint.thrift.io.FlinkHeaderTBaseSerializer; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Objects; + +/** + * @author minwoo.jung + */ +public class FlinkTcpDataSender extends TcpDataSender { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final FlinkHeaderTBaseSerializer flinkHeaderTBaseSerializer; + private final FlinkRequestFactory flinkRequestFactory; + + public FlinkTcpDataSender(String name, String host, int port, PinpointClientFactory clientFactory, FlinkHeaderTBaseSerializer serializer, FlinkRequestFactory flinkRequestFactory) { + super(name, host, port, clientFactory); + + if (StringUtils.isEmpty(name)) { + throw new IllegalArgumentException("name must not be empty."); + } + if (StringUtils.isEmpty(host)) { + throw new IllegalArgumentException("host must not be empty."); + } + if (Objects.isNull(clientFactory)) { + throw new IllegalArgumentException("clientFactory must not be null."); + } + this.flinkHeaderTBaseSerializer = Objects.requireNonNull(serializer, "serializer must not be null"); + this.flinkRequestFactory = Objects.requireNonNull(flinkRequestFactory, "clientFactory must not be null"); + } + + @Override + public boolean send(Object data) { + if (!(data instanceof TBase)) { + logger.info("unknown message:{}", data); + return false; + } + TBase message = (TBase) data; + FlinkRequest flinkRequest = flinkRequestFactory.createFlinkRequest(message, new HashMap(0)); + return executor.execute(flinkRequest); + } + + @Override + protected void sendPacket(Object flinkRequest) { + try { + if (flinkRequest instanceof FlinkRequest) { + byte[] copy = flinkHeaderTBaseSerializer.serialize((FlinkRequest) flinkRequest); + if (copy == null) { + return; + } + doSend(copy); + } else { + logger.error("sendPacket fail. invalid dto type:{}", flinkRequest.getClass()); + return; + } + } catch (Exception e) { + logger.warn("tcp send fail. Caused:{}", e.getMessage(), e); + } + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentEventService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentEventService.java index 9499a4190ae6..b18e77c0fdb9 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentEventService.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentEventService.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,149 +16,26 @@ package com.navercorp.pinpoint.collector.service; -import com.navercorp.pinpoint.collector.cluster.route.ResponseEvent; import com.navercorp.pinpoint.collector.dao.AgentEventDao; import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; -import com.navercorp.pinpoint.common.server.bo.event.DeadlockEventBo; -import com.navercorp.pinpoint.common.server.util.AgentEventMessageSerializer; -import com.navercorp.pinpoint.common.server.util.AgentEventType; -import com.navercorp.pinpoint.common.server.util.AgentEventTypeCategory; -import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.thrift.dto.command.TCommandTransfer; -import com.navercorp.pinpoint.thrift.dto.command.TCommandTransferResponse; -import com.navercorp.pinpoint.thrift.dto.command.TRouteResult; -import com.navercorp.pinpoint.thrift.io.DeserializerFactory; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; -import com.navercorp.pinpoint.thrift.util.SerializationUtils; -import org.apache.commons.collections.MapUtils; -import org.apache.thrift.TBase; -import org.apache.thrift.TException; +import com.navercorp.pinpoint.common.util.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - - -/** - * @author HyunGil Jeong - */ +@Service public class AgentEventService { - - private static final Set RESPONSE_EVENT_TYPES = AgentEventType.getTypesByCategory(AgentEventTypeCategory.USER_REQUEST); - private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private AgentEventDao agentEventDao; - @Autowired - private AgentEventMessageSerializer agentEventMessageSerializer; - - @Autowired - private DeserializerFactory commandDeserializerFactory; - - // sync method - public void service(AgentEventBo agentEventBo) { - Object eventMessage = getEventMessage(agentEventBo); - insertEvent(agentEventBo, eventMessage); - } - - @Async("agentEventWorker") - public void handleEvent(PinpointServer pinpointServer, long eventTimestamp, AgentEventType eventType) { - handleEvent(pinpointServer, eventTimestamp, eventType, null); - } - - // for test - void handleEvent(PinpointServer pinpointServer, long eventTimestamp, AgentEventType eventType, Object eventMessage) { - Objects.requireNonNull(pinpointServer, "pinpointServer must not be null"); - Objects.requireNonNull(eventType, "pinpointServer must not be null"); - - Map channelProperties = pinpointServer.getChannelProperties(); - - final String agentId = MapUtils.getString(channelProperties, HandshakePropertyType.AGENT_ID.getName()); - final long startTimestamp = MapUtils.getLong(channelProperties, - HandshakePropertyType.START_TIMESTAMP.getName()); - - AgentEventBo agentEventBo = newAgentEventBo(agentId, startTimestamp, eventTimestamp, eventType); - insertEvent(agentEventBo, eventMessage); - } - - private AgentEventBo newAgentEventBo(String agentId, long startTimestamp, long eventTimestamp, AgentEventType eventType) { - return new AgentEventBo(agentId, startTimestamp, eventTimestamp, eventType); - } - - - private void insertEvent(AgentEventBo agentEventBo, Object eventMessage) { - Objects.requireNonNull(agentEventBo, "agentEventBo must not be null"); - - try { - final byte[] eventBody = agentEventMessageSerializer.serialize(agentEventBo.getEventType(), eventMessage); - agentEventBo.setEventBody(eventBody); - } catch (Exception e) { - logger.warn("error handling agent event", e); - return; + public void insert(final AgentEventBo agentEventBo) { + Assert.requireNonNull(agentEventBo, "agentEventBo must not be null"); + if (logger.isDebugEnabled()) { + logger.debug("Insert {}", agentEventBo); } - logger.info("handle event: {}", agentEventBo); agentEventDao.insert(agentEventBo); } - - @Async("agentEventWorker") - public void handleResponseEvent(ResponseEvent responseEvent, long eventTimestamp) { - Objects.requireNonNull(responseEvent, "responseEvent must not be null"); - - TCommandTransferResponse response = responseEvent.getRouteResult(); - if (response.getRouteResult() != TRouteResult.OK) { - return; - } - insertResponseEvent(responseEvent, eventTimestamp); - } - - private void insertResponseEvent(ResponseEvent responseEvent, long eventTimestamp) { - final TCommandTransfer command = responseEvent.getDeliveryCommand(); - final String agentId = command.getAgentId(); - final long startTimestamp = command.getStartTime(); - - final TCommandTransferResponse response = responseEvent.getRouteResult(); - final byte[] payload = response.getPayload(); - - final Class payloadType = readPayload(payload); - if (payload == null) { - return; - } - - for (AgentEventType eventType : RESPONSE_EVENT_TYPES) { - if (eventType.getMessageType() == payloadType) { - AgentEventBo agentEventBo = new AgentEventBo(agentId, startTimestamp, eventTimestamp, eventType); - agentEventBo.setEventBody(payload); - agentEventDao.insert(agentEventBo); - } - } - } - - private Class readPayload(byte[] payload) { - if (payload == null) { - return Void.class; - } - - try { - final TBase tBase = SerializationUtils.deserialize(payload, commandDeserializerFactory); - return tBase.getClass(); - } catch (TException e) { - logger.warn("Error deserializing ResponseEvent payload", e); - } - return null; - } - - private Object getEventMessage(AgentEventBo agentEventBo) { - if (agentEventBo instanceof DeadlockEventBo) { - return ((DeadlockEventBo) agentEventBo).getDeadlock(); - } - return null; - } - -} +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentInfoService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentInfoService.java new file mode 100644 index 000000000000..121b19d6cbe8 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentInfoService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.service; + +import com.navercorp.pinpoint.collector.dao.AgentInfoDao; +import com.navercorp.pinpoint.collector.dao.ApplicationIndexDao; +import com.navercorp.pinpoint.common.server.bo.AgentInfoBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author emeroad + * @author koo.taejin + */ +@Service +public class AgentInfoService { + + @Autowired + private AgentInfoDao agentInfoDao; + + @Autowired + private ApplicationIndexDao applicationIndexDao; + + public void insert(final AgentInfoBo agentInfoBo) { + agentInfoDao.insert(agentInfoBo); + applicationIndexDao.insert(agentInfoBo); + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentLifeCycleService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentLifeCycleService.java new file mode 100644 index 000000000000..6006f8741ab0 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/AgentLifeCycleService.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.service; + +import com.navercorp.pinpoint.collector.dao.AgentLifeCycleDao; +import com.navercorp.pinpoint.common.server.bo.AgentLifeCycleBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +@Service +public class AgentLifeCycleService { + + @Autowired + private AgentLifeCycleDao agentLifeCycleDao; + + public void insert(final AgentLifeCycleBo agentLifeCycleBo) { + this.agentLifeCycleDao.insert(agentLifeCycleBo); + } + +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/ApiMetaDataService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/ApiMetaDataService.java new file mode 100644 index 000000000000..1a14cf2710c0 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/ApiMetaDataService.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.service; + +import com.navercorp.pinpoint.collector.dao.ApiMetaDataDao; +import com.navercorp.pinpoint.common.server.bo.ApiMetaDataBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ApiMetaDataService { + + @Autowired + private ApiMetaDataDao sqlMetaDataDao; + + public void insert(final ApiMetaDataBo apiMetaDataBo) { + sqlMetaDataDao.insert(apiMetaDataBo); + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/HBaseAgentStatService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/HBaseAgentStatService.java index b048e3078a68..0a1b3ee13f76 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/service/HBaseAgentStatService.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/HBaseAgentStatService.java @@ -20,7 +20,9 @@ import com.navercorp.pinpoint.common.server.bo.stat.AgentStatBo; import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; import com.navercorp.pinpoint.common.server.bo.stat.DataSourceListBo; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcDetailedBo; import com.navercorp.pinpoint.common.server.bo.stat.ResponseTimeBo; @@ -60,7 +62,13 @@ public class HBaseAgentStatService implements AgentStatService { private AgentStatDaoV2 responseTimeDao; @Autowired - private AgentStatDaoV2 deadlockDao; + private AgentStatDaoV2 deadlockDao; + + @Autowired + private AgentStatDaoV2 fileDescriptorDao; + + @Autowired + private AgentStatDaoV2 directBufferDao; @Override public void save(AgentStatBo agentStatBo) { @@ -73,7 +81,9 @@ public void save(AgentStatBo agentStatBo) { this.activeTraceDao.insert(agentId, agentStatBo.getActiveTraceBos()); this.dataSourceListDao.insert(agentId, agentStatBo.getDataSourceListBos()); this.responseTimeDao.insert(agentId, agentStatBo.getResponseTimeBos()); - this.deadlockDao.insert(agentId, agentStatBo.getDeadlockBos()); + this.deadlockDao.insert(agentId, agentStatBo.getDeadlockThreadCountBos()); + this.fileDescriptorDao.insert(agentId, agentStatBo.getFileDescriptorBos()); + this.directBufferDao.insert(agentId, agentStatBo.getDirectBufferBos()); } catch (Exception e) { logger.warn("Error inserting AgentStatBo. Caused:{}", e.getMessage(), e); } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/SendAgentStatService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/SendAgentStatService.java index c14f5d9ecbce..55d33af7b3ff 100644 --- a/collector/src/main/java/com/navercorp/pinpoint/collector/service/SendAgentStatService.java +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/SendAgentStatService.java @@ -17,8 +17,8 @@ import com.navercorp.pinpoint.collector.config.CollectorConfiguration; import com.navercorp.pinpoint.collector.mapper.thrift.stat.TFAgentStatBatchMapper; +import com.navercorp.pinpoint.collector.sender.FlinkTcpDataSender; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatBo; -import com.navercorp.pinpoint.profiler.sender.TcpDataSender; import com.navercorp.pinpoint.thrift.dto.flink.TFAgentStatBatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +38,7 @@ public class SendAgentStatService implements AgentStatService { private final boolean flinkClusterEnable; private final TFAgentStatBatchMapper tFAgentStatBatchMapper = new TFAgentStatBatchMapper(); - private volatile List flinkServerList = new CopyOnWriteArrayList(); + private volatile List flinkTcpDataSenderList = new CopyOnWriteArrayList<>(); private AtomicInteger callCount = new AtomicInteger(1); public SendAgentStatService(CollectorConfiguration config) { @@ -52,32 +52,28 @@ public void save(AgentStatBo agentStatBo) { } try { - TcpDataSender tcpDataSender = roundRobinTcpDataSender(); - + FlinkTcpDataSender tcpDataSender = roundRobinTcpDataSender(); if (tcpDataSender == null) { - logger.warn("not send flink server. Because TcpDataSender is null"); + logger.warn("not send flink server. Because FlinkTcpDataSender is null"); return; } - TFAgentStatBatch tFAgentStatBatch = tFAgentStatBatchMapper.map(agentStatBo); - if (logger.isDebugEnabled()) { logger.debug("send to flinkserver : {}", tFAgentStatBatch); } - tcpDataSender.send(tFAgentStatBatch); } catch (Exception e) { logger.error("Error sending to flink server. Caused:{}", e.getMessage(), e); } } - public TcpDataSender roundRobinTcpDataSender() { - if (flinkServerList.size() == 0) { + private FlinkTcpDataSender roundRobinTcpDataSender() { + if (flinkTcpDataSenderList.isEmpty()) { return null; } int count = callCount.getAndIncrement(); - int tcpDataSenderIndex = count % flinkServerList.size(); + int tcpDataSenderIndex = count % flinkTcpDataSenderList.size(); if (tcpDataSenderIndex < 0) { tcpDataSenderIndex = tcpDataSenderIndex * -1; @@ -85,15 +81,15 @@ public TcpDataSender roundRobinTcpDataSender() { } try { - return flinkServerList.get(tcpDataSenderIndex); + return flinkTcpDataSenderList.get(tcpDataSenderIndex); } catch (Exception e) { - logger.warn("not get TcpDataSender", e); + logger.warn("not get FlinkTcpDataSender", e); } return null; } - public void replaceFlinkServerList(List flinkServerList) { - this.flinkServerList = new CopyOnWriteArrayList(flinkServerList); + public void replaceFlinkTcpDataSenderList(List flinkTcpDataSenderList) { + this.flinkTcpDataSenderList = new CopyOnWriteArrayList(flinkTcpDataSenderList); } } diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/SqlMetaDataService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/SqlMetaDataService.java new file mode 100644 index 000000000000..6d9cb374fd95 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/SqlMetaDataService.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.service; + +import com.navercorp.pinpoint.collector.dao.SqlMetaDataDao; +import com.navercorp.pinpoint.common.server.bo.SqlMetaDataBo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SqlMetaDataService { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private SqlMetaDataDao sqlMetaDataDao; + + public void insert(final SqlMetaDataBo sqlMetaDataBo) { + this.sqlMetaDataDao.insert(sqlMetaDataBo); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/StatisticsService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/StatisticsService.java new file mode 100644 index 000000000000..1d89e8392e64 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/StatisticsService.java @@ -0,0 +1,83 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.service; + +import com.navercorp.pinpoint.collector.dao.MapResponseTimeDao; +import com.navercorp.pinpoint.collector.dao.MapStatisticsCalleeDao; +import com.navercorp.pinpoint.collector.dao.MapStatisticsCallerDao; +import com.navercorp.pinpoint.common.trace.ServiceType; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * + * @author netspider + * + */ +@Service +public class StatisticsService { + + @Autowired + private MapStatisticsCalleeDao mapStatisticsCalleeDao; + + @Autowired + private MapStatisticsCallerDao mapStatisticsCallerDao; + + @Autowired + private MapResponseTimeDao mapResponseTimeDao; + + /** + * Calling MySQL from Tomcat generates the following message for the caller(Tomcat) :
+ * emeroad-app (TOMCAT) -> MySQL_DB_ID (MYSQL)[10.25.141.69:3306]
+ *
+ * The following message is generated for the callee(MySQL) :
+ * MySQL (MYSQL) <- emeroad-app (TOMCAT)[localhost:8080] + * @param callerApplicationName + * @param callerServiceType + * @param calleeApplicationName + * @param calleeServiceType + * @param calleeHost + * @param elapsed + * @param isError + */ + public void updateCaller(String callerApplicationName, ServiceType callerServiceType, String callerAgentId, String calleeApplicationName, ServiceType calleeServiceType, String calleeHost, int elapsed, boolean isError) { + mapStatisticsCallerDao.update(callerApplicationName, callerServiceType, callerAgentId, calleeApplicationName, calleeServiceType, calleeHost, elapsed, isError); + } + + /** + * Calling MySQL from Tomcat generates the following message for the callee(MySQL) :
+ * MySQL_DB_ID (MYSQL) <- emeroad-app (TOMCAT)[localhost:8080]
+ *

+ * The following message is generated for the caller(Tomcat) :
+ * emeroad-app (TOMCAT) -> MySQL (MYSQL)[10.25.141.69:3306] + * @param callerApplicationName + * @param callerServiceType + * @param calleeApplicationName + * @param calleeServiceType + * @param callerHost + * @param elapsed + * @param isError + */ + public void updateCallee(String calleeApplicationName, ServiceType calleeServiceType, String callerApplicationName, ServiceType callerServiceType, String callerHost, int elapsed, boolean isError) { + mapStatisticsCalleeDao.update(calleeApplicationName, calleeServiceType, callerApplicationName, callerServiceType, callerHost, elapsed, isError); + } + + public void updateResponseTime(String applicationName, ServiceType serviceType, String agentId, int elapsed, boolean isError) { + mapResponseTimeDao.received(applicationName, serviceType, agentId, elapsed, isError); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/StringMetaDataService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/StringMetaDataService.java new file mode 100644 index 000000000000..1007d000e822 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/StringMetaDataService.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.service; + +import com.navercorp.pinpoint.collector.dao.StringMetaDataDao; +import com.navercorp.pinpoint.common.server.bo.StringMetaDataBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class StringMetaDataService { + @Autowired + private StringMetaDataDao stringMetaDataDao; + + public void insert(final StringMetaDataBo stringMetaDataBo) { + this.stringMetaDataDao.insert(stringMetaDataBo); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/service/TraceService.java b/collector/src/main/java/com/navercorp/pinpoint/collector/service/TraceService.java new file mode 100644 index 000000000000..886d8a0e7742 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/service/TraceService.java @@ -0,0 +1,200 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.service; + +import com.navercorp.pinpoint.collector.dao.ApplicationTraceIndexDao; +import com.navercorp.pinpoint.collector.dao.HostApplicationMapDao; +import com.navercorp.pinpoint.collector.dao.TraceDao; +import com.navercorp.pinpoint.common.server.bo.SpanBo; +import com.navercorp.pinpoint.common.server.bo.SpanChunkBo; +import com.navercorp.pinpoint.common.server.bo.SpanEventBo; +import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; +import com.navercorp.pinpoint.common.trace.ServiceType; +import org.apache.commons.collections.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class TraceService { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private TraceDao traceDao; + + @Autowired + private ApplicationTraceIndexDao applicationTraceIndexDao; + + @Autowired + private HostApplicationMapDao hostApplicationMapDao; + + @Autowired + private StatisticsService statisticsService; + + @Autowired + private ServiceTypeRegistryService registry; + + public void insertSpanChunk(final SpanChunkBo spanChunkBo) { + traceDao.insertSpanChunk(spanChunkBo); + final ServiceType applicationServiceType = getApplicationServiceType(spanChunkBo); + final List spanEventList = spanChunkBo.getSpanEventBoList(); + if (spanEventList != null) { + // TODO need to batch update later. + insertSpanEventList(spanEventList, applicationServiceType, spanChunkBo.getApplicationId(), spanChunkBo.getAgentId(), spanChunkBo.getEndPoint()); + } + } + + private ServiceType getApplicationServiceType(SpanChunkBo spanChunk) { + final short applicationServiceTypeCode = spanChunk.getApplicationServiceType(); + return registry.findServiceType(applicationServiceTypeCode); + } + + public void insertSpan(final SpanBo spanBo) { + traceDao.insert(spanBo); + applicationTraceIndexDao.insert(spanBo); + insertAcceptorHost(spanBo); + insertSpanStat(spanBo); + insertSpanEventStat(spanBo); + } + + private void insertAcceptorHost(SpanBo span) { + // save host application map + // acceptor host is set at profiler module only when the span is not the kind of root span + final String acceptorHost = span.getAcceptorHost(); + if (acceptorHost == null) { + return; + } + final String spanApplicationName = span.getApplicationId(); + final short applicationServiceTypeCode = getApplicationServiceType(span).getCode(); + + final String parentApplicationName = span.getParentApplicationId(); + final short parentServiceType = span.getParentApplicationServiceType(); + + final ServiceType spanServiceType = registry.findServiceType(span.getServiceType()); + if (spanServiceType.isQueue()) { + hostApplicationMapDao.insert(span.getEndPoint(), spanApplicationName, applicationServiceTypeCode, parentApplicationName, parentServiceType); + } else { + hostApplicationMapDao.insert(acceptorHost, spanApplicationName, applicationServiceTypeCode, parentApplicationName, parentServiceType); + } + } + + private ServiceType getApplicationServiceType(SpanBo span) { + // Check if applicationServiceType is set. If not, use span's service type. + final short applicationServiceTypeCode = span.getApplicationServiceType(); + return registry.findServiceType(applicationServiceTypeCode); + } + + private void insertSpanStat(SpanBo span) { + final ServiceType applicationServiceType = getApplicationServiceType(span); + final ServiceType spanServiceType = registry.findServiceType(span.getServiceType()); + + final boolean isError = span.getErrCode() != 0; + int bugCheck = 0; + if (span.getParentSpanId() == -1) { + if (spanServiceType.isQueue()) { + // create virtual queue node + statisticsService.updateCaller(span.getAcceptorHost(), spanServiceType, span.getRemoteAddr(), span.getApplicationId(), applicationServiceType, span.getEndPoint(), span.getElapsed(), isError); + + statisticsService.updateCallee(span.getApplicationId(), applicationServiceType, span.getAcceptorHost(), spanServiceType, span.getAgentId(), span.getElapsed(), isError); + } else { + // create virtual user + statisticsService.updateCaller(span.getApplicationId(), ServiceType.USER, span.getAgentId(), span.getApplicationId(), applicationServiceType, span.getAgentId(), span.getElapsed(), isError); + + // update the span information of the current node (self) + statisticsService.updateCallee(span.getApplicationId(), applicationServiceType, span.getApplicationId(), ServiceType.USER, span.getAgentId(), span.getElapsed(), isError); + } + bugCheck++; + } + + // save statistics info only when parentApplicationContext exists + // when drawing server map based on statistics info, you must know the application name of the previous node. + if (span.getParentApplicationId() != null) { + String parentApplicationName = span.getParentApplicationId(); + logger.debug("Received parent application name. {}", parentApplicationName); + + ServiceType parentApplicationType = registry.findServiceType(span.getParentApplicationServiceType()); + + // create virtual queue node if current' span's service type is a queue AND : + // 1. parent node's application service type is not a queue (it may have come from a queue that is traced) + // 2. current node's application service type is not a queue (current node may be a queue that is traced) + if (spanServiceType.isQueue()) { + if (!applicationServiceType.isQueue() && !parentApplicationType.isQueue()) { + // emulate virtual queue node's accept Span and record it's acceptor host + hostApplicationMapDao.insert(span.getRemoteAddr(), span.getAcceptorHost(), spanServiceType.getCode(), parentApplicationName, parentApplicationType.getCode()); + // emulate virtual queue node's send SpanEvent + statisticsService.updateCaller(span.getAcceptorHost(), spanServiceType, span.getRemoteAddr(), span.getApplicationId(), applicationServiceType, span.getEndPoint(), span.getElapsed(), isError); + + parentApplicationName = span.getAcceptorHost(); + parentApplicationType = spanServiceType; + } + } + + statisticsService.updateCallee(span.getApplicationId(), applicationServiceType, parentApplicationName, parentApplicationType, span.getAgentId(), span.getElapsed(), isError); + bugCheck++; + } + + // record the response time of the current node (self). + // blow code may be conflict of idea above callee key. + // it is odd to record reversely, because of already recording the caller data at previous node. + // the data may be different due to timeout or network error. + + statisticsService.updateResponseTime(span.getApplicationId(), applicationServiceType, span.getAgentId(), span.getElapsed(), isError); + + if (bugCheck != 1) { + logger.warn("ambiguous span found(bug). span:{}", span); + } + } + + private void insertSpanEventStat(SpanBo span) { + + final List spanEventList = span.getSpanEventBoList(); + if (CollectionUtils.isEmpty(spanEventList)) { + return; + } + + final ServiceType applicationServiceType = getApplicationServiceType(span); + + logger.debug("handle spanEvent size:{}", spanEventList.size()); + // TODO need to batch update later. + insertSpanEventList(spanEventList, applicationServiceType, span.getApplicationId(), span.getAgentId(), span.getEndPoint()); + } + + private void insertSpanEventList(List spanEventList, ServiceType applicationServiceType, String applicationId, String agentId, String endPoint) { + for (SpanEventBo spanEvent : spanEventList) { + final ServiceType spanEventType = registry.findServiceType(spanEvent.getServiceType()); + if (!spanEventType.isRecordStatistics()) { + continue; + } + + // if terminal update statistics + final int elapsed = spanEvent.getEndElapsed(); + final boolean hasException = spanEvent.hasException(); + + /* + * save information to draw a server map based on statistics + */ + // save the information of caller (the spanevent that called span) + statisticsService.updateCaller(applicationId, applicationServiceType, agentId, spanEvent.getDestinationId(), spanEventType, spanEvent.getEndPoint(), elapsed, hasException); + + // save the information of callee (the span that spanevent called) + statisticsService.updateCallee(spanEvent.getDestinationId(), spanEventType, applicationId, applicationServiceType, endPoint, elapsed, hasException); + } + } +} \ No newline at end of file diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/util/Address.java b/collector/src/main/java/com/navercorp/pinpoint/collector/util/Address.java new file mode 100644 index 000000000000..4c00fd273ff8 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/util/Address.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.util; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface Address { + String getHost(); + int getPort(); +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/util/AddressParser.java b/collector/src/main/java/com/navercorp/pinpoint/collector/util/AddressParser.java new file mode 100644 index 000000000000..b399ca2d7fb6 --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/util/AddressParser.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.util; + +import com.navercorp.pinpoint.common.util.NetUtils; + +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class AddressParser { + + private static final NetUtils.HostAndPortFactory

addressFactory = new NetUtils.HostAndPortFactory
() { + @Override + public Address newInstance(String host, int port) { + return new DefaultAddress(host, port); + } + }; + + public static List
parseAddressLIst(List addressList) { + return NetUtils.toHostAndPortLIst(addressList, addressFactory); + } +} diff --git a/collector/src/main/java/com/navercorp/pinpoint/collector/util/DefaultAddress.java b/collector/src/main/java/com/navercorp/pinpoint/collector/util/DefaultAddress.java new file mode 100644 index 000000000000..c35764054d7b --- /dev/null +++ b/collector/src/main/java/com/navercorp/pinpoint/collector/util/DefaultAddress.java @@ -0,0 +1,72 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.util; + +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultAddress implements Address { + private final String host; + private final int port; + + public DefaultAddress(String host, int port) { + this.host = Assert.requireNonNull(host, "host must not be null"); + if (!HostAndPort.isValidPort(port)) { + throw new IllegalArgumentException("out of range:" + port); + } + this.port = port; + } + + @Override + public String getHost() { + return host; + } + + @Override + public int getPort() { + return port; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DefaultAddress that = (DefaultAddress) o; + + if (port != that.port) return false; + return host != null ? host.equals(that.host) : that.host == null; + } + + @Override + public int hashCode() { + int result = host != null ? host.hashCode() : 0; + result = 31 * result + port; + return result; + } + + @Override + public String toString() { + return "DefaultAddress{" + + "host='" + host + '\'' + + ", port=" + port + + '}'; + } +} diff --git a/collector/src/main/resources-local/log4j.xml b/collector/src/main/resources-local/log4j.xml index 437a20705fac..f4f4653d51a1 100644 --- a/collector/src/main/resources-local/log4j.xml +++ b/collector/src/main/resources-local/log4j.xml @@ -24,7 +24,7 @@ - + diff --git a/collector/src/main/resources-release/log4j.xml b/collector/src/main/resources-release/log4j.xml index d94435d762c4..94d3dab8cbdb 100644 --- a/collector/src/main/resources-release/log4j.xml +++ b/collector/src/main/resources-release/log4j.xml @@ -1,4 +1,20 @@ + + @@ -24,22 +40,22 @@ - + - + - + - + diff --git a/collector/src/main/resources/applicationContext-collector-namespace.xml b/collector/src/main/resources/applicationContext-collector-namespace.xml new file mode 100644 index 000000000000..6ca8acb04f96 --- /dev/null +++ b/collector/src/main/resources/applicationContext-collector-namespace.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/collector/src/main/resources/applicationContext-collector.xml b/collector/src/main/resources/applicationContext-collector.xml index a4efa66a3f9c..dc9c5e540096 100644 --- a/collector/src/main/resources/applicationContext-collector.xml +++ b/collector/src/main/resources/applicationContext-collector.xml @@ -1,4 +1,20 @@ + + + @@ -107,19 +125,22 @@ - - + + + - - + + + - - + + + @@ -145,18 +166,9 @@ - - - - - - - - + - - - + @@ -198,8 +210,7 @@ - - + @@ -234,18 +245,53 @@ - + - - - - - + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -253,19 +299,94 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -277,22 +398,34 @@ + + + + + + + + + + + + - - + + @@ -300,12 +433,6 @@ - - - - - - @@ -318,8 +445,19 @@ + + + + + + + + + + + diff --git a/collector/src/main/resources/applicationContext-hbase.xml b/collector/src/main/resources/applicationContext-hbase.xml index 6fe2efcb75ba..6556064d2d58 100644 --- a/collector/src/main/resources/applicationContext-hbase.xml +++ b/collector/src/main/resources/applicationContext-hbase.xml @@ -1,7 +1,6 @@ @@ -30,7 +29,7 @@ ${hbase.client.async.enable:false} ${hbase.client.async.in.queuesize:10000} ${hbase.client.async.flush.period.ms:100} - ${hbase.client.async.max.retries.in.queue:10} + ${hbase.client.async.max.retries.in.queue:10000} @@ -46,15 +45,19 @@ - - - + + + + + + + - + @@ -64,12 +67,16 @@ - + - - + + + + + + @@ -77,9 +84,7 @@ - - 32 - + diff --git a/collector/src/main/resources/hbase.properties b/collector/src/main/resources/hbase.properties index 81624d3ecc92..01b4275d34eb 100644 --- a/collector/src/main/resources/hbase.properties +++ b/collector/src/main/resources/hbase.properties @@ -4,6 +4,9 @@ hbase.client.port=2181 # hbase default:/hbase hbase.zookeeper.znode.parent=/hbase +# hbase namespace to use default:default +hbase.namespace=default + # hbase timeout option================================================================================== # hbase default:true hbase.ipc.client.tcpnodelay=true @@ -30,5 +33,5 @@ hbase.client.async.enable=false hbase.client.async.in.queuesize=10000 # periodic asyncPut ops flush time. default:100 hbase.client.async.flush.period.ms=100 -# the max number of the retry attempts before dropping the request. default:10 -hbase.client.async.max.retries.in.queue=10 \ No newline at end of file +# the max number of the retry attempts to insert queue before dropping the request. default:10000 +hbase.client.async.max.retries.in.queue=10000 \ No newline at end of file diff --git a/collector/src/main/resources/pinpoint-collector.properties b/collector/src/main/resources/pinpoint-collector.properties index e232c9a23df4..7a9eb6deb491 100644 --- a/collector/src/main/resources/pinpoint-collector.properties +++ b/collector/src/main/resources/pinpoint-collector.properties @@ -9,6 +9,13 @@ collector.receiver.base.worker.queueSize=1024 # monitoring for tcp worker collector.receiver.base.worker.monitor=true +collector.receiver.base.request.timeout=3000 +collector.receiver.base.closewait.timeout=3000 +# 5 min +collector.receiver.base.ping.interval=300000 +# 30 min +collector.receiver.base.pingwait.timeout=1800000 + # stat receiver config --------------------------------------------------------------------- collector.receiver.stat.udp=true collector.receiver.stat.udp.ip=0.0.0.0 @@ -20,6 +27,13 @@ collector.receiver.stat.tcp=false collector.receiver.stat.tcp.ip=0.0.0.0 collector.receiver.stat.tcp.port=9995 +collector.receiver.stat.tcp.request.timeout=3000 +collector.receiver.stat.tcp.closewait.timeout=3000 +# 5 min +collector.receiver.stat.tcp.ping.interval=300000 +# 30 min +collector.receiver.stat.tcp.pingwait.timeout=1800000 + # number of udp statworker threads collector.receiver.stat.worker.threadSize=8 # capacity of udp statworker queue @@ -39,6 +53,13 @@ collector.receiver.span.tcp=false collector.receiver.span.tcp.ip=0.0.0.0 collector.receiver.span.tcp.port=9996 +collector.receiver.span.tcp.request.timeout=3000 +collector.receiver.span.tcp.closewait.timeout=3000 +# 5 min +collector.receiver.span.tcp.ping.interval=300000 +# 30 min +collector.receiver.span.tcp.pingwait.timeout=1800000 + # number of udp statworker threads collector.receiver.span.worker.threadSize=32 # capacity of udp statworker queue @@ -53,7 +74,7 @@ collector.l4.ip= # change OS level read/write socket buffer size (for linux) #sudo sysctl -w net.core.rmem_max= #sudo sysctl -w net.core.wmem_max= -# check current values using: +# check current values using: #$ /sbin/sysctl -a | grep -e rmem -e wmem # number of agent event worker threads diff --git a/collector/src/main/resources/servlet-context.xml b/collector/src/main/resources/servlet-context.xml index 98d8bc205630..806d582e1fc8 100644 --- a/collector/src/main/resources/servlet-context.xml +++ b/collector/src/main/resources/servlet-context.xml @@ -12,7 +12,7 @@ + base-package="com.navercorp.pinpoint.collector.manage.controller, com.navercorp.pinpoint.collector.controller"> maxWaitTime) { - return false; - } - } - } - -} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/cluster/route/filter/AgentEventHandlingFilterTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/cluster/route/filter/AgentEventHandlingFilterTest.java new file mode 100644 index 000000000000..d12552294f49 --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/cluster/route/filter/AgentEventHandlingFilterTest.java @@ -0,0 +1,138 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.cluster.route.filter; + +import com.navercorp.pinpoint.collector.cluster.route.ResponseEvent; +import com.navercorp.pinpoint.collector.dao.AgentEventDao; +import com.navercorp.pinpoint.collector.service.AgentEventService; +import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; +import com.navercorp.pinpoint.common.server.util.AgentEventType; +import com.navercorp.pinpoint.io.header.HeaderEntity; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; +import com.navercorp.pinpoint.io.request.DefaultMessage; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import com.navercorp.pinpoint.thrift.dto.command.TCommandEcho; +import com.navercorp.pinpoint.thrift.dto.command.TCommandThreadDumpResponse; +import com.navercorp.pinpoint.thrift.dto.command.TCommandTransfer; +import com.navercorp.pinpoint.thrift.dto.command.TCommandTransferResponse; +import com.navercorp.pinpoint.thrift.dto.command.TRouteResult; +import com.navercorp.pinpoint.thrift.io.DeserializerFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; +import org.apache.thrift.TBase; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +@RunWith(MockitoJUnitRunner.class) +public class AgentEventHandlingFilterTest { + + @Mock + private PinpointServer pinpointServer; + + @Mock + private AgentEventDao agentEventDao; + + @Mock + private AgentEventService agentEventService; + + @Mock + private DeserializerFactory deserializerFactory; + + @InjectMocks + private AgentEventHandlingFilter agentEventHandlingFilter = new AgentEventHandlingFilter(); + + private static final String TEST_AGENT_ID = "TEST_AGENT"; + private static final long TEST_START_TIMESTAMP = System.currentTimeMillis(); + private static final long TEST_EVENT_TIMESTAMP = TEST_START_TIMESTAMP + 10; + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void handler_should_handle_serialization_of_request_events() throws Exception { + // given + final AgentEventType expectedEventType = AgentEventType.USER_THREAD_DUMP; + final TCommandThreadDumpResponse expectedThreadDumpResponse = new TCommandThreadDumpResponse(); + final byte[] expectedThreadDumpResponseBody = new byte[0]; + + final TCommandTransfer tCommandTransfer = new TCommandTransfer(); + tCommandTransfer.setAgentId(TEST_AGENT_ID); + tCommandTransfer.setStartTime(TEST_START_TIMESTAMP); + + final TCommandTransferResponse tCommandTransferResponse = new TCommandTransferResponse(); + tCommandTransferResponse.setRouteResult(TRouteResult.OK); + tCommandTransferResponse.setPayload(expectedThreadDumpResponseBody); + + final ResponseEvent responseEvent = new ResponseEvent(tCommandTransfer, null, 0, tCommandTransferResponse); + + ArgumentCaptor argCaptor = ArgumentCaptor.forClass(AgentEventBo.class); + HeaderTBaseDeserializer deserializer = mock(HeaderTBaseDeserializer.class); + when(this.deserializerFactory.createDeserializer()).thenReturn(deserializer); + Message> message = new DefaultMessage<>(new HeaderV1((short)1000), HeaderEntity.EMPTY_HEADER_ENTITY, expectedThreadDumpResponse); + when(deserializer.deserialize(expectedThreadDumpResponseBody)).thenReturn(message); + // when + this.agentEventHandlingFilter.handleResponseEvent(responseEvent, TEST_EVENT_TIMESTAMP); + // then + verify(this.agentEventService, atLeast(1)).insert(argCaptor.capture()); + AgentEventBo actualAgentEventBo = argCaptor.getValue(); + assertEquals(TEST_AGENT_ID, actualAgentEventBo.getAgentId()); + assertEquals(TEST_START_TIMESTAMP, actualAgentEventBo.getStartTimestamp()); + assertEquals(TEST_EVENT_TIMESTAMP, actualAgentEventBo.getEventTimestamp()); + assertEquals(expectedEventType, actualAgentEventBo.getEventType()); + assertArrayEquals(expectedThreadDumpResponseBody, actualAgentEventBo.getEventBody()); + } + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void handler_should_ignore_request_events_with_unsupported_message_types() throws Exception { + // given + final TCommandEcho mismatchingResponse = new TCommandEcho(); + final byte[] mismatchingResponseBody = new byte[0]; + + final TCommandTransfer tCommandTransfer = new TCommandTransfer(); + tCommandTransfer.setAgentId(TEST_AGENT_ID); + tCommandTransfer.setStartTime(TEST_START_TIMESTAMP); + + final TCommandTransferResponse tCommandTransferResponse = new TCommandTransferResponse(); + tCommandTransferResponse.setRouteResult(TRouteResult.OK); + tCommandTransferResponse.setPayload(mismatchingResponseBody); + + final ResponseEvent responseEvent = new ResponseEvent(tCommandTransfer, null, 0, tCommandTransferResponse); + + ArgumentCaptor argCaptor = ArgumentCaptor.forClass(AgentEventBo.class); + HeaderTBaseDeserializer deserializer = mock(HeaderTBaseDeserializer.class); + when(this.deserializerFactory.createDeserializer()).thenReturn(deserializer); + Message> message = new DefaultMessage<>(new HeaderV1((short)1000), HeaderEntity.EMPTY_HEADER_ENTITY, mismatchingResponse); + when(deserializer.deserialize(mismatchingResponseBody)).thenReturn(message); + // when + this.agentEventHandlingFilter.handleResponseEvent(responseEvent, TEST_EVENT_TIMESTAMP); + // then + verify(this.agentEventDao, never()).insert(argCaptor.capture()); + } +} \ No newline at end of file diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperJobWorkerTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperJobWorkerTest.java index 2ee4fb9c2ab1..dc95d86a427f 100644 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperJobWorkerTest.java +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/cluster/zookeeper/ZookeeperJobWorkerTest.java @@ -16,12 +16,16 @@ package com.navercorp.pinpoint.collector.cluster.zookeeper; -import com.navercorp.pinpoint.collector.TestAwaitTaskUtils; -import com.navercorp.pinpoint.collector.TestAwaitUtils; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.PinpointZookeeperException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.BadOperationException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.PinpointZookeeperException; import com.navercorp.pinpoint.common.util.BytesUtils; import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; import com.navercorp.pinpoint.rpc.server.PinpointServer; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; +import org.apache.curator.utils.ZKPaths; +import org.apache.zookeeper.KeeperException; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; @@ -212,24 +216,28 @@ public void connect() throws IOException { } @Override - public synchronized void reconnectWhenSessionExpired() { - connected = true; + public synchronized void createPath(String value) throws PinpointZookeeperException, InterruptedException { + ZKPaths.PathAndNode pathAndNode = ZKPaths.getPathAndNode(value); + contents.put(pathAndNode.getPath(), EMPTY_BYTE); } @Override - public synchronized void createPath(String path) throws PinpointZookeeperException, InterruptedException { - contents.put(path, EMPTY_BYTE); + public synchronized String createNode(String zNodePath, byte[] data) throws PinpointZookeeperException, InterruptedException { + byte[] bytes = contents.putIfAbsent(zNodePath, data); + if (bytes != null) { + throw new BadOperationException("node already exist"); + } + return zNodePath; } @Override - public synchronized void createPath(String path, boolean createEndNode) throws PinpointZookeeperException, InterruptedException { - contents.put(path, EMPTY_BYTE); - } + public String createOrSetNode(String path, byte[] payload) throws PinpointZookeeperException, KeeperException, InterruptedException { + if (intAdder.incrementAndGet() % 2 == 1) { + throw new PinpointZookeeperException("exception"); + } - @Override - public synchronized String createNode(String zNodePath, byte[] data) throws PinpointZookeeperException, InterruptedException { - contents.put(zNodePath, data); - return ""; + contents.put(path, payload); + return path; } @Override @@ -239,16 +247,8 @@ public synchronized byte[] getData(String path) throws PinpointZookeeperExceptio } @Override - public synchronized void setData(String path, byte[] data) throws PinpointZookeeperException, InterruptedException { - // for check retry - if (intAdder.incrementAndGet() % 2 == 1) { - throw new PinpointZookeeperException("exception"); - } - - if (!contents.containsKey(path)) { - throw new PinpointZookeeperException("can't find path."); - } - contents.put(path, data); + public byte[] getData(String path, boolean watch) throws PinpointZookeeperException, InterruptedException { + return contents.get(path); } @Override @@ -256,18 +256,13 @@ public synchronized void delete(String path) throws PinpointZookeeperException, contents.remove(path); } - @Override - public synchronized boolean exists(String path) throws PinpointZookeeperException, InterruptedException { - return contents.containsKey(path); - } - @Override public synchronized boolean isConnected() { return connected; } @Override - public synchronized List getChildrenNode(String path, boolean watch) throws PinpointZookeeperException, InterruptedException { + public List getChildNodeList(String path, boolean watch) { return new ArrayList<>(); } diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/BulkIncrementerTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/BulkIncrementerTest.java new file mode 100644 index 000000000000..c6d6171c7207 --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/dao/hbase/statistics/BulkIncrementerTest.java @@ -0,0 +1,513 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.dao.hbase.statistics; + +import com.google.common.collect.Lists; +import com.navercorp.pinpoint.common.util.BytesUtils; +import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Increment; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; +import java.util.Random; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +@RunWith(MockitoJUnitRunner.class) +public class BulkIncrementerTest { + + private static final byte[] CF = Bytes.toBytes("CF"); + + private final BulkIncrementer bulkIncrementer = new BulkIncrementer(new RowKeyMerge(CF)); + + @Mock + private RowKeyDistributorByHashPrefix rowKeyDistributor; + + @Before + public void setUp() { + when(rowKeyDistributor.getDistributedKey(any(byte[].class))).then(invocation -> invocation.getArgument(0)); + } + + @Test + public void singleTable() { + // Given + TableName tableA = TableName.valueOf("A"); + TestDataSet testDataSetA_0_0 = new TestDataSet(tableA, 0, 0, 100); + TestDataSet testDataSetA_0_1 = new TestDataSet(tableA, 0, 1, 200); + + List testDatas = new ArrayList<>(); + testDatas.addAll(testDataSetA_0_0.getTestDatas()); + testDatas.addAll(testDataSetA_0_1.getTestDatas()); + Collections.shuffle(testDatas); + + // When + for (TestData testData : testDatas) { + bulkIncrementer.increment(testData.getTableName(), testData.getRowKey(), testData.getColumnName()); + } + + // Then + Map> incrementMap = bulkIncrementer.getIncrements(rowKeyDistributor); + TestVerifier verifier = new TestVerifier(incrementMap); + verifier.verify(testDataSetA_0_0); + verifier.verify(testDataSetA_0_1); + } + + @Test + public void multipleTables() { + // Given + TableName tableA = TableName.valueOf("a", "A"); + TableName tableB = TableName.valueOf("b", "A"); + TestDataSet testDataSetA_0_0 = new TestDataSet(tableA, 0, 0, 100); + TestDataSet testDataSetA_0_1 = new TestDataSet(tableA, 0, 1, 200); + TestDataSet testDataSetA_1_0 = new TestDataSet(tableA, 1, 0, 300); + TestDataSet testDataSetA_1_1 = new TestDataSet(tableA, 1, 1, 400); + TestDataSet testDataSetB_0_0 = new TestDataSet(tableB, 0, 0, 500); + TestDataSet testDataSetB_0_1 = new TestDataSet(tableB, 0, 1, 600); + TestDataSet testDataSetB_1_0 = new TestDataSet(tableB, 1, 0, 700); + TestDataSet testDataSetB_1_1 = new TestDataSet(tableB, 1, 1, 800); + + List testDatas = new ArrayList<>(); + testDatas.addAll(testDataSetA_0_0.getTestDatas()); + testDatas.addAll(testDataSetA_0_1.getTestDatas()); + testDatas.addAll(testDataSetA_1_0.getTestDatas()); + testDatas.addAll(testDataSetA_1_1.getTestDatas()); + testDatas.addAll(testDataSetB_0_0.getTestDatas()); + testDatas.addAll(testDataSetB_0_1.getTestDatas()); + testDatas.addAll(testDataSetB_1_0.getTestDatas()); + testDatas.addAll(testDataSetB_1_1.getTestDatas()); + Collections.shuffle(testDatas); + + // When + for (TestData testData : testDatas) { + bulkIncrementer.increment(testData.getTableName(), testData.getRowKey(), testData.getColumnName()); + } + + // Then + Map> incrementMap = bulkIncrementer.getIncrements(rowKeyDistributor); + TestVerifier verifier = new TestVerifier(incrementMap); + verifier.verify(testDataSetA_0_0); + verifier.verify(testDataSetA_0_1); + verifier.verify(testDataSetA_1_0); + verifier.verify(testDataSetA_1_1); + verifier.verify(testDataSetB_0_0); + verifier.verify(testDataSetB_0_1); + verifier.verify(testDataSetB_1_0); + verifier.verify(testDataSetB_1_1); + } + + @Test + public void singleTableConcurrent() throws Exception { + // Given + TableName tableA = TableName.valueOf("A"); + TestDataSet testDataSetA_0_0 = new TestDataSet(tableA, 0, 0, 1000000); + TestDataSet testDataSetA_0_1 = new TestDataSet(tableA, 0, 1, 1000001); + + List testDatas = new ArrayList<>(); + testDatas.addAll(testDataSetA_0_0.getTestDatas()); + testDatas.addAll(testDataSetA_0_1.getTestDatas()); + Collections.shuffle(testDatas); + + // When + final int numIncrementers = 16; + List> testDataPartitions = Lists.partition(testDatas, testDatas.size() / (numIncrementers - 1)); + final CountDownLatch completeLatch = new CountDownLatch(testDataPartitions.size()); + final CountDownLatch flusherLatch = new CountDownLatch(1); + + FutureTask>> flushTask = new FutureTask<>(new Flusher(completeLatch, flusherLatch)); + new Thread(flushTask, "Flusher").start(); + + int counter = 0; + for (List testDataPartition : testDataPartitions) { + Incrementer incrementer = new Incrementer(completeLatch, testDataPartition); + new Thread(incrementer, "Incrementer-" + counter++).start(); + } + + flusherLatch.await(30L, TimeUnit.SECONDS); + + // Then + Map> incrementMap = flushTask.get(5L, TimeUnit.SECONDS); + TestVerifier verifier = new TestVerifier(incrementMap); + verifier.verify(testDataSetA_0_0); + verifier.verify(testDataSetA_0_1); + } + + @Test + public void multipleTablesConcurrent() throws Exception { + // Given + final int numTables = 50; + List tableNames = new ArrayList<>(numTables); + for (int i = 0; i < numTables; i++) { + tableNames.add(TableName.valueOf(i + "")); + } + final int numRowIds = 100; + final int numColumnIds = 20; + final int numTestDataSets = numTables * numRowIds * numColumnIds; + + final int maxCallCount = 200; + final Random random = new Random(); + List testDataSets = new ArrayList<>(numTestDataSets); + for (TableName tableName : tableNames) { + for (int i = 0; i < numRowIds; i++) { + for (int j = 0; j < numColumnIds; j++) { + int callCount = random.nextInt(maxCallCount - 100) + 100; + TestDataSet testDataSet = new TestDataSet(tableName, i, j, callCount); + testDataSets.add(testDataSet); + } + } + } + final int maxNumTestDatas = numTestDataSets * maxCallCount; + List testDatas = new ArrayList<>(maxNumTestDatas); + for (TestDataSet testDataSet : testDataSets) { + testDatas.addAll(testDataSet.getTestDatas()); + } + Collections.shuffle(testDatas); + + // When + final int numIncrementers = 16; + List> testDataPartitions = Lists.partition(testDatas, testDatas.size() / (numIncrementers - 1)); + final CountDownLatch incrementorLatch = new CountDownLatch(testDataPartitions.size()); + final CountDownLatch flusherLatch = new CountDownLatch(1); + + FutureTask>> flushTask = new FutureTask<>(new Flusher(incrementorLatch, flusherLatch)); + new Thread(flushTask, "Flusher").start(); + + int counter = 0; + for (List testDataPartition : testDataPartitions) { + Incrementer incrementer = new Incrementer(incrementorLatch, testDataPartition); + new Thread(incrementer, "Incrementer-" + counter++).start(); + } + + flusherLatch.await(30L, TimeUnit.SECONDS); + + // Then + Map> incrementMap = flushTask.get(5L, TimeUnit.SECONDS); + TestVerifier verifier = new TestVerifier(incrementMap); + for (TestDataSet testDataSet : testDataSets) { + verifier.verify(testDataSet); + } + } + + private class Incrementer implements Runnable { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final CountDownLatch completeLatch; + private final List testDatas; + + private Incrementer(CountDownLatch completeLatch, List testDatas) { + this.completeLatch = completeLatch; + this.testDatas = testDatas; + } + + @Override + public void run() { + for (TestData testData : testDatas) { + bulkIncrementer.increment(testData.getTableName(), testData.getRowKey(), testData.getColumnName()); + } + completeLatch.countDown(); + } + } + + private class Flusher implements Callable>> { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final CountDownLatch awaitLatch; + private final CountDownLatch completeLatch; + + private Flusher(CountDownLatch awaitLatch, CountDownLatch completeLatch) { + this.awaitLatch = awaitLatch; + this.completeLatch = completeLatch; + } + + private void flushToMap(Map> resultMap) { + Map> incrementMap = bulkIncrementer.getIncrements(rowKeyDistributor); + for (Map.Entry> incrementMapEntry : incrementMap.entrySet()) { + TableName tableName = incrementMapEntry.getKey(); + List increments = resultMap.computeIfAbsent(tableName, k -> new ArrayList<>()); + increments.addAll(incrementMapEntry.getValue()); + } + } + + @Override + public Map> call() { + Map> resultMap = new HashMap<>(); + try { + do { + flushToMap(resultMap); + } while (!awaitLatch.await(10L, TimeUnit.MILLISECONDS)); + flushToMap(resultMap); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return Collections.emptyMap(); + } finally { + completeLatch.countDown(); + } + return resultMap; + } + } + + private static class TestVerifier { + + // Map>> + private final Map>> resultMap; + + public TestVerifier(Map> incrementMap) { + this.resultMap = new HashMap<>(); + for (Map.Entry> incrementMapEntry : incrementMap.entrySet()) { + TableName tableName = incrementMapEntry.getKey(); + List increments = incrementMapEntry.getValue(); + resultMap.put(tableName, convertIncrements(increments)); + } + } + + private Map> convertIncrements(List increments) { + if (CollectionUtils.isEmpty(increments)) { + return Collections.emptyMap(); + } + Map> convertedMap = new HashMap<>(); + for (Increment increment : increments) { + ByteBuffer rowKey = ByteBuffer.wrap(increment.getRow()); + + Map convertedKeyValueMap = convertedMap.computeIfAbsent(rowKey, key -> new HashMap<>()); + NavigableMap keyValues = increment.getFamilyMapOfLongs().get(CF); + for (Map.Entry keyValue : keyValues.entrySet()) { + ByteBuffer key = ByteBuffer.wrap(keyValue.getKey()); + Long value = keyValue.getValue(); + if (value != null) { + convertedKeyValueMap.merge(key, value, (val, prev) -> val + prev); + } + } + } + return convertedMap; + } + + public void verify(TestDataSet testDataSet) { + TableName expectedTableName = testDataSet.getTableName(); + RowKey expectedRowKey = testDataSet.getRowKey(); + ColumnName expectedColumnName = testDataSet.getColumnName(); + long expectedCount = testDataSet.getCount(); + Map> rows = resultMap.get(expectedTableName); + if (rows == null) { + Assert.fail("Expected rows not found for " + testDataSet); + } + Map keyValues = rows.get(ByteBuffer.wrap(expectedRowKey.getRowKey())); + if (keyValues == null) { + Assert.fail("Expected row not found for " + testDataSet); + } + Long actualCount = keyValues.get(ByteBuffer.wrap(expectedColumnName.getColumnName())); + if (actualCount == null) { + Assert.fail("Expected column not found for " + testDataSet); + } + Assert.assertEquals("Expected counts do not match for " + testDataSet, expectedCount, (long) actualCount); + } + } + + private static class TestDataSet { + + private final TableName tableName; + private final TestRowKey rowKey; + private final TestColumnName columnName; + private final int count; + private List testDatas; + + private TestDataSet(TableName tableName, int rowId, int columnId, int count) { + this.tableName = tableName; + this.rowKey = new TestRowKey(rowId); + this.columnName = new TestColumnName(columnId); + this.count = count; + } + + public TableName getTableName() { + return tableName; + } + + public RowKey getRowKey() { + return rowKey; + } + + public ColumnName getColumnName() { + return columnName; + } + + public int getCount() { + return count; + } + + public List getTestDatas() { + if (testDatas == null) { + if (count < 1) { + testDatas = Collections.emptyList(); + } else { + testDatas = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + TestData testData = new TestData(this.tableName, this.rowKey, this.columnName); + testDatas.add(testData); + } + } + } + return testDatas; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("TestDataSet{"); + sb.append("tableName=").append(tableName); + sb.append(", row=").append(rowKey.getId()); + sb.append(", column=").append(columnName.getId()); + sb.append(", count=").append(count); + sb.append('}'); + return sb.toString(); + } + } + + private static class TestData { + + private final TableName tableName; + private final RowKey rowKey; + private final ColumnName columnName; + + private TestData(TableName tableName, RowKey rowKey, ColumnName columnName) { + this.tableName = tableName; + this.rowKey = rowKey; + this.columnName = columnName; + } + + public TableName getTableName() { + return tableName; + } + + public RowKey getRowKey() { + return rowKey; + } + + public ColumnName getColumnName() { + return columnName; + } + } + + private static class TestRowKey implements RowKey { + + private final int id; + + private TestRowKey(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + @Override + public byte[] getRowKey() { + return BytesUtils.intToVar32(id); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TestRowKey that = (TestRowKey) o; + + return id == that.id; + } + + @Override + public int hashCode() { + return id; + } + } + + private static class TestColumnName implements ColumnName { + + private final int id; + private long count; + + private TestColumnName(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + @Override + public byte[] getColumnName() { + return BytesUtils.intToVar32(id); + } + + @Override + public long getCallCount() { + return count; + } + + @Override + public void setCallCount(long callCount) { + this.count = callCount; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TestColumnName that = (TestColumnName) o; + + return id == that.id; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("TestColumnName{"); + sb.append("id=").append(id); + sb.append(", count=").append(count); + sb.append('}'); + return sb.toString(); + } + } + +} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/handler/AgentStatHandlerV2Test.java b/collector/src/test/java/com/navercorp/pinpoint/collector/handler/AgentStatHandlerV2Test.java deleted file mode 100644 index 48e1cebb5d97..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/handler/AgentStatHandlerV2Test.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.handler; - -import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; -import com.navercorp.pinpoint.collector.mapper.thrift.stat.AgentStatBatchMapper; -import com.navercorp.pinpoint.collector.mapper.thrift.stat.AgentStatMapper; -import com.navercorp.pinpoint.collector.service.AgentStatService; -import com.navercorp.pinpoint.collector.service.HBaseAgentStatService; -import com.navercorp.pinpoint.common.server.bo.stat.ActiveTraceBo; -import com.navercorp.pinpoint.common.server.bo.stat.AgentStatBo; -import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; -import com.navercorp.pinpoint.common.server.bo.stat.DataSourceListBo; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; -import com.navercorp.pinpoint.common.server.bo.stat.JvmGcBo; -import com.navercorp.pinpoint.common.server.bo.stat.JvmGcDetailedBo; -import com.navercorp.pinpoint.common.server.bo.stat.ResponseTimeBo; -import com.navercorp.pinpoint.common.server.bo.stat.TransactionBo; -import com.navercorp.pinpoint.thrift.dto.TAgentInfo; -import com.navercorp.pinpoint.thrift.dto.TAgentStat; -import com.navercorp.pinpoint.thrift.dto.TAgentStatBatch; -import com.navercorp.pinpoint.thrift.dto.TCpuLoad; -import com.navercorp.pinpoint.thrift.dto.TDataSourceList; -import com.navercorp.pinpoint.thrift.dto.TDeadlock; -import com.navercorp.pinpoint.thrift.dto.TJvmGc; -import com.navercorp.pinpoint.thrift.dto.TResponseTime; -import org.junit.Before; -import org.junit.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.fail; -import static org.mockito.Mockito.*; - -/** - * @author HyunGil Jeong - */ -public class AgentStatHandlerV2Test { - - @Mock - private AgentStatMapper agentStatMapper; - - @Mock - private AgentStatBatchMapper agentStatBatchMapper; - - @Mock - private AgentStatDaoV2 jvmGcDao; - - @Mock - private AgentStatDaoV2 jvmGcDetailedDao; - - @Mock - private AgentStatDaoV2 cpuLoadDao; - - @Mock - private AgentStatDaoV2 transactionDao; - - @Mock - private AgentStatDaoV2 activeTraceDao; - - @Mock - private AgentStatDaoV2 dataSourceDao; - - @Mock - private AgentStatDaoV2 responseTimeDao; - - @Mock - private AgentStatDaoV2 deadlockDao; - - @InjectMocks - private HBaseAgentStatService hBaseAgentStatService = new HBaseAgentStatService(); - - @Spy - private List agentStatServiceList = new ArrayList<>(); - - @InjectMocks - private AgentStatHandlerV2 agentStatHandler = new AgentStatHandlerV2(); - - @Before - public void setUp() throws Exception { - agentStatServiceList.add(hBaseAgentStatService); - MockitoAnnotations.initMocks(this); - } - - @Test - public void testHandleForTAgentStat() { - // Given - final String agentId = "agentId"; - final long startTimestamp = Long.MAX_VALUE; - final TAgentStat agentStat = createAgentStat(agentId, startTimestamp); - final AgentStatBo mappedAgentStat = new AgentStatBo(); - when(this.agentStatMapper.map(agentStat)).thenReturn(mappedAgentStat); - // When - agentStatHandler.handleSimple(agentStat); - // Then - verify(jvmGcDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getJvmGcBos()); - verify(jvmGcDetailedDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getJvmGcDetailedBos()); - verify(cpuLoadDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getCpuLoadBos()); - verify(transactionDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getTransactionBos()); - verify(activeTraceDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getActiveTraceBos()); - verify(dataSourceDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDataSourceListBos()); - verify(responseTimeDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getResponseTimeBos()); - verify(deadlockDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDeadlockBos()); - - } - - @Test - public void testHandleForTAgentStatBatch() { - // Given - final int numBatches = 6; - final String agentId = "agentId"; - final long startTimestamp = Long.MAX_VALUE; - final TAgentStatBatch agentStatBatch = createAgentStatBatch(agentId, startTimestamp, numBatches); - final AgentStatBo mappedAgentStat = new AgentStatBo(); - when(this.agentStatBatchMapper.map(agentStatBatch)).thenReturn(mappedAgentStat); - // When - agentStatHandler.handleSimple(agentStatBatch); - // Then - verify(jvmGcDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getJvmGcBos()); - verify(jvmGcDetailedDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getJvmGcDetailedBos()); - verify(cpuLoadDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getCpuLoadBos()); - verify(transactionDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getTransactionBos()); - verify(activeTraceDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getActiveTraceBos()); - verify(dataSourceDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDataSourceListBos()); - verify(responseTimeDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getResponseTimeBos()); - verify(deadlockDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDeadlockBos()); - } - - @Test - public void insertShouldNotBeCalledIfTAgentStatIsMappedToNull() { - // Given - final String agentId = "agentId"; - final long startTimestamp = Long.MAX_VALUE; - final TAgentStat agentStat = createAgentStat(agentId, startTimestamp); - final AgentStatBo mappedAgentStat = null; - when(this.agentStatMapper.map(agentStat)).thenReturn(mappedAgentStat); - // When - agentStatHandler.handleSimple(agentStat); - // Then - verifyZeroInteractions(jvmGcDao); - verifyZeroInteractions(jvmGcDetailedDao); - verifyZeroInteractions(cpuLoadDao); - verifyZeroInteractions(transactionDao); - verifyZeroInteractions(activeTraceDao); - verifyZeroInteractions(dataSourceDao); - verifyZeroInteractions(responseTimeDao); - } - - @Test - public void insertShouldNotBeCalledIfTAgentStatBatchIsMappedToNull() { - // Given - final int numBatches = 6; - final String agentId = "agentId"; - final long startTimestamp = Long.MAX_VALUE; - final TAgentStatBatch agentStatBatch = createAgentStatBatch(agentId, startTimestamp, numBatches); - final AgentStatBo mappedAgentStat = null; - when(this.agentStatBatchMapper.map(agentStatBatch)).thenReturn(mappedAgentStat); - // When - agentStatHandler.handleSimple(agentStatBatch); - // Then - verifyZeroInteractions(jvmGcDao); - verifyZeroInteractions(jvmGcDetailedDao); - verifyZeroInteractions(cpuLoadDao); - verifyZeroInteractions(transactionDao); - verifyZeroInteractions(activeTraceDao); - verifyZeroInteractions(dataSourceDao); - verifyZeroInteractions(responseTimeDao); - } - - @Test(expected=IllegalArgumentException.class) - public void handleShouldThrowIllegalArgumentExceptionForIncorrectTBaseObjects() { - // Given - final TAgentInfo wrongTBaseObject = new TAgentInfo(); - // When - agentStatHandler.handleSimple(wrongTBaseObject); - // Then - fail(); - } - - private TAgentStatBatch createAgentStatBatch(String agentId, long startTimestamp, int numBatches) { - final TAgentStatBatch agentStatBatch = new TAgentStatBatch(); - agentStatBatch.setAgentId(agentId); - agentStatBatch.setStartTimestamp(startTimestamp); - final List agentStats = new ArrayList<>(numBatches); - for (int i = 0; i < numBatches; i++) { - agentStats.add(createAgentStat(agentId, startTimestamp)); - } - agentStatBatch.setAgentStats(agentStats); - return agentStatBatch; - } - - private TAgentStat createAgentStat(String agentId, long startTimestamp) { - final TAgentStat agentStat = new TAgentStat(); - agentStat.setAgentId(agentId); - agentStat.setStartTimestamp(startTimestamp); - agentStat.setGc(new TJvmGc()); - agentStat.setCpuLoad(new TCpuLoad()); - agentStat.setDataSourceList(new TDataSourceList()); - agentStat.setResponseTime(new TResponseTime()); - agentStat.setDeadlock(new TDeadlock()); - return agentStat; - } - -} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/handler/DirectExecutor.java b/collector/src/test/java/com/navercorp/pinpoint/collector/handler/DirectExecutor.java new file mode 100644 index 000000000000..87e989108f75 --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/handler/DirectExecutor.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler; + +import java.util.concurrent.Executor; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DirectExecutor implements Executor { + @Override + public void execute(Runnable command) { + command.run(); + } +} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentStatHandlerV2Test.java b/collector/src/test/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentStatHandlerV2Test.java new file mode 100644 index 000000000000..4a1e4eb9683a --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/handler/thrift/ThriftAgentStatHandlerV2Test.java @@ -0,0 +1,243 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.handler.thrift; + +import com.navercorp.pinpoint.collector.dao.AgentStatDaoV2; +import com.navercorp.pinpoint.collector.mapper.thrift.stat.AgentStatBatchMapper; +import com.navercorp.pinpoint.collector.mapper.thrift.stat.AgentStatMapper; +import com.navercorp.pinpoint.collector.service.AgentStatService; +import com.navercorp.pinpoint.collector.service.HBaseAgentStatService; +import com.navercorp.pinpoint.common.server.bo.stat.ActiveTraceBo; +import com.navercorp.pinpoint.common.server.bo.stat.AgentStatBo; +import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; +import com.navercorp.pinpoint.common.server.bo.stat.DataSourceListBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import com.navercorp.pinpoint.common.server.bo.stat.JvmGcBo; +import com.navercorp.pinpoint.common.server.bo.stat.JvmGcDetailedBo; +import com.navercorp.pinpoint.common.server.bo.stat.ResponseTimeBo; +import com.navercorp.pinpoint.common.server.bo.stat.TransactionBo; +import com.navercorp.pinpoint.thrift.dto.TAgentInfo; +import com.navercorp.pinpoint.thrift.dto.TAgentStat; +import com.navercorp.pinpoint.thrift.dto.TAgentStatBatch; +import com.navercorp.pinpoint.thrift.dto.TCpuLoad; +import com.navercorp.pinpoint.thrift.dto.TDataSourceList; +import com.navercorp.pinpoint.thrift.dto.TDeadlock; +import com.navercorp.pinpoint.thrift.dto.TDirectBuffer; +import com.navercorp.pinpoint.thrift.dto.TFileDescriptor; +import com.navercorp.pinpoint.thrift.dto.TJvmGc; +import com.navercorp.pinpoint.thrift.dto.TResponseTime; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.*; + +/** + * @author HyunGil Jeong + */ +public class ThriftAgentStatHandlerV2Test { + + @Mock + private AgentStatMapper agentStatMapper; + + @Mock + private AgentStatBatchMapper agentStatBatchMapper; + + @Mock + private AgentStatDaoV2 jvmGcDao; + + @Mock + private AgentStatDaoV2 jvmGcDetailedDao; + + @Mock + private AgentStatDaoV2 cpuLoadDao; + + @Mock + private AgentStatDaoV2 transactionDao; + + @Mock + private AgentStatDaoV2 activeTraceDao; + + @Mock + private AgentStatDaoV2 dataSourceDao; + + @Mock + private AgentStatDaoV2 responseTimeDao; + + @Mock + private AgentStatDaoV2 deadlockDao; + + @Mock + private AgentStatDaoV2 fileDescriptorDao; + + @Mock + private AgentStatDaoV2 directBufferDao; + + @InjectMocks + private HBaseAgentStatService hBaseAgentStatService = new HBaseAgentStatService(); + + @Spy + private List agentStatServiceList = new ArrayList<>(); + + @InjectMocks + private ThriftAgentStatHandlerV2 thriftAgentStatHandlerV2 = new ThriftAgentStatHandlerV2(); + + @Before + public void setUp() throws Exception { + agentStatServiceList.add(hBaseAgentStatService); + MockitoAnnotations.initMocks(this); + } + + @Test + public void testHandleForTAgentStat() { + // Given + final String agentId = "agentId"; + final long startTimestamp = Long.MAX_VALUE; + final TAgentStat agentStat = createAgentStat(agentId, startTimestamp); + final AgentStatBo mappedAgentStat = new AgentStatBo(); + when(this.agentStatMapper.map(agentStat)).thenReturn(mappedAgentStat); + // When + thriftAgentStatHandlerV2.handleSimple(agentStat); + // Then + verify(jvmGcDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getJvmGcBos()); + verify(jvmGcDetailedDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getJvmGcDetailedBos()); + verify(cpuLoadDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getCpuLoadBos()); + verify(transactionDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getTransactionBos()); + verify(activeTraceDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getActiveTraceBos()); + verify(dataSourceDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDataSourceListBos()); + verify(responseTimeDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getResponseTimeBos()); + verify(deadlockDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDeadlockThreadCountBos()); + verify(fileDescriptorDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getFileDescriptorBos()); + verify(directBufferDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDirectBufferBos()); + + } + + @Test + public void testHandleForTAgentStatBatch() { + // Given + final int numBatches = 6; + final String agentId = "agentId"; + final long startTimestamp = Long.MAX_VALUE; + final TAgentStatBatch agentStatBatch = createAgentStatBatch(agentId, startTimestamp, numBatches); + final AgentStatBo mappedAgentStat = new AgentStatBo(); + when(this.agentStatBatchMapper.map(agentStatBatch)).thenReturn(mappedAgentStat); + // When + thriftAgentStatHandlerV2.handleSimple(agentStatBatch); + // Then + verify(jvmGcDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getJvmGcBos()); + verify(jvmGcDetailedDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getJvmGcDetailedBos()); + verify(cpuLoadDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getCpuLoadBos()); + verify(transactionDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getTransactionBos()); + verify(activeTraceDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getActiveTraceBos()); + verify(dataSourceDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDataSourceListBos()); + verify(responseTimeDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getResponseTimeBos()); + verify(deadlockDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDeadlockThreadCountBos()); + verify(fileDescriptorDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getFileDescriptorBos()); + verify(directBufferDao).insert(mappedAgentStat.getAgentId(), mappedAgentStat.getDirectBufferBos()); + } + + @Test + public void insertShouldNotBeCalledIfTAgentStatIsMappedToNull() { + // Given + final String agentId = "agentId"; + final long startTimestamp = Long.MAX_VALUE; + final TAgentStat agentStat = createAgentStat(agentId, startTimestamp); + final AgentStatBo mappedAgentStat = null; + when(this.agentStatMapper.map(agentStat)).thenReturn(mappedAgentStat); + // When + thriftAgentStatHandlerV2.handleSimple(agentStat); + // Then + verifyZeroInteractions(jvmGcDao); + verifyZeroInteractions(jvmGcDetailedDao); + verifyZeroInteractions(cpuLoadDao); + verifyZeroInteractions(transactionDao); + verifyZeroInteractions(activeTraceDao); + verifyZeroInteractions(dataSourceDao); + verifyZeroInteractions(responseTimeDao); + verifyZeroInteractions(fileDescriptorDao); + verifyZeroInteractions(directBufferDao); + } + + @Test + public void insertShouldNotBeCalledIfTAgentStatBatchIsMappedToNull() { + // Given + final int numBatches = 6; + final String agentId = "agentId"; + final long startTimestamp = Long.MAX_VALUE; + final TAgentStatBatch agentStatBatch = createAgentStatBatch(agentId, startTimestamp, numBatches); + final AgentStatBo mappedAgentStat = null; + when(this.agentStatBatchMapper.map(agentStatBatch)).thenReturn(mappedAgentStat); + // When + thriftAgentStatHandlerV2.handleSimple(agentStatBatch); + // Then + verifyZeroInteractions(jvmGcDao); + verifyZeroInteractions(jvmGcDetailedDao); + verifyZeroInteractions(cpuLoadDao); + verifyZeroInteractions(transactionDao); + verifyZeroInteractions(activeTraceDao); + verifyZeroInteractions(dataSourceDao); + verifyZeroInteractions(responseTimeDao); + verifyZeroInteractions(fileDescriptorDao); + verifyZeroInteractions(directBufferDao); + } + + @Test(expected=IllegalArgumentException.class) + public void handleShouldThrowIllegalArgumentExceptionForIncorrectTBaseObjects() { + // Given + final TAgentInfo wrongTBaseObject = new TAgentInfo(); + // When + thriftAgentStatHandlerV2.handleSimple(wrongTBaseObject); + // Then + fail(); + } + + private TAgentStatBatch createAgentStatBatch(String agentId, long startTimestamp, int numBatches) { + final TAgentStatBatch agentStatBatch = new TAgentStatBatch(); + agentStatBatch.setAgentId(agentId); + agentStatBatch.setStartTimestamp(startTimestamp); + final List agentStats = new ArrayList<>(numBatches); + for (int i = 0; i < numBatches; i++) { + agentStats.add(createAgentStat(agentId, startTimestamp)); + } + agentStatBatch.setAgentStats(agentStats); + return agentStatBatch; + } + + private TAgentStat createAgentStat(String agentId, long startTimestamp) { + final TAgentStat agentStat = new TAgentStat(); + agentStat.setAgentId(agentId); + agentStat.setStartTimestamp(startTimestamp); + agentStat.setGc(new TJvmGc()); + agentStat.setCpuLoad(new TCpuLoad()); + agentStat.setDataSourceList(new TDataSourceList()); + agentStat.setResponseTime(new TResponseTime()); + agentStat.setDeadlock(new TDeadlock()); + agentStat.setFileDescriptor(new TFileDescriptor()); + agentStat.setDirectBuffer(new TDirectBuffer()); + return agentStat; + } + +} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventMapperTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventMapperTest.java index d861d417b1e8..9258bc7c47ed 100644 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventMapperTest.java +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/event/AgentEventMapperTest.java @@ -17,7 +17,9 @@ package com.navercorp.pinpoint.collector.mapper.thrift.event; import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; +import com.navercorp.pinpoint.common.server.bo.event.DeadlockBo; import com.navercorp.pinpoint.common.server.bo.event.DeadlockEventBo; +import com.navercorp.pinpoint.common.server.util.AgentEventType; import com.navercorp.pinpoint.thrift.dto.TAgentStat; import com.navercorp.pinpoint.thrift.dto.TDeadlock; import com.navercorp.pinpoint.thrift.dto.command.TThreadDump; @@ -40,6 +42,9 @@ public class AgentEventMapperTest { @Mock private DeadlockEventBoMapper deadlockEventBoMapper; + @Mock + private DeadlockBoMapper deadlockBoMapper; + @InjectMocks private AgentEventMapper agentEventMapper; @@ -50,10 +55,11 @@ public void simpleTest1() { final long eventTimestamp = startTimestamp; final TAgentStat agentStat = createAgentStat(agentId, startTimestamp, eventTimestamp, 2); - DeadlockEventBo expectedEventBo = getExpectedDeadlockEventBo(agentId, startTimestamp, eventTimestamp, agentStat); + DeadlockBo deadlockBo = new DeadlockBo(); + deadlockBo.setDeadlockedThreadCount(agentStat.getDeadlock().getDeadlockedThreadCount()); + DeadlockEventBo expectedEventBo = new DeadlockEventBo(agentId, startTimestamp, eventTimestamp, AgentEventType.AGENT_DEADLOCK_DETECTED, deadlockBo); when(this.deadlockEventBoMapper.map(agentId, startTimestamp, startTimestamp, agentStat.getDeadlock())).thenReturn(expectedEventBo); - AgentEventBo actualEventBo = agentEventMapper.map(agentStat); Assert.assertEquals(expectedEventBo, actualEventBo); } @@ -65,7 +71,9 @@ public void simpleTest2() { final long eventTimestamp = startTimestamp; final TAgentStat agentStat = createAgentStat(agentId, startTimestamp, eventTimestamp, 0); - DeadlockEventBo expectedEventBo = getExpectedDeadlockEventBo(agentId, startTimestamp, eventTimestamp, agentStat); + DeadlockBo deadlockBo = new DeadlockBo(); + DeadlockEventBo expectedEventBo = new DeadlockEventBo(agentId, startTimestamp, eventTimestamp, AgentEventType.AGENT_DEADLOCK_DETECTED, deadlockBo); + when(this.deadlockEventBoMapper.map(any(String.class), any(Long.class), any(Long.class), any(TDeadlock.class))).thenReturn(expectedEventBo); AgentEventBo actualEventBo = agentEventMapper.map(agentStat); diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockBoMapperTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockBoMapperTest.java deleted file mode 100644 index ad7440cc9795..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockBoMapperTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.mapper.thrift.stat; - -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; -import com.navercorp.pinpoint.thrift.dto.TDeadlock; -import org.junit.Assert; - -/** - * @author Taejin Koo - */ -public class DeadlockBoMapperTest extends ThriftBoMapperTestBase { - - private static final int MAX_DEADLOCKED_THREAD_COUNT = 100; - - @Override - protected TDeadlock create() { - TDeadlock tDeadlock = new TDeadlock(); - tDeadlock.setDeadlockedThreadCount(getRandomInteger(0, MAX_DEADLOCKED_THREAD_COUNT)); - - return tDeadlock; - } - - @Override - protected DeadlockBo convert(TDeadlock original) { - DeadlockBoMapper deadlockBoMapper = new DeadlockBoMapper(); - return deadlockBoMapper.map(original); - } - - @Override - protected void verify(TDeadlock original, DeadlockBo mappedStatDataPoint) { - Assert.assertEquals("deadlockedThreadCount", original.getDeadlockedThreadCount(), mappedStatDataPoint.getDeadlockedThreadCount()); - } - -} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockThreadCountBoMapperTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockThreadCountBoMapperTest.java new file mode 100644 index 000000000000..48867f1b9ac6 --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DeadlockThreadCountBoMapperTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import com.navercorp.pinpoint.thrift.dto.TDeadlock; +import org.junit.Assert; + +/** + * @author Taejin Koo + */ +public class DeadlockThreadCountBoMapperTest extends ThriftBoMapperTestBase { + + private static final int MAX_DEADLOCKED_THREAD_COUNT = 100; + + @Override + protected TDeadlock create() { + TDeadlock tDeadlock = new TDeadlock(); + tDeadlock.setDeadlockedThreadCount(getRandomInteger(0, MAX_DEADLOCKED_THREAD_COUNT)); + + return tDeadlock; + } + + @Override + protected DeadlockThreadCountBo convert(TDeadlock original) { + DeadlockThreadCountBoMapper deadlockThreadCountBoMapper = new DeadlockThreadCountBoMapper(); + return deadlockThreadCountBoMapper.map(original); + } + + @Override + protected void verify(TDeadlock original, DeadlockThreadCountBo mappedStatDataPoint) { + Assert.assertEquals("deadlockedThreadCount", original.getDeadlockedThreadCount(), mappedStatDataPoint.getDeadlockedThreadCount()); + } + +} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DirectBufferBoMapperTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DirectBufferBoMapperTest.java new file mode 100644 index 000000000000..3839ed2719e1 --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/DirectBufferBoMapperTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.thrift.dto.TDirectBuffer; +import org.junit.Assert; + +/** + * @author Roy Kim + */ +public class DirectBufferBoMapperTest extends ThriftBoMapperTestBase { + + @Override + protected TDirectBuffer create() { + TDirectBuffer directBuffer = new TDirectBuffer(); + directBuffer.setDirectCount(getRandomLong(0, 5000)); + directBuffer.setDirectMemoryUsed(getRandomLong(0, 1000000)); + directBuffer.setMappedCount(getRandomLong(0, 5000)); + directBuffer.setMappedMemoryUsed(getRandomLong(0, 1000000)); + return directBuffer; + } + + @Override + protected DirectBufferBo convert(TDirectBuffer original) { + DirectBufferBoMapper directBufferBoMapper = new DirectBufferBoMapper(); + return directBufferBoMapper.map(original); + } + + @Override + protected void verify(TDirectBuffer original, DirectBufferBo mappedStatDataPoint) { + Assert.assertEquals("DirectCount", original.getDirectCount(), mappedStatDataPoint.getDirectCount(), 0); + Assert.assertEquals("DirectMemoryUsed", original.getDirectMemoryUsed(), mappedStatDataPoint.getDirectMemoryUsed(), 0); + Assert.assertEquals("MappedCount", original.getMappedCount(), mappedStatDataPoint.getMappedCount(), 0); + Assert.assertEquals("MappedMemoryUsed", original.getMappedMemoryUsed(), mappedStatDataPoint.getMappedMemoryUsed(), 0); + } + +} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/FileDescriptorBoMapperTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/FileDescriptorBoMapperTest.java new file mode 100644 index 000000000000..9433ac34410f --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/FileDescriptorBoMapperTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import com.navercorp.pinpoint.thrift.dto.TFileDescriptor; +import org.junit.Assert; + +/** + * @author Roy Kim + */ +public class FileDescriptorBoMapperTest extends ThriftBoMapperTestBase { + + @Override + protected TFileDescriptor create() { + TFileDescriptor fileDescriptor = new TFileDescriptor(); + fileDescriptor.setOpenFileDescriptorCount(getRandomLong(0, 1000)); + return fileDescriptor; + } + + @Override + protected FileDescriptorBo convert(TFileDescriptor original) { + FileDescriptorBoMapper fileDescriptorBoMapper = new FileDescriptorBoMapper(); + return fileDescriptorBoMapper.map(original); + } + + @Override + protected void verify(TFileDescriptor original, FileDescriptorBo mappedStatDataPoint) { + Assert.assertEquals("openFileDescriptorCount", original.getOpenFileDescriptorCount(), mappedStatDataPoint.getOpenFileDescriptorCount(), 0); + } + +} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFAgentStatMapperTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFAgentStatMapperTest.java index b6dbd342d671..9fac8c8c11c9 100644 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFAgentStatMapperTest.java +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFAgentStatMapperTest.java @@ -384,5 +384,60 @@ private List createResponseTimeBoList() { return responseTimeBoList; } + @Test + public void map6Test() throws Exception { + final AgentStatBo agentStatBo = new AgentStatBo(); + agentStatBo.setStartTimestamp(startTimestamp); + agentStatBo.setAgentId(TEST_AGENT); + agentStatBo.setFileDescriptorBos(createFileDescriptorBoList()); + + List tFAgentStatList = new TFAgentStatMapper().map(agentStatBo); + assertEquals(3, tFAgentStatList.size()); + + TFAgentStat tFAgentStat1 = tFAgentStatList.get(0); + assertEquals(TEST_AGENT, tFAgentStat1.getAgentId()); + assertEquals(startTimestamp, tFAgentStat1.getStartTimestamp()); + assertEquals(collectTime1st, tFAgentStat1.getTimestamp()); + assertEquals(4, tFAgentStat1.getFileDescriptor().getOpenFileDescriptorCount(), 0); + + TFAgentStat tFAgentStat2 = tFAgentStatList.get(1); + assertEquals(TEST_AGENT, tFAgentStat2.getAgentId()); + assertEquals(startTimestamp, tFAgentStat2.getStartTimestamp()); + assertEquals(collectTime2nd, tFAgentStat2.getTimestamp()); + assertEquals(5, tFAgentStat2.getFileDescriptor().getOpenFileDescriptorCount(), 0); + + TFAgentStat tFAgentStat3 = tFAgentStatList.get(2); + assertEquals(TEST_AGENT, tFAgentStat3.getAgentId()); + assertEquals(startTimestamp, tFAgentStat3.getStartTimestamp()); + assertEquals(collectTime3rd, tFAgentStat3.getTimestamp()); + assertEquals(8, tFAgentStat3.getFileDescriptor().getOpenFileDescriptorCount(), 0); + } + + private List createFileDescriptorBoList() { + final List fileDescriptorBoList = new ArrayList<>(); + + FileDescriptorBo fileDescriptorBo1 = new FileDescriptorBo(); + fileDescriptorBo1.setAgentId(TEST_AGENT); + fileDescriptorBo1.setTimestamp(collectTime1st); + fileDescriptorBo1.setStartTimestamp(startTimestamp); + fileDescriptorBo1.setOpenFileDescriptorCount(4); + fileDescriptorBoList.add(fileDescriptorBo1); + + FileDescriptorBo fileDescriptorBo2 = new FileDescriptorBo(); + fileDescriptorBo2.setAgentId(TEST_AGENT); + fileDescriptorBo2.setTimestamp(collectTime2nd); + fileDescriptorBo2.setStartTimestamp(startTimestamp); + fileDescriptorBo2.setOpenFileDescriptorCount(5); + fileDescriptorBoList.add(fileDescriptorBo2); + + FileDescriptorBo fileDescriptorBo3 = new FileDescriptorBo(); + fileDescriptorBo3.setAgentId(TEST_AGENT); + fileDescriptorBo3.setTimestamp(collectTime3rd); + fileDescriptorBo3.setStartTimestamp(startTimestamp); + fileDescriptorBo3.setOpenFileDescriptorCount(8); + fileDescriptorBoList.add(fileDescriptorBo3); + + return fileDescriptorBoList; + } } \ No newline at end of file diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFDirectBufferMapperTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFDirectBufferMapperTest.java new file mode 100644 index 000000000000..78c8f61959ed --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFDirectBufferMapperTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.thrift.dto.flink.TFDirectBuffer; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Roy Kim + */ +public class TFDirectBufferMapperTest { + @Test + public void mapTest() throws Exception { + TFDirectBufferMapper tFDirectBufferMapper = new TFDirectBufferMapper(); + DirectBufferBo directBufferBo = new DirectBufferBo(); + directBufferBo.setDirectCount(30); + directBufferBo.setDirectMemoryUsed(30); + directBufferBo.setMappedCount(30); + directBufferBo.setMappedMemoryUsed(30); + TFDirectBuffer tFDirectBuffer = tFDirectBufferMapper.map(directBufferBo); + assertEquals(tFDirectBuffer.getDirectCount(), 30, 0); + assertEquals(tFDirectBuffer.getDirectMemoryUsed(), 30, 0); + assertEquals(tFDirectBuffer.getMappedCount(), 30, 0); + assertEquals(tFDirectBuffer.getMappedMemoryUsed(), 30, 0); + } + +} \ No newline at end of file diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFFileDescriptorMapperTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFFileDescriptorMapperTest.java new file mode 100644 index 000000000000..e4ad69f7093e --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/mapper/thrift/stat/TFFileDescriptorMapperTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import com.navercorp.pinpoint.thrift.dto.flink.TFFileDescriptor; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Roy Kim + */ +public class TFFileDescriptorMapperTest { + @Test + public void mapTest() throws Exception { + TFFileDescriptorMapper tFFileDescriptorMapper = new TFFileDescriptorMapper(); + FileDescriptorBo fileDescriptorBo = new FileDescriptorBo(); + fileDescriptorBo.setOpenFileDescriptorCount(30); + TFFileDescriptor tFFileDescriptor = tFFileDescriptorMapper.map(fileDescriptorBo); + assertEquals(tFFileDescriptor.getOpenFileDescriptorCount(), 30, 0); + } + +} \ No newline at end of file diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/AddressFilterAdaptorTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/AddressFilterAdaptorTest.java index b31713d8f854..2bbd0faf3c21 100644 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/AddressFilterAdaptorTest.java +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/AddressFilterAdaptorTest.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.collector.receiver; +import com.navercorp.pinpoint.collector.receiver.thrift.AddressFilterAdaptor; import com.navercorp.pinpoint.common.server.util.AddressFilter; import com.navercorp.pinpoint.common.server.util.IgnoreAddressFilter; import org.apache.hadoop.hbase.shaded.com.google.common.net.InetAddresses; diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/DataReceiverGroupTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/DataReceiverGroupTest.java index 4b37aa250253..10b7fc87f2eb 100644 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/DataReceiverGroupTest.java +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/DataReceiverGroupTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,10 +16,22 @@ package com.navercorp.pinpoint.collector.receiver; +import com.google.common.util.concurrent.MoreExecutors; import com.navercorp.pinpoint.collector.config.DataReceiverGroupConfiguration; +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.collector.receiver.thrift.PinpointServerAcceptorProvider; +import com.navercorp.pinpoint.collector.receiver.thrift.TCPReceiverBean; +import com.navercorp.pinpoint.collector.receiver.thrift.UDPReceiverBean; import com.navercorp.pinpoint.common.server.util.AddressFilter; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.profiler.context.thrift.BypassMessageConverter; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import com.navercorp.pinpoint.profiler.sender.ByteMessage; import com.navercorp.pinpoint.profiler.sender.DataSender; +import com.navercorp.pinpoint.profiler.sender.MessageSerializer; import com.navercorp.pinpoint.profiler.sender.TcpDataSender; +import com.navercorp.pinpoint.profiler.sender.ThriftUdpMessageSerializer; import com.navercorp.pinpoint.profiler.sender.UdpDataSender; import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; @@ -29,9 +41,9 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; import org.springframework.util.SocketUtils; -import java.net.InetSocketAddress; import java.util.Collections; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -50,23 +62,24 @@ public class DataReceiverGroupTest { public void receiverGroupTest1() throws Exception { DataReceiverGroupConfiguration mockConfig = createMockConfig(true, true); - CountDownLatch sendLatch = new CountDownLatch(2); - CountDownLatch requestLatch = new CountDownLatch(1); + TestDispatchHandler dispatchHandler = new TestDispatchHandler(2, 1); + + UDPReceiverBean udpReceiverBean = createUdpReceiverBean(mockConfig, dispatchHandler); + TCPReceiverBean tcpReceiverBean = createTcpReceiverBean(mockConfig, dispatchHandler); + - DataReceiverGroup receiver = null; DataSender udpDataSender = null; TcpDataSender tcpDataSender = null; PinpointClientFactory pinpointClientFactory = null; try { - receiver = new DataReceiverGroup("name", mockConfig, AddressFilter.ALL, new TestDispatchHandler(sendLatch, requestLatch)); - receiver.start(); + udpReceiverBean.afterPropertiesSet(); + tcpReceiverBean.afterPropertiesSet(); - udpDataSender = new UdpDataSender("127.0.0.1", mockConfig.getUdpBindPort(), "test", 10, 1000, 1024 * 64 * 100); + udpDataSender = newUdpDataSender(mockConfig); pinpointClientFactory = createPinpointClientFactory(); - InetSocketAddress address = new InetSocketAddress("127.0.0.1", mockConfig.getTcpBindPort()); - tcpDataSender = new TcpDataSender(address, pinpointClientFactory); + tcpDataSender = new TcpDataSender(this.getClass().getName(), "127.0.0.1", mockConfig.getTcpBindPort(), pinpointClientFactory); udpDataSender.send(new TResult()); @@ -75,51 +88,88 @@ public void receiverGroupTest1() throws Exception { Assert.assertTrue(tcpDataSender.isConnected()); - Assert.assertTrue(sendLatch.await(1000, TimeUnit.MILLISECONDS)); - Assert.assertTrue(requestLatch.await(1000, TimeUnit.MILLISECONDS)); + Assert.assertTrue(dispatchHandler.getSendLatch().await(1000, TimeUnit.MILLISECONDS)); + Assert.assertTrue(dispatchHandler.getRequestLatch().await(1000, TimeUnit.MILLISECONDS)); } finally { closeDataSender(udpDataSender); closeDataSender(tcpDataSender); closeClientFactory(pinpointClientFactory); + closeBean(udpReceiverBean); + closeBean(tcpReceiverBean); } } + public UdpDataSender newUdpDataSender(DataReceiverGroupConfiguration mockConfig) { + String threadName = this.getClass().getName(); + MessageConverter> messageConverter = new BypassMessageConverter<>(); + final MessageSerializer thriftMessageSerializer = new ThriftUdpMessageSerializer(messageConverter, ThriftUdpMessageSerializer.UDP_MAX_PACKET_LENGTH); + return new UdpDataSender("127.0.0.1", mockConfig.getUdpBindPort(), threadName, 10, 1000, 1024 * 64 * 100, + thriftMessageSerializer); + } + + private PinpointServerAcceptorProvider createPinpointAcceptorProvider() { + return new PinpointServerAcceptorProvider(); + } + + private TCPReceiverBean createTcpReceiverBean(DataReceiverGroupConfiguration mockConfig, DispatchHandler dispatchHandler) { + TCPReceiverBean tcpReceiverBean = new TCPReceiverBean(); + tcpReceiverBean.setBeanName("tcpReceiver"); + tcpReceiverBean.setBindIp(mockConfig.getTcpBindIp()); + tcpReceiverBean.setBindPort(mockConfig.getTcpBindPort()); + tcpReceiverBean.setAcceptorProvider(createPinpointAcceptorProvider()); + tcpReceiverBean.setDispatchHandler(dispatchHandler); + tcpReceiverBean.setExecutor(MoreExecutors.directExecutor()); + tcpReceiverBean.setEnable(true); + return tcpReceiverBean; + } + + private UDPReceiverBean createUdpReceiverBean(DataReceiverGroupConfiguration mockConfig, DispatchHandler dispatchHandler) { + UDPReceiverBean udpReceiverBean = new UDPReceiverBean(); + udpReceiverBean.setBeanName("udpReceiver"); + udpReceiverBean.setBindIp(mockConfig.getUdpBindIp()); + udpReceiverBean.setBindPort(mockConfig.getUdpBindPort()); + udpReceiverBean.setAddressFilter(AddressFilter.ALL); + udpReceiverBean.setDispatchHandler(dispatchHandler); + udpReceiverBean.setExecutor(MoreExecutors.directExecutor()); + udpReceiverBean.setUdpBufferSize(mockConfig.getUdpReceiveBufferSize()); + udpReceiverBean.setEnable(true); + return udpReceiverBean; + } + @Test public void receiverGroupTest2() throws Exception { DataReceiverGroupConfiguration mockConfig = createMockConfig(true, false); - CountDownLatch sendLatch = new CountDownLatch(1); - CountDownLatch requestLatch = new CountDownLatch(1); + TestDispatchHandler testDispatchHandler = new TestDispatchHandler(1, 1); - DataReceiverGroup receiver = null; + TCPReceiverBean receiver = createTcpReceiverBean(mockConfig, testDispatchHandler); DataSender udpDataSender = null; TcpDataSender tcpDataSender = null; PinpointClientFactory pinpointClientFactory = null; try { - receiver = new DataReceiverGroup("name", mockConfig, AddressFilter.ALL, new TestDispatchHandler(sendLatch, requestLatch)); - receiver.start(); + receiver.afterPropertiesSet(); - udpDataSender = new UdpDataSender("127.0.0.1", mockConfig.getUdpBindPort(), "test", 10, 1000, 1024 * 64 * 100); + udpDataSender = newUdpDataSender(mockConfig); udpDataSender.send(new TResult()); - Assert.assertFalse(sendLatch.await(1000, TimeUnit.MILLISECONDS)); + Assert.assertFalse(testDispatchHandler.getSendLatch().await(1000, TimeUnit.MILLISECONDS)); pinpointClientFactory = createPinpointClientFactory(); - InetSocketAddress address = new InetSocketAddress("127.0.0.1", mockConfig.getTcpBindPort()); - tcpDataSender = new TcpDataSender(address, pinpointClientFactory); + tcpDataSender = new TcpDataSender(this.getClass().getName(), "127.0.0.1", mockConfig.getTcpBindPort(), pinpointClientFactory); Assert.assertTrue(tcpDataSender.isConnected()); tcpDataSender.send(new TResult()); tcpDataSender.request(new TResult()); - Assert.assertTrue(sendLatch.await(1000, TimeUnit.MILLISECONDS)); - Assert.assertTrue(requestLatch.await(1000, TimeUnit.MILLISECONDS)); + Assert.assertTrue(testDispatchHandler.getSendLatch().await(1000, TimeUnit.MILLISECONDS)); + Assert.assertTrue(testDispatchHandler.getRequestLatch().await(1000, TimeUnit.MILLISECONDS)); } finally { closeDataSender(udpDataSender); closeDataSender(tcpDataSender); closeClientFactory(pinpointClientFactory); + closeBean(receiver); } } @@ -127,45 +177,38 @@ public void receiverGroupTest2() throws Exception { public void receiverGroupTest3() throws Exception { DataReceiverGroupConfiguration mockConfig = createMockConfig(false, true); - CountDownLatch sendLatch = new CountDownLatch(1); + TestDispatchHandler testDispatchHandler = new TestDispatchHandler(1, 1); - DataReceiverGroup receiver = null; + UDPReceiverBean receiver = createUdpReceiverBean(mockConfig, testDispatchHandler); DataSender udpDataSender = null; TcpDataSender tcpDataSender = null; PinpointClientFactory pinpointClientFactory = null; try { - receiver = new DataReceiverGroup("name", mockConfig, AddressFilter.ALL, new TestDispatchHandler(sendLatch, new CountDownLatch(1))); - receiver.start(); + receiver.afterPropertiesSet(); - udpDataSender = new UdpDataSender("127.0.0.1", mockConfig.getUdpBindPort(), "test", 10, 1000, 1024 * 64 * 100); + udpDataSender = newUdpDataSender(mockConfig); udpDataSender.send(new TResult()); - Assert.assertTrue(sendLatch.await(1000, TimeUnit.MILLISECONDS)); + Assert.assertTrue(testDispatchHandler.getSendLatch().await(1000, TimeUnit.MILLISECONDS)); pinpointClientFactory = createPinpointClientFactory(); - InetSocketAddress address = new InetSocketAddress("127.0.0.1", mockConfig.getTcpBindPort()); - tcpDataSender = new TcpDataSender(address, pinpointClientFactory); + tcpDataSender = new TcpDataSender(this.getClass().getName(), "127.0.0.1", mockConfig.getTcpBindPort(), pinpointClientFactory); Assert.assertFalse(tcpDataSender.isConnected()); } finally { closeDataSender(udpDataSender); closeDataSender(tcpDataSender); closeClientFactory(pinpointClientFactory); + closeBean(receiver); } } - @Test(expected = IllegalArgumentException.class) - public void receiverGroupTest4() throws Exception { - DataReceiverGroupConfiguration mockConfig = createMockConfig(false, false); - - new DataReceiverGroup("name", mockConfig, AddressFilter.ALL, new TestDispatchHandler(new CountDownLatch(1), new CountDownLatch(1))); - } - private void closeReceiver(DataReceiver receiver) { + private void closeBean(DisposableBean bean) { try { - if (receiver != null) { - receiver.shutdown(); + if (bean != null) { + bean.destroy(); } } catch (Exception e) { // ignore @@ -202,10 +245,10 @@ private DataReceiverGroupConfiguration createMockConfig(boolean tcpEnable, boole when(config.isUdpEnable()).thenReturn(udpEnable); when(config.getUdpBindIp()).thenReturn("0.0.0.0"); when(config.getUdpBindPort()).thenReturn(SocketUtils.findAvailableTcpPort(29099)); + when(config.getUdpReceiveBufferSize()).thenReturn(65535); when(config.getWorkerThreadSize()).thenReturn(2); when(config.getWorkerQueueSize()).thenReturn(10); - when(config.getUdpReceiveBufferSize()).thenReturn(65535); when(config.isWorkerMonitorEnable()).thenReturn(false); return config; @@ -213,7 +256,8 @@ private DataReceiverGroupConfiguration createMockConfig(boolean tcpEnable, boole private PinpointClientFactory createPinpointClientFactory() { PinpointClientFactory clientFactory = new DefaultPinpointClientFactory(); - clientFactory.setTimeoutMillis(1000 * 5); + clientFactory.setWriteTimeoutMillis(1000 * 3); + clientFactory.setRequestTimeoutMillis(1000 * 5); clientFactory.setProperties(Collections.emptyMap()); return clientFactory; @@ -225,24 +269,35 @@ private static class TestDispatchHandler implements DispatchHandler { private final CountDownLatch sendLatch; private final CountDownLatch requestLatch; - public TestDispatchHandler(CountDownLatch sendLatch, CountDownLatch requestLatch) { - this.sendLatch = sendLatch; - this.requestLatch = requestLatch; + public TestDispatchHandler(int sendLatchCount, int requestLatchCount) { + this.sendLatch = new CountDownLatch(sendLatchCount); + this.requestLatch = new CountDownLatch(requestLatchCount); } + public CountDownLatch getSendLatch() { + return sendLatch; + } + + public CountDownLatch getRequestLatch() { + return requestLatch; + } + + @Override - public void dispatchSendMessage(TBase tBase) { - LOGGER.info("===================================== send {}", tBase); + public void dispatchSendMessage(ServerRequest serverRequest) { + LOGGER.debug("===================================== send {}", serverRequest); sendLatch.countDown(); } @Override - public TBase dispatchRequestMessage(TBase tBase) { - LOGGER.info("===================================== request {}", tBase); + public void dispatchRequestMessage(ServerRequest serverRequest, ServerResponse serverResponse) { + LOGGER.debug("===================================== request {}", serverRequest); requestLatch.countDown(); - return new TResult(); + Object tResult = new TResult(); + + serverResponse.write(tResult); } - } + } } diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/DispatchHandlerTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/DispatchHandlerTest.java index 0eb521f30454..1a6d9699b0fb 100644 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/DispatchHandlerTest.java +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/DispatchHandlerTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,10 @@ import com.navercorp.pinpoint.collector.handler.RequestResponseHandler; import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; import com.navercorp.pinpoint.thrift.dto.TResult; import org.apache.thrift.TBase; import org.junit.Assert; @@ -28,10 +31,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * @author Taejin Koo @@ -54,52 +55,65 @@ public void setUp() throws Exception { @Test(expected = UnsupportedOperationException.class) public void throwExceptionTest1() { - testDispatchHandler.dispatchSendMessage(null); - } - - @Test(expected = UnsupportedOperationException.class) - public void throwExceptionTest2() { - testDispatchHandler.dispatchRequestMessage(null); + ServerRequest request = mock(ServerRequest.class); + when(request.getData()).thenReturn(null); + testDispatchHandler.dispatchSendMessage(request); } @Test public void dispatchSendMessageTest() { - testDispatchHandler.dispatchSendMessage(new TResult()); + ServerRequest serverRequest = mock(ServerRequest.class); + when(serverRequest.getData()).thenReturn(new TResult()); + testDispatchHandler.dispatchSendMessage(serverRequest); Assert.assertTrue(TEST_SIMPLE_HANDLER.getExecutedCount() > 0); } @Test public void dispatchRequestMessageTest() { - testDispatchHandler.dispatchRequestMessage(new TResult()); + ServerRequest request = mock(ServerRequest.class); + when(request.getData()).thenReturn(new TResult()); + + ServerResponse response = mock(ServerResponse.class); + testDispatchHandler.dispatchRequestMessage(request, response); Assert.assertTrue(TEST_REQUEST_HANDLER.getExecutedCount() > 0); } - private static class TestDispatchHandler extends AbstractDispatchHandler { + private static class TestDispatchHandler implements DispatchHandler { @Override - protected List getSimpleHandler(TBase tBase) { - if (tBase == null) { - return Collections.emptyList(); - } + public void dispatchSendMessage(ServerRequest serverRequest) { + SimpleHandler simpleHandler = getSimpleHandler(serverRequest); + simpleHandler.handleSimple(serverRequest); + } + + @Override + public void dispatchRequestMessage(ServerRequest serverRequest, ServerResponse serverResponse) { + RequestResponseHandler requestResponseHandler = getRequestResponseHandler(serverRequest); + requestResponseHandler.handleRequest(serverRequest, serverResponse); + } - int random = ThreadLocalRandom.current().nextInt(1, MAX_HANDLER_COUNT); - List handlerList = new ArrayList<>(random); - for (int i = 0; i < random; i++) { - handlerList.add(TEST_SIMPLE_HANDLER); + private RequestResponseHandler getRequestResponseHandler(ServerRequest serverRequest) { + final Object data = serverRequest.getData(); + return TEST_REQUEST_HANDLER; + } + + private SimpleHandler getSimpleHandler(ServerRequest serverRequest) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + return getSimpleHandler((TBase) data); } - return handlerList; + throw new UnsupportedOperationException("data is not support type : " + data); } - @Override - protected RequestResponseHandler getRequestResponseHandler(TBase tBase) { + private SimpleHandler getSimpleHandler(TBase tBase) { if (tBase == null) { return null; } - return TEST_REQUEST_HANDLER; + return TEST_SIMPLE_HANDLER; } } @@ -108,9 +122,15 @@ private static class TestSimpleHandler implements SimpleHandler { private int executedCount = 0; + @Override - public void handleSimple(TBase tbase) { - executedCount++; + public void handleSimple(ServerRequest serverRequest) { + final Object data = serverRequest.getData(); + if (data instanceof TBase) { + executedCount++; + } else { + throw new UnsupportedOperationException(serverRequest.getClass() + "is not support type : " + serverRequest); + } } public int getExecutedCount() { @@ -124,11 +144,13 @@ private static class TestRequestHandler implements RequestResponseHandler { private int executedCount = 0; @Override - public TBase handleRequest(TBase tbase) { + public void handleRequest(ServerRequest serverRequest, ServerResponse serverResponse) { executedCount++; - return new TResult(); + TResult tResult = new TResult(); + serverResponse.write(tResult); } + public int getExecutedCount() { return executedCount; } diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/WorkerOptionTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/WorkerOptionTest.java deleted file mode 100644 index eb79753eafe4..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/WorkerOptionTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver; - -import org.junit.Assert; -import org.junit.Test; - -/** - * @author Taejin Koo - */ -public class WorkerOptionTest { - - public static final boolean DEFAULT_COLLECT_METRIC_ENABLE = false; - - @Test - public void getTest1() throws Exception { - int workerThreadSize = 1; - int workerThreadQueueSize = 10; - - DispatchWorkerOption workerOption = new DispatchWorkerOption("testWorker", workerThreadSize, workerThreadQueueSize); - - Assert.assertEquals("testWorker", workerOption.getName()); - - Assert.assertEquals(workerThreadSize, workerOption.getThreadSize()); - Assert.assertEquals(workerThreadQueueSize, workerOption.getQueueSize()); - - Assert.assertEquals(DEFAULT_COLLECT_METRIC_ENABLE, workerOption.isEnableCollectMetric()); - } - - @Test - public void getTest2() throws Exception { - int workerThreadSize = 1; - int workerThreadQueueSize = 10; - int recordLogRate = 100; - boolean collectMetric = true; - - DispatchWorkerOption workerOption = new DispatchWorkerOption("testWorker", workerThreadSize, workerThreadQueueSize, recordLogRate, collectMetric); - - Assert.assertEquals(workerThreadSize, workerOption.getThreadSize()); - Assert.assertEquals(workerThreadQueueSize, workerOption.getQueueSize()); - Assert.assertEquals(recordLogRate, workerOption.getRecordLogRate()); - - Assert.assertEquals(collectMetric, workerOption.isEnableCollectMetric()); - } - - @Test(expected = IllegalArgumentException.class) - public void throwExceptionTest1() { - new DispatchWorkerOption("testWorker", 0, 100); - } - - @Test(expected = IllegalArgumentException.class) - public void throwExceptionTest2() { - new DispatchWorkerOption ("testWorker", 100, 0); - } - - @Test(expected = IllegalArgumentException.class) - public void throwExceptionTest3() { - new DispatchWorkerOption ("testWorker", 1, 1, 0); - } - -} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/tcp/TCPReceiverTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/tcp/TCPReceiverTest.java deleted file mode 100644 index e5808e891fd9..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/tcp/TCPReceiverTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.tcp; - -import com.navercorp.pinpoint.collector.config.AgentBaseDataReceiverConfiguration; -import com.navercorp.pinpoint.collector.config.DeprecatedConfiguration; -import com.navercorp.pinpoint.collector.receiver.DispatchHandler; -import com.navercorp.pinpoint.common.server.util.AddressFilter; -import com.navercorp.pinpoint.thrift.dto.TResult; -import org.apache.thrift.TBase; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.SocketUtils; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Properties; - -/** - * @author emeroad - */ -public class TCPReceiverTest { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Test - public void server() throws InterruptedException { - AgentBaseDataReceiver tcpReceiver = new AgentBaseDataReceiver(createConfiguration(), AddressFilter.ALL, new DispatchHandler() { - - @Override - public void dispatchSendMessage(TBase tBase) { - } - - @Override - public TBase dispatchRequestMessage(TBase tBase) { - return new TResult(true); - } - - }); - try { - tcpReceiver.start(); - } finally { - tcpReceiver.stop(); - } - } - - @Test - public void l4ip() throws UnknownHostException { - InetAddress byName = InetAddress.getByName("10.118.202.30"); - logger.debug("byName:{}", byName); - } - - @Test - public void l4ipList() throws UnknownHostException { - String two = "10.118.202.30,10.118.202.31"; - String[] split = two.split(","); - Assert.assertEquals(split.length, 2); - - String twoEmpty = "10.118.202.30,"; - String[] splitEmpty = twoEmpty.split(","); - Assert.assertEquals(splitEmpty.length, 1); - - } - - private AgentBaseDataReceiverConfiguration createConfiguration() { - Properties properties = new Properties(); - properties.put("collector.receiver.base.ip", "0.0.0.0"); - final int availableTcpPort = SocketUtils.findAvailableTcpPort(19099); - properties.put("collector.receiver.base.port", String.valueOf(availableTcpPort)); - properties.put("collector.receiver.base.worker.threadSize", "8"); - properties.put("collector.receiver.base.worker.queueSize", "1024"); - - AgentBaseDataReceiverConfiguration config = new AgentBaseDataReceiverConfiguration(properties, new DeprecatedConfiguration()); - return config; - } - -} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentEventHandlerTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentEventHandlerTest.java new file mode 100644 index 000000000000..534594d06fa6 --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentEventHandlerTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.service.AgentEventService; +import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; +import com.navercorp.pinpoint.common.server.util.AgentEventType; +import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +@RunWith(MockitoJUnitRunner.class) +public class AgentEventHandlerTest { + @Mock + private PinpointServer pinpointServer; + + @Mock + private AgentEventService agentEventService; + + @InjectMocks + private AgentEventHandler agentEventHandler = new AgentEventHandler(); + + private static final String TEST_AGENT_ID = "TEST_AGENT"; + private static final long TEST_START_TIMESTAMP = System.currentTimeMillis(); + private static final long TEST_EVENT_TIMESTAMP = TEST_START_TIMESTAMP + 10; + + private static final Map TEST_CHANNEL_PROPERTIES = createTestChannelProperties(); + + @Before + public void setUp() { + when(this.pinpointServer.getChannelProperties()).thenReturn(TEST_CHANNEL_PROPERTIES); + } + + @Test + public void handler_should_handle_events_with_empty_message_body() throws Exception { + // given + final AgentEventType expectedEventType = AgentEventType.AGENT_CONNECTED; + ArgumentCaptor argCaptor = ArgumentCaptor.forClass(AgentEventBo.class); + // when + this.agentEventHandler.handleEvent(this.pinpointServer, TEST_EVENT_TIMESTAMP, expectedEventType); + verify(this.agentEventService, times(1)).insert(argCaptor.capture()); + // then + AgentEventBo actualAgentEventBo = argCaptor.getValue(); + assertEquals(TEST_AGENT_ID, actualAgentEventBo.getAgentId()); + assertEquals(TEST_START_TIMESTAMP, actualAgentEventBo.getStartTimestamp()); + assertEquals(TEST_EVENT_TIMESTAMP, actualAgentEventBo.getEventTimestamp()); + assertEquals(expectedEventType, actualAgentEventBo.getEventType()); + assertEquals(0, actualAgentEventBo.getEventBody().length); + } + + private static Map createTestChannelProperties() { + return createChannelProperties(TEST_AGENT_ID, TEST_START_TIMESTAMP); + } + + private static Map createChannelProperties(String agentId, long startTimestamp) { + Map map = new HashMap<>(); + map.put(HandshakePropertyType.AGENT_ID.getName(), agentId); + map.put(HandshakePropertyType.START_TIMESTAMP.getName(), startTimestamp); + return map; + } +} \ No newline at end of file diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleChangeEventHandlerTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleChangeEventHandlerTest.java similarity index 83% rename from collector/src/test/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleChangeEventHandlerTest.java rename to collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleChangeEventHandlerTest.java index 6cd5b5dc94b9..9beb099d10ec 100644 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleChangeEventHandlerTest.java +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleChangeEventHandlerTest.java @@ -1,124 +1,123 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.rpc.handler; - -import com.navercorp.pinpoint.collector.service.AgentEventService; -import com.navercorp.pinpoint.collector.util.ManagedAgentLifeCycle; -import com.navercorp.pinpoint.common.server.util.AgentEventType; -import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; -import com.navercorp.pinpoint.rpc.common.SocketStateCode; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import java.util.HashSet; -import java.util.Set; - -import static org.mockito.Mockito.*; - -/** - * @author HyunGil Jeong - */ -@RunWith(MockitoJUnitRunner.class) -public class AgentLifeCycleChangeEventHandlerTest { - - @Mock - private AgentLifeCycleHandler lifeCycleHandler; - - @Mock - private AgentEventService eventService; - - @Mock - private PinpointServer server; - - @InjectMocks - private AgentLifeCycleChangeEventHandler lifeCycleChangeEventHandler = new AgentLifeCycleChangeEventHandler(); - - @Before - public void setUp() throws Exception { - doReturn("TestPinpointServer").when(this.server).toString(); - } - - @Test - public void runningStatesShouldBeHandledCorrectly() throws Exception { - // given - final Set runningStates = ManagedAgentLifeCycle.RUNNING.getManagedStateCodes(); - runAndVerifyByStateCodes(runningStates); - } - - @Test - public void closedByClientStatesShouldBeHandledCorrectly() throws Exception { - // given - final Set closedByClientStates = ManagedAgentLifeCycle.CLOSED_BY_CLIENT.getManagedStateCodes(); - runAndVerifyByStateCodes(closedByClientStates); - } - - @Test - public void unexpectedCloseByClientStatesShouldBeHandledCorrectly() throws Exception { - // given - final Set unexpectedCloseByClientStates = ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_CLIENT.getManagedStateCodes(); - runAndVerifyByStateCodes(unexpectedCloseByClientStates); - } - - @Test - public void closedByServerStatesShouldBeHandledCorrectly() throws Exception { - // given - final Set closedByServerStates = ManagedAgentLifeCycle.CLOSED_BY_SERVER.getManagedStateCodes(); - runAndVerifyByStateCodes(closedByServerStates); - } - - @Test - public void unexpectedCloseByServerStatesShouldBeHandledCorrectly() throws Exception { - // given - final Set unexpectedCloseByServerStates = ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_SERVER.getManagedStateCodes(); - runAndVerifyByStateCodes(unexpectedCloseByServerStates); - } - - @Test - public void unmanagedStatesShouldNotBeHandled() throws Exception { - // given - final Set unmanagedStates = new HashSet<>(); - for (SocketStateCode socketStateCode : SocketStateCode.values()) { - if (ManagedAgentLifeCycle.getManagedAgentLifeCycleByStateCode(socketStateCode) == AgentLifeCycleChangeEventHandler.STATE_NOT_MANAGED) { - unmanagedStates.add(socketStateCode); - } - } - for (SocketStateCode unmanagedState : unmanagedStates) { - // when - this.lifeCycleChangeEventHandler.eventPerformed(this.server, unmanagedState); - // then - verify(this.lifeCycleHandler, never()).handleLifeCycleEvent(any(PinpointServer.class), anyLong(), any(AgentLifeCycleState.class), anyInt()); - verify(this.eventService, never()).handleEvent(any(PinpointServer.class), anyLong(), any(AgentEventType.class)); - } - } - - private void runAndVerifyByStateCodes(Set socketStates) throws Exception { - int testCount = 0; - for (SocketStateCode socketState : socketStates) { - this.lifeCycleChangeEventHandler.eventPerformed(this.server, socketState); - testCount++; - verify(this.lifeCycleHandler, times(testCount)) - .handleLifeCycleEvent(any(PinpointServer.class), anyLong(), any(AgentLifeCycleState.class), anyInt()); - verify(this.eventService, times(testCount)).handleEvent(any(PinpointServer.class), anyLong(), any(AgentEventType.class)); - } - } - -} +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.util.ManagedAgentLifeCycle; +import com.navercorp.pinpoint.common.server.util.AgentEventType; +import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; +import com.navercorp.pinpoint.rpc.common.SocketStateCode; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.HashSet; +import java.util.Set; + +import static org.mockito.Mockito.*; + +/** + * @author HyunGil Jeong + */ +@RunWith(MockitoJUnitRunner.class) +public class AgentLifeCycleChangeEventHandlerTest { + + @Mock + private AgentLifeCycleEventHandler agentLifeCycleEventHandler; + + @Mock + private AgentEventHandler agentEventHandler; + + @Mock + private PinpointServer server; + + @InjectMocks + private AgentLifeCycleChangeEventHandler lifeCycleChangeEventHandler = new AgentLifeCycleChangeEventHandler(); + + @Before + public void setUp() throws Exception { + doReturn("TestPinpointServer").when(this.server).toString(); + } + + @Test + public void runningStatesShouldBeHandledCorrectly() throws Exception { + // given + final Set runningStates = ManagedAgentLifeCycle.RUNNING.getManagedStateCodes(); + runAndVerifyByStateCodes(runningStates); + } + + @Test + public void closedByClientStatesShouldBeHandledCorrectly() throws Exception { + // given + final Set closedByClientStates = ManagedAgentLifeCycle.CLOSED_BY_CLIENT.getManagedStateCodes(); + runAndVerifyByStateCodes(closedByClientStates); + } + + @Test + public void unexpectedCloseByClientStatesShouldBeHandledCorrectly() throws Exception { + // given + final Set unexpectedCloseByClientStates = ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_CLIENT.getManagedStateCodes(); + runAndVerifyByStateCodes(unexpectedCloseByClientStates); + } + + @Test + public void closedByServerStatesShouldBeHandledCorrectly() throws Exception { + // given + final Set closedByServerStates = ManagedAgentLifeCycle.CLOSED_BY_SERVER.getManagedStateCodes(); + runAndVerifyByStateCodes(closedByServerStates); + } + + @Test + public void unexpectedCloseByServerStatesShouldBeHandledCorrectly() throws Exception { + // given + final Set unexpectedCloseByServerStates = ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_SERVER.getManagedStateCodes(); + runAndVerifyByStateCodes(unexpectedCloseByServerStates); + } + + @Test + public void unmanagedStatesShouldNotBeHandled() throws Exception { + // given + final Set unmanagedStates = new HashSet<>(); + for (SocketStateCode socketStateCode : SocketStateCode.values()) { + if (ManagedAgentLifeCycle.getManagedAgentLifeCycleByStateCode(socketStateCode) == AgentLifeCycleChangeEventHandler.STATE_NOT_MANAGED) { + unmanagedStates.add(socketStateCode); + } + } + for (SocketStateCode unmanagedState : unmanagedStates) { + // when + this.lifeCycleChangeEventHandler.eventPerformed(this.server, unmanagedState); + // then + verify(this.agentLifeCycleEventHandler, never()).handleLifeCycleEvent(any(PinpointServer.class), anyLong(), any(AgentLifeCycleState.class), anyInt()); + verify(this.agentEventHandler, never()).handleEvent(any(PinpointServer.class), anyLong(), any(AgentEventType.class)); + } + } + + private void runAndVerifyByStateCodes(Set socketStates) throws Exception { + int testCount = 0; + for (SocketStateCode socketState : socketStates) { + this.lifeCycleChangeEventHandler.eventPerformed(this.server, socketState); + testCount++; + verify(this.agentLifeCycleEventHandler, times(testCount)) + .handleLifeCycleEvent(any(PinpointServer.class), anyLong(), any(AgentLifeCycleState.class), anyInt()); + verify(this.agentEventHandler, times(testCount)).handleEvent(any(PinpointServer.class), anyLong(), any(AgentEventType.class)); + } + } + +} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleEventHandlerTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleEventHandlerTest.java new file mode 100644 index 000000000000..9532aebdf8ee --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/AgentLifeCycleEventHandlerTest.java @@ -0,0 +1,189 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.dao.AgentLifeCycleDao; +import com.navercorp.pinpoint.collector.handler.DirectExecutor; +import com.navercorp.pinpoint.collector.service.AgentLifeCycleService; +import com.navercorp.pinpoint.collector.util.ManagedAgentLifeCycle; +import com.navercorp.pinpoint.common.server.bo.AgentLifeCycleBo; +import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; +import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; + +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +@RunWith(MockitoJUnitRunner.class) +public class AgentLifeCycleEventHandlerTest { + + // FIX guava 19.0.0 update error. MoreExecutors.sameThreadExecutor(); change final class + @Spy + private Executor executor = new DirectExecutor(); + + @Mock + private PinpointServer pinpointServer; + + @Mock + private AgentLifeCycleService agentLifeCycleService; + + @InjectMocks + private AgentLifeCycleEventHandler agentLifeCycleEventHandler = new AgentLifeCycleEventHandler(); + + private static final String TEST_AGENT_ID = "TEST_AGENT"; + private static final long TEST_START_TIMESTAMP = System.currentTimeMillis(); + private static final long TEST_EVENT_TIMESTAMP = TEST_START_TIMESTAMP + 10; + private static final int TEST_SOCKET_ID = 999; + private static final Map TEST_CHANNEL_PROPERTIES = createTestChannelProperties(); + + @Before + public void setUp() throws Exception { + when(this.pinpointServer.getChannelProperties()).thenReturn(TEST_CHANNEL_PROPERTIES); + } + + @Test + public void runningStateShouldBeInserted() { + runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.RUNNING); + } + + @Test + public void closedByClientStateShouldBeInserted() { + runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.CLOSED_BY_CLIENT); + } + + @Test + public void unexpectedCloseByClientStateShouldBeInserted() { + runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_CLIENT); + } + + @Test + public void closedByServerStateShouldBeInserted() { + runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.CLOSED_BY_SERVER); + } + + @Test + public void unexpectedCloseByServerStateShouldBeInserted() { + runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_SERVER); + } + + @Test + public void testValidTimestampCreation() { + // socketId = 1, eventCounter = 1 -> timestamp = 0x100000001 + int givenSocketId = 1; + int givenEventCounter = 1; + long expectedTimestamp = new BigInteger("100000001", 16).longValue(); + long timestamp = this.agentLifeCycleEventHandler.createEventIdentifier(givenSocketId, givenEventCounter); + assertEquals(expectedTimestamp, timestamp); + // socketId = 0, eventCounter = 0 -> timestamp = 0x0 + givenSocketId = 0; + givenEventCounter = 0; + expectedTimestamp = new BigInteger("0000000000000000", 16).longValue(); + timestamp = this.agentLifeCycleEventHandler.createEventIdentifier(givenSocketId, givenEventCounter); + assertEquals(expectedTimestamp, timestamp); + // socketId = Integer.MAX_VALUE, eventCounter = 0 -> timestamp = 0x7fffffff00000000 + givenSocketId = Integer.MAX_VALUE; + givenEventCounter = 0; + expectedTimestamp = new BigInteger("7fffffff00000000", 16).longValue(); + timestamp = this.agentLifeCycleEventHandler.createEventIdentifier(givenSocketId, givenEventCounter); + assertEquals(expectedTimestamp, timestamp); + // socketId = Integer.MAX_VALUE, eventCounter = Integer.MAX_VALUE -> timestamp = 0x7fffffff7fffffff + givenSocketId = Integer.MAX_VALUE; + givenEventCounter = Integer.MAX_VALUE; + expectedTimestamp = new BigInteger("7fffffff7fffffff", 16).longValue(); + timestamp = this.agentLifeCycleEventHandler.createEventIdentifier(givenSocketId, givenEventCounter); + assertEquals(expectedTimestamp, timestamp); + } + + @Test + public void testTimestampOrdering() { + // 0x7fffffff < 0x100000000 + long smallerTimestamp = this.agentLifeCycleEventHandler.createEventIdentifier(0, Integer.MAX_VALUE); + long largerTimestamp = this.agentLifeCycleEventHandler.createEventIdentifier(1, 0); + assertTrue(smallerTimestamp < largerTimestamp); + } + + @Test + public void testInvalidTimestampCreation() { + final int negativeSocketId = new BigInteger("ffffffff", 16).intValue(); + final int eventCounter = 0; + try { + this.agentLifeCycleEventHandler.createEventIdentifier(negativeSocketId, eventCounter); + fail(); + } catch (IllegalArgumentException expected) { + // expected + } + final int socketId = 0; + final int negativeEventCounter = new BigInteger("ffffffff", 16).intValue(); + try { + this.agentLifeCycleEventHandler.createEventIdentifier(socketId, negativeEventCounter); + fail(); + } catch (IllegalArgumentException expected) { + // expected + } + } + + private static Map createTestChannelProperties() { + return createChannelProperties(TEST_AGENT_ID, TEST_START_TIMESTAMP, TEST_SOCKET_ID); + } + + private static Map createChannelProperties(String agentId, long startTimestamp, int socketId) { + Map map = new HashMap<>(); + map.put(HandshakePropertyType.AGENT_ID.getName(), agentId); + map.put(HandshakePropertyType.START_TIMESTAMP.getName(), startTimestamp); + map.put(AgentLifeCycleEventHandler.SOCKET_ID_KEY, socketId); + return map; + } + + private void runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle managedAgentLifeCycle) { + // given + final AgentLifeCycleState expectedLifeCycleState = managedAgentLifeCycle.getMappedState(); + final int expectedEventCounter = managedAgentLifeCycle.getEventCounter(); + final long expectedEventIdentifier = this.agentLifeCycleEventHandler.createEventIdentifier(TEST_SOCKET_ID, expectedEventCounter); + ArgumentCaptor argCaptor = ArgumentCaptor.forClass(AgentLifeCycleBo.class); + + // when + this.agentLifeCycleEventHandler.handleLifeCycleEvent(this.pinpointServer, TEST_EVENT_TIMESTAMP, expectedLifeCycleState, expectedEventCounter); + verify(this.agentLifeCycleService, times(1)).insert(argCaptor.capture()); + + // then + AgentLifeCycleBo actualAgentLifeCycleBo = argCaptor.getValue(); + assertEquals(AgentLifeCycleBo.CURRENT_VERSION, actualAgentLifeCycleBo.getVersion()); + assertEquals(TEST_AGENT_ID, actualAgentLifeCycleBo.getAgentId()); + assertEquals(TEST_START_TIMESTAMP, actualAgentLifeCycleBo.getStartTimestamp()); + assertEquals(TEST_EVENT_TIMESTAMP, actualAgentLifeCycleBo.getEventTimestamp()); + assertEquals(expectedLifeCycleState, actualAgentLifeCycleBo.getAgentLifeCycleState()); + assertEquals(expectedEventIdentifier, actualAgentLifeCycleBo.getEventIdentifier()); + } +} \ No newline at end of file diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPReceiverTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPReceiverTest.java new file mode 100644 index 000000000000..41dc1b017b25 --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/tcp/TCPReceiverTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.tcp; + +import com.navercorp.pinpoint.collector.config.AgentBaseDataReceiverConfiguration; +import com.navercorp.pinpoint.collector.config.DeprecatedConfiguration; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.SocketUtils; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Properties; + +/** + * @author emeroad + */ +public class TCPReceiverTest { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void l4ip() throws UnknownHostException { + InetAddress byName = InetAddress.getByName("10.12.13.10"); + logger.debug("byName:{}", byName); + } + + @Test + public void l4ipList() throws UnknownHostException { + String two = "10.12.13.10,10.12.13.20"; + String[] split = two.split(","); + Assert.assertEquals(split.length, 2); + + String twoEmpty = "10.12.13.10,"; + String[] splitEmpty = twoEmpty.split(","); + Assert.assertEquals(splitEmpty.length, 1); + + } + + private AgentBaseDataReceiverConfiguration createConfiguration() { + Properties properties = new Properties(); + properties.put("collector.receiver.base.ip", "0.0.0.0"); + final int availableTcpPort = SocketUtils.findAvailableTcpPort(19099); + properties.put("collector.receiver.base.port", String.valueOf(availableTcpPort)); + properties.put("collector.receiver.base.worker.threadSize", "8"); + properties.put("collector.receiver.base.worker.queueSize", "1024"); + + AgentBaseDataReceiverConfiguration config = new AgentBaseDataReceiverConfiguration(properties, new DeprecatedConfiguration()); + return config; + } + +} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/NettyUdpReceiverTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/NettyUdpReceiverTest.java similarity index 98% rename from collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/NettyUdpReceiverTest.java rename to collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/NettyUdpReceiverTest.java index 8f8e299b35e6..6e3a1b631eae 100644 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/NettyUdpReceiverTest.java +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/NettyUdpReceiverTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.navercorp.pinpoint.collector.receiver.udp; +package com.navercorp.pinpoint.collector.receiver.thrift.udp; import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.channel.*; diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/NetworkAvailabilityCheckPacketFilterTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/NetworkAvailabilityCheckPacketFilterTest.java similarity index 92% rename from collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/NetworkAvailabilityCheckPacketFilterTest.java rename to collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/NetworkAvailabilityCheckPacketFilterTest.java index c25578201734..9bbb2dfb4a6e 100644 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/NetworkAvailabilityCheckPacketFilterTest.java +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/NetworkAvailabilityCheckPacketFilterTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.navercorp.pinpoint.collector.receiver.udp; +package com.navercorp.pinpoint.collector.receiver.thrift.udp; import com.navercorp.pinpoint.thrift.dto.TSpan; import com.navercorp.pinpoint.thrift.io.NetworkAvailabilityCheckPacket; @@ -37,7 +37,7 @@ public class NetworkAvailabilityCheckPacketFilterTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private NetworkAvailabilityCheckPacketFilter filter; + private TBaseFilter filter; private DatagramSocket senderSocket; private DatagramSocket receiverSocket; @@ -50,7 +50,6 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { - filter.destroy(); try { senderSocket.close(); } catch (Exception e) { @@ -68,7 +67,8 @@ public void testFilter() throws Exception { logger.debug("localSocket:{}", localSocketAddress); NetworkAvailabilityCheckPacket packet = new NetworkAvailabilityCheckPacket(); - boolean skipResult = filter.filter(receiverSocket, packet, new InetSocketAddress("localhost", senderSocket.getLocalPort())); + SocketAddress inetSocketAddress = new InetSocketAddress("localhost", senderSocket.getLocalPort()); + boolean skipResult = filter.filter(receiverSocket, packet, inetSocketAddress); Assert.assertEquals(skipResult, TBaseFilter.BREAK); diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/SpanStreamUDPSenderTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/SpanStreamUDPSenderTest.java new file mode 100644 index 000000000000..1ab60848816b --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/SpanStreamUDPSenderTest.java @@ -0,0 +1,308 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.udp; + +import com.google.common.util.concurrent.MoreExecutors; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.collector.util.DatagramPacketFactory; +import com.navercorp.pinpoint.collector.util.DefaultObjectPool; +import com.navercorp.pinpoint.collector.util.ObjectPool; +import com.navercorp.pinpoint.collector.util.ObjectPoolFactory; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.profiler.context.Span; +import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.profiler.context.compress.Context; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessorV1; +import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.id.Shared; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import com.navercorp.pinpoint.profiler.context.thrift.SpanThriftMessageConverter; +import com.navercorp.pinpoint.profiler.sender.SpanStreamUdpSender; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; +import com.navercorp.pinpoint.thrift.dto.TResult; +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; +import org.apache.thrift.TBase; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.SocketUtils; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; + +import static org.mockito.Mockito.mock; + +/** + * @author emeroad + */ +public class SpanStreamUDPSenderTest { + + private String applicationName = "appName"; + private String agentId = "agentId"; + private long agentStartTime = 0; + private ServiceType applicationServiceType = ServiceType.STAND_ALONE; + + private static MessageHolderDispatchHandler messageHolder; + private static UDPReceiver receiver = null; + + private static int port; + + private final TestAwaitUtils awaitUtils = new TestAwaitUtils(100, 6000); + + private final TransactionIdEncoder transactionIdEncoder = new DefaultTransactionIdEncoder(agentId, agentStartTime); + private final SpanPostProcessor spanPostProcessor = new SpanPostProcessorV1(); + private final MessageConverter> messageConverter + = new SpanThriftMessageConverter(applicationName, agentId, agentStartTime, applicationServiceType.getCode(), + transactionIdEncoder, spanPostProcessor); + + @BeforeClass + public static void setUp() throws IOException { + port = SocketUtils.findAvailableUdpPort(21111); + + messageHolder = new MessageHolderDispatchHandler(); + + Executor executor = MoreExecutors.directExecutor(); + InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", port); + PacketHandlerFactory packetHandlerFactory = new SpanStreamUDPPacketHandlerFactory<>(messageHolder, new TestTBaseFilter()); + + ObjectPoolFactory packetFactory = new DatagramPacketFactory(); + ObjectPool pool = new DefaultObjectPool<>(packetFactory, 10); + receiver = new UDPReceiver("test", packetHandlerFactory, executor, 1024, inetSocketAddress, pool); + receiver.start(); + } + + @AfterClass + public static void tearDown() { + if (receiver != null) { + receiver.shutdown(); + } + } + + private TraceRoot mockTraceRoot() { + final TraceRoot traceRoot = mock(TraceRoot.class); + TraceId traceId = mock(TraceId.class); + Mockito.when(traceRoot.getTraceId()).thenReturn(traceId); + + Shared shared = mock(Shared.class); + Mockito.when(traceRoot.getShared()).thenReturn(shared); + return traceRoot; + } + + @Test + public void sendTest1() throws InterruptedException { + SpanStreamUdpSender sender = null; + try { + final TraceRoot traceRoot = mockTraceRoot(); + + sender = new SpanStreamUdpSender("127.0.0.1", port, "threadName", 10, 200, SpanStreamUdpSender.SEND_BUFFER_SIZE, messageConverter); + sender.send(createSpanChunk(traceRoot, 10)); + sender.send(createSpanChunk(traceRoot, 3)); + + awaitMessageReceived(2, messageHolder, TSpanChunk.class); + + List tBaseList = messageHolder.getMessageHolder(); + tBaseList.clear(); + } finally { + if (sender != null) { + sender.stop(); + } + } + } + + @Test + public void sendTest2() throws InterruptedException { + SpanStreamUdpSender sender = null; + try { + final TraceRoot traceRoot = mockTraceRoot(); + sender = new SpanStreamUdpSender("127.0.0.1", port, "threadName", 10, 200, SpanStreamUdpSender.SEND_BUFFER_SIZE, messageConverter); + sender.send(createSpan(traceRoot, 10)); + sender.send(createSpan(traceRoot, 3)); + + awaitMessageReceived(2, messageHolder, TSpan.class); + + List tBaseList = messageHolder.getMessageHolder(); + tBaseList.clear(); + } finally { + if (sender != null) { + sender.stop(); + } + } + } + + @Test + public void sendTest3() throws InterruptedException { + SpanStreamUdpSender sender = null; + try { + final TraceRoot traceRoot = mockTraceRoot(); + sender = new SpanStreamUdpSender("127.0.0.1", port, "threadName", 10, 200, SpanStreamUdpSender.SEND_BUFFER_SIZE, messageConverter); + sender.send(createSpan(traceRoot, 10)); + sender.send(createSpan(traceRoot, 3)); + sender.send(createSpanChunk(traceRoot, 3)); + + awaitMessageReceived(2, messageHolder, TSpan.class); + awaitMessageReceived(1, messageHolder, TSpanChunk.class); + + List tBaseList = messageHolder.getMessageHolder(); + tBaseList.clear(); + } finally { + if (sender != null) { + sender.stop(); + } + } + } + + private Span createSpan(TraceRoot traceRoot, int spanEventSize) throws InterruptedException { + + List spanEventList = createSpanEventList(traceRoot, spanEventSize); + + Span span = new Span(traceRoot); + span.setSpanEventList(spanEventList); + return span; + } + + private SpanChunk createSpanChunk(TraceRoot traceRoot, int spanEventSize) throws InterruptedException { + + List originalSpanEventList = createSpanEventList(traceRoot, spanEventSize); + SpanChunk spanChunk = newSpanChunk(traceRoot, originalSpanEventList); + return spanChunk; + } + + + private SpanChunk newSpanChunk(TraceRoot traceRoot, List spanEventList) { + SpanChunk spanChunk = new SpanChunk(traceRoot, spanEventList); + return spanChunk; + } + private int getObjectCount(List tbaseList, Class clazz) { + int count = 0; + + + for (ServerRequest t : tbaseList) { + if (clazz.isInstance(t.getData())) { + count++; + } + } + + return count; + } + + private List createSpanEventList(TraceRoot traceRoot, int size) throws InterruptedException { + + int elapsedTime = 0; + + List spanEventList = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + SpanEvent spanEvent = new SpanEvent(); + spanEvent.setStartTime(traceRoot.getTraceStartTime() + elapsedTime++); + spanEvent.setElapsedTime(elapsedTime++); + + spanEventList.add(spanEvent); + } + + return spanEventList; + } + +// private void waitExpectedRequestCount(final AtomicInteger requestCount, final int expectedRequestCount) { +// boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { +// @Override +// public boolean checkCompleted() { +// return requestCount.get() == expectedRequestCount; +// }; +// }); +// +// Assert.assertTrue(pass); +// } + + private void waitMessageReceived(final int receivedCount, final int awaitReceiveCount) { + boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return receivedCount == awaitReceiveCount; + } + }); + + Assert.assertTrue(pass); + } + + private void awaitMessageReceived(final int receivedCount, final MessageHolderDispatchHandler dispatchHandler, final Class clazz) { + boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + List messageHolder = dispatchHandler.getMessageHolder(); + int objectCount = getObjectCount(messageHolder, clazz); + return receivedCount == objectCount; + } + }); + + Assert.assertTrue(pass); + } + + static class TestTBaseFilter implements TBaseFilter { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public boolean filter(DatagramSocket localSocket, TBase tBase, T remoteHostAddress) { + logger.debug("filter"); + return false; + } + + } + + static class MessageHolderDispatchHandler implements DispatchHandler { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private List messageHolder = new ArrayList<>(); + + + @Override + public void dispatchSendMessage(ServerRequest serverRequest) { + logger.debug("dispatchSendMessage"); + } + + @Override + public void dispatchRequestMessage(ServerRequest serverRequest, ServerResponse serverResponse) { + messageHolder.add(serverRequest); + TResult tResult = new TResult(true); + serverResponse.write(tResult); + } + + public List getMessageHolder() { + return messageHolder; + } + + } + +} \ No newline at end of file diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/TBaseFilterChainTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/TBaseFilterChainTest.java new file mode 100644 index 000000000000..66dcc0078e2d --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/TBaseFilterChainTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.udp; + +import org.junit.Test; + +import java.net.InetSocketAddress; +import java.util.Collections; + +import static org.mockito.Mockito.mock; + +/** + * @author Woonduk Kang(emeroad) + */ +public class TBaseFilterChainTest { + + @Test + public void constructor_generic_array() { + TBaseFilter filter = mock(TBaseFilter.class); + TBaseFilterChain chain = new TBaseFilterChain<>(Collections.singletonList(filter)); + chain.filter(null, null, null); + } +} \ No newline at end of file diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/UDPReceiverTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/UDPReceiverTest.java new file mode 100644 index 000000000000..79e54ef9a669 --- /dev/null +++ b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/thrift/udp/UDPReceiverTest.java @@ -0,0 +1,186 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.collector.receiver.thrift.udp; + +import com.google.common.util.concurrent.MoreExecutors; +import com.navercorp.pinpoint.collector.util.DatagramPacketFactory; +import com.navercorp.pinpoint.collector.util.DefaultObjectPool; +import com.navercorp.pinpoint.collector.util.ObjectPool; +import com.navercorp.pinpoint.collector.util.ObjectPoolFactory; +import org.apache.hadoop.hbase.shaded.org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.SocketUtils; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author emeroad + */ +public class UDPReceiverTest { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static final String ADDRESS = "127.0.0.1"; + private static final int PORT = SocketUtils.findAvailableUdpPort(10999); + + private final PacketHandler loggingPacketHandler = new PacketHandler() { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Override + public void receive(DatagramSocket localSocket, Object packet) { + logger.info("receive localSocket:{} packet:{}", localSocket, packet); + } + }; + + @Test + public void startStop() { + UDPReceiver receiver = null; + + InetSocketAddress bindAddress = new InetSocketAddress(ADDRESS, PORT); + + Executor executor = MoreExecutors.directExecutor(); + PacketHandlerFactory packetHandlerFactory = mock(PacketHandlerFactory.class); + when(packetHandlerFactory.createPacketHandler()).thenReturn(loggingPacketHandler); + try { + ObjectPoolFactory packetFactory = new DatagramPacketFactory(); + ObjectPool pool = new DefaultObjectPool<>(packetFactory, 10); + receiver = new UDPReceiver("test", packetHandlerFactory, executor, 8, bindAddress, pool); + } catch (Exception e) { + logger.debug(e.getMessage(), e); + Assert.fail(e.getMessage()); + } finally { + if (receiver != null) { + receiver.shutdown(); + } + } + } + + @Test + public void hostNullCheck() { + InetSocketAddress address = new InetSocketAddress((InetAddress) null, PORT); + logger.debug(address.toString()); + } + + @Test + public void socketBufferSize() throws SocketException { + DatagramSocket datagramSocket = new DatagramSocket(); + int receiveBufferSize = datagramSocket.getReceiveBufferSize(); + logger.debug("{}", receiveBufferSize); + + datagramSocket.setReceiveBufferSize(64 * 1024 * 10); + logger.debug("{}", datagramSocket.getReceiveBufferSize()); + + datagramSocket.close(); + } + + @Test + public void sendSocketBufferSize() throws IOException { + DatagramPacket datagramPacket = new DatagramPacket(new byte[0], 0, 0); + + DatagramSocket datagramSocket = new DatagramSocket(); + datagramSocket.connect(new InetSocketAddress(ADDRESS, PORT)); + + datagramSocket.send(datagramPacket); + datagramSocket.close(); + } + + private final AtomicInteger zeroPacketCounter = new AtomicInteger(); + void interceptValidatePacket(DatagramPacket packet) { + if (packet.getLength() == 0) { + zeroPacketCounter.incrementAndGet(); + } + } + + @Test + public void datagramPacket_length_zero() { + UDPReceiver receiver = null; + DatagramSocket datagramSocket = null; + + CountDownLatch latch = new CountDownLatch(1); + Executor mockExecutor = mockDispatchWorker(latch); + + PacketHandlerFactory packetHandlerFactory = mock(PacketHandlerFactory.class); + when(packetHandlerFactory.createPacketHandler()).thenReturn(loggingPacketHandler); + + try { + InetSocketAddress bindAddress = new InetSocketAddress(ADDRESS, PORT); + ObjectPoolFactory packetFactory = new DatagramPacketFactory(); + ObjectPool pool = new DefaultObjectPool<>(packetFactory, 10); + receiver = new UDPReceiver("test", packetHandlerFactory, mockExecutor, 8, bindAddress, pool) { + @Override + boolean validatePacket(DatagramPacket packet) { + interceptValidatePacket(packet); + return super.validatePacket(packet); + } + }; + receiver.start(); + + datagramSocket = new DatagramSocket(); + datagramSocket.connect(new InetSocketAddress(ADDRESS, PORT)); + + datagramSocket.send(new DatagramPacket(new byte[0], 0)); + datagramSocket.send(new DatagramPacket(new byte[1], 1)); + + Assert.assertTrue(latch.await(30000, TimeUnit.MILLISECONDS)); + Assert.assertEquals(zeroPacketCounter.get(), 1); + Mockito.verify(mockExecutor).execute(any(Runnable.class)); + } catch (Exception e) { + logger.debug(e.getMessage(), e); + Assert.fail(e.getMessage()); + } finally { + if (receiver != null) { + receiver.shutdown(); + } + IOUtils.closeQuietly(datagramSocket); + + + } + } + + private Executor mockDispatchWorker(CountDownLatch latch) { + + Executor mockWorker = new Executor() { + @Override + public void execute(Runnable runnable) { + logger.info("execute:{}", runnable.getClass()); + try { + runnable.run(); + } finally { + latch.countDown(); + } + } + }; + return Mockito.spy(mockWorker); + } + + +} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/SpanStreamUDPSenderTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/SpanStreamUDPSenderTest.java deleted file mode 100644 index 821a7c12038a..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/SpanStreamUDPSenderTest.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.udp; - -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.collector.TestAwaitTaskUtils; -import com.navercorp.pinpoint.collector.TestAwaitUtils; -import com.navercorp.pinpoint.collector.receiver.AbstractDispatchHandler; -import com.navercorp.pinpoint.collector.receiver.DataReceiver; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactoryV1; -import com.navercorp.pinpoint.profiler.context.Span; -import com.navercorp.pinpoint.profiler.context.SpanChunk; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactory; -import com.navercorp.pinpoint.profiler.context.SpanEvent; -import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; -import com.navercorp.pinpoint.profiler.context.id.Shared; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; -import com.navercorp.pinpoint.profiler.sender.SpanStreamUdpSender; -import com.navercorp.pinpoint.thrift.dto.TResult; -import com.navercorp.pinpoint.thrift.dto.TSpan; -import com.navercorp.pinpoint.thrift.dto.TSpanChunk; -import org.apache.thrift.TBase; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mockito; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.SocketUtils; - -import java.io.IOException; -import java.net.DatagramSocket; -import java.util.ArrayList; -import java.util.List; - -import static org.mockito.Mockito.mock; - -/** - * @author emeroad - */ -public class SpanStreamUDPSenderTest { - - private static MessageHolderDispatchHandler messageHolder; - private static DataReceiver receiver = null; - - private static int port; - - private final TestAwaitUtils awaitUtils = new TestAwaitUtils(100, 6000); - - @BeforeClass - public static void setUp() throws IOException { - port = SocketUtils.findAvailableUdpPort(21111); - - try { - messageHolder = new MessageHolderDispatchHandler(); - receiver = new TestUDPReceiver("test", new SpanStreamUDPPacketHandlerFactory<>(messageHolder, new TestTBaseFilter()), "127.0.0.1", - port, 1024, 1, 10); - receiver.start(); - } catch (Exception ignored) { - } - } - - @AfterClass - public static void tearDown() { - if (receiver != null) { - receiver.shutdown(); - } - } - - private TraceRoot mockTraceRoot() { - final TraceRoot traceRoot = mock(TraceRoot.class); - TraceId traceId = mock(TraceId.class); - Mockito.when(traceRoot.getTraceId()).thenReturn(traceId); - - Shared shared = mock(Shared.class); - Mockito.when(traceRoot.getShared()).thenReturn(shared); - return traceRoot; - } - - @Test - public void sendTest1() throws InterruptedException { - SpanStreamUdpSender sender = null; - try { - final TraceRoot traceRoot = mockTraceRoot(); - - sender = new SpanStreamUdpSender("127.0.0.1", port, "threadName", 10, 200, SpanStreamUdpSender.SEND_BUFFER_SIZE); - sender.send(createSpanChunk(traceRoot, 10)); - sender.send(createSpanChunk(traceRoot, 3)); - - awaitMessageReceived(2, messageHolder, TSpanChunk.class); - - List tBaseList = messageHolder.getMessageHolder(); - tBaseList.clear(); - } finally { - if (sender != null) { - sender.stop(); - } - } - } - - @Test - public void sendTest2() throws InterruptedException { - SpanStreamUdpSender sender = null; - try { - final TraceRoot traceRoot = mockTraceRoot(); - sender = new SpanStreamUdpSender("127.0.0.1", port, "threadName", 10, 200, SpanStreamUdpSender.SEND_BUFFER_SIZE); - sender.send(createSpan(traceRoot, 10)); - sender.send(createSpan(traceRoot, 3)); - - awaitMessageReceived(2, messageHolder, TSpan.class); - - List tBaseList = messageHolder.getMessageHolder(); - tBaseList.clear(); - } finally { - if (sender != null) { - sender.stop(); - } - } - } - - @Test - public void sendTest3() throws InterruptedException { - SpanStreamUdpSender sender = null; - try { - final TraceRoot traceRoot = mockTraceRoot(); - sender = new SpanStreamUdpSender("127.0.0.1", port, "threadName", 10, 200, SpanStreamUdpSender.SEND_BUFFER_SIZE); - sender.send(createSpan(traceRoot, 10)); - sender.send(createSpan(traceRoot, 3)); - sender.send(createSpanChunk(traceRoot, 3)); - - awaitMessageReceived(2, messageHolder, TSpan.class); - awaitMessageReceived(1, messageHolder, TSpanChunk.class); - - List tBaseList = messageHolder.getMessageHolder(); - tBaseList.clear(); - } finally { - if (sender != null) { - sender.stop(); - } - } - } - - private Span createSpan(TraceRoot traceRoot, int spanEventSize) throws InterruptedException { - - List spanEventList = createSpanEventList(traceRoot, spanEventSize); - - Span span = new Span(traceRoot); - span.setSpanEventList((List)spanEventList); - return span; - } - - private SpanChunk createSpanChunk(TraceRoot traceRoot, int spanEventSize) throws InterruptedException { - final String agentId = "agentId"; - final long agentStartTime = System.currentTimeMillis(); - final TransactionIdEncoder transactionIdEncoder = new DefaultTransactionIdEncoder(agentId, agentStartTime); - SpanChunkFactory spanChunkFactory = new SpanChunkFactoryV1("applicationName", agentId, agentStartTime, ServiceType.STAND_ALONE, transactionIdEncoder); - - List originalSpanEventList = createSpanEventList(traceRoot, spanEventSize); - SpanChunk spanChunk = spanChunkFactory.create(traceRoot, originalSpanEventList); - return spanChunk; - } - - private int getObjectCount(List tbaseList, Class clazz) { - int count = 0; - - for (TBase t : tbaseList) { - if (clazz.isInstance(t)) { - count++; - } - } - - return count; - } - - private List createSpanEventList(TraceRoot traceRoot, int size) throws InterruptedException { - - List spanEventList = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - SpanEvent spanEvent = new SpanEvent(traceRoot); - spanEvent.markStartTime(); - Thread.sleep(1); - spanEvent.markAfterTime(); - - spanEventList.add(spanEvent); - } - - return spanEventList; - } - -// private void waitExpectedRequestCount(final AtomicInteger requestCount, final int expectedRequestCount) { -// boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { -// @Override -// public boolean checkCompleted() { -// return requestCount.get() == expectedRequestCount; -// }; -// }); -// -// Assert.assertTrue(pass); -// } - - private void waitMessageReceived(final int receivedCount, final int awaitReceiveCount) { - boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - return receivedCount == awaitReceiveCount; - } - }); - - Assert.assertTrue(pass); - } - - private void awaitMessageReceived(final int receivedCount, final MessageHolderDispatchHandler dispatchHandler, final Class clazz) { - boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - List messageHolder = dispatchHandler.getMessageHolder(); - int objectCount = getObjectCount(messageHolder, clazz); - return receivedCount == objectCount; - } - }); - - Assert.assertTrue(pass); - } - - static class TestTBaseFilter implements TBaseFilter { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - @Override - public boolean filter(DatagramSocket localSocket, TBase tBase, T remoteHostAddress) { - logger.debug("filter"); - return false; - } - - } - - static class MessageHolderDispatchHandler extends AbstractDispatchHandler { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private List messageHolder = new ArrayList<>(); - - @Override - public void dispatchSendMessage(TBase tBase) { - logger.debug("dispatchSendMessage"); - } - - @Override - public TBase dispatchRequestMessage(TBase tBase) { - messageHolder.add(tBase); - return new TResult(true); - } - - public List getMessageHolder() { - return messageHolder; - } - - } - -} \ No newline at end of file diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/TestUDPReceiver.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/TestUDPReceiver.java deleted file mode 100644 index 977115ef59ba..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/TestUDPReceiver.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.udp; - -import com.navercorp.pinpoint.collector.receiver.DataReceiver; -import com.navercorp.pinpoint.collector.util.DatagramPacketFactory; -import com.navercorp.pinpoint.collector.util.DefaultObjectPool; -import com.navercorp.pinpoint.collector.util.ObjectPool; -import com.navercorp.pinpoint.collector.util.PacketUtils; -import com.navercorp.pinpoint.collector.util.PooledObject; -import com.navercorp.pinpoint.common.util.ExecutorFactory; -import com.navercorp.pinpoint.common.util.PinpointThreadFactory; -import com.navercorp.pinpoint.common.util.CpuUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.Assert; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -public class TestUDPReceiver implements DataReceiver { - - private final Logger logger; - - private final String bindAddress; - private final int port; - - private final String receiverName; - - // increasing ioThread size wasn't very effective - private final int ioThreadSize = CpuUtils.cpuCount(); - private ThreadPoolExecutor io; - - // modify thread pool size appropriately when modifying queue capacity - private ThreadPoolExecutor worker; - private int workerThreadSize = 128; - private int workerThreadQueueSize = 1024; - - // can't really allocate memory as max udp packet sizes are unknown. - // not allocating memory in advance as I am unsure of the max udp packet - // size. - // packet cache is necessary as the JVM does not last long if they are - // dynamically created with the maximum size. - private ObjectPool datagramPacketPool; - - private final DatagramSocket socket; - - private final PacketHandlerFactory packetHandlerFactory; - - private final AtomicInteger rejectedExecutionCount = new AtomicInteger(0); - - private final AtomicBoolean state = new AtomicBoolean(true); - - public TestUDPReceiver(String receiverName, PacketHandlerFactory packetHandlerFactory, String bindAddress, int port, - int receiverBufferSize, int workerThreadSize, int workerThreadQueueSize) { - if (receiverName != null) { - this.logger = LoggerFactory.getLogger(receiverName); - } else { - this.logger = LoggerFactory.getLogger(this.getClass()); - } - if (packetHandlerFactory == null) { - throw new NullPointerException("packetHandlerFactory must not be null"); - } - if (bindAddress == null) { - throw new NullPointerException("bindAddress must not be null"); - } - - this.receiverName = receiverName; - this.bindAddress = bindAddress; - this.port = port; - this.socket = createSocket(receiverBufferSize); - - this.workerThreadSize = workerThreadSize; - this.workerThreadQueueSize = workerThreadQueueSize; - this.packetHandlerFactory = packetHandlerFactory; - } - - public void afterPropertiesSet() { - Assert.notNull(packetHandlerFactory, "packetHandlerFactory must not be null"); - - final int packetPoolSize = getPacketPoolSize(workerThreadSize, workerThreadQueueSize); - this.datagramPacketPool = new DefaultObjectPool<>(new DatagramPacketFactory(), packetPoolSize); - this.worker = ExecutorFactory.newFixedThreadPool(workerThreadSize, workerThreadQueueSize, receiverName + "-Worker", true); - - this.io = (ThreadPoolExecutor) Executors.newCachedThreadPool(new PinpointThreadFactory(receiverName + "-Io", true)); - } - - private void receive(final DatagramSocket socket) { - if (logger.isInfoEnabled()) { - logger.info("start ioThread localAddress:{}, IoThread:{}", this.socket.getLocalAddress(), Thread.currentThread().getName()); - } - final SocketAddress localSocketAddress = socket.getLocalSocketAddress(); - final boolean debugEnabled = logger.isDebugEnabled(); - - // need shutdown logic - while (state.get()) { - PooledObject pooledPacket = read0(socket); - if (pooledPacket == null) { - continue; - } - final DatagramPacket packet = pooledPacket.getObject(); - if (packet.getLength() == 0) { - if (debugEnabled) { - logger.debug("length is 0 ip:{}, port:{}", packet.getAddress(), packet.getPort()); - } - return; - } - if (debugEnabled) { - logger.debug("pool getActiveCount:{}", worker.getActiveCount()); - } - try { - Runnable dispatchTask = wrapDispatchTask(pooledPacket); - worker.execute(dispatchTask); - } catch (RejectedExecutionException ree) { - logger.warn(ree.getMessage(), ree); - } - } - if (logger.isInfoEnabled()) { - logger.info("stop ioThread localAddress:{}, IoThread:{}", localSocketAddress, Thread.currentThread().getName()); - } - } - - private Runnable wrapDispatchTask(final PooledObject pooledPacket) { - final Runnable lazyExecution = new Runnable() { - @Override - public void run() { - PacketHandler dispatchPacket = packetHandlerFactory.createPacketHandler(); - PooledPacketWrap pooledPacketWrap = new PooledPacketWrap(socket, dispatchPacket, pooledPacket); - Runnable execution = pooledPacketWrap; - execution.run(); - } - }; - return lazyExecution; - } - - private PooledObject read0(final DatagramSocket socket) { - boolean success = false; - PooledObject pooledObject = datagramPacketPool.getObject(); - if (pooledObject == null) { - logger.error("datagramPacketPool is empty"); - return null; - } - DatagramPacket packet = pooledObject.getObject(); - try { - try { - socket.receive(packet); - success = true; - } catch (SocketTimeoutException e) { - return null; - } - if (logger.isDebugEnabled()) { - logger.debug("DatagramPacket SocketAddress:{} read size:{}", packet.getSocketAddress(), packet.getLength()); - if (logger.isTraceEnabled()) { - // use trace as packet dump may be large - logger.trace("dump packet:{}", PacketUtils.dumpDatagramPacket(packet)); - } - } - } catch (IOException e) { - if (!state.get()) { - // shutdown - } else { - logger.error("IoError, Caused:", e.getMessage(), e); - } - return null; - } finally { - if (!success) { - pooledObject.returnObject(); - } - } - return pooledObject; - } - - private DatagramSocket createSocket(int receiveBufferSize) { - try { - DatagramSocket socket = new DatagramSocket(null); - socket.setReceiveBufferSize(receiveBufferSize); - if (logger.isWarnEnabled()) { - final int checkReceiveBufferSize = socket.getReceiveBufferSize(); - if (receiveBufferSize != checkReceiveBufferSize) { - logger.warn("DatagramSocket.setReceiveBufferSize() error. {}!={}", receiveBufferSize, checkReceiveBufferSize); - } - } - socket.setSoTimeout(1000 * 5); - return socket; - } catch (SocketException ex) { - throw new RuntimeException("Socket create Fail. Caused:" + ex.getMessage(), ex); - } - } - - private void bindSocket(DatagramSocket socket, String bindAddress, int port) { - if (socket == null) { - throw new NullPointerException("socket must not be null"); - } - try { - logger.info("DatagramSocket.bind() {}/{}", bindAddress, port); - socket.bind(new InetSocketAddress(bindAddress, port)); - } catch (SocketException ex) { - throw new IllegalStateException("Socket bind Fail. port:" + port + " Caused:" + ex.getMessage(), ex); - } - } - - private int getPacketPoolSize(int workerThreadSize, int workerThreadQueueSize) { - return workerThreadSize + workerThreadQueueSize + ioThreadSize; - } - - @PostConstruct - @Override - public void start() { - logger.info("{} start.", receiverName); - afterPropertiesSet(); - final DatagramSocket socket = this.socket; - if (socket == null) { - throw new IllegalStateException("socket is null."); - } - bindSocket(socket, bindAddress, port); - - logger.info("UDP Packet reader:{} started.", ioThreadSize); - for (int i = 0; i < ioThreadSize; i++) { - io.execute(new Runnable() { - @Override - public void run() { - receive(socket); - } - }); - } - - } - - @PreDestroy - @Override - public void shutdown() { - logger.info("{} shutdown.", this.receiverName); - state.set(false); - // is it okay to just close here? - if (socket != null) { - socket.close(); - } - shutdownExecutor(io, "IoExecutor"); - shutdownExecutor(worker, "WorkerExecutor"); - } - - private void shutdownExecutor(ExecutorService executor, String executorName) { - logger.info("{} shutdown.", executorName); - executor.shutdown(); - try { - executor.awaitTermination(1000 * 10, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - logger.info("{}.shutdown() Interrupted", executorName, e); - Thread.currentThread().interrupt(); - } - } -} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/UDPReceiverTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/UDPReceiverTest.java deleted file mode 100644 index 334b82f14506..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/receiver/udp/UDPReceiverTest.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.receiver.udp; - -import com.navercorp.pinpoint.collector.receiver.DataReceiver; -import com.navercorp.pinpoint.collector.receiver.DispatchWorker; -import com.navercorp.pinpoint.collector.receiver.DispatchWorkerOption; -import com.navercorp.pinpoint.collector.util.ObjectPool; -import org.apache.hadoop.hbase.shaded.org.apache.commons.io.IOUtils; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.util.SocketUtils; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; - -/** - * @author emeroad - */ -public class UDPReceiverTest { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private static final String ADDRESS = "127.0.0.1"; - private static final int PORT = SocketUtils.findAvailableUdpPort(10999); - - @Test - public void startStop() { - DataReceiver receiver = null; - - InetSocketAddress bindAddress = new InetSocketAddress(ADDRESS, PORT); - - DispatchWorker mockWorker = mock(DispatchWorker.class); - try { - receiver = new UDPReceiver("test", new PacketHandlerFactory() { - @Override - public PacketHandler createPacketHandler() { - return null; - } - }, mockWorker, 8, bindAddress); - } catch (Exception e) { - logger.debug(e.getMessage(), e); - Assert.fail(e.getMessage()); - } finally { - if (receiver!= null) { - receiver.shutdown(); - } - } - } - - @Test - public void hostNullCheck() { - InetSocketAddress address = new InetSocketAddress((InetAddress) null, PORT); - logger.debug(address.toString()); - } - - @Test - public void socketBufferSize() throws SocketException { - DatagramSocket datagramSocket = new DatagramSocket(); - int receiveBufferSize = datagramSocket.getReceiveBufferSize(); - logger.debug("{}", receiveBufferSize); - - datagramSocket.setReceiveBufferSize(64*1024*10); - logger.debug("{}", datagramSocket.getReceiveBufferSize()); - - datagramSocket.close(); - } - - @Test - public void sendSocketBufferSize() throws IOException { - DatagramPacket datagramPacket = new DatagramPacket(new byte[0], 0, 0); - - DatagramSocket datagramSocket = new DatagramSocket(); - datagramSocket.connect(new InetSocketAddress(ADDRESS, PORT)); - - datagramSocket.send(datagramPacket); - datagramSocket.close(); - } - - private final AtomicInteger zeroPacketCounter = new AtomicInteger(); - void interceptValidatePacket(DatagramPacket packet) { - if (packet.getLength() == 0) { - zeroPacketCounter.incrementAndGet(); - } - } - - @Test - public void datagramPacket_length_zero() { - DataReceiver receiver = null; - DatagramSocket datagramSocket = null; - - CountDownLatch latch = new CountDownLatch(1); - DispatchWorker mockWorker = mockDispatchWorker(latch); - mockWorker.start(); - PacketHandlerFactory packetHandlerFactory = mock(PacketHandlerFactory.class); - - try { - InetSocketAddress bindAddress = new InetSocketAddress(ADDRESS, PORT); - - receiver = new UDPReceiver("test", packetHandlerFactory, mockWorker, 8, bindAddress) { - @Override - boolean validatePacket(DatagramPacket packet) { - interceptValidatePacket(packet); - return super.validatePacket(packet); - } - }; - receiver.start(); - - datagramSocket = new DatagramSocket(); - datagramSocket.connect(new InetSocketAddress(ADDRESS, PORT)); - - datagramSocket.send(new DatagramPacket(new byte[0], 0)); - datagramSocket.send(new DatagramPacket(new byte[1], 1)); - - Assert.assertTrue(latch.await(30000, TimeUnit.MILLISECONDS)); - Assert.assertEquals(zeroPacketCounter.get(), 1); - Mockito.verify(mockWorker).execute(any(Runnable.class)); - } catch (Exception e) { - logger.debug(e.getMessage(), e); - Assert.fail(e.getMessage()); - } finally { - if (receiver != null) { - receiver.shutdown(); - } - IOUtils.closeQuietly(datagramSocket); - - if (mockWorker != null) { - mockWorker.shutdown(); - } - } - } - - private DispatchWorker mockDispatchWorker(CountDownLatch latch) { - DispatchWorkerOption option = new DispatchWorkerOption("test", 1, 10); - DispatchWorker mockWorker = new DispatchWorker(option) { - @Override - public void execute(Runnable runnable) { - logger.info("execute:{}", runnable.getClass()); - latch.countDown(); - } - }; - return Mockito.spy(mockWorker); - } - - -} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleHandlerTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleHandlerTest.java deleted file mode 100644 index 90e5fabd66f9..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/rpc/handler/AgentLifeCycleHandlerTest.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2015 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.rpc.handler; - -import com.navercorp.pinpoint.collector.dao.AgentLifeCycleDao; -import com.navercorp.pinpoint.collector.util.ManagedAgentLifeCycle; -import com.navercorp.pinpoint.common.server.bo.AgentLifeCycleBo; -import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; -import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Spy; -import org.mockito.junit.MockitoJUnitRunner; - -import java.math.BigInteger; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Executor; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -/** - * @author HyunGil Jeong - */ -@RunWith(MockitoJUnitRunner.class) -public class AgentLifeCycleHandlerTest { - // FIX guava 19.0.0 update error. MoreExecutors.sameThreadExecutor(); change final class - @Spy - private Executor executor = new DirectExecutor(); - - @Mock - private PinpointServer pinpointServer; - - @Mock - private AgentLifeCycleDao agentLifeCycleDao; - - @InjectMocks - private AgentLifeCycleHandler agentLifeCycleHandler = new AgentLifeCycleHandler(); - - private static final String TEST_AGENT_ID = "TEST_AGENT"; - private static final long TEST_START_TIMESTAMP = System.currentTimeMillis(); - private static final long TEST_EVENT_TIMESTAMP = TEST_START_TIMESTAMP + 10; - private static final int TEST_SOCKET_ID = 999; - private static final Map TEST_CHANNEL_PROPERTIES = createTestChannelProperties(); - - @Before - public void setUp() throws Exception { - when(this.pinpointServer.getChannelProperties()).thenReturn(TEST_CHANNEL_PROPERTIES); - } - - @Test - public void runningStateShouldBeInserted() { - runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.RUNNING); - } - - @Test - public void closedByClientStateShouldBeInserted() { - runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.CLOSED_BY_CLIENT); - } - - @Test - public void unexpectedCloseByClientStateShouldBeInserted() { - runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_CLIENT); - } - - @Test - public void closedByServerStateShouldBeInserted() { - runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.CLOSED_BY_SERVER); - } - - @Test - public void unexpectedCloseByServerStateShouldBeInserted() { - runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle.UNEXPECTED_CLOSE_BY_SERVER); - } - - @Test - public void testValidTimestampCreation() { - // socketId = 1, eventCounter = 1 -> timestamp = 0x100000001 - int givenSocketId = 1; - int givenEventCounter = 1; - long expectedTimestamp = new BigInteger("100000001", 16).longValue(); - long timestamp = this.agentLifeCycleHandler.createEventIdentifier(givenSocketId, givenEventCounter); - assertEquals(expectedTimestamp, timestamp); - // socketId = 0, eventCounter = 0 -> timestamp = 0x0 - givenSocketId = 0; - givenEventCounter = 0; - expectedTimestamp = new BigInteger("0000000000000000", 16).longValue(); - timestamp = this.agentLifeCycleHandler.createEventIdentifier(givenSocketId, givenEventCounter); - assertEquals(expectedTimestamp, timestamp); - // socketId = Integer.MAX_VALUE, eventCounter = 0 -> timestamp = 0x7fffffff00000000 - givenSocketId = Integer.MAX_VALUE; - givenEventCounter = 0; - expectedTimestamp = new BigInteger("7fffffff00000000", 16).longValue(); - timestamp = this.agentLifeCycleHandler.createEventIdentifier(givenSocketId, givenEventCounter); - assertEquals(expectedTimestamp, timestamp); - // socketId = Integer.MAX_VALUE, eventCounter = Integer.MAX_VALUE -> timestamp = 0x7fffffff7fffffff - givenSocketId = Integer.MAX_VALUE; - givenEventCounter = Integer.MAX_VALUE; - expectedTimestamp = new BigInteger("7fffffff7fffffff", 16).longValue(); - timestamp = this.agentLifeCycleHandler.createEventIdentifier(givenSocketId, givenEventCounter); - assertEquals(expectedTimestamp, timestamp); - } - - @Test - public void testTimestampOrdering() { - // 0x7fffffff < 0x100000000 - long smallerTimestamp = this.agentLifeCycleHandler.createEventIdentifier(0, Integer.MAX_VALUE); - long largerTimestamp = this.agentLifeCycleHandler.createEventIdentifier(1, 0); - assertTrue(smallerTimestamp < largerTimestamp); - } - - @Test - public void testInvalidTimestampCreation() { - final int negativeSocketId = new BigInteger("ffffffff", 16).intValue(); - final int eventCounter = 0; - try { - this.agentLifeCycleHandler.createEventIdentifier(negativeSocketId, eventCounter); - fail(); - } catch (IllegalArgumentException expected) { - // expected - } - final int socketId = 0; - final int negativeEventCounter = new BigInteger("ffffffff", 16).intValue(); - try { - this.agentLifeCycleHandler.createEventIdentifier(socketId, negativeEventCounter); - fail(); - } catch (IllegalArgumentException expected) { - // expected - } - } - - private static Map createTestChannelProperties() { - return createChannelProperties(TEST_AGENT_ID, TEST_START_TIMESTAMP, TEST_SOCKET_ID); - } - - private static Map createChannelProperties(String agentId, long startTimestamp, int socketId) { - Map map = new HashMap<>(); - map.put(HandshakePropertyType.AGENT_ID.getName(), agentId); - map.put(HandshakePropertyType.START_TIMESTAMP.getName(), startTimestamp); - map.put(AgentLifeCycleHandler.SOCKET_ID_KEY, socketId); - return map; - } - - private void runAndVerifyAgentLifeCycle(ManagedAgentLifeCycle managedAgentLifeCycle) { - // given - final AgentLifeCycleState expectedLifeCycleState = managedAgentLifeCycle.getMappedState(); - final int expectedEventCounter = managedAgentLifeCycle.getEventCounter(); - final long expectedEventIdentifier = this.agentLifeCycleHandler.createEventIdentifier(TEST_SOCKET_ID, expectedEventCounter); - ArgumentCaptor argCaptor = ArgumentCaptor.forClass(AgentLifeCycleBo.class); - - // when - this.agentLifeCycleHandler.handleLifeCycleEvent(this.pinpointServer, TEST_EVENT_TIMESTAMP, expectedLifeCycleState, expectedEventCounter); - verify(this.agentLifeCycleDao, times(1)).insert(argCaptor.capture()); - - // then - AgentLifeCycleBo actualAgentLifeCycleBo = argCaptor.getValue(); - assertEquals(AgentLifeCycleBo.CURRENT_VERSION, actualAgentLifeCycleBo.getVersion()); - assertEquals(TEST_AGENT_ID, actualAgentLifeCycleBo.getAgentId()); - assertEquals(TEST_START_TIMESTAMP, actualAgentLifeCycleBo.getStartTimestamp()); - assertEquals(TEST_EVENT_TIMESTAMP, actualAgentLifeCycleBo.getEventTimestamp()); - assertEquals(expectedLifeCycleState, actualAgentLifeCycleBo.getAgentLifeCycleState()); - assertEquals(expectedEventIdentifier, actualAgentLifeCycleBo.getEventIdentifier()); - } - -} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/rpc/handler/DirectExecutor.java b/collector/src/test/java/com/navercorp/pinpoint/collector/rpc/handler/DirectExecutor.java deleted file mode 100644 index fb74e2ee0b91..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/rpc/handler/DirectExecutor.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.navercorp.pinpoint.collector.rpc.handler; - -import java.util.concurrent.Executor; - -/** - * @author Woonduk Kang(emeroad) - */ -public class DirectExecutor implements Executor { - @Override - public void execute(Runnable command) { - command.run(); - } -} diff --git a/collector/src/test/java/com/navercorp/pinpoint/collector/service/AgentEventServiceTest.java b/collector/src/test/java/com/navercorp/pinpoint/collector/service/AgentEventServiceTest.java deleted file mode 100644 index b69c826fdb83..000000000000 --- a/collector/src/test/java/com/navercorp/pinpoint/collector/service/AgentEventServiceTest.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.collector.service; - -import com.navercorp.pinpoint.collector.cluster.route.ResponseEvent; -import com.navercorp.pinpoint.collector.dao.AgentEventDao; -import com.navercorp.pinpoint.collector.rpc.handler.DirectExecutor; -import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; -import com.navercorp.pinpoint.common.server.util.AgentEventMessageSerializer; -import com.navercorp.pinpoint.common.server.util.AgentEventType; -import com.navercorp.pinpoint.common.util.BytesUtils; -import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.thrift.dto.command.TCommandEcho; -import com.navercorp.pinpoint.thrift.dto.command.TCommandThreadDumpResponse; -import com.navercorp.pinpoint.thrift.dto.command.TCommandTransfer; -import com.navercorp.pinpoint.thrift.dto.command.TCommandTransferResponse; -import com.navercorp.pinpoint.thrift.dto.command.TRouteResult; -import com.navercorp.pinpoint.thrift.io.DeserializerFactory; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; -import org.apache.thrift.TBase; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Spy; -import org.mockito.junit.MockitoJUnitRunner; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Executor; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -/** - * @author HyunGil Jeong - */ -@RunWith(MockitoJUnitRunner.class) -public class AgentEventServiceTest { - // FIX guava 19.0.0 update error. MoreExecutors.sameThreadExecutor(); change final class - @Spy - private Executor executor = new DirectExecutor(); - - @Mock - private PinpointServer pinpointServer; - - @Mock - private AgentEventDao agentEventDao; - - @Mock - private AgentEventMessageSerializer agentEventMessageSerializer; - - @Mock - private DeserializerFactory deserializerFactory; - - @InjectMocks - private AgentEventService agentEventService = new AgentEventService(); - - private static final String TEST_AGENT_ID = "TEST_AGENT"; - private static final long TEST_START_TIMESTAMP = System.currentTimeMillis(); - private static final long TEST_EVENT_TIMESTAMP = TEST_START_TIMESTAMP + 10; - private static final Map TEST_CHANNEL_PROPERTIES = createTestChannelProperties(); - - @Before - public void setUp() { - when(this.pinpointServer.getChannelProperties()).thenReturn(TEST_CHANNEL_PROPERTIES); - } - - @Test - public void handler_should_handle_events_with_empty_message_body() throws Exception { - // given - final AgentEventType expectedEventType = AgentEventType.AGENT_CONNECTED; - ArgumentCaptor argCaptor = ArgumentCaptor.forClass(AgentEventBo.class); - // when - this.agentEventService.handleEvent(this.pinpointServer, TEST_EVENT_TIMESTAMP, expectedEventType); - verify(this.agentEventDao, times(1)).insert(argCaptor.capture()); - // then - AgentEventBo actualAgentEventBo = argCaptor.getValue(); - assertEquals(TEST_AGENT_ID, actualAgentEventBo.getAgentId()); - assertEquals(TEST_START_TIMESTAMP, actualAgentEventBo.getStartTimestamp()); - assertEquals(TEST_EVENT_TIMESTAMP, actualAgentEventBo.getEventTimestamp()); - assertEquals(expectedEventType, actualAgentEventBo.getEventType()); - assertNull(actualAgentEventBo.getEventBody()); - } - - @Test - public void handler_should_handle_serialization_of_messages_appropriately() throws Exception { - // given - final AgentEventType expectedEventType = AgentEventType.OTHER; - final String expectedMessageBody = "test event message"; - final byte[] expectedMessageBodyBytes = BytesUtils.toBytes(expectedMessageBody); - ArgumentCaptor argCaptor = ArgumentCaptor.forClass(AgentEventBo.class); - when(this.agentEventMessageSerializer.serialize(expectedEventType, expectedMessageBody)).thenReturn( - expectedMessageBodyBytes); - // when - this.agentEventService.handleEvent(this.pinpointServer, TEST_EVENT_TIMESTAMP, expectedEventType, - expectedMessageBody); - verify(this.agentEventDao, times(1)).insert(argCaptor.capture()); - // then - AgentEventBo actualAgentEventBo = argCaptor.getValue(); - assertEquals(TEST_AGENT_ID, actualAgentEventBo.getAgentId()); - assertEquals(TEST_START_TIMESTAMP, actualAgentEventBo.getStartTimestamp()); - assertEquals(TEST_EVENT_TIMESTAMP, actualAgentEventBo.getEventTimestamp()); - assertEquals(expectedEventType, actualAgentEventBo.getEventType()); - assertEquals(expectedMessageBodyBytes, actualAgentEventBo.getEventBody()); - } - - @Test - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void handler_should_handle_serialization_of_request_events() throws Exception { - // given - final AgentEventType expectedEventType = AgentEventType.USER_THREAD_DUMP; - final TCommandThreadDumpResponse expectedThreadDumpResponse = new TCommandThreadDumpResponse(); - final byte[] expectedThreadDumpResponseBody = new byte[0]; - - final TCommandTransfer tCommandTransfer = new TCommandTransfer(); - tCommandTransfer.setAgentId(TEST_AGENT_ID); - tCommandTransfer.setStartTime(TEST_START_TIMESTAMP); - - final TCommandTransferResponse tCommandTransferResponse = new TCommandTransferResponse(); - tCommandTransferResponse.setRouteResult(TRouteResult.OK); - tCommandTransferResponse.setPayload(expectedThreadDumpResponseBody); - - final ResponseEvent responseEvent = new ResponseEvent(tCommandTransfer, null, 0, tCommandTransferResponse); - - ArgumentCaptor argCaptor = ArgumentCaptor.forClass(AgentEventBo.class); - HeaderTBaseDeserializer deserializer = mock(HeaderTBaseDeserializer.class); - when(this.deserializerFactory.createDeserializer()).thenReturn(deserializer); - when(deserializer.deserialize(expectedThreadDumpResponseBody)).thenReturn((TBase)expectedThreadDumpResponse); - // when - this.agentEventService.handleResponseEvent(responseEvent, TEST_EVENT_TIMESTAMP); - // then - verify(this.agentEventDao, atLeast(1)).insert(argCaptor.capture()); - AgentEventBo actualAgentEventBo = argCaptor.getValue(); - assertEquals(TEST_AGENT_ID, actualAgentEventBo.getAgentId()); - assertEquals(TEST_START_TIMESTAMP, actualAgentEventBo.getStartTimestamp()); - assertEquals(TEST_EVENT_TIMESTAMP, actualAgentEventBo.getEventTimestamp()); - assertEquals(expectedEventType, actualAgentEventBo.getEventType()); - assertArrayEquals(expectedThreadDumpResponseBody, actualAgentEventBo.getEventBody()); - } - - @Test - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void handler_should_ignore_request_events_with_unsupported_message_types() throws Exception { - // given - final TCommandEcho mismatchingResponse = new TCommandEcho(); - final byte[] mismatchingResponseBody = new byte[0]; - - final TCommandTransfer tCommandTransfer = new TCommandTransfer(); - tCommandTransfer.setAgentId(TEST_AGENT_ID); - tCommandTransfer.setStartTime(TEST_START_TIMESTAMP); - - final TCommandTransferResponse tCommandTransferResponse = new TCommandTransferResponse(); - tCommandTransferResponse.setRouteResult(TRouteResult.OK); - tCommandTransferResponse.setPayload(mismatchingResponseBody); - - final ResponseEvent responseEvent = new ResponseEvent(tCommandTransfer, null, 0, tCommandTransferResponse); - - ArgumentCaptor argCaptor = ArgumentCaptor.forClass(AgentEventBo.class); - HeaderTBaseDeserializer deserializer = mock(HeaderTBaseDeserializer.class); - when(this.deserializerFactory.createDeserializer()).thenReturn(deserializer); - when(deserializer.deserialize(mismatchingResponseBody)).thenReturn((TBase)mismatchingResponse); - // when - this.agentEventService.handleResponseEvent(responseEvent, TEST_EVENT_TIMESTAMP); - // then - verify(this.agentEventDao, never()).insert(argCaptor.capture()); - } - - private static Map createTestChannelProperties() { - return createChannelProperties(TEST_AGENT_ID, TEST_START_TIMESTAMP); - } - - private static Map createChannelProperties(String agentId, long startTimestamp) { - Map map = new HashMap<>(); - map.put(HandshakePropertyType.AGENT_ID.getName(), agentId); - map.put(HandshakePropertyType.START_TIMESTAMP.getName(), startTimestamp); - return map; - } - -} diff --git a/collector/start-collector.sh b/collector/start-collector.sh deleted file mode 100644 index 05d40b2f2479..000000000000 --- a/collector/start-collector.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -set -e -set -x - -CLUSTER_ENABLE=${CLUSTER_ENABLE:-false} -CLUSTER_ZOOKEEPER_ADDRESS=${CLUSTER_ZOOKEEPER_ADDRESS:-localhost} - -COLLECTOR_TCP_PORT=${COLLECTOR_TCP_PORT:-9994} -COLLECTOR_UDP_STAT_LISTEN_PORT=${COLLECTOR_UDP_STAT_LISTEN_PORT:-9995} -COLLECTOR_UDP_SPAN_LISTEN_PORT=${COLLECTOR_UDP_SPAN_LISTEN_PORT:-9996} - -HBASE_HOST=${HBASE_HOST:-localhost} -HBASE_PORT=${HBASE_PORT:-2181} - -DISABLE_DEBUG=${DISABLE_DEBUG:-true} - -cp /assets/pinpoint-collector.properties /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-collector.properties -cp /assets/hbase.properties /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/hbase.properties - -sed -i "s/cluster.enable=true/cluster.enable=${CLUSTER_ENABLE}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-collector.properties -sed -i "s/cluster.zookeeper.address=localhost/cluster.zookeeper.address=${CLUSTER_ZOOKEEPER_ADDRESS}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-collector.properties - -sed -i "s/collector.tcpListenPort=9994/collector.tcpListenPort=${COLLECTOR_TCP_PORT}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-collector.properties -sed -i "s/collector.udpStatListenPort=9995/collector.udpStatListenPort=${COLLECTOR_UDP_STAT_LISTEN_PORT}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-collector.properties -sed -i "s/collector.udpSpanListenPort=9996/collector.udpSpanListenPort=${COLLECTOR_UDP_SPAN_LISTEN_PORT}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-collector.properties - -sed -i "s/hbase.client.host=localhost/hbase.client.host=${HBASE_HOST}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/hbase.properties -sed -i "s/hbase.client.port=2181/hbase.client.port=${HBASE_PORT}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/hbase.properties - -if [ "$DISABLE_DEBUG" == "true" ]; then - sed -i 's/level value="DEBUG"/level value="INFO"/' /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/log4j.xml -fi - -exec /usr/local/tomcat/bin/catalina.sh run \ No newline at end of file diff --git a/commons-hbase/clover.license b/commons-hbase/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/commons-hbase/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-commons-hbase @@ -18,20 +18,13 @@ - + + com.navercorp.pinpoint + pinpoint-annotations + com.navercorp.pinpoint pinpoint-commons - - - org.slf4j - slf4j-api - - - com.navercorp.pinpoint - pinpoint-thrift - - diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/AdminCallback.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/AdminCallback.java new file mode 100644 index 000000000000..2471036675b5 --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/AdminCallback.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase; + +import org.apache.hadoop.hbase.client.Admin; + +/** + * Callback interface for Hbase admin operations to be used with {@link HBaseAdminTemplate}'s methods. + * Similar to {@link TableCallback}. + * + * @author HyunGil Jeong + * @see TableCallback + */ +public interface AdminCallback { + + T doInAdmin(Admin admin) throws Throwable; +} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/AdminFactory.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/AdminFactory.java new file mode 100644 index 000000000000..a9785ad374b8 --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/AdminFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase; + +import org.apache.hadoop.hbase.client.Admin; + +/** + * @author HyunGil Jeong + */ +public interface AdminFactory { + + Admin getAdmin(); + + void releaseAdmin(Admin admin); + +} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/ConnectionFactoryBean.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/ConnectionFactoryBean.java new file mode 100644 index 000000000000..8f922055b787 --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/ConnectionFactoryBean.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.FactoryBean; + +import java.io.IOException; +import java.util.Objects; +import java.util.concurrent.ExecutorService; + +/** + * @author HyunGil Jeong + */ +public class ConnectionFactoryBean implements FactoryBean, DisposableBean { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final Connection connection; + + public ConnectionFactoryBean(Configuration configuration) { + Objects.requireNonNull(configuration, " must not be null"); + try { + connection = ConnectionFactory.createConnection(configuration); + } catch (IOException e) { + throw new HbaseSystemException(e); + } + } + + public ConnectionFactoryBean(Configuration configuration, ExecutorService executorService) { + Objects.requireNonNull(configuration, "configuration must not be null"); + Objects.requireNonNull(executorService, "executorService must not be null"); + try { + connection = ConnectionFactory.createConnection(configuration, executorService); + } catch (IOException e) { + throw new HbaseSystemException(e); + } + } + + @Override + public Connection getObject() throws Exception { + return connection; + } + + @Override + public Class getObjectType() { + if (connection == null) { + return Connection.class; + } + return connection.getClass(); + } + + @Override + public boolean isSingleton() { + return true; + } + + @Override + public void destroy() throws Exception { + logger.info("Hbase Connection destroy()"); + if (connection != null) { + try { + connection.close(); + } catch (IOException e) { + logger.warn("Hbase Connection.close() error: " + e.getMessage(), e); + } + } + } +} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseAdminTemplate.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseAdminTemplate.java index 1294c329cc54..c7db095ef907 100644 --- a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseAdminTemplate.java +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseAdminTemplate.java @@ -16,80 +16,73 @@ package com.navercorp.pinpoint.common.hbase; -import java.io.IOException; +import java.util.Objects; -import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Admin; -import org.apache.hadoop.hbase.client.Connection; -import org.apache.hadoop.hbase.client.ConnectionFactory; /** * @author emeroad + * @author HyunGil Jeong */ public class HBaseAdminTemplate { - private final Admin admin; - private final Connection connection; + private final AdminFactory adminFactory; - public HBaseAdminTemplate(Configuration configuration) { - try { - connection = ConnectionFactory.createConnection(configuration); - admin = connection.getAdmin(); - } catch (Exception e) { - throw new HbaseSystemException(e); - } + public HBaseAdminTemplate(AdminFactory adminFactory) { + this.adminFactory = Objects.requireNonNull(adminFactory, "adminFactory must not be null"); } - public boolean createTableIfNotExist(HTableDescriptor htd) { - try { - if (!admin.tableExists(htd.getTableName())) { - this.admin.createTable(htd); + public boolean createTableIfNotExists(HTableDescriptor htd) { + return execute(admin -> { + TableName tableName = htd.getTableName(); + if (!admin.tableExists(tableName)) { + admin.createTable(htd); return true; } return false; - } catch (IOException e) { - throw new HbaseSystemException(e); - } + }); } public boolean tableExists(TableName tableName) { - try { - return admin.tableExists(tableName); - } catch (IOException e) { - throw new HbaseSystemException(e); - } + return execute(admin -> admin.tableExists(tableName)); } - public boolean dropTableIfExist(TableName tableName) { - try { + public boolean dropTableIfExists(TableName tableName) { + return execute(admin -> { if (admin.tableExists(tableName)) { - this.admin.disableTable(tableName); - this.admin.deleteTable(tableName); + admin.disableTable(tableName); + admin.deleteTable(tableName); return true; } return false; - } catch (IOException e) { - throw new HbaseSystemException(e); - } + }); } public void dropTable(TableName tableName) { - try { - this.admin.disableTable(tableName); - this.admin.deleteTable(tableName); - } catch (IOException e) { - throw new HbaseSystemException(e); - } + execute((AdminCallback) admin -> { + admin.disableTable(tableName); + admin.deleteTable(tableName); + return null; + }); } - public void close() { + public final T execute(AdminCallback action) { + Objects.requireNonNull(action, "action must not be null"); + Admin admin = adminFactory.getAdmin(); try { - this.admin.close(); - this.connection.close(); - } catch (IOException e) { - throw new HbaseSystemException(e); + return action.doInAdmin(admin); + } catch (Throwable e) { + if (e instanceof Error) { + throw (Error) e; + } + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } + throw new HbaseSystemException((Exception) e); + } finally { + adminFactory.releaseAdmin(admin); } } } diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseAsyncOperationFactory.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseAsyncOperationFactory.java index f107b33f4ea5..27ee1b817277 100644 --- a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseAsyncOperationFactory.java +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseAsyncOperationFactory.java @@ -19,6 +19,7 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.HTableMultiplexer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,11 +38,11 @@ public class HBaseAsyncOperationFactory { public static final String ASYNC_IN_QUEUE_SIZE = "hbase.client.async.in.queuesize"; public static final int DEFAULT_ASYNC_IN_QUEUE_SIZE = 10000; - public static final String ASYNC_PERIODIC_FLUSH_TIME = "hbase.tablemultiplexer.flush.period.ms"; + public static final String ASYNC_PERIODIC_FLUSH_TIME = HTableMultiplexer.TABLE_MULTIPLEXER_FLUSH_PERIOD_MS; public static final int DEFAULT_ASYNC_PERIODIC_FLUSH_TIME = 100; - public static final String ASYNC_RETRY_COUNT = "hbase.client.max.retries.in.queue"; - public static final int DEFAULT_ASYNC_RETRY_COUNT = 10; + public static final String ASYNC_MAX_RETRIES_IN_QUEUE = HTableMultiplexer.TABLE_MULTIPLEXER_MAX_RETRIES_IN_QUEUE; + public static final int DEFAULT_ASYNC_RETRY_COUNT = 10000; public static HBaseAsyncOperation create(Configuration configuration) throws IOException { boolean enableAsyncMethod = configuration.getBoolean(ENABLE_ASYNC_METHOD, DEFAULT_ENABLE_ASYNC_METHOD); @@ -55,8 +56,8 @@ public static HBaseAsyncOperation create(Configuration configuration) throws IOE configuration.setInt(ASYNC_PERIODIC_FLUSH_TIME, DEFAULT_ASYNC_PERIODIC_FLUSH_TIME); } - if (configuration.get(ASYNC_RETRY_COUNT, null) == null) { - configuration.setInt(ASYNC_RETRY_COUNT, DEFAULT_ASYNC_RETRY_COUNT); + if (configuration.get(ASYNC_MAX_RETRIES_IN_QUEUE, null) == null) { + configuration.setInt(ASYNC_MAX_RETRIES_IN_QUEUE, DEFAULT_ASYNC_RETRY_COUNT); } return new HBaseAsyncTemplate(configuration, queueSize); @@ -74,8 +75,8 @@ public static HBaseAsyncOperation create(Connection connection, Configuration co configuration.setInt(ASYNC_PERIODIC_FLUSH_TIME, DEFAULT_ASYNC_PERIODIC_FLUSH_TIME); } - if (configuration.get(ASYNC_RETRY_COUNT, null) == null) { - configuration.setInt(ASYNC_RETRY_COUNT, DEFAULT_ASYNC_RETRY_COUNT); + if (configuration.get(ASYNC_MAX_RETRIES_IN_QUEUE, null) == null) { + configuration.setInt(ASYNC_MAX_RETRIES_IN_QUEUE, DEFAULT_ASYNC_RETRY_COUNT); } return new HBaseAsyncTemplate(connection, configuration, queueSize); diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseTables.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseTables.java index 4946d474c076..aecdcbf8822a 100644 --- a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseTables.java +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HBaseTables.java @@ -32,59 +32,89 @@ public final class HBaseTables { // Time delta (in milliseconds) we can store in each row of AgentStatV2 public static final int AGENT_STAT_TIMESPAN_MS = 5 * 60 * 1000; - public static final TableName APPLICATION_TRACE_INDEX = TableName.valueOf("ApplicationTraceIndex"); + + public static final String APPLICATION_TRACE_INDEX_STR = "ApplicationTraceIndex"; + @Deprecated + public static final TableName APPLICATION_TRACE_INDEX = TableName.valueOf(APPLICATION_TRACE_INDEX_STR); public static final byte[] APPLICATION_TRACE_INDEX_CF_TRACE = Bytes.toBytes("I"); // applicationIndex public static final int APPLICATION_TRACE_INDEX_ROW_DISTRIBUTE_SIZE = 1; // applicationIndex hash size - public static final TableName AGENT_STAT_VER2 = TableName.valueOf("AgentStatV2"); - + public static final String AGENT_STAT_VER2_STR = "AgentStatV2"; + @Deprecated + public static final TableName AGENT_STAT_VER2 = TableName.valueOf(AGENT_STAT_VER2_STR); public static final byte[] AGENT_STAT_CF_STATISTICS = Bytes.toBytes("S"); // agent statistics column family - public static final TableName TRACE_V2 = TableName.valueOf("TraceV2"); + public static final String TRACE_V2_STR = "TraceV2"; + @Deprecated + public static final TableName TRACE_V2 = TableName.valueOf(TRACE_V2_STR); public static final byte[] TRACE_V2_CF_SPAN = Bytes.toBytes("S"); //Span - public static final TableName APPLICATION_INDEX = TableName.valueOf("ApplicationIndex"); + public static final String APPLICATION_INDEX_STR = "ApplicationIndex"; + @Deprecated + public static final TableName APPLICATION_INDEX = TableName.valueOf(APPLICATION_INDEX_STR); public static final byte[] APPLICATION_INDEX_CF_AGENTS = Bytes.toBytes("Agents"); - public static final TableName AGENTINFO = TableName.valueOf("AgentInfo"); + public static final String AGENTINFO_STR = "AgentInfo"; + @Deprecated + public static final TableName AGENTINFO = TableName.valueOf(AGENTINFO_STR); public static final byte[] AGENTINFO_CF_INFO = Bytes.toBytes("Info"); public static final byte[] AGENTINFO_CF_INFO_IDENTIFIER = Bytes.toBytes("i"); public static final byte[] AGENTINFO_CF_INFO_SERVER_META_DATA = Bytes.toBytes("m"); public static final byte[] AGENTINFO_CF_INFO_JVM = Bytes.toBytes("j"); - public static final TableName AGENT_LIFECYCLE = TableName.valueOf("AgentLifeCycle"); + public static final String AGENT_LIFECYCLE_STR = "AgentLifeCycle"; + @Deprecated + public static final TableName AGENT_LIFECYCLE = TableName.valueOf(AGENT_LIFECYCLE_STR); public static final byte[] AGENT_LIFECYCLE_CF_STATUS = Bytes.toBytes("S"); // agent lifecycle column family public static final byte[] AGENT_LIFECYCLE_CF_STATUS_QUALI_STATES = Bytes.toBytes("states"); // qualifier for agent lifecycle states - public static final TableName AGENT_EVENT = TableName.valueOf("AgentEvent"); + public static final String AGENT_EVENT_STR = "AgentEvent"; + @Deprecated + public static final TableName AGENT_EVENT = TableName.valueOf(AGENT_EVENT_STR); public static final byte[] AGENT_EVENT_CF_EVENTS = Bytes.toBytes("E"); // agent events column family - public static final TableName SQL_METADATA_VER2 = TableName.valueOf("SqlMetaData_Ver2"); + public static final String SQL_METADATA_VER2_STR = "SqlMetaData_Ver2"; + @Deprecated + public static final TableName SQL_METADATA_VER2 = TableName.valueOf(SQL_METADATA_VER2_STR); public static final byte[] SQL_METADATA_VER2_CF_SQL = Bytes.toBytes("Sql"); public static final byte[] SQL_METADATA_VER2_CF_SQL_QUALI_SQLSTATEMENT = Bytes.toBytes("P_sql_statement"); - public static final TableName STRING_METADATA = TableName.valueOf("StringMetaData"); + public static final String STRING_METADATA_STR = "StringMetaData"; + @Deprecated + public static final TableName STRING_METADATA = TableName.valueOf(STRING_METADATA_STR); public static final byte[] STRING_METADATA_CF_STR = Bytes.toBytes("Str"); public static final byte[] STRING_METADATA_CF_STR_QUALI_STRING = Bytes.toBytes("P_string"); - public static final TableName API_METADATA = TableName.valueOf("ApiMetaData"); + public static final String API_METADATA_STR = "ApiMetaData"; + @Deprecated + public static final TableName API_METADATA = TableName.valueOf(API_METADATA_STR); public static final byte[] API_METADATA_CF_API = Bytes.toBytes("Api"); public static final byte[] API_METADATA_CF_API_QUALI_SIGNATURE = Bytes.toBytes("P_api_signature"); - public static final TableName MAP_STATISTICS_CALLER_VER2 = TableName.valueOf("ApplicationMapStatisticsCaller_Ver2"); + public static final String MAP_STATISTICS_CALLER_VER2_STR = "ApplicationMapStatisticsCaller_Ver2"; + @Deprecated + public static final TableName MAP_STATISTICS_CALLER_VER2 = TableName.valueOf(MAP_STATISTICS_CALLER_VER2_STR); public static final byte[] MAP_STATISTICS_CALLER_VER2_CF_COUNTER = Bytes.toBytes("C"); - public static final TableName MAP_STATISTICS_CALLEE_VER2 = TableName.valueOf("ApplicationMapStatisticsCallee_Ver2"); + public static final String MAP_STATISTICS_CALLEE_VER2_STR = "ApplicationMapStatisticsCallee_Ver2"; + @Deprecated + public static final TableName MAP_STATISTICS_CALLEE_VER2 = TableName.valueOf(MAP_STATISTICS_CALLEE_VER2_STR); public static final byte[] MAP_STATISTICS_CALLEE_VER2_CF_COUNTER = Bytes.toBytes("C"); - public static final TableName MAP_STATISTICS_SELF_VER2 = TableName.valueOf("ApplicationMapStatisticsSelf_Ver2"); + public static final String MAP_STATISTICS_SELF_VER2_STR = "ApplicationMapStatisticsSelf_Ver2"; + @Deprecated + public static final TableName MAP_STATISTICS_SELF_VER2 = TableName.valueOf(MAP_STATISTICS_SELF_VER2_STR); public static final byte[] MAP_STATISTICS_SELF_VER2_CF_COUNTER = Bytes.toBytes("C"); - public static final TableName HOST_APPLICATION_MAP_VER2 = TableName.valueOf("HostApplicationMap_Ver2"); + public static final String HOST_APPLICATION_MAP_VER2_STR = "HostApplicationMap_Ver2"; + @Deprecated + public static final TableName HOST_APPLICATION_MAP_VER2 = TableName.valueOf(HOST_APPLICATION_MAP_VER2_STR); public static final byte[] HOST_APPLICATION_MAP_VER2_CF_MAP = Bytes.toBytes("M"); public static final int APPLICATION_STAT_TIMESPAN_MS = 5 * 60 * 1000; - public static final TableName APPLICATION_STAT_AGGRE = TableName.valueOf("ApplicationStatAggre"); + public static final String APPLICATION_STAT_AGGRE_STR = "ApplicationStatAggre"; + @Deprecated + public static final TableName APPLICATION_STAT_AGGRE = TableName.valueOf(APPLICATION_STAT_AGGRE_STR); public static final byte[] APPLICATION_STAT_CF_STATISTICS = Bytes.toBytes("S"); } diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseAdminFactory.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseAdminFactory.java new file mode 100644 index 000000000000..e5636c0b1bf8 --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseAdminFactory.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase; + +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.Connection; + +import java.io.IOException; +import java.util.Objects; + +/** + * @author HyunGil Jeong + */ +public class HbaseAdminFactory implements AdminFactory { + + private final Connection connection; + + public HbaseAdminFactory(Connection connection) { + this.connection = Objects.requireNonNull(connection, "connection must not be null"); + } + + @Override + public Admin getAdmin() { + if (connection.isClosed()) { + throw new HBaseAccessException("Connection already closed"); + } + try { + return connection.getAdmin(); + } catch (IOException e) { + throw new HbaseSystemException(e); + } + } + + @Override + public void releaseAdmin(Admin admin) { + if (admin == null) { + return; + } + try { + admin.close(); + } catch (IOException e) { + throw new HbaseSystemException(e); + } + } +} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTableFactory.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTableFactory.java new file mode 100644 index 000000000000..cecd54e18daa --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTableFactory.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase; + +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.Table; + +import java.io.IOException; +import java.util.Objects; +import java.util.concurrent.ExecutorService; + +/** + * HTableInterfaceFactory based on HTablePool. + * @author emeroad + * @author minwoo.jung + * @author HyunGil Jeong + */ +public class HbaseTableFactory implements TableFactory { + + private final Connection connection; + + public HbaseTableFactory(Connection connection) { + this.connection = Objects.requireNonNull(connection, "connection must not be null"); + } + + @Override + public Table getTable(TableName tableName) { + try { + return connection.getTable(tableName); + } catch (IOException e) { + throw new HbaseSystemException(e); + } + } + + @Override + public Table getTable(TableName tableName, ExecutorService executorService) { + try { + return connection.getTable(tableName, executorService); + } catch (IOException e) { + throw new HbaseSystemException(e); + } + } + + @Override + public void releaseTable(Table table) { + if (table == null) { + return; + } + + try { + table.close(); + } catch (IOException ex) { + throw new HbaseSystemException(ex); + } + } +} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTableNameProvider.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTableNameProvider.java new file mode 100644 index 000000000000..f4788b3ccb58 --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTableNameProvider.java @@ -0,0 +1,61 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase; + +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; +import com.navercorp.pinpoint.common.hbase.namespace.HbaseNamespaceValidator; +import com.navercorp.pinpoint.common.hbase.namespace.NamespaceValidator; +import com.navercorp.pinpoint.common.hbase.util.HbaseTableNameCache; +import com.navercorp.pinpoint.common.util.StringUtils; +import org.apache.hadoop.hbase.TableName; + +import java.util.Objects; + +/** + * @author HyunGil Jeong + */ +public class HbaseTableNameProvider implements TableNameProvider { + + private static final HbaseTableNameCache CACHE = new HbaseTableNameCache(); + + private final String namespace; + + public HbaseTableNameProvider(String namespace) { + this(namespace, HbaseNamespaceValidator.INSTANCE); + } + + @VisibleForTesting + HbaseTableNameProvider(String namespace, NamespaceValidator namespaceValidator) { + Objects.requireNonNull(namespaceValidator, "namespaceValidator must not be null"); + this.namespace = requireValidation(namespace, namespaceValidator); + } + + private String requireValidation(String namespace, NamespaceValidator namespaceValidator) { + if (StringUtils.isEmpty(namespace)) { + throw new IllegalArgumentException("Namespace must not be empty"); + } + if (!namespaceValidator.validate(namespace)) { + throw new IllegalArgumentException("Invalid namespace : " + namespace); + } + return namespace; + } + + @Override + public TableName getTableName(String tableName) { + return CACHE.get(namespace, tableName); + } +} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate2.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate2.java index 2756c8de370f..5beaca6d1c90 100644 --- a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate2.java +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate2.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -145,7 +145,10 @@ private boolean awaitAsyncPutOpsCleared(long waitTimeout, long checkUnitTime) { while (true) { Long currentPutOpsCount = asyncOperation.getCurrentOpsCount(); - logger.warn("count " + currentPutOpsCount); + if (logger.isWarnEnabled()) { + logger.warn("count {}", currentPutOpsCount); + } + if (currentPutOpsCount <= 0L) { return true; } diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/PooledHTableFactory.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/PooledHTableFactory.java deleted file mode 100644 index 5cb3e591ddf3..000000000000 --- a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/PooledHTableFactory.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.common.hbase; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hbase.TableName; -import org.apache.hadoop.hbase.client.Connection; -import org.apache.hadoop.hbase.client.ConnectionFactory; -import org.apache.hadoop.hbase.client.Table; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; - -import java.io.IOException; -import java.util.Objects; -import java.util.concurrent.ExecutorService; - -/** - * HTableInterfaceFactory based on HTablePool. - * @author emeroad - * @autor minwoo.jung - */ -public class PooledHTableFactory implements TableFactory, DisposableBean { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final ExecutorService executor; - private final Connection connection; - - public PooledHTableFactory(Configuration config, ExecutorService executor) { - Objects.requireNonNull(config, "config must not be null"); - this.executor = Objects.requireNonNull(executor, "executor must not be null"); - - try { - this.connection = ConnectionFactory.createConnection(config, executor); - } catch (IOException e) { - throw new HbaseSystemException(e); - } - } - - public Connection getConnection() { - return connection; - } - - - @Override - public Table getTable(TableName tableName) { - try { - return connection.getTable(tableName, executor); - } catch (IOException e) { - throw new HbaseSystemException(e); - } - } - - @Override - public Table getTable(TableName tableName, ExecutorService executorService) { - try { - return connection.getTable(tableName, executorService); - } catch (IOException e) { - throw new HbaseSystemException(e); - } - } - - @Override - public void releaseTable(Table table) { - if (table == null) { - return; - } - - try { - table.close(); - } catch (IOException ex) { - throw new HbaseSystemException(ex); - } - } - - - @Override - public void destroy() throws Exception { - logger.info("PooledHTableFactory.destroy()"); - - if (connection != null) { - try { - this.connection.close(); - } catch (IOException ex) { - logger.warn("Connection.close() error:" + ex.getMessage(), ex); - } - } - } -} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/TableNameProvider.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/TableNameProvider.java new file mode 100644 index 000000000000..f646deac1072 --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/TableNameProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase; + +import org.apache.hadoop.hbase.TableName; + +/** + * @author HyunGil Jeong + */ +public interface TableNameProvider { + + TableName getTableName(String tableName); +} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/namespace/HbaseNamespaceValidator.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/namespace/HbaseNamespaceValidator.java new file mode 100644 index 000000000000..8f26c7497500 --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/namespace/HbaseNamespaceValidator.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase.namespace; + +import org.apache.hadoop.hbase.TableName; + +import java.util.regex.Pattern; + +/** + * @author HyunGil Jeong + */ +public class HbaseNamespaceValidator implements NamespaceValidator { + + public static final NamespaceValidator INSTANCE = new HbaseNamespaceValidator(); + + private static final Pattern VALID_NAMESPACE = Pattern.compile(TableName.VALID_NAMESPACE_REGEX); + + private HbaseNamespaceValidator() { + + } + + @Override + public boolean validate(String namespace) { + if (namespace == null) { + return false; + } + return VALID_NAMESPACE.matcher(namespace).matches(); + } +} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/namespace/NamespaceValidator.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/namespace/NamespaceValidator.java new file mode 100644 index 000000000000..5b06db6f8dc5 --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/namespace/NamespaceValidator.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase.namespace; + +/** + * @author HyunGil Jeong + */ +public interface NamespaceValidator { + + boolean validate(String namespace); +} diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/parallel/ParallelResultScanner.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/parallel/ParallelResultScanner.java index 3d597bf13262..2bb2f16c2725 100644 --- a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/parallel/ParallelResultScanner.java +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/parallel/ParallelResultScanner.java @@ -93,7 +93,7 @@ private List createScanTasks(ScanTaskConfig scanTaskConfig, Scan[] spl } List scanTasks = new ArrayList<>(numParallelThreads); for (List scanDistribution : scanDistributions) { - Scan[] scansForSingleTask = scanDistribution.toArray(new Scan[scanDistribution.size()]); + Scan[] scansForSingleTask = scanDistribution.toArray(new Scan[0]); scanTasks.add(new ScanTask(scanTaskConfig, scansForSingleTask)); } return scanTasks; @@ -168,7 +168,7 @@ public Result[] next(int nbRows) throws IOException { break; } } - return resultSets.toArray(new Result[resultSets.size()]); + return resultSets.toArray(new Result[0]); } @Override diff --git a/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/util/HbaseTableNameCache.java b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/util/HbaseTableNameCache.java new file mode 100644 index 000000000000..1f836c448b01 --- /dev/null +++ b/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/util/HbaseTableNameCache.java @@ -0,0 +1,96 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase.util; + +import com.navercorp.pinpoint.common.util.StringUtils; +import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.TableName; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author HyunGil Jeong + */ +public class HbaseTableNameCache { + + private final Map tableNameCache = new ConcurrentHashMap<>(); + + public TableName get(String qualifier) { + return get(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR, qualifier); + } + + public TableName get(String namespace, String qualifier) { + Objects.requireNonNull(qualifier, "qualifier must not be null"); + String nonEmptyNamespace = StringUtils.isEmpty(namespace) ? NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR : namespace; + + TableNameKey tableNameKey = new TableNameKey(nonEmptyNamespace, qualifier); + TableName tableName = tableNameCache.get(tableNameKey); + if (tableName != null) { + return tableName; + } + tableName = TableName.valueOf(tableNameKey.getNamespace(), tableNameKey.getQualifier()); + TableName prevTableName = tableNameCache.putIfAbsent(tableNameKey, tableName); + if (prevTableName != null) { + return prevTableName; + } + return tableName; + } + + private static class TableNameKey { + + private final String namespace; + private final String qualifier; + + private TableNameKey(String namespace, String qualifier) { + this.namespace = Objects.requireNonNull(namespace, "namespace must not be null"); + this.qualifier = Objects.requireNonNull(qualifier, "qualifier must not be null"); + } + + public String getNamespace() { + return namespace; + } + + public String getQualifier() { + return qualifier; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TableNameKey that = (TableNameKey) o; + + if (!namespace.equals(that.namespace)) return false; + return qualifier.equals(that.qualifier); + } + + @Override + public int hashCode() { + int result = namespace.hashCode(); + result = 31 * result + qualifier.hashCode(); + return result; + } + + @Override + public String toString() { + return namespace + ":" + qualifier; + } + } +} diff --git a/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/HbaseTableNameProviderTest.java b/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/HbaseTableNameProviderTest.java new file mode 100644 index 000000000000..3e4c5a8210dd --- /dev/null +++ b/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/HbaseTableNameProviderTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase; + +import com.navercorp.pinpoint.common.hbase.namespace.NamespaceValidator; +import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.TableName; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.only; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +@RunWith(MockitoJUnitRunner.class) +public class HbaseTableNameProviderTest { + + private static final String TABLE_QUALIFIER = "testTable"; + + @Mock + private NamespaceValidator namespaceValidator; + + @Test(expected = IllegalArgumentException.class) + public void nullNamespaceShouldThrowException() { + // Given + final String nullNamespace = null; + // When + new HbaseTableNameProvider(nullNamespace, namespaceValidator); + Assert.fail("Expected IllegalArgumentException to be thrown"); + } + + @Test(expected = IllegalArgumentException.class) + public void emptyNamespaceShouldThrowException() { + // Given + final String emptyNamespace = ""; + // When + new HbaseTableNameProvider(emptyNamespace, namespaceValidator); + Assert.fail("Expected IllegalArgumentException to be thrown"); + } + + @Test + public void validNamespace() { + // Given + final String validNamespace = "namespace"; + when(namespaceValidator.validate(validNamespace)).thenReturn(true); + // When + final TableNameProvider tableNameProvider = new HbaseTableNameProvider(validNamespace, namespaceValidator); + final TableName tableName = tableNameProvider.getTableName(TABLE_QUALIFIER); + // Then + verify(namespaceValidator, only()).validate(validNamespace); + Assert.assertEquals(validNamespace, tableName.getNamespaceAsString()); + Assert.assertEquals(TABLE_QUALIFIER, tableName.getQualifierAsString()); + } + + @Test + public void invalidNamespace() { + // Given + final String invalidNamespace = "invalidNamespace"; + when(namespaceValidator.validate(invalidNamespace)).thenReturn(false); + // When + try { + new HbaseTableNameProvider(invalidNamespace, namespaceValidator); + Assert.fail("Expected IllegalArgumentException to be thrown"); + } catch (IllegalArgumentException e) { + verify(namespaceValidator, only()).validate(invalidNamespace); + } + } +} diff --git a/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate2IT.java b/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate2IT.java index f20a2d159310..9ad281f14e15 100644 --- a/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate2IT.java +++ b/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate2IT.java @@ -18,13 +18,13 @@ import java.io.IOException; import java.util.Properties; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableNotFoundException; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException; import org.junit.AfterClass; import org.junit.Assert; @@ -40,7 +40,7 @@ * @author minwoo.jung */ public class HbaseTemplate2IT { - private static ExecutorService executorService; + private static Connection connection; private static HbaseTemplate2 hbaseTemplate2; @BeforeClass @@ -51,10 +51,10 @@ public static void beforeClass() throws IOException { cfg.set("hbase.zookeeper.quorum", properties.getProperty("hbase.client.host")); cfg.set("hbase.zookeeper.property.clientPort", properties.getProperty("hbase.client.port")); - executorService = Executors.newFixedThreadPool(10); + connection = ConnectionFactory.createConnection(cfg); hbaseTemplate2 = new HbaseTemplate2(); hbaseTemplate2.setConfiguration(cfg); - hbaseTemplate2.setTableFactory(new PooledHTableFactory(cfg, executorService)); + hbaseTemplate2.setTableFactory(new HbaseTableFactory(connection)); hbaseTemplate2.afterPropertiesSet(); } @@ -63,8 +63,8 @@ public static void afterClass() throws Exception { if (hbaseTemplate2 != null) { hbaseTemplate2.destroy(); } - if (executorService != null) { - executorService.shutdown(); + if (connection != null) { + connection.close(); } } diff --git a/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/namespace/HbaseNamespaceValidatorTest.java b/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/namespace/HbaseNamespaceValidatorTest.java new file mode 100644 index 000000000000..484e800cd9f4 --- /dev/null +++ b/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/namespace/HbaseNamespaceValidatorTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase.namespace; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author HyunGil Jeong + */ +public class HbaseNamespaceValidatorTest { + + @Test + public void testValidate() { + String valid1 = "a"; + String valid2 = "_a0"; + String valid3 = "0_Z"; + String valid4 = "C09_"; + + String invalid1 = ""; + String invalid2 = "-"; + String invalid3 = "abc-1"; + String invalid4 = "abc!"; + String invalid5 = null; + + Assert.assertTrue(valid1 + " should be valid.", HbaseNamespaceValidator.INSTANCE.validate(valid1)); + Assert.assertTrue(valid2 + " should be valid.", HbaseNamespaceValidator.INSTANCE.validate(valid2)); + Assert.assertTrue(valid3 + " should be valid.", HbaseNamespaceValidator.INSTANCE.validate(valid3)); + Assert.assertTrue(valid4 + " should be valid.", HbaseNamespaceValidator.INSTANCE.validate(valid4)); + + Assert.assertFalse(invalid1 + " should be invalid.", HbaseNamespaceValidator.INSTANCE.validate(invalid1)); + Assert.assertFalse(invalid2 + " should be invalid.", HbaseNamespaceValidator.INSTANCE.validate(invalid2)); + Assert.assertFalse(invalid3 + " should be invalid.", HbaseNamespaceValidator.INSTANCE.validate(invalid3)); + Assert.assertFalse(invalid4 + " should be invalid.", HbaseNamespaceValidator.INSTANCE.validate(invalid4)); + Assert.assertFalse(invalid4 + " should be invalid.", HbaseNamespaceValidator.INSTANCE.validate(invalid5)); + } +} diff --git a/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/util/HbaseTableNameCacheTest.java b/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/util/HbaseTableNameCacheTest.java new file mode 100644 index 000000000000..c81e7ca38fb8 --- /dev/null +++ b/commons-hbase/src/test/java/com/navercorp/pinpoint/common/hbase/util/HbaseTableNameCacheTest.java @@ -0,0 +1,71 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.hbase.util; + +import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.TableName; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author HyunGil Jeong + */ +public class HbaseTableNameCacheTest { + + private final HbaseTableNameCache cache = new HbaseTableNameCache(); + + @Test + public void emptyNamespaceShouldReturnDefaultNamespace() { + // Given + final String nullNamespace = null; + final String emptyNamespace = ""; + final String qualifier = "table"; + // When + TableName tableName1 = cache.get(qualifier); + TableName tableName2 = cache.get(nullNamespace, qualifier); + TableName tableName3 = cache.get(emptyNamespace, qualifier); + // Then + Assert.assertEquals(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR, tableName1.getNamespaceAsString()); + Assert.assertEquals(qualifier, tableName1.getQualifierAsString()); + Assert.assertEquals(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR, tableName2.getNamespaceAsString()); + Assert.assertEquals(qualifier, tableName2.getQualifierAsString()); + Assert.assertEquals(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR, tableName3.getNamespaceAsString()); + Assert.assertEquals(qualifier, tableName3.getQualifierAsString()); + } + + @Test + public void specifiedNamespace() { + // Given + final String namespace = "namespace"; + final String qualifier = "table"; + // When + TableName tableName = cache.get(namespace, qualifier); + // Then + Assert.assertEquals(namespace, tableName.getNamespaceAsString()); + Assert.assertEquals(qualifier, tableName.getQualifierAsString()); + } + + @Test(expected = NullPointerException.class) + public void nullQualifierShouldThrowException() { + // Given + final String nullQualifier = null; + // When + cache.get(nullQualifier); + // Then + Assert.fail(); + } +} diff --git a/commons-server/clover.license b/commons-server/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/commons-server/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-commons-server @@ -12,12 +28,10 @@ jar - - - 1.6 + 1.8 ${env.JAVA_8_HOME} ${jdk.home} - java16 + java18 @@ -54,6 +68,10 @@ + + org.apache.zookeeper + zookeeper + org.springframework spring-test @@ -67,6 +85,10 @@ org.apache.commons commons-lang3 + + org.apache.curator + curator-framework + @@ -97,6 +119,12 @@ log4j test + + org.apache.curator + curator-test + test + + diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/AgentInfoBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/AgentInfoBo.java index 42d11e1593cc..f87334d72680 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/AgentInfoBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/AgentInfoBo.java @@ -55,6 +55,8 @@ private String defaultString(String string) { private final long endTimeStamp; private final int endStatus; + private final boolean container; + // Should be serialized separately private final ServerMetaDataBo serverMetaData; private final JvmInfoBo jvmInfo; @@ -72,6 +74,7 @@ private AgentInfoBo(Builder builder) { this.startTime = builder.startTime; this.endTimeStamp = builder.endTimeStamp; this.endStatus = builder.endStatus; + this.container = builder.container; this.serverMetaData = builder.serverMetaData; this.jvmInfo = builder.jvmInfo; } @@ -124,7 +127,11 @@ public String getVmVersion() { public String getAgentVersion() { return agentVersion; } - + + public boolean isContainer() { + return container; + } + public ServerMetaDataBo getServerMetaData() { return this.serverMetaData; } @@ -149,6 +156,8 @@ public byte[] writeValue() { buffer.putPrefixedString(this.getVmVersion()); + buffer.putBoolean(this.isContainer()); + return buffer.getBuffer(); } @@ -210,6 +219,8 @@ public static class Builder { private long startTime; private long endTimeStamp; private int endStatus; + + private boolean container; // Should be serialized separately private ServerMetaDataBo serverMetaData; @@ -269,6 +280,10 @@ public void setEndTimeStamp(long endTimeStamp) { public void setEndStatus(int endStatus) { this.endStatus = endStatus; } + + public void isContainer(boolean container) { + this.container = container; + } public void setServerMetaData(ServerMetaDataBo serverMetaData) { this.serverMetaData = serverMetaData; diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/ApiMetaDataBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/ApiMetaDataBo.java index 88fe1289a4c6..09f667eaba9c 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/ApiMetaDataBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/ApiMetaDataBo.java @@ -32,7 +32,7 @@ public class ApiMetaDataBo { private int apiId; private String apiInfo; - private int lineNumber; + private int lineNumber = -1; private MethodTypeEnum methodTypeEnum = MethodTypeEnum.DEFAULT; public ApiMetaDataBo() { @@ -128,12 +128,14 @@ public byte[] toRowKey() { @Override public String toString() { - return "ApiMetaDataBo{" + - "agentId='" + agentId + '\'' + - ", apiId=" + apiId + - ", startTime=" + startTime + - ", apiInfo='" + apiInfo + '\'' + - ", lineNumber=" + lineNumber + - '}'; + final StringBuilder sb = new StringBuilder("ApiMetaDataBo{"); + sb.append("agentId='").append(agentId).append('\''); + sb.append(", startTime=").append(startTime); + sb.append(", apiId=").append(apiId); + sb.append(", apiInfo='").append(apiInfo).append('\''); + sb.append(", lineNumber=").append(lineNumber); + sb.append(", methodTypeEnum=").append(methodTypeEnum); + sb.append('}'); + return sb.toString(); } } \ No newline at end of file diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/SpanEventBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/SpanEventBo.java index fbe98d7c7333..81bb8de8d368 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/SpanEventBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/SpanEventBo.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -33,7 +33,7 @@ public class SpanEventBo implements Event { private int startElapsed; private int endElapsed; - private String rpc; +// private String rpc; private short serviceType; private String destinationId; @@ -92,12 +92,14 @@ public void setEndElapsed(int endElapsed) { this.endElapsed = endElapsed; } + @Deprecated public String getRpc() { - return rpc; + return null; } + @Deprecated public void setRpc(String rpc) { - this.rpc = rpc; +// this.rpc = rpc; } public short getServiceType() { @@ -228,8 +230,6 @@ public String toString() { builder.append(startElapsed); builder.append(", endElapsed="); builder.append(endElapsed); - builder.append(", rpc="); - builder.append(rpc); builder.append(", serviceType="); builder.append(serviceType); builder.append(", destinationId="); diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/SpanFactory.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/SpanFactory.java index 5c60bd7dc7a1..5f01f0dee494 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/SpanFactory.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/SpanFactory.java @@ -6,9 +6,9 @@ import com.navercorp.pinpoint.common.server.bo.filter.SpanEventFilter; import com.navercorp.pinpoint.common.server.util.AcceptedTimeService; import com.navercorp.pinpoint.common.server.util.EmptyAcceptedTimeService; -import com.navercorp.pinpoint.common.util.AnnotationTranscoder; import com.navercorp.pinpoint.common.util.TransactionId; import com.navercorp.pinpoint.common.util.TransactionIdUtils; +import com.navercorp.pinpoint.io.util.AnnotationTranscoder; import com.navercorp.pinpoint.thrift.dto.TAnnotation; import com.navercorp.pinpoint.thrift.dto.TIntStringValue; import com.navercorp.pinpoint.thrift.dto.TSpan; diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DeadlockDecoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DeadlockDecoder.java index 9d9410ff9aec..25e2fe644e3a 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DeadlockDecoder.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DeadlockDecoder.java @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.common.server.bo.codec.stat; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -26,10 +26,10 @@ * @author Taejin Koo */ @Component -public class DeadlockDecoder extends AgentStatDecoder { +public class DeadlockDecoder extends AgentStatDecoder { @Autowired - public DeadlockDecoder(List> deadlockCodecs) { + public DeadlockDecoder(List> deadlockCodecs) { super(deadlockCodecs); } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DeadlockEncoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DeadlockEncoder.java index 06445524249a..e4f3d78b9416 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DeadlockEncoder.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DeadlockEncoder.java @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.common.server.bo.codec.stat; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @@ -25,10 +25,10 @@ * @author Taejin Koo */ @Component -public class DeadlockEncoder extends AgentStatEncoder { +public class DeadlockEncoder extends AgentStatEncoder { @Autowired - public DeadlockEncoder(@Qualifier("deadlockCodecV2") AgentStatCodec deadlockCodec) { + public DeadlockEncoder(@Qualifier("deadlockCodecV2") AgentStatCodec deadlockCodec) { super(deadlockCodec); } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DirectBufferDecoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DirectBufferDecoder.java new file mode 100644 index 000000000000..340f007244be --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DirectBufferDecoder.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Component +public class DirectBufferDecoder extends AgentStatDecoder { + + @Autowired + public DirectBufferDecoder(List> directBufferCodecs) { + super(directBufferCodecs); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DirectBufferEncoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DirectBufferEncoder.java new file mode 100644 index 000000000000..575151894199 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/DirectBufferEncoder.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +/** + * @author Roy Kim + */ +@Component +public class DirectBufferEncoder extends AgentStatEncoder { + + @Autowired + private DirectBufferEncoder(@Qualifier("directBufferCodecV2") AgentStatCodec directBufferCodec) { + super(directBufferCodec); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/FileDescriptorDecoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/FileDescriptorDecoder.java new file mode 100644 index 000000000000..95cf8667d630 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/FileDescriptorDecoder.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Component +public class FileDescriptorDecoder extends AgentStatDecoder { + + @Autowired + public FileDescriptorDecoder(List> fileDescriptorCodecs) { + super(fileDescriptorCodecs); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/FileDescriptorEncoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/FileDescriptorEncoder.java new file mode 100644 index 000000000000..5d80291f587e --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/FileDescriptorEncoder.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +/** + * @author Roy Kim + */ +@Component +public class FileDescriptorEncoder extends AgentStatEncoder { + + @Autowired + private FileDescriptorEncoder(@Qualifier("fileDescriptorCodecV2") AgentStatCodec fileDescriptorCodec) { + super(fileDescriptorCodec); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferCodec.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferCodec.java new file mode 100644 index 000000000000..18d555cd48cb --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferCodec.java @@ -0,0 +1,328 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.codec.stat.join; + +import com.navercorp.pinpoint.common.buffer.Buffer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatDataPointCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.ApplicationStatCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.AgentStatHeaderDecoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.AgentStatHeaderEncoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.BitCountingHeaderDecoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.BitCountingHeaderEncoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.StrategyAnalyzer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.StringEncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.UnsignedLongEncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.codec.strategy.EncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatDecodingContext; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinDirectBufferBo; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Roy Kim + */ +@Component("joinDirectBufferCodec") +public class DirectBufferCodec implements ApplicationStatCodec { + + private static final byte VERSION = 1; + + private final AgentStatDataPointCodec codec; + + @Autowired + public DirectBufferCodec(AgentStatDataPointCodec codec) { + Assert.notNull(codec, "agentStatDataPointCodec must not be null"); + this.codec = codec; + } + + @Override + public byte getVersion() { + return VERSION; + } + + @Override + public void encodeValues(Buffer valueBuffer, List joinDirectBufferBoList) { + if (CollectionUtils.isEmpty(joinDirectBufferBoList)) { + throw new IllegalArgumentException("directBufferBoList must not be empty"); + } + + final int numValues = joinDirectBufferBoList.size(); + valueBuffer.putVInt(numValues); + List timestamps = new ArrayList(numValues); + UnsignedLongEncodingStrategy.Analyzer.Builder avgDirectCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder minDirectCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder minDirectCountAgentIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder maxDirectCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder maxDirectCountAgentIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + + UnsignedLongEncodingStrategy.Analyzer.Builder avgDirectMemoryUsedAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder minDirectMemoryUsedAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder minDirectMemoryUsedAgentIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder maxDirectMemoryUsedAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder maxDirectMemoryUsedAgentIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + + UnsignedLongEncodingStrategy.Analyzer.Builder avgMappedCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder minMappedCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder minMappedCountAgentIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder maxMappedCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder maxMappedCountAgentIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + + UnsignedLongEncodingStrategy.Analyzer.Builder avgMappedMemoryUsedAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder minMappedMemoryUsedAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder minMappedMemoryUsedAgentIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder maxMappedMemoryUsedAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder maxMappedMemoryUsedAgentIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + + for (JoinStatBo joinStatBo : joinDirectBufferBoList) { + JoinDirectBufferBo joinDirectBufferBo = (JoinDirectBufferBo) joinStatBo; + timestamps.add(joinDirectBufferBo.getTimestamp()); + avgDirectCountAnalyzerBuilder.addValue(joinDirectBufferBo.getAvgDirectCount()); + minDirectCountAnalyzerBuilder.addValue(joinDirectBufferBo.getMinDirectCount()); + minDirectCountAgentIdAnalyzerBuilder.addValue(joinDirectBufferBo.getMinDirectCountAgentId()); + maxDirectCountAnalyzerBuilder.addValue(joinDirectBufferBo.getMaxDirectCount()); + maxDirectCountAgentIdAnalyzerBuilder.addValue(joinDirectBufferBo.getMaxDirectCountAgentId()); + + avgDirectMemoryUsedAnalyzerBuilder.addValue(joinDirectBufferBo.getAvgMappedMemoryUsed()); + minDirectMemoryUsedAnalyzerBuilder.addValue(joinDirectBufferBo.getMinDirectMemoryUsed()); + minDirectMemoryUsedAgentIdAnalyzerBuilder.addValue(joinDirectBufferBo.getMinDirectMemoryUsedAgentId()); + maxDirectMemoryUsedAnalyzerBuilder.addValue(joinDirectBufferBo.getMaxDirectMemoryUsed()); + maxDirectMemoryUsedAgentIdAnalyzerBuilder.addValue(joinDirectBufferBo.getMaxDirectMemoryUsedAgentId()); + + avgMappedCountAnalyzerBuilder.addValue(joinDirectBufferBo.getAvgMappedCount()); + minMappedCountAnalyzerBuilder.addValue(joinDirectBufferBo.getMinMappedCount()); + minMappedCountAgentIdAnalyzerBuilder.addValue(joinDirectBufferBo.getMinMappedCountAgentId()); + maxMappedCountAnalyzerBuilder.addValue(joinDirectBufferBo.getMaxMappedCount()); + maxMappedCountAgentIdAnalyzerBuilder.addValue(joinDirectBufferBo.getMaxMappedCountAgentId()); + + avgMappedMemoryUsedAnalyzerBuilder.addValue(joinDirectBufferBo.getAvgMappedMemoryUsed()); + minMappedMemoryUsedAnalyzerBuilder.addValue(joinDirectBufferBo.getMinMappedMemoryUsed()); + minMappedMemoryUsedAgentIdAnalyzerBuilder.addValue(joinDirectBufferBo.getMinMappedMemoryUsedAgentId()); + maxMappedMemoryUsedAnalyzerBuilder.addValue(joinDirectBufferBo.getMaxMappedMemoryUsed()); + maxMappedMemoryUsedAgentIdAnalyzerBuilder.addValue(joinDirectBufferBo.getMaxMappedMemoryUsedAgentId()); + + + } + codec.encodeTimestamps(valueBuffer, timestamps); + encodeDataPoints(valueBuffer + , avgDirectCountAnalyzerBuilder.build() + , minDirectCountAnalyzerBuilder.build() + , minDirectCountAgentIdAnalyzerBuilder.build() + , maxDirectCountAnalyzerBuilder.build() + , maxDirectCountAgentIdAnalyzerBuilder.build() + + , avgDirectMemoryUsedAnalyzerBuilder.build() + , minDirectMemoryUsedAnalyzerBuilder.build() + , minDirectMemoryUsedAgentIdAnalyzerBuilder.build() + , maxDirectMemoryUsedAnalyzerBuilder.build() + , maxDirectMemoryUsedAgentIdAnalyzerBuilder.build() + + , avgMappedCountAnalyzerBuilder.build() + , minMappedCountAnalyzerBuilder.build() + , minMappedCountAgentIdAnalyzerBuilder.build() + , maxMappedCountAnalyzerBuilder.build() + , maxMappedCountAgentIdAnalyzerBuilder.build() + + , avgMappedMemoryUsedAnalyzerBuilder.build() + , minMappedMemoryUsedAnalyzerBuilder.build() + , minMappedMemoryUsedAgentIdAnalyzerBuilder.build() + , maxMappedMemoryUsedAnalyzerBuilder.build() + , maxMappedMemoryUsedAgentIdAnalyzerBuilder.build() + ); + } + + private void encodeDataPoints(Buffer valueBuffer + , StrategyAnalyzer avgDirectCountAnalyzer + , StrategyAnalyzer minDirectCountAnalyzer + , StrategyAnalyzer minDirectCountAgentIdAnalyzer + , StrategyAnalyzer maxDirectCountAnalyzer + , StrategyAnalyzer maxDirectCountAgentIdAnalyzer + + , StrategyAnalyzer avgDirectMemoryUsedAnalyzer + , StrategyAnalyzer minDirectMemoryUsedAnalyzer + , StrategyAnalyzer minDirectMemoryUsedAgentIdAnalyzer + , StrategyAnalyzer maxDirectMemoryUsedAnalyzer + , StrategyAnalyzer maxDirectMemoryUsedAgentIdAnalyzer + + , StrategyAnalyzer avgMappedCountAnalyzer + , StrategyAnalyzer minMappedCountAnalyzer + , StrategyAnalyzer minMappedCountAgentIdAnalyzer + , StrategyAnalyzer maxMappedCountAnalyzer + , StrategyAnalyzer maxMappedCountAgentIdAnalyzer + + , StrategyAnalyzer avgMappedMemoryUsedAnalyzer + , StrategyAnalyzer minMappedMemoryUsedAnalyzer + , StrategyAnalyzer minMappedMemoryUsedAgentIdAnalyzer + , StrategyAnalyzer maxMappedMemoryUsedAnalyzer + , StrategyAnalyzer maxMappedMemoryUsedAgentIdAnalyzer + ) { + // encode header + AgentStatHeaderEncoder headerEncoder = new BitCountingHeaderEncoder(); + headerEncoder.addCode(avgDirectCountAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minDirectCountAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minDirectCountAgentIdAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxDirectCountAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxDirectCountAgentIdAnalyzer.getBestStrategy().getCode()); + + headerEncoder.addCode(avgDirectMemoryUsedAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minDirectMemoryUsedAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minDirectMemoryUsedAgentIdAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxDirectMemoryUsedAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxDirectMemoryUsedAgentIdAnalyzer.getBestStrategy().getCode()); + + headerEncoder.addCode(avgMappedCountAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minMappedCountAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minMappedCountAgentIdAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxMappedCountAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxMappedCountAgentIdAnalyzer.getBestStrategy().getCode()); + + headerEncoder.addCode(avgMappedMemoryUsedAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minMappedMemoryUsedAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minMappedMemoryUsedAgentIdAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxMappedMemoryUsedAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxMappedMemoryUsedAgentIdAnalyzer.getBestStrategy().getCode()); + + + final byte[] header = headerEncoder.getHeader(); + valueBuffer.putPrefixedBytes(header); + // encode values + this.codec.encodeValues(valueBuffer, avgDirectCountAnalyzer.getBestStrategy(), avgDirectCountAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minDirectCountAnalyzer.getBestStrategy(), minDirectCountAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minDirectCountAgentIdAnalyzer.getBestStrategy(), minDirectCountAgentIdAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxDirectCountAnalyzer.getBestStrategy(), maxDirectCountAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxDirectCountAgentIdAnalyzer.getBestStrategy(), maxDirectCountAgentIdAnalyzer.getValues()); + + this.codec.encodeValues(valueBuffer, avgDirectMemoryUsedAnalyzer.getBestStrategy(), avgDirectMemoryUsedAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minDirectMemoryUsedAnalyzer.getBestStrategy(), minDirectMemoryUsedAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minDirectMemoryUsedAgentIdAnalyzer.getBestStrategy(), minDirectMemoryUsedAgentIdAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxDirectMemoryUsedAnalyzer.getBestStrategy(), maxDirectMemoryUsedAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxDirectMemoryUsedAgentIdAnalyzer.getBestStrategy(), maxDirectMemoryUsedAgentIdAnalyzer.getValues()); + + this.codec.encodeValues(valueBuffer, avgMappedCountAnalyzer.getBestStrategy(), avgMappedCountAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minMappedCountAnalyzer.getBestStrategy(), minMappedCountAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minMappedCountAgentIdAnalyzer.getBestStrategy(), minMappedCountAgentIdAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxMappedCountAnalyzer.getBestStrategy(), maxMappedCountAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxMappedCountAgentIdAnalyzer.getBestStrategy(), maxMappedCountAgentIdAnalyzer.getValues()); + + this.codec.encodeValues(valueBuffer, avgMappedMemoryUsedAnalyzer.getBestStrategy(), avgMappedMemoryUsedAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minMappedMemoryUsedAnalyzer.getBestStrategy(), minMappedMemoryUsedAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minMappedMemoryUsedAgentIdAnalyzer.getBestStrategy(), minMappedMemoryUsedAgentIdAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxMappedMemoryUsedAnalyzer.getBestStrategy(), maxMappedMemoryUsedAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxMappedMemoryUsedAgentIdAnalyzer.getBestStrategy(), maxMappedMemoryUsedAgentIdAnalyzer.getValues()); + + } + + @Override + public List decodeValues(Buffer valueBuffer, ApplicationStatDecodingContext decodingContext) { + final String id = decodingContext.getApplicationId(); + final long baseTimestamp = decodingContext.getBaseTimestamp(); + final long timestampDelta = decodingContext.getTimestampDelta(); + final long initialTimestamp = baseTimestamp + timestampDelta; + + int numValues = valueBuffer.readVInt(); + List timestamps = this.codec.decodeTimestamps(initialTimestamp, valueBuffer, numValues); + + // decode headers + final byte[] header = valueBuffer.readPrefixedBytes(); + AgentStatHeaderDecoder headerDecoder = new BitCountingHeaderDecoder(header); + EncodingStrategy avgDirectCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minDirectCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minDirectCountAgentIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxDirectCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxDirectCountAgentIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + + EncodingStrategy avgDirectMemoryUsedEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minDirectMemoryUsedEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minDirectMemoryUsedAgentIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxDirectMemoryUsedEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxDirectMemoryUsedAgentIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + + EncodingStrategy avgMappedCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minMappedCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minMappedCountAgentIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxMappedCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxMappedCountAgentIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + + EncodingStrategy avgMappedMemoryUsedEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minMappedMemoryUsedEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minMappedMemoryUsedAgentIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxMappedMemoryUsedEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxMappedMemoryUsedAgentIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + + // decode values + List avgDirectCounts = this.codec.decodeValues(valueBuffer, avgDirectCountEncodingStrategy, numValues); + List minDirectCounts = this.codec.decodeValues(valueBuffer, minDirectCountEncodingStrategy, numValues); + List minDirectCountAgentIds = this.codec.decodeValues(valueBuffer, minDirectCountAgentIdEncodingStrategy, numValues); + List maxDirectCounts = this.codec.decodeValues(valueBuffer, maxDirectCountEncodingStrategy, numValues); + List maxDirectCountAgentIds = this.codec.decodeValues(valueBuffer, maxDirectCountAgentIdEncodingStrategy, numValues); + + List avgDirectMemoryUseds = this.codec.decodeValues(valueBuffer, avgDirectMemoryUsedEncodingStrategy, numValues); + List minDirectMemoryUseds = this.codec.decodeValues(valueBuffer, minDirectMemoryUsedEncodingStrategy, numValues); + List minDirectMemoryUsedAgentIds = this.codec.decodeValues(valueBuffer, minDirectMemoryUsedAgentIdEncodingStrategy, numValues); + List maxDirectMemoryUseds = this.codec.decodeValues(valueBuffer, maxDirectMemoryUsedEncodingStrategy, numValues); + List maxDirectMemoryUsedAgentIds = this.codec.decodeValues(valueBuffer, maxDirectMemoryUsedAgentIdEncodingStrategy, numValues); + + List avgMappedCounts = this.codec.decodeValues(valueBuffer, avgMappedCountEncodingStrategy, numValues); + List minMappedCounts = this.codec.decodeValues(valueBuffer, minMappedCountEncodingStrategy, numValues); + List minMappedCountAgentIds = this.codec.decodeValues(valueBuffer, minMappedCountAgentIdEncodingStrategy, numValues); + List maxMappedCounts = this.codec.decodeValues(valueBuffer, maxMappedCountEncodingStrategy, numValues); + List maxMappedCountAgentIds = this.codec.decodeValues(valueBuffer, maxMappedCountAgentIdEncodingStrategy, numValues); + + List avgMappedMemoryUseds = this.codec.decodeValues(valueBuffer, avgMappedMemoryUsedEncodingStrategy, numValues); + List minMappedMemoryUseds = this.codec.decodeValues(valueBuffer, minMappedMemoryUsedEncodingStrategy, numValues); + List minMappedMemoryUsedAgentIds = this.codec.decodeValues(valueBuffer, minMappedMemoryUsedAgentIdEncodingStrategy, numValues); + List maxMappedMemoryUseds = this.codec.decodeValues(valueBuffer, maxMappedMemoryUsedEncodingStrategy, numValues); + List maxMappedMemoryUsedAgentIds = this.codec.decodeValues(valueBuffer, maxMappedMemoryUsedAgentIdEncodingStrategy, numValues); + + List joinDirectBufferBoList = new ArrayList(numValues); + for (int i = 0; i < numValues; i++) { + JoinDirectBufferBo joinDirectBufferBo = new JoinDirectBufferBo(); + joinDirectBufferBo.setId(id); + joinDirectBufferBo.setTimestamp(timestamps.get(i)); + + joinDirectBufferBo.setAvgDirectCount(avgDirectCounts.get(i)); + joinDirectBufferBo.setMinDirectCount(minDirectCounts.get(i)); + joinDirectBufferBo.setMinDirectCountAgentId(minDirectCountAgentIds.get(i)); + joinDirectBufferBo.setMaxDirectCount(maxDirectCounts.get(i)); + joinDirectBufferBo.setMaxDirectCountAgentId(maxDirectCountAgentIds.get(i)); + + joinDirectBufferBo.setAvgDirectMemoryUsed(avgDirectMemoryUseds.get(i)); + joinDirectBufferBo.setMinDirectMemoryUsed(minDirectMemoryUseds.get(i)); + joinDirectBufferBo.setMinDirectMemoryUsedAgentId(minDirectMemoryUsedAgentIds.get(i)); + joinDirectBufferBo.setMaxDirectMemoryUsed(maxDirectMemoryUseds.get(i)); + joinDirectBufferBo.setMaxDirectMemoryUsedAgentId(maxDirectMemoryUsedAgentIds.get(i)); + + joinDirectBufferBo.setAvgMappedCount(avgMappedCounts.get(i)); + joinDirectBufferBo.setMinMappedCount(minMappedCounts.get(i)); + joinDirectBufferBo.setMinMappedCountAgentId(minMappedCountAgentIds.get(i)); + joinDirectBufferBo.setMaxMappedCount(maxMappedCounts.get(i)); + joinDirectBufferBo.setMaxMappedCountAgentId(maxMappedCountAgentIds.get(i)); + + joinDirectBufferBo.setAvgMappedMemoryUsed(avgMappedMemoryUseds.get(i)); + joinDirectBufferBo.setMinMappedMemoryUsed(minMappedMemoryUseds.get(i)); + joinDirectBufferBo.setMinMappedMemoryUsedAgentId(minMappedMemoryUsedAgentIds.get(i)); + joinDirectBufferBo.setMaxMappedMemoryUsed(maxMappedMemoryUseds.get(i)); + joinDirectBufferBo.setMaxMappedMemoryUsedAgentId(maxMappedMemoryUsedAgentIds.get(i)); + + joinDirectBufferBoList.add(joinDirectBufferBo); + } + return joinDirectBufferBoList; + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferDecoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferDecoder.java new file mode 100644 index 000000000000..bbc4813a5923 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferDecoder.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.codec.stat.join; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.ApplicationStatDecoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Component("joinDirectBufferDecoder") +public class DirectBufferDecoder extends ApplicationStatDecoder { + + @Autowired + public DirectBufferDecoder(List directBufferCodecList) { + super(directBufferCodecList); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferEncoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferEncoder.java new file mode 100644 index 000000000000..21230f561054 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferEncoder.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.codec.stat.join; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.ApplicationStatCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.ApplicationStatEncoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * @author Roy Kim + */ +public class DirectBufferEncoder extends ApplicationStatEncoder { + + @Autowired + private DirectBufferEncoder(@Qualifier("joinDirectBufferCodec") ApplicationStatCodec directBufferCodec) { + super(directBufferCodec); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorCodec.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorCodec.java new file mode 100644 index 000000000000..d6c455198d38 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorCodec.java @@ -0,0 +1,157 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.codec.stat.join; + +import com.navercorp.pinpoint.common.buffer.Buffer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatDataPointCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.ApplicationStatCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.AgentStatHeaderDecoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.AgentStatHeaderEncoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.BitCountingHeaderDecoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.BitCountingHeaderEncoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.StrategyAnalyzer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.StringEncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.UnsignedLongEncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.codec.strategy.EncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatDecodingContext; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinFileDescriptorBo; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Roy Kim + */ +@Component("joinFileDescriptorCodec") +public class FileDescriptorCodec implements ApplicationStatCodec { + + private static final byte VERSION = 1; + + private final AgentStatDataPointCodec codec; + + @Autowired + public FileDescriptorCodec(AgentStatDataPointCodec codec) { + Assert.notNull(codec, "agentStatDataPointCodec must not be null"); + this.codec = codec; + } + + @Override + public byte getVersion() { + return VERSION; + } + + @Override + public void encodeValues(Buffer valueBuffer, List joinFileDescriptorBoList) { + if (CollectionUtils.isEmpty(joinFileDescriptorBoList)) { + throw new IllegalArgumentException("fileDescriptorBoList must not be empty"); + } + + final int numValues = joinFileDescriptorBoList.size(); + valueBuffer.putVInt(numValues); + List timestamps = new ArrayList(numValues); + UnsignedLongEncodingStrategy.Analyzer.Builder openFileDescriptorCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder minOpenFileDescriptorCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder minOpenFileDescriptorCountIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + UnsignedLongEncodingStrategy.Analyzer.Builder maxOpenFileDescriptorCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + StringEncodingStrategy.Analyzer.Builder maxOpenFileDescriptorCountIdAnalyzerBuilder = new StringEncodingStrategy.Analyzer.Builder(); + + for (JoinStatBo joinStatBo : joinFileDescriptorBoList) { + JoinFileDescriptorBo joinFileDescriptorBo = (JoinFileDescriptorBo) joinStatBo; + timestamps.add(joinFileDescriptorBo.getTimestamp()); + openFileDescriptorCountAnalyzerBuilder.addValue(joinFileDescriptorBo.getAvgOpenFDCount()); + minOpenFileDescriptorCountAnalyzerBuilder.addValue(joinFileDescriptorBo.getMinOpenFDCount()); + minOpenFileDescriptorCountIdAnalyzerBuilder.addValue(joinFileDescriptorBo.getMinOpenFDCountAgentId()); + maxOpenFileDescriptorCountAnalyzerBuilder.addValue(joinFileDescriptorBo.getMaxOpenFDCount()); + maxOpenFileDescriptorCountIdAnalyzerBuilder.addValue(joinFileDescriptorBo.getMaxOpenFDCountAgentId()); + + } + codec.encodeTimestamps(valueBuffer, timestamps); + encodeDataPoints(valueBuffer, openFileDescriptorCountAnalyzerBuilder.build(), minOpenFileDescriptorCountAnalyzerBuilder.build(), minOpenFileDescriptorCountIdAnalyzerBuilder.build(), maxOpenFileDescriptorCountAnalyzerBuilder.build(), maxOpenFileDescriptorCountIdAnalyzerBuilder.build()); + } + + private void encodeDataPoints(Buffer valueBuffer, + StrategyAnalyzer openFileDescriptorCountAnalyzer, + StrategyAnalyzer minOpenFileDescriptorCountAnalyzer, + StrategyAnalyzer minOpenFileDescriptorCountIdAnalyzer, + StrategyAnalyzer maxOpenFileDescriptorCountAnalyzer, + StrategyAnalyzer maxOpenFileDescriptorCountIdAnalyzer) { + // encode header + AgentStatHeaderEncoder headerEncoder = new BitCountingHeaderEncoder(); + headerEncoder.addCode(openFileDescriptorCountAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minOpenFileDescriptorCountAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(minOpenFileDescriptorCountIdAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxOpenFileDescriptorCountAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(maxOpenFileDescriptorCountIdAnalyzer.getBestStrategy().getCode()); + + final byte[] header = headerEncoder.getHeader(); + valueBuffer.putPrefixedBytes(header); + // encode values + this.codec.encodeValues(valueBuffer, openFileDescriptorCountAnalyzer.getBestStrategy(), openFileDescriptorCountAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minOpenFileDescriptorCountAnalyzer.getBestStrategy(), minOpenFileDescriptorCountAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, minOpenFileDescriptorCountIdAnalyzer.getBestStrategy(), minOpenFileDescriptorCountIdAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxOpenFileDescriptorCountAnalyzer.getBestStrategy(), maxOpenFileDescriptorCountAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, maxOpenFileDescriptorCountIdAnalyzer.getBestStrategy(), maxOpenFileDescriptorCountIdAnalyzer.getValues()); + + } + + @Override + public List decodeValues(Buffer valueBuffer, ApplicationStatDecodingContext decodingContext) { + final String id = decodingContext.getApplicationId(); + final long baseTimestamp = decodingContext.getBaseTimestamp(); + final long timestampDelta = decodingContext.getTimestampDelta(); + final long initialTimestamp = baseTimestamp + timestampDelta; + + int numValues = valueBuffer.readVInt(); + List timestamps = this.codec.decodeTimestamps(initialTimestamp, valueBuffer, numValues); + + // decode headers + final byte[] header = valueBuffer.readPrefixedBytes(); + AgentStatHeaderDecoder headerDecoder = new BitCountingHeaderDecoder(header); + EncodingStrategy openFileDescriptorCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minOpenFileDescriptorCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy minOpenFileDescriptorCountIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxOpenFileDescriptorCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy maxOpenFileDescriptorCountIdEncodingStrategy = StringEncodingStrategy.getFromCode(headerDecoder.getCode()); + + + // decode values + List openFileDescriptorCounts = this.codec.decodeValues(valueBuffer, openFileDescriptorCountEncodingStrategy, numValues); + List minOpenFileDescriptorCounts = this.codec.decodeValues(valueBuffer, minOpenFileDescriptorCountEncodingStrategy, numValues); + List minOpenFileDescriptorCountAgentIds = this.codec.decodeValues(valueBuffer, minOpenFileDescriptorCountIdEncodingStrategy, numValues); + List maxOpenFileDescriptorCounts = this.codec.decodeValues(valueBuffer, maxOpenFileDescriptorCountEncodingStrategy, numValues); + List maxOpenFileDescriptorCountAgentIds = this.codec.decodeValues(valueBuffer, maxOpenFileDescriptorCountIdEncodingStrategy, numValues); + + + List joinFileDescriptorBoList = new ArrayList(numValues); + for (int i = 0; i < numValues; i++) { + JoinFileDescriptorBo joinFileDescriptorBo = new JoinFileDescriptorBo(); + joinFileDescriptorBo.setId(id); + joinFileDescriptorBo.setTimestamp(timestamps.get(i)); + joinFileDescriptorBo.setAvgOpenFDCount(openFileDescriptorCounts.get(i)); + joinFileDescriptorBo.setMinOpenFDCount(minOpenFileDescriptorCounts.get(i)); + joinFileDescriptorBo.setMinOpenFDCountAgentId(minOpenFileDescriptorCountAgentIds.get(i)); + joinFileDescriptorBo.setMaxOpenFDCount(maxOpenFileDescriptorCounts.get(i)); + joinFileDescriptorBo.setMaxOpenFDCountAgentId(maxOpenFileDescriptorCountAgentIds.get(i)); + joinFileDescriptorBoList.add(joinFileDescriptorBo); + } + return joinFileDescriptorBoList; + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorDecoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorDecoder.java new file mode 100644 index 000000000000..8da65fa17211 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorDecoder.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.codec.stat.join; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.ApplicationStatDecoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Component("joinFileDescriptorDecoder") +public class FileDescriptorDecoder extends ApplicationStatDecoder { + + @Autowired + public FileDescriptorDecoder(List fileDescriptorCodecList) { + super(fileDescriptorCodecList); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorEncoder.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorEncoder.java new file mode 100644 index 000000000000..4da4a426372e --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorEncoder.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.codec.stat.join; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.ApplicationStatCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.ApplicationStatEncoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * @author Roy Kim + */ +public class FileDescriptorEncoder extends ApplicationStatEncoder { + + @Autowired + private FileDescriptorEncoder(@Qualifier("joinFileDescriptorCodec") ApplicationStatCodec fileDescriptorCodec) { + super(fileDescriptorCodec); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DeadlockCodecV2.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DeadlockCodecV2.java index 3a0036d315d2..f50ed3821f39 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DeadlockCodecV2.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DeadlockCodecV2.java @@ -26,7 +26,7 @@ import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.StrategyAnalyzer; import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.UnsignedIntegerEncodingStrategy; import com.navercorp.pinpoint.common.server.bo.codec.strategy.EncodingStrategy; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.Assert; @@ -37,7 +37,7 @@ * @author Taejin Koo */ @Component("deadlockCodecV2") -public class DeadlockCodecV2 extends AgentStatCodecV2 { +public class DeadlockCodecV2 extends AgentStatCodecV2 { @Autowired public DeadlockCodecV2(AgentStatDataPointCodec codec) { @@ -45,7 +45,7 @@ public DeadlockCodecV2(AgentStatDataPointCodec codec) { } - private static class DeadlockCodecFactory implements CodecFactory { + private static class DeadlockCodecFactory implements CodecFactory { private final AgentStatDataPointCodec codec; @@ -60,17 +60,17 @@ public AgentStatDataPointCodec getCodec() { } @Override - public CodecEncoder createCodecEncoder() { + public CodecEncoder createCodecEncoder() { return new DeadlockCodecEncoder(codec); } @Override - public CodecDecoder createCodecDecoder() { + public CodecDecoder createCodecDecoder() { return new DeadlockCodecDecoder(codec); } } - private static class DeadlockCodecEncoder implements AgentStatCodec.CodecEncoder { + private static class DeadlockCodecEncoder implements AgentStatCodec.CodecEncoder { private final AgentStatDataPointCodec codec; private final UnsignedIntegerEncodingStrategy.Analyzer.Builder deadlockedThreadCountAnalyzerBuilder = new UnsignedIntegerEncodingStrategy.Analyzer.Builder(); @@ -81,8 +81,8 @@ private DeadlockCodecEncoder(AgentStatDataPointCodec codec) { } @Override - public void addValue(DeadlockBo deadlockBo) { - deadlockedThreadCountAnalyzerBuilder.addValue(deadlockBo.getDeadlockedThreadCount()); + public void addValue(DeadlockThreadCountBo deadlockThreadCountBo) { + deadlockedThreadCountAnalyzerBuilder.addValue(deadlockThreadCountBo.getDeadlockedThreadCount()); } @Override @@ -102,7 +102,7 @@ public void encode(Buffer valueBuffer) { } - private static class DeadlockCodecDecoder implements AgentStatCodec.CodecDecoder { + private static class DeadlockCodecDecoder implements AgentStatCodec.CodecDecoder { private final AgentStatDataPointCodec codec; @@ -122,10 +122,10 @@ public void decode(Buffer valueBuffer, AgentStatHeaderDecoder headerDecoder, int } @Override - public DeadlockBo getValue(int index) { - DeadlockBo deadlockBo = new DeadlockBo(); - deadlockBo.setDeadlockedThreadCount(deadlockedThreadCountList.get(index)); - return deadlockBo; + public DeadlockThreadCountBo getValue(int index) { + DeadlockThreadCountBo deadlockThreadCountBo = new DeadlockThreadCountBo(); + deadlockThreadCountBo.setDeadlockedThreadCount(deadlockedThreadCountList.get(index)); + return deadlockThreadCountBo; } } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DirectBufferCodecV2.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DirectBufferCodecV2.java new file mode 100644 index 000000000000..da2be0d6c1b4 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DirectBufferCodecV2.java @@ -0,0 +1,159 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat.v2; + +import com.navercorp.pinpoint.common.buffer.Buffer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatDataPointCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.CodecFactory; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.AgentStatHeaderDecoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.AgentStatHeaderEncoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.BitCountingHeaderEncoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.StrategyAnalyzer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.UnsignedLongEncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.codec.strategy.EncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Component("directBufferCodecV2") +public class DirectBufferCodecV2 extends AgentStatCodecV2 { + + @Autowired + public DirectBufferCodecV2(AgentStatDataPointCodec codec) { + super(new DirectBufferCodecFactory(codec)); + } + + + private static class DirectBufferCodecFactory implements CodecFactory { + + private final AgentStatDataPointCodec codec; + + private DirectBufferCodecFactory(AgentStatDataPointCodec codec) { + Assert.notNull(codec, "codec must not be null"); + this.codec = codec; + } + + @Override + public AgentStatDataPointCodec getCodec() { + return codec; + } + + @Override + public CodecEncoder createCodecEncoder() { + return new DirectBufferCodecEncoder(codec); + } + + @Override + public CodecDecoder createCodecDecoder() { + return new DirectBufferCodecDecoder(codec); + } + } + + public static class DirectBufferCodecEncoder implements CodecEncoder { + + private final AgentStatDataPointCodec codec; + private final UnsignedLongEncodingStrategy.Analyzer.Builder directCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + private final UnsignedLongEncodingStrategy.Analyzer.Builder directMemoryUsedAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + private final UnsignedLongEncodingStrategy.Analyzer.Builder mappedCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + private final UnsignedLongEncodingStrategy.Analyzer.Builder mappedMemoryUsedAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + + + public DirectBufferCodecEncoder(AgentStatDataPointCodec codec) { + Assert.notNull(codec, "codec must not be null"); + this.codec = codec; + } + + @Override + public void addValue(DirectBufferBo directBufferBo) { + directCountAnalyzerBuilder.addValue(directBufferBo.getDirectCount()); + directMemoryUsedAnalyzerBuilder.addValue(directBufferBo.getDirectMemoryUsed()); + mappedCountAnalyzerBuilder.addValue(directBufferBo.getMappedCount()); + mappedMemoryUsedAnalyzerBuilder.addValue(directBufferBo.getMappedMemoryUsed()); + } + + @Override + public void encode(Buffer valueBuffer) { + StrategyAnalyzer directCountStrategyAnalyzer = directCountAnalyzerBuilder.build(); + StrategyAnalyzer directMemoryUsedStrategyAnalyzer = directMemoryUsedAnalyzerBuilder.build(); + StrategyAnalyzer mappedCountStrategyAnalyzer = mappedCountAnalyzerBuilder.build(); + StrategyAnalyzer mappedMemoryUsedStrategyAnalyzer = mappedMemoryUsedAnalyzerBuilder.build(); + + + // encode header + AgentStatHeaderEncoder headerEncoder = new BitCountingHeaderEncoder(); + headerEncoder.addCode(directCountStrategyAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(directMemoryUsedStrategyAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(mappedCountStrategyAnalyzer.getBestStrategy().getCode()); + headerEncoder.addCode(mappedMemoryUsedStrategyAnalyzer.getBestStrategy().getCode()); + + final byte[] header = headerEncoder.getHeader(); + valueBuffer.putPrefixedBytes(header); + // encode values + this.codec.encodeValues(valueBuffer, directCountStrategyAnalyzer.getBestStrategy(), directCountStrategyAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, directMemoryUsedStrategyAnalyzer.getBestStrategy(), directMemoryUsedStrategyAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, mappedCountStrategyAnalyzer.getBestStrategy(), mappedCountStrategyAnalyzer.getValues()); + this.codec.encodeValues(valueBuffer, mappedMemoryUsedStrategyAnalyzer.getBestStrategy(), mappedMemoryUsedStrategyAnalyzer.getValues()); + } + + } + + public static class DirectBufferCodecDecoder implements CodecDecoder { + + private final AgentStatDataPointCodec codec; + + private List directCount; + private List directMemoryUsed; + private List mappedCount; + private List mappedMemoryUsed; + + public DirectBufferCodecDecoder(AgentStatDataPointCodec codec) { + Assert.notNull(codec, "codec must not be null"); + this.codec = codec; + } + + @Override + public void decode(Buffer valueBuffer, AgentStatHeaderDecoder headerDecoder, int valueSize) { + EncodingStrategy directCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy directMemoryUsedEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy mappedCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + EncodingStrategy mappedMemoryUsedCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + // decode values + this.directCount = this.codec.decodeValues(valueBuffer, directCountEncodingStrategy, valueSize); + this.directMemoryUsed = this.codec.decodeValues(valueBuffer, directMemoryUsedEncodingStrategy, valueSize); + this.mappedCount = this.codec.decodeValues(valueBuffer, mappedCountEncodingStrategy, valueSize); + this.mappedMemoryUsed = this.codec.decodeValues(valueBuffer, mappedMemoryUsedCountEncodingStrategy, valueSize); + } + + @Override + public DirectBufferBo getValue(int index) { + DirectBufferBo directBufferBo = new DirectBufferBo(); + directBufferBo.setDirectCount(directCount.get(index)); + directBufferBo.setDirectMemoryUsed(directMemoryUsed.get(index)); + directBufferBo.setMappedCount(mappedCount.get(index)); + directBufferBo.setMappedMemoryUsed(mappedMemoryUsed.get(index)); + return directBufferBo; + } + + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/FileDescriptorCodecV2.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/FileDescriptorCodecV2.java new file mode 100644 index 000000000000..757edc358c22 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/FileDescriptorCodecV2.java @@ -0,0 +1,130 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat.v2; + +import com.navercorp.pinpoint.common.buffer.Buffer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatDataPointCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.CodecFactory; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.AgentStatHeaderDecoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.AgentStatHeaderEncoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.header.BitCountingHeaderEncoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.StrategyAnalyzer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.strategy.UnsignedLongEncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.codec.strategy.EncodingStrategy; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Component("fileDescriptorCodecV2") +public class FileDescriptorCodecV2 extends AgentStatCodecV2 { + + @Autowired + public FileDescriptorCodecV2(AgentStatDataPointCodec codec) { + super(new FileDescriptorCodecFactory(codec)); + } + + + private static class FileDescriptorCodecFactory implements CodecFactory { + + private final AgentStatDataPointCodec codec; + + private FileDescriptorCodecFactory(AgentStatDataPointCodec codec) { + Assert.notNull(codec, "codec must not be null"); + this.codec = codec; + } + + @Override + public AgentStatDataPointCodec getCodec() { + return codec; + } + + @Override + public CodecEncoder createCodecEncoder() { + return new FileDescriptorCodecEncoder(codec); + } + + @Override + public CodecDecoder createCodecDecoder() { + return new FileDescriptorCodecDecoder(codec); + } + } + + public static class FileDescriptorCodecEncoder implements CodecEncoder { + + private final AgentStatDataPointCodec codec; + private final UnsignedLongEncodingStrategy.Analyzer.Builder openFileDescriptorCountAnalyzerBuilder = new UnsignedLongEncodingStrategy.Analyzer.Builder(); + + public FileDescriptorCodecEncoder(AgentStatDataPointCodec codec) { + Assert.notNull(codec, "codec must not be null"); + this.codec = codec; + } + + @Override + public void addValue(FileDescriptorBo fileDescriptorBo) { + openFileDescriptorCountAnalyzerBuilder.addValue(fileDescriptorBo.getOpenFileDescriptorCount()); + } + + @Override + public void encode(Buffer valueBuffer) { + StrategyAnalyzer openFileDescriptorCountStrategyAnalyzer = openFileDescriptorCountAnalyzerBuilder.build(); + + // encode header + AgentStatHeaderEncoder headerEncoder = new BitCountingHeaderEncoder(); + headerEncoder.addCode(openFileDescriptorCountStrategyAnalyzer.getBestStrategy().getCode()); + final byte[] header = headerEncoder.getHeader(); + valueBuffer.putPrefixedBytes(header); + // encode values + this.codec.encodeValues(valueBuffer, openFileDescriptorCountStrategyAnalyzer.getBestStrategy(), openFileDescriptorCountStrategyAnalyzer.getValues()); + + } + + } + + public static class FileDescriptorCodecDecoder implements CodecDecoder { + + private final AgentStatDataPointCodec codec; + + private List openFileDescriptorCounts; + + public FileDescriptorCodecDecoder(AgentStatDataPointCodec codec) { + Assert.notNull(codec, "codec must not be null"); + this.codec = codec; + } + + @Override + public void decode(Buffer valueBuffer, AgentStatHeaderDecoder headerDecoder, int valueSize) { + EncodingStrategy openFileDescriptorCountEncodingStrategy = UnsignedLongEncodingStrategy.getFromCode(headerDecoder.getCode()); + // decode values + this.openFileDescriptorCounts = this.codec.decodeValues(valueBuffer, openFileDescriptorCountEncodingStrategy, valueSize); + } + + @Override + public FileDescriptorBo getValue(int index) { + FileDescriptorBo fileDescriptorBo = new FileDescriptorBo(); + fileDescriptorBo.setOpenFileDescriptorCount(openFileDescriptorCounts.get(index)); + return fileDescriptorBo; + } + + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/AgentEventBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/AgentEventBo.java index 3a1b1d689b67..124f6041ccb1 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/AgentEventBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/AgentEventBo.java @@ -20,10 +20,11 @@ /** * @author HyunGil Jeong + * @author jaehong.kim - Update version & Remove hashcode, equals */ public class AgentEventBo { - public static final int CURRENT_VERSION = 0; + public static final int CURRENT_VERSION = 1; private final byte version; private final String agentId; @@ -55,7 +56,7 @@ public AgentEventBo(int version, String agentId, long startTimestamp, long event if (eventType == null) { throw new IllegalArgumentException("agentEventType cannot be null"); } - this.version = (byte)(version & 0xFF); + this.version = (byte) (version & 0xFF); this.agentId = agentId; this.startTimestamp = startTimestamp; this.eventTimestamp = eventTimestamp; @@ -90,43 +91,6 @@ public void setEventBody(byte[] eventBody) { this.eventBody = eventBody; } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((agentId == null) ? 0 : agentId.hashCode()); - result = prime * result + (int)(eventTimestamp ^ (eventTimestamp >>> 32)); - result = prime * result + ((eventType == null) ? 0 : eventType.hashCode()); - result = prime * result + (int)(startTimestamp ^ (startTimestamp >>> 32)); - result = prime * result + version; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - AgentEventBo other = (AgentEventBo)obj; - if (agentId == null) { - if (other.agentId != null) - return false; - } else if (!agentId.equals(other.agentId)) - return false; - if (eventTimestamp != other.eventTimestamp) - return false; - if (eventType != other.eventType) - return false; - if (startTimestamp != other.startTimestamp) - return false; - if (version != other.version) - return false; - return true; - } - @Override public String toString() { final StringBuilder sb = new StringBuilder("AgentEventBo{"); diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/DeadlockBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/DeadlockBo.java new file mode 100644 index 000000000000..dd43487f2570 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/DeadlockBo.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.event; + +import java.util.List; + +/** + * @author jaehong.kim + */ +public class DeadlockBo { + public static final int UNCOLLECTED_INT_VALUE = -1; + + private int deadlockedThreadCount = UNCOLLECTED_INT_VALUE; + private List threadDumpBoList; + + public int getDeadlockedThreadCount() { + return deadlockedThreadCount; + } + + public void setDeadlockedThreadCount(int deadlockedThreadCount) { + this.deadlockedThreadCount = deadlockedThreadCount; + } + + public List getThreadDumpBoList() { + return threadDumpBoList; + } + + public void setThreadDumpBoList(List threadDumpBoList) { + this.threadDumpBoList = threadDumpBoList; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DeadlockBo{"); + sb.append("deadlockedThreadCount=").append(deadlockedThreadCount); + sb.append(", threadDumpBoList=").append(threadDumpBoList); + sb.append('}'); + return sb.toString(); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/DeadlockEventBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/DeadlockEventBo.java index f24ab67bb7f5..029b636ded7d 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/DeadlockEventBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/DeadlockEventBo.java @@ -17,60 +17,29 @@ package com.navercorp.pinpoint.common.server.bo.event; import com.navercorp.pinpoint.common.server.util.AgentEventType; -import com.navercorp.pinpoint.thrift.dto.TDeadlock; /** * @author Taejin Koo + * @author jaehong.kim - Replace TDeadlock to DeadlockBo */ public class DeadlockEventBo extends AgentEventBo { - private final TDeadlock deadlock; + private final DeadlockBo deadlockBo; - public DeadlockEventBo(String agentId, long startTimestamp, long eventTimestamp, AgentEventType eventType, TDeadlock deadlock) { + public DeadlockEventBo(String agentId, long startTimestamp, long eventTimestamp, AgentEventType eventType, DeadlockBo deadlockBo) { super(agentId, startTimestamp, eventTimestamp, eventType); - this.deadlock = deadlock; + this.deadlockBo = deadlockBo; } - public TDeadlock getDeadlock() { - return deadlock; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - - DeadlockEventBo that = (DeadlockEventBo) o; - - return deadlock != null ? deadlock.equals(that.deadlock) : that.deadlock == null; - - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((getAgentId() == null) ? 0 : getAgentId().hashCode()); - result = prime * result + (int)(getEventTimestamp() ^ (getEventTimestamp() >>> 32)); - result = prime * result + ((getEventType() == null) ? 0 : getEventType().hashCode()); - result = prime * result + (int)(getStartTimestamp() ^ (getStartTimestamp() >>> 32)); - result = prime * result + getVersion(); - result = prime * result + (deadlock != null ? deadlock.hashCode() : 0); - return result; + public DeadlockBo getDeadlockBo() { + return deadlockBo; } @Override public String toString() { - final StringBuilder sb = new StringBuilder("AgentEventBo{"); - sb.append("version=").append(this.getVersion()); - sb.append(", agentId='").append(this.getAgentId()).append('\''); - sb.append(", startTimestamp=").append(this.getStartTimestamp()); - sb.append(", eventTimestamp=").append(this.getEventTimestamp()); - sb.append(", eventType='").append(this.getEventType().getDesc()).append('\''); - sb.append(", deadlock=").append(deadlock).append('\''); + final StringBuilder sb = new StringBuilder("DeadlockEventBo{"); + sb.append("deadlockBo=").append(deadlockBo); sb.append('}'); return sb.toString(); } - } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/MonitorInfoBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/MonitorInfoBo.java new file mode 100644 index 000000000000..e4cc7bc3010c --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/MonitorInfoBo.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.event; + +/** + * @author jaehong.kim + */ +public class MonitorInfoBo { + private int stackDepth; + private String stackFrame; + + public int getStackDepth() { + return stackDepth; + } + + public void setStackDepth(int stackDepth) { + this.stackDepth = stackDepth; + } + + public String getStackFrame() { + return stackFrame; + } + + public void setStackFrame(String stackFrame) { + this.stackFrame = stackFrame; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("MonitorInfoBo{"); + sb.append("stackDepth=").append(stackDepth); + sb.append(", stackFrame='").append(stackFrame).append('\''); + sb.append('}'); + return sb.toString(); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/ThreadDumpBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/ThreadDumpBo.java new file mode 100644 index 000000000000..a865f8128809 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/ThreadDumpBo.java @@ -0,0 +1,182 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.event; + +import java.util.List; + +/** + * @author jaehong.kim + */ +public class ThreadDumpBo { + private String threadName; + private long threadId; + private long blockedTime; + private long blockedCount; + private long waitedTime; + private long waitedCount; + private String lockName; + private long lockOwnerId; + private String lockOwnerName; + private boolean inNative; + private boolean suspended; + private ThreadState threadState; + private List stackTraceList; + private List lockedMonitorInfoList; + private List lockedSynchronizerList; + + public String getThreadName() { + return threadName; + } + + public void setThreadName(String threadName) { + this.threadName = threadName; + } + + public long getThreadId() { + return threadId; + } + + public void setThreadId(long threadId) { + this.threadId = threadId; + } + + public long getBlockedTime() { + return blockedTime; + } + + public void setBlockedTime(long blockedTime) { + this.blockedTime = blockedTime; + } + + public long getBlockedCount() { + return blockedCount; + } + + public void setBlockedCount(long blockedCount) { + this.blockedCount = blockedCount; + } + + public long getWaitedTime() { + return waitedTime; + } + + public void setWaitedTime(long waitedTime) { + this.waitedTime = waitedTime; + } + + public long getWaitedCount() { + return waitedCount; + } + + public void setWaitedCount(long waitedCount) { + this.waitedCount = waitedCount; + } + + public String getLockName() { + return lockName; + } + + public void setLockName(String lockName) { + this.lockName = lockName; + } + + public long getLockOwnerId() { + return lockOwnerId; + } + + public void setLockOwnerId(long lockOwnerId) { + this.lockOwnerId = lockOwnerId; + } + + public String getLockOwnerName() { + return lockOwnerName; + } + + public void setLockOwnerName(String lockOwnerName) { + this.lockOwnerName = lockOwnerName; + } + + public boolean isInNative() { + return inNative; + } + + public void setInNative(boolean inNative) { + this.inNative = inNative; + } + + public boolean isSuspended() { + return suspended; + } + + public void setSuspended(boolean suspended) { + this.suspended = suspended; + } + + public ThreadState getThreadState() { + return threadState; + } + + public void setThreadState(ThreadState threadState) { + this.threadState = threadState; + } + + public List getStackTraceList() { + return stackTraceList; + } + + public void setStackTraceList(List stackTraceList) { + this.stackTraceList = stackTraceList; + } + + public List getLockedMonitorInfoList() { + return lockedMonitorInfoList; + } + + public void setLockedMonitorInfoList(List lockedMonitorInfoList) { + this.lockedMonitorInfoList = lockedMonitorInfoList; + } + + public List getLockedSynchronizerList() { + return lockedSynchronizerList; + } + + public void setLockedSynchronizerList(List lockedSynchronizerList) { + this.lockedSynchronizerList = lockedSynchronizerList; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ThreadDumpBo{"); + sb.append("threadName='").append(threadName).append('\''); + sb.append(", threadId=").append(threadId); + sb.append(", blockedTime=").append(blockedTime); + sb.append(", blockedCount=").append(blockedCount); + sb.append(", waitedTime=").append(waitedTime); + sb.append(", waitedCount=").append(waitedCount); + sb.append(", lockName='").append(lockName).append('\''); + sb.append(", lockOwnerId=").append(lockOwnerId); + sb.append(", lockOwnerName='").append(lockOwnerName).append('\''); + sb.append(", inNative=").append(inNative); + sb.append(", suspended=").append(suspended); + sb.append(", threadState=").append(threadState); + sb.append(", stackTraceList=").append(stackTraceList); + sb.append(", lockedMonitorInfoList=").append(lockedMonitorInfoList); + sb.append(", lockedSynchronizerList=").append(lockedSynchronizerList); + sb.append('}'); + return sb.toString(); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/ThreadState.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/ThreadState.java new file mode 100644 index 000000000000..9a9d830ce19f --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/event/ThreadState.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.navercorp.pinpoint.common.server.bo.event; + +/** + * @author jaehong.kim - Copy TThreadState + */ +public enum ThreadState { + NEW(0), + RUNNABLE(1), + BLOCKED(2), + WAITING(3), + TIMED_WAITING(4), + TERMINATED(5), + UNKNOWN(6); + + private final int value; + + private ThreadState(int value) { + this.value = value; + } + + public int getValue() { + return this.value; + } + + public static ThreadState findByValue(int value) { + switch (value) { + case 0: + return NEW; + case 1: + return RUNNABLE; + case 2: + return BLOCKED; + case 3: + return WAITING; + case 4: + return TIMED_WAITING; + case 5: + return TERMINATED; + case 6: + return UNKNOWN; + default: + return null; + } + } +} \ No newline at end of file diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/DeadlockSerializer.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/DeadlockSerializer.java deleted file mode 100644 index 4313aec5316a..000000000000 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/DeadlockSerializer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.common.server.bo.serializer.stat; - -import com.navercorp.pinpoint.common.server.bo.codec.stat.DeadlockEncoder; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -/** - * @author Taejin Koo - */ -@Component -public class DeadlockSerializer extends AgentStatSerializer { - - @Autowired - public DeadlockSerializer(DeadlockEncoder deadlockEncoder) { - super(deadlockEncoder); - } - -} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/DeadlockThreadCountSerializer.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/DeadlockThreadCountSerializer.java new file mode 100644 index 000000000000..95f0eb5c6f6b --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/DeadlockThreadCountSerializer.java @@ -0,0 +1,35 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.serializer.stat; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.DeadlockEncoder; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Taejin Koo + */ +@Component +public class DeadlockThreadCountSerializer extends AgentStatSerializer { + + @Autowired + public DeadlockThreadCountSerializer(DeadlockEncoder deadlockEncoder) { + super(deadlockEncoder); + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/DirectBufferSerializer.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/DirectBufferSerializer.java new file mode 100644 index 000000000000..92f9b5311459 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/DirectBufferSerializer.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.serializer.stat; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.DirectBufferEncoder; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Roy Kim + */ +@Component +public class DirectBufferSerializer extends AgentStatSerializer { + + @Autowired + public DirectBufferSerializer(DirectBufferEncoder directBufferEncoder) { + super(directBufferEncoder); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/FileDescriptorSerializer.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/FileDescriptorSerializer.java new file mode 100644 index 000000000000..566d8a0a8cea --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/FileDescriptorSerializer.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.serializer.stat; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.CpuLoadEncoder; +import com.navercorp.pinpoint.common.server.bo.codec.stat.FileDescriptorEncoder; +import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Roy Kim + */ +@Component +public class FileDescriptorSerializer extends AgentStatSerializer { + + @Autowired + public FileDescriptorSerializer(FileDescriptorEncoder fileDescriptorEncoder) { + super(fileDescriptorEncoder); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/DataSourceSerializer.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/DataSourceSerializer.java index 6204ffdc2575..87f39230e23d 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/DataSourceSerializer.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/DataSourceSerializer.java @@ -16,7 +16,6 @@ package com.navercorp.pinpoint.common.server.bo.serializer.stat.join; import com.navercorp.pinpoint.common.server.bo.codec.stat.join.DataSourceEncoder; -import com.navercorp.pinpoint.common.server.bo.codec.stat.join.ResponseTimeEncoder; import org.springframework.beans.factory.annotation.Autowired; /** diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/DirectBufferSerializer.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/DirectBufferSerializer.java new file mode 100644 index 000000000000..9a9d3a88c5dd --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/DirectBufferSerializer.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.serializer.stat.join; + + +import com.navercorp.pinpoint.common.server.bo.codec.stat.join.DirectBufferEncoder; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author Roy Kim + */ +public class DirectBufferSerializer extends ApplicationStatSerializer { + + @Autowired + public DirectBufferSerializer(DirectBufferEncoder directBufferEncoder) { + super(directBufferEncoder); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/FileDescriptorSerializer.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/FileDescriptorSerializer.java new file mode 100644 index 000000000000..b773d89494da --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/stat/join/FileDescriptorSerializer.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.serializer.stat.join; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.join.FileDescriptorEncoder; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author Roy Kim + */ +public class FileDescriptorSerializer extends ApplicationStatSerializer { + + @Autowired + public FileDescriptorSerializer(FileDescriptorEncoder fileDescriptorEncoder) { + super(fileDescriptorEncoder); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanDecoderV0.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanDecoderV0.java index efc7e8e2bb96..38e02e04dfb7 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanDecoderV0.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanDecoderV0.java @@ -9,8 +9,8 @@ import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield.SpanBitFiled; import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield.SpanEventBitField; import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield.SpanEventQualifierBitField; -import com.navercorp.pinpoint.common.util.AnnotationTranscoder; import com.navercorp.pinpoint.common.util.TransactionId; +import com.navercorp.pinpoint.io.util.AnnotationTranscoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanEncoderV0.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanEncoderV0.java index 501289674b6c..9311b82be183 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanEncoderV0.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanEncoderV0.java @@ -9,7 +9,7 @@ import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield.SpanBitFiled; import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield.SpanEventBitField; import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield.SpanEventQualifierBitField; -import com.navercorp.pinpoint.common.util.AnnotationTranscoder; +import com.navercorp.pinpoint.io.util.AnnotationTranscoder; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/bitfield/SpanEventBitField.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/bitfield/SpanEventBitField.java index 524cbcc018e8..58aed970bacf 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/bitfield/SpanEventBitField.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/bitfield/SpanEventBitField.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield; import com.navercorp.pinpoint.common.server.bo.AnnotationBo; @@ -197,11 +213,12 @@ void setDestinationId(boolean destinationId) { setBit(SET_DESTINATIONID, destinationId); } - + @Deprecated public boolean isSetRpc() { return testBit(SET_RPC); } + @Deprecated void setRpc(boolean rpc) { setBit(SET_RPC, rpc); } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/AgentStatBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/AgentStatBo.java index 4588fdf20e6e..a4f259147784 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/AgentStatBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/AgentStatBo.java @@ -34,7 +34,9 @@ public class AgentStatBo { private List activeTraceBos; private List dataSourceListBos; private List responseTimeBos; - private List deadlockBos; + private List deadlockThreadCountBos; + private List fileDescriptorBos; + private List directBufferBos; public long getStartTimestamp() { return startTimestamp; @@ -108,14 +110,26 @@ public void setResponseTimeBos(List responseTimeBos) { this.responseTimeBos = responseTimeBos; } - public List getDeadlockBos() { - return deadlockBos; + public List getDeadlockThreadCountBos() { + return deadlockThreadCountBos; } - public void setDeadlockBos(List deadlockBos) { - this.deadlockBos = deadlockBos; + public void setDeadlockThreadCountBos(List deadlockThreadCountBos) { + this.deadlockThreadCountBos = deadlockThreadCountBos; } + public List getFileDescriptorBos() { + return fileDescriptorBos; + } + + public void setFileDescriptorBos(List fileDescriptorBos) { + this.fileDescriptorBos = fileDescriptorBos; + } + + public List getDirectBufferBos() { return directBufferBos; } + + public void setDirectBufferBos(List directBufferBos) { this.directBufferBos = directBufferBos; } + @Override public String toString() { final StringBuilder sb = new StringBuilder("AgentStatBo{"); @@ -127,7 +141,9 @@ public String toString() { sb.append(", activeTraceBos=").append(activeTraceBos); sb.append(", dataSourceListBos=").append(dataSourceListBos); sb.append(", responseTimeBos=").append(responseTimeBos); - sb.append(", deadlockBos=").append(deadlockBos); + sb.append(", deadlockThreadCountBos=").append(deadlockThreadCountBos); + sb.append(", fileDescriptorBos=").append(fileDescriptorBos); + sb.append(", directBufferBos=").append(directBufferBos); sb.append('}'); return sb.toString(); } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/AgentStatType.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/AgentStatType.java index 7b46827bb698..c6b3fb84cea7 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/AgentStatType.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/AgentStatType.java @@ -31,7 +31,10 @@ public enum AgentStatType { ACTIVE_TRACE((byte) 5, "Active Trace"), DATASOURCE((byte) 6, "DataSource"), RESPONSE_TIME((byte) 7, "Response Time"), - DEADLOCK((byte) 8, "Deadlock"); + DEADLOCK((byte) 8, "Deadlock"), + FILE_DESCRIPTOR((byte) 9, "FileDescriptor"), + DIRECT_BUFFER((byte) 10, "DirectBuffer"); + public static final int TYPE_CODE_BYTE_LENGTH = 1; diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/DeadlockBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/DeadlockBo.java deleted file mode 100644 index 7dafa0b9e2db..000000000000 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/DeadlockBo.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.common.server.bo.stat; - -import com.navercorp.pinpoint.thrift.dto.command.TThreadDump; - -import java.util.List; - -/** - * @author Taejin Koo - */ -public class DeadlockBo implements AgentWarningStatDataPoint { - - public static final int UNCOLLECTED_INT_VALUE = -1; - - private String agentId; - private long startTimestamp; - private long timestamp; - private int deadlockedThreadCount = UNCOLLECTED_INT_VALUE; - private List threadDumpList; - - @Override - public String getAgentId() { - return agentId; - } - - @Override - public void setAgentId(String agentId) { - this.agentId = agentId; - } - - @Override - public long getStartTimestamp() { - return startTimestamp; - } - - @Override - public void setStartTimestamp(long startTimestamp) { - this.startTimestamp = startTimestamp; - } - - @Override - public long getTimestamp() { - return timestamp; - } - - @Override - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - @Override - public AgentStatType getAgentStatType() { - return AgentStatType.DEADLOCK; - } - - public int getDeadlockedThreadCount() { - return deadlockedThreadCount; - } - - public void setDeadlockedThreadCount(int deadlockedThreadCount) { - this.deadlockedThreadCount = deadlockedThreadCount; - } - - public List getThreadDumpList() { - return threadDumpList; - } - - public void setThreadDumpList(List threadDumpList) { - this.threadDumpList = threadDumpList; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("DeadlockBo{"); - sb.append("agentId='").append(agentId).append('\''); - sb.append(", startTimestamp=").append(startTimestamp); - sb.append(", timestamp=").append(timestamp); - sb.append(", deadlockedThreadCount=").append(deadlockedThreadCount); - sb.append(", threadDumpList=").append(threadDumpList); - sb.append('}'); - return sb.toString(); - } - -} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/DeadlockThreadCountBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/DeadlockThreadCountBo.java new file mode 100644 index 000000000000..57e7ed927bc6 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/DeadlockThreadCountBo.java @@ -0,0 +1,86 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.stat; + +/** + * @author Taejin Koo + * @author jaehong.kim - Remove TThreadDump List + */ +public class DeadlockThreadCountBo implements AgentWarningStatDataPoint { + + public static final int UNCOLLECTED_INT_VALUE = -1; + + private String agentId; + private long startTimestamp; + private long timestamp; + private int deadlockedThreadCount = UNCOLLECTED_INT_VALUE; + + @Override + public String getAgentId() { + return agentId; + } + + @Override + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + @Override + public long getStartTimestamp() { + return startTimestamp; + } + + @Override + public void setStartTimestamp(long startTimestamp) { + this.startTimestamp = startTimestamp; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + @Override + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + @Override + public AgentStatType getAgentStatType() { + return AgentStatType.DEADLOCK; + } + + public int getDeadlockedThreadCount() { + return deadlockedThreadCount; + } + + public void setDeadlockedThreadCount(int deadlockedThreadCount) { + this.deadlockedThreadCount = deadlockedThreadCount; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DeadlockThreadCountBo{"); + sb.append("agentId='").append(agentId).append('\''); + sb.append(", startTimestamp=").append(startTimestamp); + sb.append(", timestamp=").append(timestamp); + sb.append(", deadlockedThreadCount=").append(deadlockedThreadCount); + sb.append('}'); + return sb.toString(); + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/DirectBufferBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/DirectBufferBo.java new file mode 100644 index 000000000000..756e3f1b8db4 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/DirectBufferBo.java @@ -0,0 +1,144 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.stat; + +/** + * @author Roy Kim + */ +public class DirectBufferBo implements AgentStatDataPoint { + + public static final long UNCOLLECTED_VALUE = -1; + + private String agentId; + private long startTimestamp; + private long timestamp; + + private long directCount = UNCOLLECTED_VALUE;; + private long directMemoryUsed = UNCOLLECTED_VALUE;; + private long mappedCount = UNCOLLECTED_VALUE;; + private long mappedMemoryUsed = UNCOLLECTED_VALUE;; + + @Override + public String getAgentId() { + return agentId; + } + + @Override + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + @Override + public long getStartTimestamp() { + return startTimestamp; + } + + @Override + public void setStartTimestamp(long startTimestamp) { + this.startTimestamp = startTimestamp; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + @Override + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + @Override + public AgentStatType getAgentStatType() { + return AgentStatType.DIRECT_BUFFER; + } + + public long getDirectCount() { + return directCount; + } + + public void setDirectCount(long directCount) { + this.directCount = directCount; + } + + public long getDirectMemoryUsed() { + return directMemoryUsed; + } + + public void setDirectMemoryUsed(long directMemoryUsed) { + this.directMemoryUsed = directMemoryUsed; + } + + public long getMappedCount() { + return mappedCount; + } + + public void setMappedCount(long mappedCount) { + this.mappedCount = mappedCount; + } + + public long getMappedMemoryUsed() { + return mappedMemoryUsed; + } + + public void setMappedMemoryUsed(long mappedMemoryUsed) { + this.mappedMemoryUsed = mappedMemoryUsed; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DirectBufferBo directBufferBo = (DirectBufferBo) o; + + if (startTimestamp != directBufferBo.startTimestamp) return false; + if (timestamp != directBufferBo.timestamp) return false; + if (directCount != directBufferBo.directCount) return false; + if (directMemoryUsed != directBufferBo.directMemoryUsed) return false; + if (mappedCount != directBufferBo.mappedCount) return false; + if (mappedMemoryUsed != directBufferBo.mappedMemoryUsed) return false; + return agentId != null ? agentId.equals(directBufferBo.agentId) : directBufferBo.agentId == null; + + } + + @Override + public int hashCode() { + int result; + result = agentId != null ? agentId.hashCode() : 0; + result = 31 * result + (int) (startTimestamp ^ (startTimestamp >>> 32)); + result = 31 * result + (int) (timestamp ^ (timestamp >>> 32)); + result = 31 * result + (int) (directCount ^ (directCount >>> 32)); + result = 31 * result + (int) (directMemoryUsed ^ (directMemoryUsed >>> 32)); + result = 31 * result + (int) (mappedCount ^ (mappedCount >>> 32)); + result = 31 * result + (int) (mappedMemoryUsed ^ (mappedMemoryUsed >>> 32)); + return result; + } + + @Override + public String toString() { + return "DirectBufferBo{" + + "agentId='" + agentId + '\'' + + ", startTimestamp=" + startTimestamp + + ", timestamp=" + timestamp + + ", directCount=" + directCount + + ", directMemoryUsed=" + directMemoryUsed + + ", mappedCount=" + mappedCount + + ", mappedMemoryUsed=" + mappedMemoryUsed + + '}'; + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/FileDescriptorBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/FileDescriptorBo.java new file mode 100644 index 000000000000..9930e3d38885 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/FileDescriptorBo.java @@ -0,0 +1,109 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.stat; + +/** + * @author Roy Kim + */ +public class FileDescriptorBo implements AgentStatDataPoint { + + public static final long UNCOLLECTED_VALUE = -1; + + private String agentId; + private long startTimestamp; + private long timestamp; + + private long openFileDescriptorCount = UNCOLLECTED_VALUE; + + @Override + public String getAgentId() { + return agentId; + } + + @Override + public void setAgentId(String agentId) { + this.agentId = agentId; + } + + @Override + public long getStartTimestamp() { + return startTimestamp; + } + + @Override + public void setStartTimestamp(long startTimestamp) { + this.startTimestamp = startTimestamp; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + @Override + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + @Override + public AgentStatType getAgentStatType() { + return AgentStatType.FILE_DESCRIPTOR; + } + + public long getOpenFileDescriptorCount() { + return openFileDescriptorCount; + } + + public void setOpenFileDescriptorCount(long openFileDescriptorCount) { + this.openFileDescriptorCount = openFileDescriptorCount; + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + FileDescriptorBo fileDescriptorBo = (FileDescriptorBo) o; + + if (startTimestamp != fileDescriptorBo.startTimestamp) return false; + if (timestamp != fileDescriptorBo.timestamp) return false; + if (openFileDescriptorCount != fileDescriptorBo.openFileDescriptorCount) return false; + return agentId != null ? agentId.equals(fileDescriptorBo.agentId) : fileDescriptorBo.agentId == null; + + } + + @Override + public int hashCode() { + int result; + result = agentId != null ? agentId.hashCode() : 0; + result = 31 * result + (int) (startTimestamp ^ (startTimestamp >>> 32)); + result = 31 * result + (int) (timestamp ^ (timestamp >>> 32)); + result = 31 * result + (int) (openFileDescriptorCount ^ (openFileDescriptorCount >>> 32)); + return result; + } + + @Override + public String toString() { + return "FileDescriptorBo{" + + "agentId='" + agentId + '\'' + + ", startTimestamp=" + startTimestamp + + ", timestamp=" + timestamp + + ", openFileDescriptorCount=" + openFileDescriptorCount + + '}'; + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinAgentStatBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinAgentStatBo.java index e3df5619b9bd..7534079b2dfc 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinAgentStatBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinAgentStatBo.java @@ -35,6 +35,29 @@ public class JoinAgentStatBo implements JoinStatBo { private List joinActiveTraceBoList = Collections.emptyList(); private List joinResponseTimeBoList = Collections.emptyList(); private List joinDataSourceListBoList = Collections.emptyList(); + private List joinFileDescriptorBoList = Collections.emptyList(); + private List joinDirectBufferBoList = Collections.emptyList(); + + protected JoinAgentStatBo(JoinAgentStatBo joinAgentStatBo) { + if (joinAgentStatBo == null) { + throw new IllegalArgumentException("joinAgentStatBo cannot be null"); + } + + this.agentId = joinAgentStatBo.getId(); + this.agentStartTimestamp = joinAgentStatBo.getAgentStartTimestamp(); + this.timestamp = joinAgentStatBo.getTimestamp(); + this.joinCpuLoadBoList = joinAgentStatBo.getJoinCpuLoadBoList(); + this.joinMemoryBoList = joinAgentStatBo.getJoinMemoryBoList(); + this.joinTransactionBoList = joinAgentStatBo.getJoinTransactionBoList(); + this.joinActiveTraceBoList = joinAgentStatBo.getJoinActiveTraceBoList(); + this.joinResponseTimeBoList = joinAgentStatBo.getJoinResponseTimeBoList(); + this.joinDataSourceListBoList = joinAgentStatBo.getJoinDataSourceListBoList(); + this.joinFileDescriptorBoList = joinAgentStatBo.getJoinFileDescriptorBoList(); + this.joinDirectBufferBoList = joinAgentStatBo.getJoinDirectBufferBoList(); + } + + public JoinAgentStatBo() { + } public List getJoinResponseTimeBoList() { return joinResponseTimeBoList; @@ -68,10 +91,26 @@ public long getTimestamp() { return timestamp; } + public List getJoinFileDescriptorBoList() { + return joinFileDescriptorBoList; + } + + public void setJoinFileDescriptorBoList(List joinFileDescriptorBoList) { + this.joinFileDescriptorBoList = joinFileDescriptorBoList; + } + public List getJoinCpuLoadBoList() { return joinCpuLoadBoList; } + public List getJoinDirectBufferBoList() { + return joinDirectBufferBoList; + } + + public void setJoinDirectBufferBoList(List joinDirectBufferBoList) { + this.joinDirectBufferBoList = joinDirectBufferBoList; + } + public long getAgentStartTimestamp() { return agentStartTimestamp; } @@ -130,4 +169,21 @@ public List getJoinActiveTraceBoList() { public List getJoinDataSourceListBoList() { return joinDataSourceListBoList; } + + @Override + public String toString() { + return "JoinAgentStatBo{" + + "agentId='" + agentId + '\'' + + ", agentStartTimestamp=" + agentStartTimestamp + + ", timestamp=" + timestamp + + ", joinCpuLoadBoList=" + joinCpuLoadBoList + + ", joinMemoryBoList=" + joinMemoryBoList + + ", joinTransactionBoList=" + joinTransactionBoList + + ", joinActiveTraceBoList=" + joinActiveTraceBoList + + ", joinResponseTimeBoList=" + joinResponseTimeBoList + + ", joinDataSourceListBoList=" + joinDataSourceListBoList + + ", joinFileDescriptorBoList=" + joinFileDescriptorBoList + + ", joinDirectBufferBoList=" + joinDirectBufferBoList + + '}'; + } } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinApplicationStatBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinApplicationStatBo.java index 57a595c421a5..62b658b638af 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinApplicationStatBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinApplicationStatBo.java @@ -32,12 +32,36 @@ public class JoinApplicationStatBo implements JoinStatBo { private List joinActiveTraceBoList = Collections.emptyList(); private List joinResponseTimeBoList = Collections.emptyList(); private List joinDataSourceListBoList = Collections.emptyList(); + private List joinFileDescriptorBoList = Collections.emptyList(); + private List joinDirectBufferBoList = Collections.emptyList(); private long timestamp = Long.MIN_VALUE; private StatType statType = StatType.APP_STST; + protected JoinApplicationStatBo(JoinApplicationStatBo joinApplicationStatBo) { + if (joinApplicationStatBo == null) { + throw new IllegalArgumentException("joinApplicationStatBo cannot be null"); + } + + this.applicationId = joinApplicationStatBo.getId(); + this.joinCpuLoadBoList = joinApplicationStatBo.getJoinCpuLoadBoList(); + this.joinMemoryBoList = joinApplicationStatBo.getJoinMemoryBoList(); + this.joinTransactionBoList = joinApplicationStatBo.getJoinTransactionBoList(); + this.joinActiveTraceBoList = joinApplicationStatBo.getJoinActiveTraceBoList(); + this.joinResponseTimeBoList = joinApplicationStatBo.getJoinResponseTimeBoList(); + this.joinDataSourceListBoList = joinApplicationStatBo.getJoinDataSourceListBoList(); + this.joinFileDescriptorBoList = joinApplicationStatBo.getJoinFileDescriptorBoList(); + this.joinDirectBufferBoList = joinApplicationStatBo.getJoinDirectBufferBoList(); + + this.timestamp= joinApplicationStatBo.getTimestamp(); + this.statType = joinApplicationStatBo.getStatType(); + } + + public JoinApplicationStatBo() { + } + public static JoinApplicationStatBo joinApplicationStatBoByTimeSlice(final List joinApplicationStatBoList) { - if (joinApplicationStatBoList.size() == 0) { + if (joinApplicationStatBoList.isEmpty()) { return EMPTY_JOIN_APPLICATION_STAT_BO; } @@ -49,6 +73,8 @@ public static JoinApplicationStatBo joinApplicationStatBoByTimeSlice(final List< newJoinApplicationStatBo.setJoinActiveTraceBoList(joinActiveTraceBoByTimeSlice(joinApplicationStatBoList)); newJoinApplicationStatBo.setJoinResponseTimeBoList(joinResponseTimeBoByTimeSlice(joinApplicationStatBoList)); newJoinApplicationStatBo.setJoinDataSourceListBoList(JoinDataSourceListBoBytTimeSlice(joinApplicationStatBoList)); + newJoinApplicationStatBo.setJoinFileDescriptorBoList(joinFileDescriptorBoByTimeSlice(joinApplicationStatBoList)); + newJoinApplicationStatBo.setJoinDirectBufferBoList(joinDirectBufferBoByTimeSlice(joinApplicationStatBoList)); newJoinApplicationStatBo.setTimestamp(extractMinTimestamp(newJoinApplicationStatBo)); return newJoinApplicationStatBo; } @@ -92,6 +118,18 @@ private static long extractMinTimestamp(JoinApplicationStatBo joinApplicationSta } } + for (JoinFileDescriptorBo joinFileDescriptorBo : joinApplicationStatBo.getJoinFileDescriptorBoList()) { + if (joinFileDescriptorBo.getTimestamp() < minTimestamp) { + minTimestamp = joinFileDescriptorBo.getTimestamp(); + } + } + + for (JoinDirectBufferBo joinDirectBufferBo : joinApplicationStatBo.getJoinDirectBufferBoList()) { + if (joinDirectBufferBo.getTimestamp() < minTimestamp) { + minTimestamp = joinDirectBufferBo.getTimestamp(); + } + } + return minTimestamp; } @@ -264,10 +302,63 @@ private static List joinCpuLoadBoByTimeSlice(List joinFileDescriptorBoByTimeSlice(List joinApplicationStatBoList) { + Map> joinFileDescriptorBoMap = new HashMap>(); + + for (JoinApplicationStatBo joinApplicationStatBo : joinApplicationStatBoList) { + for (JoinFileDescriptorBo joinFileDescriptorBo : joinApplicationStatBo.getJoinFileDescriptorBoList()) { + long shiftTimestamp = shiftTimestamp(joinFileDescriptorBo.getTimestamp()); + List joinFileDescriptorBoList = joinFileDescriptorBoMap.get(shiftTimestamp); + + if (joinFileDescriptorBoList == null) { + joinFileDescriptorBoList = new ArrayList(); + joinFileDescriptorBoMap.put(shiftTimestamp, joinFileDescriptorBoList); + } + + joinFileDescriptorBoList.add(joinFileDescriptorBo); + } + } + + List newJoinFileDescriptorBoList = new ArrayList(); + + for (Map.Entry> entry : joinFileDescriptorBoMap.entrySet()) { + List joinFileDescriptorBoList = entry.getValue(); + JoinFileDescriptorBo joinFileDescriptorBo = JoinFileDescriptorBo.joinFileDescriptorBoList(joinFileDescriptorBoList, entry.getKey()); + newJoinFileDescriptorBoList.add(joinFileDescriptorBo); + } + return newJoinFileDescriptorBoList; + } + + private static List joinDirectBufferBoByTimeSlice(List joinApplicationStatBoList) { + Map> joinDirectBufferBoMap = new HashMap>(); + + for (JoinApplicationStatBo joinApplicationStatBo : joinApplicationStatBoList) { + for (JoinDirectBufferBo joinDirectBufferBo : joinApplicationStatBo.getJoinDirectBufferBoList()) { + long shiftTimestamp = shiftTimestamp(joinDirectBufferBo.getTimestamp()); + List joinDirectBufferBoList = joinDirectBufferBoMap.get(shiftTimestamp); + + if (joinDirectBufferBoList == null) { + joinDirectBufferBoList = new ArrayList(); + joinDirectBufferBoMap.put(shiftTimestamp, joinDirectBufferBoList); + } + + joinDirectBufferBoList.add(joinDirectBufferBo); + } + } + + List newJoinDirectBufferBoList = new ArrayList(); + + for (Map.Entry> entry : joinDirectBufferBoMap.entrySet()) { + List joinDirectBufferBoList = entry.getValue(); + JoinDirectBufferBo joinDirectBufferBo = JoinDirectBufferBo.joinDirectBufferBoList(joinDirectBufferBoList, entry.getKey()); + newJoinDirectBufferBoList.add(joinDirectBufferBo); + } + return newJoinDirectBufferBoList; + } public static JoinApplicationStatBo joinApplicationStatBo(List joinApplicationStatBoList) { JoinApplicationStatBo newJoinApplicationStatBo = new JoinApplicationStatBo(); - if (joinApplicationStatBoList.size() == 0) { + if (joinApplicationStatBoList.isEmpty()) { return newJoinApplicationStatBo; } @@ -364,6 +455,22 @@ public List getJoinDataSourceListBoList() { return joinDataSourceListBoList; } + public List getJoinFileDescriptorBoList() { + return joinFileDescriptorBoList; + } + + public void setJoinFileDescriptorBoList(List joinFileDescriptorBoList) { + this.joinFileDescriptorBoList = joinFileDescriptorBoList; + } + + public List getJoinDirectBufferBoList() { + return joinDirectBufferBoList; + } + + public void setJoinDirectBufferBoList(List joinDirectBufferBoList) { + this.joinDirectBufferBoList = joinDirectBufferBoList; + } + public static List createJoinApplicationStatBo(String applicationId, JoinAgentStatBo joinAgentStatBo, long rangeTime) { List joinApplicationStatBoList = new ArrayList(); List joinAgentStatBoList = splitJoinAgentStatBo(applicationId, joinAgentStatBo, rangeTime); @@ -378,6 +485,8 @@ public static List createJoinApplicationStatBo(String app joinApplicationStatBo.setJoinActiveTraceBoList(sliceJoinAgentStatBo.getJoinActiveTraceBoList()); joinApplicationStatBo.setJoinResponseTimeBoList(sliceJoinAgentStatBo.getJoinResponseTimeBoList()); joinApplicationStatBo.setJoinDataSourceListBoList(sliceJoinAgentStatBo.getJoinDataSourceListBoList()); + joinApplicationStatBo.setJoinFileDescriptorBoList(sliceJoinAgentStatBo.getJoinFileDescriptorBoList()); + joinApplicationStatBo.setJoinDirectBufferBoList(sliceJoinAgentStatBo.getJoinDirectBufferBoList()); joinApplicationStatBoList.add(joinApplicationStatBo); } @@ -392,6 +501,8 @@ private static List splitJoinAgentStatBo(String applicationId, sliceJoinActiveTraceBo(applicationId, joinAgentStatBo, rangeTime, joinAgentStatBoMap); sliceJoinResponseTimeBo(applicationId, joinAgentStatBo, rangeTime, joinAgentStatBoMap); sliceJoinDataSourceListBo(applicationId, joinAgentStatBo, rangeTime, joinAgentStatBoMap); + sliceJoinFileDescriptorBo(applicationId, joinAgentStatBo, rangeTime, joinAgentStatBoMap); + sliceJoinDirectBufferBo(applicationId, joinAgentStatBo, rangeTime, joinAgentStatBoMap); return new ArrayList(joinAgentStatBoMap.values()); } @@ -528,6 +639,49 @@ private static void sliceJoinCpuLoadBo(String applicationId, JoinAgentStatBo joi } } + private static void sliceJoinFileDescriptorBo(String applicationId, JoinAgentStatBo joinAgentStatBo, long rangeTime, Map joinAgentStatBoMap) { + Map> joinFileDescriptorBoMap = new HashMap>(); + + for (JoinFileDescriptorBo joinFileDescriptorBo : joinAgentStatBo.getJoinFileDescriptorBoList()) { + long timestamp = joinFileDescriptorBo.getTimestamp(); + long time = timestamp - (timestamp % rangeTime); + List joinFileDescriptorBoList = joinFileDescriptorBoMap.get(time); + + if (joinFileDescriptorBoList == null) { + joinFileDescriptorBoList = new ArrayList(); + joinFileDescriptorBoMap.put(time, joinFileDescriptorBoList); + } + + joinFileDescriptorBoList.add(joinFileDescriptorBo); + } + for (Map.Entry> entry : joinFileDescriptorBoMap.entrySet()) { + long time = entry.getKey(); + JoinAgentStatBo sliceJoinAgentStatBo = getORCreateJoinAgentStatBo(applicationId, joinAgentStatBoMap, time); + sliceJoinAgentStatBo.setJoinFileDescriptorBoList(entry.getValue()); + } + } + + private static void sliceJoinDirectBufferBo(String applicationId, JoinAgentStatBo joinAgentStatBo, long rangeTime, Map joinAgentStatBoMap) { + Map> joinDirectBufferBoMap = new HashMap>(); + + for (JoinDirectBufferBo joinDirectBufferBo : joinAgentStatBo.getJoinDirectBufferBoList()) { + long timestamp = joinDirectBufferBo.getTimestamp(); + long time = timestamp - (timestamp % rangeTime); + List joinDirectBufferBoList = joinDirectBufferBoMap.get(time); + + if (joinDirectBufferBoList == null) { + joinDirectBufferBoList = new ArrayList(); + joinDirectBufferBoMap.put(time, joinDirectBufferBoList); + } + + joinDirectBufferBoList.add(joinDirectBufferBo); + } + for (Map.Entry> entry : joinDirectBufferBoMap.entrySet()) { + long time = entry.getKey(); + JoinAgentStatBo sliceJoinAgentStatBo = getORCreateJoinAgentStatBo(applicationId, joinAgentStatBoMap, time); + sliceJoinAgentStatBo.setJoinDirectBufferBoList(entry.getValue()); + } + } private static JoinAgentStatBo getORCreateJoinAgentStatBo(String applicationId, Map joinAgentStatBoMap, long time) { JoinAgentStatBo joinAgentStatBo = joinAgentStatBoMap.get(time); @@ -552,6 +706,8 @@ public String toString() { ", joinActiveTraceBoList=" + joinActiveTraceBoList + ", joinResponseTimeBoList=" + joinResponseTimeBoList + ", joinDataSourceListBoList=" + joinDataSourceListBoList + + ", joinFileDescriptorBoList=" + joinFileDescriptorBoList + + ", joinDirectBufferBoList=" + joinDirectBufferBoList + ", statType=" + statType + '}'; } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinCpuLoadBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinCpuLoadBo.java index 0e0817040b13..a9e251215ac2 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinCpuLoadBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinCpuLoadBo.java @@ -61,7 +61,7 @@ public JoinCpuLoadBo(String id, double jvmCpuLoad, double maxJvmCpuLoad, String public static JoinCpuLoadBo joinCpuLoadBoList(List joinCpuLoadBoList, Long timestamp) { int boCount = joinCpuLoadBoList.size(); - if (joinCpuLoadBoList.size() == 0) { + if (joinCpuLoadBoList.isEmpty()) { return EMPTY_JOIN_CPU_LOAD_BO; } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDataSourceBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDataSourceBo.java index f5c60c7c4f74..2d4220499e83 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDataSourceBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDataSourceBo.java @@ -15,8 +15,6 @@ */ package com.navercorp.pinpoint.common.server.bo.stat.join; -import com.navercorp.pinpoint.common.util.CollectionUtils; - import java.util.List; /** diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDataSourceListBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDataSourceListBo.java index aa757e22808a..47940f00404e 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDataSourceListBo.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDataSourceListBo.java @@ -15,8 +15,6 @@ */ package com.navercorp.pinpoint.common.server.bo.stat.join; -import com.navercorp.pinpoint.common.server.bo.stat.DataSourceBo; - import java.util.*; /** @@ -66,7 +64,7 @@ public void setTimestamp(long timestamp) { } public static JoinDataSourceListBo joinDataSourceListBoList(List joinDataSourceListBoList, Long timestamp) { - if (joinDataSourceListBoList.size() == 0) { + if (joinDataSourceListBoList.isEmpty()) { return EMPTY_JOIN_DATA_SOURCE_LIST_BO; } @@ -88,7 +86,6 @@ private static List joinDatasourceBo(List joinDataSourceBoList = dataSourceBoListMap.get(dataSourceKey); - if (joinDataSourceBoList == null) { joinDataSourceBoList = new ArrayList(); dataSourceBoListMap.put(dataSourceKey, joinDataSourceBoList); diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDirectBufferBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDirectBufferBo.java new file mode 100644 index 000000000000..c40836d88636 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDirectBufferBo.java @@ -0,0 +1,463 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.stat.join; + +import java.util.Date; +import java.util.List; + +/** + * @author Roy Kim + */ +public class JoinDirectBufferBo implements JoinStatBo { + public static final JoinDirectBufferBo EMPTY_JOIN_DIRECT_BUFFER_BO = new JoinDirectBufferBo(); + public static final long UNCOLLECTED_VALUE = -1; + + private String id = UNKNOWN_ID; + private long timestamp = Long.MIN_VALUE; + + private long avgDirectCount = UNCOLLECTED_VALUE; + private String maxDirectCountAgentId = UNKNOWN_AGENT; + private long maxDirectCount = UNCOLLECTED_VALUE; + private String minDirectCountAgentId = UNKNOWN_AGENT; + private long minDirectCount = UNCOLLECTED_VALUE; + + private long avgDirectMemoryUsed = UNCOLLECTED_VALUE; + private String maxDirectMemoryUsedAgentId = UNKNOWN_AGENT; + private long maxDirectMemoryUsed = UNCOLLECTED_VALUE; + private String minDirectMemoryUsedAgentId = UNKNOWN_AGENT; + private long minDirectMemoryUsed = UNCOLLECTED_VALUE; + + private long avgMappedCount = UNCOLLECTED_VALUE; + private String maxMappedCountAgentId = UNKNOWN_AGENT; + private long maxMappedCount = UNCOLLECTED_VALUE; + private String minMappedCountAgentId = UNKNOWN_AGENT; + private long minMappedCount = UNCOLLECTED_VALUE; + + private long avgMappedMemoryUsed = UNCOLLECTED_VALUE; + private String maxMappedMemoryUsedAgentId = UNKNOWN_AGENT; + private long maxMappedMemoryUsed = UNCOLLECTED_VALUE; + private String minMappedMemoryUsedAgentId = UNKNOWN_AGENT; + private long minMappedMemoryUsed = UNCOLLECTED_VALUE; + + public JoinDirectBufferBo() { + } + + public JoinDirectBufferBo(String id, long avgDirectCount, long maxDirectCount, String maxDirectCountAgentId, long minDirectCount, String minDirectCountAgentId + , long avgDirectMemoryUsed, long maxDirectMemoryUsed, String maxDirectMemoryUsedAgentId, long minDirectMemoryUsed, String minDirectMemoryUsedAgentId + , long avgMappedCount, long maxMappedCount, String maxMappedCountAgentId, long minMappedCount, String minMappedCountAgentId + , long avgMappedMemoryUsed, long maxMappedMemoryUsed, String maxMappedMemoryUsedAgentId, long minMappedMemoryUsed, String minMappedMemoryUsedAgentId + , long timestamp) { + this.id = id; + this.timestamp = timestamp; + this.avgDirectCount = avgDirectCount; + this.maxDirectCountAgentId = maxDirectCountAgentId; + this.maxDirectCount = maxDirectCount; + this.minDirectCountAgentId = minDirectCountAgentId; + this.minDirectCount = minDirectCount; + this.avgDirectMemoryUsed = avgDirectMemoryUsed; + this.maxDirectMemoryUsedAgentId = maxDirectMemoryUsedAgentId; + this.maxDirectMemoryUsed = maxDirectMemoryUsed; + this.minDirectMemoryUsedAgentId = minDirectMemoryUsedAgentId; + this.minDirectMemoryUsed = minDirectMemoryUsed; + this.avgMappedCount = avgMappedCount; + this.maxMappedCountAgentId = maxMappedCountAgentId; + this.maxMappedCount = maxMappedCount; + this.minMappedCountAgentId = minMappedCountAgentId; + this.minMappedCount = minMappedCount; + this.avgMappedMemoryUsed = avgMappedMemoryUsed; + this.maxMappedMemoryUsedAgentId = maxMappedMemoryUsedAgentId; + this.maxMappedMemoryUsed = maxMappedMemoryUsed; + this.minMappedMemoryUsedAgentId = minMappedMemoryUsedAgentId; + this.minMappedMemoryUsed = minMappedMemoryUsed; + } + + public static JoinDirectBufferBo joinDirectBufferBoList(List joinDirectBufferBoList, Long timestamp) { + int boCount = joinDirectBufferBoList.size(); + + if (joinDirectBufferBoList.size() == 0) { + return EMPTY_JOIN_DIRECT_BUFFER_BO; + } + + JoinDirectBufferBo newJoinDirectBufferBo = new JoinDirectBufferBo(); + JoinDirectBufferBo initJoinDirectBufferBo = joinDirectBufferBoList.get(0); + newJoinDirectBufferBo.setId(initJoinDirectBufferBo.getId()); + newJoinDirectBufferBo.setTimestamp(timestamp); + + long sumDirectCount = 0L; + String maxDirectCountAgentId = initJoinDirectBufferBo.getMaxDirectCountAgentId(); + long maxDirectCount = initJoinDirectBufferBo.getMaxDirectCount(); + String minDirectCountAgentId = initJoinDirectBufferBo.getMinDirectCountAgentId(); + long minDirectCount = initJoinDirectBufferBo.getMinDirectCount(); + + long sumDirectMemoryUsed = 0L; + String maxDirectMemoryUsedAgentId = initJoinDirectBufferBo.getMaxDirectMemoryUsedAgentId(); + long maxDirectMemoryUsed = initJoinDirectBufferBo.getMaxDirectMemoryUsed(); + String minDirectMemoryUsedAgentId = initJoinDirectBufferBo.getMinDirectMemoryUsedAgentId(); + long minDirectMemoryUsed = initJoinDirectBufferBo.getMinDirectMemoryUsed(); + + long sumMappedCount = 0L; + String maxMappedCountAgentId = initJoinDirectBufferBo.getMaxMappedCountAgentId(); + long maxMappedCount = initJoinDirectBufferBo.getMaxMappedCount(); + String minMappedCountAgentId = initJoinDirectBufferBo.getMinMappedCountAgentId(); + long minMappedCount = initJoinDirectBufferBo.getMinMappedCount(); + + long sumMappedMemoryUsed = 0L; + String maxMappedMemoryUsedAgentId = initJoinDirectBufferBo.getMaxMappedMemoryUsedAgentId(); + long maxMappedMemoryUsed = initJoinDirectBufferBo.getMaxMappedMemoryUsed(); + String minMappedMemoryUsedAgentId = initJoinDirectBufferBo.getMinMappedMemoryUsedAgentId(); + long minMappedMemoryUsed = initJoinDirectBufferBo.getMinMappedMemoryUsed(); + + for (JoinDirectBufferBo joinDirectBufferBo : joinDirectBufferBoList) { + + sumDirectCount += joinDirectBufferBo.getAvgDirectCount(); + if (joinDirectBufferBo.getMaxDirectCount() > maxDirectCount) { + maxDirectCount = joinDirectBufferBo.getMaxDirectCount(); + maxDirectCountAgentId = joinDirectBufferBo.getMaxDirectCountAgentId(); + } + if (joinDirectBufferBo.getMinDirectCount() < minDirectCount) { + minDirectCount = joinDirectBufferBo.getMinDirectCount(); + minDirectCountAgentId = joinDirectBufferBo.getMinDirectCountAgentId(); + } + + sumDirectMemoryUsed += joinDirectBufferBo.getAvgDirectMemoryUsed(); + if (joinDirectBufferBo.getMaxDirectMemoryUsed() > maxDirectMemoryUsed) { + maxDirectMemoryUsed = joinDirectBufferBo.getMaxDirectMemoryUsed(); + maxDirectMemoryUsedAgentId = joinDirectBufferBo.getMaxDirectMemoryUsedAgentId(); + } + if (joinDirectBufferBo.getMinDirectMemoryUsed() < minDirectMemoryUsed) { + minDirectMemoryUsed = joinDirectBufferBo.getMinDirectMemoryUsed(); + minDirectMemoryUsedAgentId = joinDirectBufferBo.getMinDirectMemoryUsedAgentId(); + } + + sumMappedCount += joinDirectBufferBo.getAvgMappedCount(); + if (joinDirectBufferBo.getMaxMappedCount() > maxMappedCount) { + maxMappedCount = joinDirectBufferBo.getMaxMappedCount(); + maxMappedCountAgentId = joinDirectBufferBo.getMaxMappedCountAgentId(); + } + if (joinDirectBufferBo.getMinMappedCount() < minMappedCount) { + minMappedCount = joinDirectBufferBo.getMinMappedCount(); + minMappedCountAgentId = joinDirectBufferBo.getMinMappedCountAgentId(); + } + + sumMappedMemoryUsed += joinDirectBufferBo.getAvgMappedMemoryUsed(); + if (joinDirectBufferBo.getMaxMappedMemoryUsed() > maxMappedMemoryUsed) { + maxMappedMemoryUsed = joinDirectBufferBo.getMaxMappedMemoryUsed(); + maxMappedMemoryUsedAgentId = joinDirectBufferBo.getMaxMappedMemoryUsedAgentId(); + } + if (joinDirectBufferBo.getMinMappedMemoryUsed() < minMappedMemoryUsed) { + minMappedMemoryUsed = joinDirectBufferBo.getMinMappedMemoryUsed(); + minMappedMemoryUsedAgentId = joinDirectBufferBo.getMinMappedMemoryUsedAgentId(); + } + } + + newJoinDirectBufferBo.setAvgDirectCount((sumDirectCount / boCount)); + newJoinDirectBufferBo.setMaxDirectCount(maxDirectCount); + newJoinDirectBufferBo.setMaxDirectCountAgentId(maxDirectCountAgentId); + newJoinDirectBufferBo.setMinDirectCount(minDirectCount); + newJoinDirectBufferBo.setMinDirectCountAgentId(minDirectCountAgentId); + + newJoinDirectBufferBo.setAvgDirectMemoryUsed((sumDirectMemoryUsed / boCount)); + newJoinDirectBufferBo.setMaxDirectMemoryUsed(maxDirectMemoryUsed); + newJoinDirectBufferBo.setMaxDirectMemoryUsedAgentId(maxDirectMemoryUsedAgentId); + newJoinDirectBufferBo.setMinDirectMemoryUsed(minDirectMemoryUsed); + newJoinDirectBufferBo.setMinDirectMemoryUsedAgentId(minDirectMemoryUsedAgentId); + + newJoinDirectBufferBo.setAvgMappedCount((sumMappedCount / boCount)); + newJoinDirectBufferBo.setMaxMappedCount(maxMappedCount); + newJoinDirectBufferBo.setMaxMappedCountAgentId(maxMappedCountAgentId); + newJoinDirectBufferBo.setMinMappedCount(minMappedCount); + newJoinDirectBufferBo.setMinMappedCountAgentId(minMappedCountAgentId); + + newJoinDirectBufferBo.setAvgMappedMemoryUsed((sumMappedMemoryUsed / boCount)); + newJoinDirectBufferBo.setMaxMappedMemoryUsed(maxMappedMemoryUsed); + newJoinDirectBufferBo.setMaxMappedMemoryUsedAgentId(maxMappedMemoryUsedAgentId); + newJoinDirectBufferBo.setMinMappedMemoryUsed(minMappedMemoryUsed); + newJoinDirectBufferBo.setMinMappedMemoryUsedAgentId(minMappedMemoryUsedAgentId); + + return newJoinDirectBufferBo; + } + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public long getAvgDirectCount() { + return avgDirectCount; + } + + public void setAvgDirectCount(long avgDirectCount) { + this.avgDirectCount = avgDirectCount; + } + + public String getMaxDirectCountAgentId() { + return maxDirectCountAgentId; + } + + public void setMaxDirectCountAgentId(String maxDirectCountAgentId) { + this.maxDirectCountAgentId = maxDirectCountAgentId; + } + + public long getMaxDirectCount() { + return maxDirectCount; + } + + public void setMaxDirectCount(long maxDirectCount) { + this.maxDirectCount = maxDirectCount; + } + + public String getMinDirectCountAgentId() { + return minDirectCountAgentId; + } + + public void setMinDirectCountAgentId(String minDirectCountAgentId) { + this.minDirectCountAgentId = minDirectCountAgentId; + } + + public long getMinDirectCount() { + return minDirectCount; + } + + public void setMinDirectCount(long minDirectCount) { + this.minDirectCount = minDirectCount; + } + + public long getAvgDirectMemoryUsed() { + return avgDirectMemoryUsed; + } + + public void setAvgDirectMemoryUsed(long avgDirectMemoryUsed) { + this.avgDirectMemoryUsed = avgDirectMemoryUsed; + } + + public String getMaxDirectMemoryUsedAgentId() { + return maxDirectMemoryUsedAgentId; + } + + public void setMaxDirectMemoryUsedAgentId(String maxDirectMemoryUsedAgentId) { + this.maxDirectMemoryUsedAgentId = maxDirectMemoryUsedAgentId; + } + + public long getMaxDirectMemoryUsed() { + return maxDirectMemoryUsed; + } + + public void setMaxDirectMemoryUsed(long maxDirectMemoryUsed) { + this.maxDirectMemoryUsed = maxDirectMemoryUsed; + } + + public String getMinDirectMemoryUsedAgentId() { + return minDirectMemoryUsedAgentId; + } + + public void setMinDirectMemoryUsedAgentId(String minDirectMemoryUsedAgentId) { + this.minDirectMemoryUsedAgentId = minDirectMemoryUsedAgentId; + } + + public long getMinDirectMemoryUsed() { + return minDirectMemoryUsed; + } + + public void setMinDirectMemoryUsed(long minDirectMemoryUsed) { + this.minDirectMemoryUsed = minDirectMemoryUsed; + } + + public long getAvgMappedCount() { + return avgMappedCount; + } + + public void setAvgMappedCount(long avgMappedCount) { + this.avgMappedCount = avgMappedCount; + } + + public String getMaxMappedCountAgentId() { + return maxMappedCountAgentId; + } + + public void setMaxMappedCountAgentId(String maxMappedCountAgentId) { + this.maxMappedCountAgentId = maxMappedCountAgentId; + } + + public long getMaxMappedCount() { + return maxMappedCount; + } + + public void setMaxMappedCount(long maxMappedCount) { + this.maxMappedCount = maxMappedCount; + } + + public String getMinMappedCountAgentId() { + return minMappedCountAgentId; + } + + public void setMinMappedCountAgentId(String minMappedCountAgentId) { + this.minMappedCountAgentId = minMappedCountAgentId; + } + + public long getMinMappedCount() { + return minMappedCount; + } + + public void setMinMappedCount(long minMappedCount) { + this.minMappedCount = minMappedCount; + } + + public long getAvgMappedMemoryUsed() { + return avgMappedMemoryUsed; + } + + public void setAvgMappedMemoryUsed(long avgMappedMemoryUsed) { + this.avgMappedMemoryUsed = avgMappedMemoryUsed; + } + + public String getMaxMappedMemoryUsedAgentId() { + return maxMappedMemoryUsedAgentId; + } + + public void setMaxMappedMemoryUsedAgentId(String maxMappedMemoryUsedAgentId) { + this.maxMappedMemoryUsedAgentId = maxMappedMemoryUsedAgentId; + } + + public long getMaxMappedMemoryUsed() { + return maxMappedMemoryUsed; + } + + public void setMaxMappedMemoryUsed(long maxMappedMemoryUsed) { + this.maxMappedMemoryUsed = maxMappedMemoryUsed; + } + + public String getMinMappedMemoryUsedAgentId() { + return minMappedMemoryUsedAgentId; + } + + public void setMinMappedMemoryUsedAgentId(String minMappedMemoryUsedAgentId) { + this.minMappedMemoryUsedAgentId = minMappedMemoryUsedAgentId; + } + + public long getMinMappedMemoryUsed() { + return minMappedMemoryUsed; + } + + public void setMinMappedMemoryUsed(long minMappedMemoryUsed) { + this.minMappedMemoryUsed = minMappedMemoryUsed; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JoinDirectBufferBo that = (JoinDirectBufferBo) o; + + if (timestamp != that.timestamp) return false; + if (avgDirectCount != that.avgDirectCount) return false; + if (maxDirectCount != that.maxDirectCount) return false; + if (minDirectCount != that.minDirectCount) return false; + if (avgDirectMemoryUsed != that.avgDirectMemoryUsed) return false; + if (maxDirectMemoryUsed != that.maxDirectMemoryUsed) return false; + if (minDirectMemoryUsed != that.minDirectMemoryUsed) return false; + if (avgMappedCount != that.avgMappedCount) return false; + if (maxMappedCount != that.maxMappedCount) return false; + if (minMappedCount != that.minMappedCount) return false; + if (avgMappedMemoryUsed != that.avgMappedMemoryUsed) return false; + if (maxMappedMemoryUsed != that.maxMappedMemoryUsed) return false; + if (minMappedMemoryUsed != that.minMappedMemoryUsed) return false; + if (!id.equals(that.id)) return false; + if (!maxDirectCountAgentId.equals(that.maxDirectCountAgentId)) return false; + if (!minDirectCountAgentId.equals(that.minDirectCountAgentId)) return false; + if (!maxDirectMemoryUsedAgentId.equals(that.maxDirectMemoryUsedAgentId)) return false; + if (!minDirectMemoryUsedAgentId.equals(that.minDirectMemoryUsedAgentId)) return false; + if (!maxMappedCountAgentId.equals(that.maxMappedCountAgentId)) return false; + if (!minMappedCountAgentId.equals(that.minMappedCountAgentId)) return false; + if (!maxMappedMemoryUsedAgentId.equals(that.maxMappedMemoryUsedAgentId)) return false; + return minMappedMemoryUsedAgentId.equals(that.minMappedMemoryUsedAgentId); + + } + + @Override + public int hashCode() { + int result; + + result = id.hashCode(); + result = 31 * result + (int) (timestamp ^ (timestamp >>> 32)); + + result = 31 * result + (int) (avgDirectCount ^ (avgDirectCount >>> 32)); + result = 31 * result + maxDirectCountAgentId.hashCode(); + result = 31 * result + (int) (maxDirectCount ^ (maxDirectCount >>> 32)); + result = 31 * result + minDirectCountAgentId.hashCode(); + result = 31 * result + (int) (minDirectCount ^ (minDirectCount >>> 32)); + + result = 31 * result + (int) (avgDirectMemoryUsed ^ (avgDirectMemoryUsed >>> 32)); + result = 31 * result + maxDirectMemoryUsedAgentId.hashCode(); + result = 31 * result + (int) (maxDirectMemoryUsed ^ (maxDirectMemoryUsed >>> 32)); + result = 31 * result + minDirectMemoryUsedAgentId.hashCode(); + result = 31 * result + (int) (minDirectMemoryUsed ^ (minDirectMemoryUsed >>> 32)); + + result = 31 * result + (int) (avgMappedCount ^ (avgMappedCount >>> 32)); + result = 31 * result + maxMappedCountAgentId.hashCode(); + result = 31 * result + (int) (maxMappedCount ^ (maxMappedCount >>> 32)); + result = 31 * result + minMappedCountAgentId.hashCode(); + result = 31 * result + (int) (minMappedCount ^ (minMappedCount >>> 32)); + + result = 31 * result + (int) (avgMappedMemoryUsed ^ (avgMappedMemoryUsed >>> 32)); + result = 31 * result + maxMappedMemoryUsedAgentId.hashCode(); + result = 31 * result + (int) (maxMappedMemoryUsed ^ (maxMappedMemoryUsed >>> 32)); + result = 31 * result + minMappedMemoryUsedAgentId.hashCode(); + result = 31 * result + (int) (minMappedMemoryUsed ^ (minMappedMemoryUsed >>> 32)); + return result; + } + + @Override + public String toString() { + return "JoinDirectBufferBo{" + + "id='" + id + '\'' + + ", avgDirectCount=" + avgDirectCount + + ", maxDirectCountAgentId='" + maxDirectCountAgentId + '\'' + + ", maxDirectCount=" + maxDirectCount + + ", minDirectCountAgentId='" + minDirectCountAgentId + '\'' + + ", minDirectCount=" + minDirectCount + + ", avgDirectMemoryUsed=" + avgDirectMemoryUsed + + ", maxDirectMemoryUsedAgentId='" + maxDirectMemoryUsedAgentId + '\'' + + ", maxDirectMemoryUsed=" + maxDirectMemoryUsed + + ", minDirectMemoryUsedAgentId='" + minDirectMemoryUsedAgentId + '\'' + + ", minDirectMemoryUsed=" + minDirectMemoryUsed + + ", avgMappedCount=" + avgMappedCount + + ", maxMappedCountAgentId='" + maxMappedCountAgentId + '\'' + + ", maxMappedCount=" + maxMappedCount + + ", minMappedCountAgentId='" + minMappedCountAgentId + '\'' + + ", minMappedCount=" + minMappedCount + + ", avgMappedMemoryUsed=" + avgMappedMemoryUsed + + ", maxMappedMemoryUsedAgentId='" + maxMappedMemoryUsedAgentId + '\'' + + ", maxMappedMemoryUsed=" + maxMappedMemoryUsed + + ", minMappedMemoryUsedAgentId='" + minMappedMemoryUsedAgentId + '\'' + + ", minMappedMemoryUsed=" + minMappedMemoryUsed + + ", timestamp=" + timestamp +"(" + new Date(timestamp)+ ")" + + '}'; + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinFileDescriptorBo.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinFileDescriptorBo.java new file mode 100644 index 000000000000..ec5066e76286 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinFileDescriptorBo.java @@ -0,0 +1,190 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.common.server.bo.stat.join; + +import java.util.Date; +import java.util.List; + +/** + * @author Roy Kim + */ +public class JoinFileDescriptorBo implements JoinStatBo { + public static final JoinFileDescriptorBo EMPTY_JOIN_FILE_DESCRIPTOR_BO = new JoinFileDescriptorBo(); + public static final long UNCOLLECTED_VALUE = -1; + + private String id = UNKNOWN_ID; + private long timestamp = Long.MIN_VALUE; + + private long avgOpenFDCount = UNCOLLECTED_VALUE; + private String maxOpenFDCountAgentId = UNKNOWN_AGENT; + private long maxOpenFDCount = UNCOLLECTED_VALUE; + private String minOpenFDCountAgentId = UNKNOWN_AGENT; + private long minOpenFDCount = UNCOLLECTED_VALUE; + + public JoinFileDescriptorBo() { + } + + public JoinFileDescriptorBo(String id, long avgOpenFDCount, long maxOpenFDCount, String maxOpenFDCountAgentId, long minOpenFDCount, String minOpenFDCountAgentId, long timestamp) { + this.id = id; + this.avgOpenFDCount = avgOpenFDCount; + this.minOpenFDCount = minOpenFDCount; + this.minOpenFDCountAgentId = minOpenFDCountAgentId; + this.maxOpenFDCount = maxOpenFDCount; + this.maxOpenFDCountAgentId = maxOpenFDCountAgentId; + this.timestamp = timestamp; + } + + public static JoinFileDescriptorBo joinFileDescriptorBoList(List joinFileDescriptorBoList, Long timestamp) { + int boCount = joinFileDescriptorBoList.size(); + + if (joinFileDescriptorBoList.size() == 0) { + return EMPTY_JOIN_FILE_DESCRIPTOR_BO; + } + + JoinFileDescriptorBo newJoinFileDescriptorBo = new JoinFileDescriptorBo(); + JoinFileDescriptorBo initJoinFileDescriptorBo = joinFileDescriptorBoList.get(0); + newJoinFileDescriptorBo.setId(initJoinFileDescriptorBo.getId()); + newJoinFileDescriptorBo.setTimestamp(timestamp); + + long sumCount = 0L; + String maxOpenFDCountAgentId = initJoinFileDescriptorBo.getMaxOpenFDCountAgentId(); + long maxOpenFDCount = initJoinFileDescriptorBo.getMaxOpenFDCount(); + String minOpenFDCountAgentId = initJoinFileDescriptorBo.getMinOpenFDCountAgentId(); + long minOpenFDCount = initJoinFileDescriptorBo.getMinOpenFDCount(); + + for (JoinFileDescriptorBo joinFileDescriptorBo : joinFileDescriptorBoList) { + sumCount += joinFileDescriptorBo.getAvgOpenFDCount(); + if (joinFileDescriptorBo.getMaxOpenFDCount() > maxOpenFDCount) { + maxOpenFDCount = joinFileDescriptorBo.getMaxOpenFDCount(); + maxOpenFDCountAgentId = joinFileDescriptorBo.getMaxOpenFDCountAgentId(); + } + if (joinFileDescriptorBo.getMinOpenFDCount() < minOpenFDCount) { + minOpenFDCount = joinFileDescriptorBo.getMinOpenFDCount(); + minOpenFDCountAgentId = joinFileDescriptorBo.getMinOpenFDCountAgentId(); + } + } + + newJoinFileDescriptorBo.setAvgOpenFDCount((sumCount / boCount)); + newJoinFileDescriptorBo.setMaxOpenFDCount(maxOpenFDCount); + newJoinFileDescriptorBo.setMaxOpenFDCountAgentId(maxOpenFDCountAgentId); + newJoinFileDescriptorBo.setMinOpenFDCount(minOpenFDCount); + newJoinFileDescriptorBo.setMinOpenFDCountAgentId(minOpenFDCountAgentId); + + return newJoinFileDescriptorBo; + } + + public String getMaxOpenFDCountAgentId() { + return maxOpenFDCountAgentId; + } + + public String getMinOpenFDCountAgentId() { + return minOpenFDCountAgentId; + } + + public void setMaxOpenFDCountAgentId(String maxOpenFDCountAgentId) { + this.maxOpenFDCountAgentId = maxOpenFDCountAgentId; + } + + public void setMinOpenFDCountAgentId(String minOpenFDCountAgentId) { + this.minOpenFDCountAgentId = minOpenFDCountAgentId; + } + + public void setAvgOpenFDCount(long avgOpenFDCount) { + this.avgOpenFDCount = avgOpenFDCount; + } + + public void setId(String id) { + this.id = id; + } + + public long getAvgOpenFDCount() { + return avgOpenFDCount; + } + + public String getId() { + return id; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public void setMaxOpenFDCount(long maxOpenFDCount) { + this.maxOpenFDCount = maxOpenFDCount; + } + + public void setMinOpenFDCount(long minOpenFDCount) { + this.minOpenFDCount = minOpenFDCount; + } + + public long getMaxOpenFDCount() { + return maxOpenFDCount; + } + + public long getMinOpenFDCount() { + return minOpenFDCount; + } + + @Override + public String toString() { + return "JoinFileDescriptorBo{" + + "id='" + id + '\'' + + ", avgOpenFDCount=" + avgOpenFDCount + + ", maxOpenFDCountAgentId='" + maxOpenFDCountAgentId + '\'' + + ", maxOpenFDCount=" + maxOpenFDCount + + ", minOpenFDCountAgentId='" + minOpenFDCountAgentId + '\'' + + ", minOpenFDCount=" + minOpenFDCount + + ", timestamp=" + timestamp +"(" + new Date(timestamp)+ ")" + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JoinFileDescriptorBo that = (JoinFileDescriptorBo) o; + + if (timestamp != that.timestamp) return false; + if (avgOpenFDCount != that.avgOpenFDCount) return false; + if (maxOpenFDCount != that.maxOpenFDCount) return false; + if (minOpenFDCount != that.minOpenFDCount) return false; + if (!id.equals(that.id)) return false; + if (!maxOpenFDCountAgentId.equals(that.maxOpenFDCountAgentId)) return false; + return minOpenFDCountAgentId.equals(that.minOpenFDCountAgentId); + + } + + @Override + public int hashCode() { + int result; + + result = id.hashCode(); + result = 31 * result + (int) (timestamp ^ (timestamp >>> 32)); + result = 31 * result + (int) (avgOpenFDCount ^ (avgOpenFDCount >>> 32)); + result = 31 * result + maxOpenFDCountAgentId.hashCode(); + result = 31 * result + (int) (maxOpenFDCount ^ (maxOpenFDCount >>> 32)); + result = 31 * result + minOpenFDCountAgentId.hashCode(); + result = 31 * result + (int) (minOpenFDCount ^ (minOpenFDCount >>> 32)); + + return result; + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/StatType.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/StatType.java index ab2220565d0c..679c36502f02 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/StatType.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/bo/stat/join/StatType.java @@ -30,6 +30,8 @@ public enum StatType { APP_ACTIVE_TRACE_COUNT(5, "Application Active trace Count"), APP_RESPONSE_TIME(6, "Application Response Time"), APP_DATA_SOURCE(7, "Application data Source"), + APP_FILE_DESCRIPTOR(8, "Application File Descriptor Count"), + APP_DIRECT_BUFFER(9, "Application Direct Buffer"), APP_STST_AGGRE(51, "Application stst aggregation"), APP_CPU_LOAD_AGGRE(52, "Application Cpu Usage aggregation"), @@ -38,6 +40,8 @@ public enum StatType { APP_ACTIVE_TRACE_COUNT_AGGRE(55, "Application Active trace count aggregation"), APP_RESPONSE_TIME_AGGRE(56, "Application Response Time aggregation"), APP_DATA_SOURCE_AGGRE(57, "Application Data Source aggregation"), + APP_FILE_DESCRIPTOR_AGGRE(58, "Application File Descriptor count aggregation"), + APP_DIRECT_BUFFER_AGGRE(59, "Application Direct Buffer aggregation"), AGENT_STST_AGGRE(101, "Agent stst aggregation"), AGENT_CPU_LOAD_AGGRE(102, "Agent Cpu Usage aggregation"), @@ -45,7 +49,9 @@ public enum StatType { AGENT_TRANSACTION_COUNT_AGGRE(104, "Agent Transaction count aggregation"), AGENT_ACTIVE_TRACE_COUNT_AGGRE(105, "Agent Active trace count aggregation"), AGENT_RESPONSE_TIME_AGGRE(106, "Agent response time aggregation"), - AGENT_DATA_SOURCE_AGGRE(107, "Agent data source aggregation"); + AGENT_DATA_SOURCE_AGGRE(107, "Agent data source aggregation"), + AGENT_FILE_DESCRIPTOR_AGGRE(108, "Agent File Descriptor count aggregation"), + AGENT_DIRECT_BUFFER_AGGRE(109, "Agent Direct Buffer aggregation"); public static final int TYPE_CODE_BYTE_LENGTH = 1; diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/CuratorZookeeperClient.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/CuratorZookeeperClient.java new file mode 100644 index 000000000000..8ca492d5214e --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/CuratorZookeeperClient.java @@ -0,0 +1,256 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper; + +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.ConnectionException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.PinpointZookeeperException; +import com.navercorp.pinpoint.common.server.util.concurrent.CommonStateContext; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.api.CreateBuilder; +import org.apache.curator.utils.ZKPaths; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.data.Stat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +/** + * @author Taejin Koo + */ +public class CuratorZookeeperClient implements ZookeeperClient { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final CommonStateContext stateContext = new CommonStateContext(); + + private final ZookeeperEventWatcher zookeeperEventWatcher; + + private final CuratorZookeeperConnectionManager connectionManager; + + public CuratorZookeeperClient(String hostPort, int sessionTimeout, ZookeeperEventWatcher zookeeperEventWatcher) { + this.zookeeperEventWatcher = Assert.requireNonNull(zookeeperEventWatcher, "zookeeperEventWatcher must not be null"); + + this.connectionManager = new CuratorZookeeperConnectionManager(hostPort, sessionTimeout, zookeeperEventWatcher); + } + + @Override + public void connect() throws IOException { + logger.debug("connect() started"); + if (stateContext.changeStateInitializing()) { + stateContext.changeStateStarted(); + try { + connectionManager.start(); + } catch (PinpointZookeeperException e) { + stateContext.changeStateIllegal(); + throw new IOException(e.getMessage(), e); + } + } else { + logger.warn("connect() failed. error : Illegal State. State may be {}.", stateContext.getCurrentState()); + } + } + + @Override + public void createPath(String value) throws PinpointZookeeperException { + checkState(); + String path = getPath(value, false); + + logger.debug("createPath() started. value:{}, path:{}", value, path); + + CuratorFramework client = connectionManager.getZookeeperClient(); + Stat stat = null; + try { + stat = client.checkExists().forPath(path); + } catch (Exception e) { + ZookeeperExceptionResolver.resolve(e, true); + } + + if (stat == null) { + try { + client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path); + } catch (KeeperException.NodeExistsException nodeExists) { + // skip + } catch (Exception e) { + ZookeeperExceptionResolver.resolve(e, true); + } + } + } + + private String getPath(String value, boolean includeEndPath) { + assertPathHasLength(value); + + if (value.length() == 1 && value.charAt(0) == '/') { + return value; + } + + if (value.charAt(value.length() - 1) == '/') { + return value.substring(0, value.length() - 1); + } + + if (includeEndPath) { + return value; + } else { + ZKPaths.PathAndNode pathAndNode = ZKPaths.getPathAndNode(value); + return pathAndNode.getPath(); + } + } + + @Override + public String createNode(String path, byte[] payload) throws PinpointZookeeperException { + checkState(); + assertPathHasLength(path); + + logger.debug("createNode() started. path:{}", path); + + try { + CuratorFramework client = connectionManager.getZookeeperClient(); + + CreateBuilder createBuilder = client.create(); + createBuilder.withMode(CreateMode.EPHEMERAL).forPath(path, payload); + return path; + } catch (Exception e) { + PinpointZookeeperException exception = ZookeeperExceptionResolver.resolve(e); + throw exception; + } + } + + @Override + public String createOrSetNode(String path, byte[] payload) throws PinpointZookeeperException { + checkState(); + assertPathHasLength(path); + + logger.debug("createOrSetNode() started. path:{}", path); + + try { + CuratorFramework client = connectionManager.getZookeeperClient(); + + CreateBuilder createBuilder = client.create(); + createBuilder.orSetData().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path, payload); + return path; + } catch (Exception e) { + PinpointZookeeperException exception = ZookeeperExceptionResolver.resolve(e); + throw exception; + } + } + + @Override + public byte[] getData(String path) throws PinpointZookeeperException { + return getData(path, false); + } + + @Override + public byte[] getData(String path, boolean watch) throws PinpointZookeeperException { + checkState(); + assertPathHasLength(path); + + logger.debug("getData() started. path:{}, watch:{}", path, watch); + + try { + CuratorFramework client = connectionManager.getZookeeperClient(); + + if (watch) { + byte[] bytes = client.getData().usingWatcher(zookeeperEventWatcher).forPath(path); + return bytes; + } else { + byte[] bytes = client.getData().forPath(path); + return bytes; + } + } catch (Exception e) { + PinpointZookeeperException resolveException = ZookeeperExceptionResolver.resolve(e); + throw resolveException; + } + } + + @Override + public List getChildNodeList(String value, boolean watch) throws PinpointZookeeperException, InterruptedException { + checkState(); + + String path = getPath(value, true); + + logger.debug("getChildNodeList() started. path:{}, watch:{}", path, watch); + + try { + CuratorFramework client = connectionManager.getZookeeperClient(); + + if (watch) { + List childList = client.getChildren().usingWatcher(zookeeperEventWatcher).forPath(path); + return childList; + } else { + List childList = client.getChildren().forPath(path); + return childList; + } + } catch (KeeperException.NoNodeException noNode) { + // skip + } catch (Exception e) { + ZookeeperExceptionResolver.resolve(e, true); + } + + return Collections.emptyList(); + } + + @Override + public void delete(String path) throws PinpointZookeeperException { + checkState(); + assertPathHasLength(path); + + logger.debug("delete() started. path:{}", path); + + try { + CuratorFramework client = connectionManager.getZookeeperClient(); + + client.delete().forPath(path); + } catch (KeeperException.NoNodeException noNode) { + // skip + } catch (Exception e) { + ZookeeperExceptionResolver.resolve(e, true); + } + } + + @Override + public void close() { + logger.debug("close() started."); + + if (stateContext.changeStateDestroying()) { + connectionManager.stop(); + stateContext.changeStateStopped(); + } + } + + private void checkState() throws PinpointZookeeperException { + if (!isConnected()) { + throw new ConnectionException("Instance must be connected."); + } + } + + private void assertPathHasLength(String path) { + Assert.isTrue(StringUtils.hasLength(path), "path must not be empty"); + } + + public boolean isConnected() { + if (!connectionManager.isConnected() || !stateContext.isStarted()) { + return false; + } + + return true; + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/CuratorZookeeperConnectionManager.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/CuratorZookeeperConnectionManager.java new file mode 100644 index 000000000000..d8d434dad8bd --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/CuratorZookeeperConnectionManager.java @@ -0,0 +1,101 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper; + +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.PinpointZookeeperException; +import com.navercorp.pinpoint.common.util.Assert; +import org.apache.curator.RetryPolicy; +import org.apache.curator.RetrySleeper; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * @author Taejin Koo + */ +class CuratorZookeeperConnectionManager { + + private static final int DEFAULT_CONNECTION_TIMEOUT = 3000; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final CuratorFramework curatorFramework; + private final PinpointZookeeperConnectionStateListener connectionStateListener; + + + public CuratorZookeeperConnectionManager(String hostPort, int sessionTimeout, ZookeeperEventWatcher zookeeperEventWatcher) { + Assert.requireNonNull(hostPort, "hostPort must not be null"); + Assert.isTrue(sessionTimeout > 0, "sessionTimeout must be greater than 0"); + Assert.requireNonNull(zookeeperEventWatcher, "zookeeperEventWatcher must not be null"); + + CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder(); + builder.connectString(hostPort); + builder.retryPolicy(new RetryPolicy() { + @Override + public boolean allowRetry(int retryCount, long elapsedTimeMs, RetrySleeper sleeper) { + return false; + } + }); + + if (sessionTimeout < DEFAULT_CONNECTION_TIMEOUT) { + builder.connectionTimeoutMs(sessionTimeout); + } else { + builder.connectionTimeoutMs(DEFAULT_CONNECTION_TIMEOUT); + } + + builder.sessionTimeoutMs(sessionTimeout); + + this.curatorFramework = builder.build(); + + this.connectionStateListener = new PinpointZookeeperConnectionStateListener(zookeeperEventWatcher); + curatorFramework.getConnectionStateListenable().addListener(connectionStateListener); + } + + public void start() throws IOException, PinpointZookeeperException { + try { + curatorFramework.start(); + boolean connected = curatorFramework.blockUntilConnected(3000, TimeUnit.MILLISECONDS); + if (!connected) { + logger.info("failed while to connect(). it will be retried automatically"); + } + } catch (Exception e) { + if (curatorFramework != null) { + curatorFramework.close(); + } + ZookeeperExceptionResolver.resolve(e, true); + } + } + + public void stop() { + if (curatorFramework != null) { + curatorFramework.close(); + } + } + + public boolean isConnected() { + return curatorFramework.getZookeeperClient().isConnected(); + } + + CuratorFramework getZookeeperClient() { + return curatorFramework; + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/PinpointZookeeperConnectionStateListener.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/PinpointZookeeperConnectionStateListener.java new file mode 100644 index 000000000000..695abe229fc5 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/PinpointZookeeperConnectionStateListener.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper; + +import com.navercorp.pinpoint.common.util.Assert; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.state.ConnectionState; +import org.apache.curator.framework.state.ConnectionStateListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author Taejin Koo + */ +class PinpointZookeeperConnectionStateListener implements ConnectionStateListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final AtomicBoolean connected = new AtomicBoolean(false); + + private final ZookeeperEventWatcher zookeeperEventWatcher; + + public PinpointZookeeperConnectionStateListener(ZookeeperEventWatcher zookeeperEventWatcher) { + this.zookeeperEventWatcher = Assert.requireNonNull(zookeeperEventWatcher, "zookeeperEventWatcher must not be null"); + } + + @Override + public void stateChanged(CuratorFramework client, ConnectionState newState) { + if (newState.isConnected()) { + boolean changed = connected.compareAndSet(false, true); + if (changed) { + logger.info("handleConnected() started."); + boolean result = zookeeperEventWatcher.handleConnected(); + logger.info("handleConnected() completed. result:{}", result); + } + } else { + boolean changed = connected.compareAndSet(true, false); + if (changed) { + logger.info("handleDisconnected() started."); + boolean result = zookeeperEventWatcher.handleDisconnected(); + logger.info("handleDisconnected() completed. result:{}", result); + } + } + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperClient.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperClient.java new file mode 100644 index 000000000000..feccb0b8890a --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperClient.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper; + +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.PinpointZookeeperException; +import org.apache.zookeeper.KeeperException; + +import java.io.IOException; +import java.util.List; + +/** + * @author Taejin Koo + */ +public interface ZookeeperClient { + + void connect() throws IOException; + + void createPath(String path) throws PinpointZookeeperException, InterruptedException; + + String createNode(String zNodePath, byte[] data) throws PinpointZookeeperException, InterruptedException; + + String createOrSetNode(String path, byte[] payload) throws PinpointZookeeperException, KeeperException, InterruptedException; + + byte[] getData(String path) throws PinpointZookeeperException, InterruptedException; + + byte[] getData(String path, boolean watch) throws PinpointZookeeperException, InterruptedException; + + List getChildNodeList(String path, boolean watch) throws PinpointZookeeperException, InterruptedException; + + void delete(String path) throws PinpointZookeeperException, InterruptedException; + + boolean isConnected(); + + + void close(); + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperConstants.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperConstants.java new file mode 100644 index 000000000000..9ef2fa62d4b1 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperConstants.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper; + +/** + * @author Taejin Koo + */ +public class ZookeeperConstants { + + public static final String PATH_SEPARATOR = "/"; + + public static final String PINPOINT_CLUSTER_PATH = "/pinpoint-cluster"; + + public static final String PINPOINT_WEB_CLUSTER_PATH = PINPOINT_CLUSTER_PATH + "/web"; + + public static final String PINPOINT_COLLECTOR_CLUSTER_PATH = PINPOINT_CLUSTER_PATH + "/collector"; + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperEventWatcher.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperEventWatcher.java new file mode 100644 index 000000000000..f1affeea4334 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperEventWatcher.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper; + +import org.apache.zookeeper.Watcher; + +/** + * @author Taejin Koo + */ +public interface ZookeeperEventWatcher extends Watcher { + + boolean handleConnected(); + + boolean handleDisconnected(); + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperExceptionResolver.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperExceptionResolver.java new file mode 100644 index 000000000000..7858753dd902 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ZookeeperExceptionResolver.java @@ -0,0 +1,72 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper; + +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.AuthException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.BadOperationException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.ConnectionException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.NoNodeException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.PinpointZookeeperException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.TimeoutException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.UnknownException; +import org.apache.zookeeper.KeeperException; + +/** + * @author Taejin Koo + */ +public class ZookeeperExceptionResolver { + + public static PinpointZookeeperException resolve(Exception exception, boolean throwException) throws PinpointZookeeperException { + PinpointZookeeperException newException = resolve(exception); + + if (throwException) { + throw newException; + } else { + return newException; + } + } + + static PinpointZookeeperException resolve(Exception exception) { + if (exception instanceof KeeperException) { + KeeperException keeperException = (KeeperException) exception; + switch (keeperException.code()) { + case CONNECTIONLOSS: + case SESSIONEXPIRED: + return new ConnectionException(keeperException.getMessage(), keeperException); + case AUTHFAILED: + case INVALIDACL: + case NOAUTH: + return new AuthException(keeperException.getMessage(), keeperException); + case BADARGUMENTS: + case BADVERSION: + case NOCHILDRENFOREPHEMERALS: + case NOTEMPTY: + case NODEEXISTS: + return new BadOperationException(keeperException.getMessage(), keeperException); + case NONODE: + return new NoNodeException(keeperException.getMessage(), keeperException); + case OPERATIONTIMEOUT: + return new TimeoutException(keeperException.getMessage(), keeperException); + default: + return new UnknownException(keeperException.getMessage(), keeperException); + } + } else { + return new UnknownException(exception.getMessage(), exception); + } + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/AuthException.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/AuthException.java new file mode 100644 index 000000000000..2e2bae9211b6 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/AuthException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper.exception; + +/** + * @author koo.taejin + */ +public class AuthException extends PinpointZookeeperException { + + public AuthException() { + } + + public AuthException(String message) { + super(message); + } + + public AuthException(String message, Throwable cause) { + super(message, cause); + } + + public AuthException(Throwable cause) { + super(cause); + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/BadOperationException.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/BadOperationException.java new file mode 100644 index 000000000000..d70ee888a96c --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/BadOperationException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper.exception; + +/** + * @author koo.taejin + */ +public class BadOperationException extends PinpointZookeeperException { + + public BadOperationException() { + } + + public BadOperationException(String message) { + super(message); + } + + public BadOperationException(String message, Throwable cause) { + super(message, cause); + } + + public BadOperationException(Throwable cause) { + super(cause); + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/ConnectionException.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/ConnectionException.java new file mode 100644 index 000000000000..285e3a0ea3a2 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/ConnectionException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper.exception; + +/** + * @author koo.taejin + */ +public class ConnectionException extends PinpointZookeeperException { + + public ConnectionException() { + } + + public ConnectionException(String message) { + super(message); + } + + public ConnectionException(String message, Throwable cause) { + super(message, cause); + } + + public ConnectionException(Throwable cause) { + super(cause); + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/NoNodeException.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/NoNodeException.java new file mode 100644 index 000000000000..a8006cab8a8a --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/NoNodeException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper.exception; + +/** + * @author koo.taejin + */ +public class NoNodeException extends PinpointZookeeperException { + + public NoNodeException() { + } + + public NoNodeException(String message) { + super(message); + } + + public NoNodeException(String message, Throwable cause) { + super(message, cause); + } + + public NoNodeException(Throwable cause) { + super(cause); + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/PinpointZookeeperException.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/PinpointZookeeperException.java new file mode 100644 index 000000000000..bbbb5362f588 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/PinpointZookeeperException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper.exception; + +/** + * @author koo.taejin + */ +public class PinpointZookeeperException extends Exception { + + public PinpointZookeeperException() { + } + + public PinpointZookeeperException(String message) { + super(message); + } + + public PinpointZookeeperException(String message, Throwable cause) { + super(message, cause); + } + + public PinpointZookeeperException(Throwable cause) { + super(cause); + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/TimeoutException.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/TimeoutException.java new file mode 100644 index 000000000000..944ed29af8e2 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/TimeoutException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper.exception; + +/** + * @author koo.taejin + */ +public class TimeoutException extends PinpointZookeeperException { + + public TimeoutException() { + } + + public TimeoutException(String message) { + super(message); + } + + public TimeoutException(String message, Throwable cause) { + super(message, cause); + } + + public TimeoutException(Throwable cause) { + super(cause); + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/UnknownException.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/UnknownException.java new file mode 100644 index 000000000000..2da28885d183 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/exception/UnknownException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper.exception; + +/** + * @author koo.taejin + */ +public class UnknownException extends PinpointZookeeperException { + + public UnknownException() { + } + + public UnknownException(String message) { + super(message); + } + + public UnknownException(String message, Throwable cause) { + super(message, cause); + } + + public UnknownException(Throwable cause) { + super(cause); + } + +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageDeserializer.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageDeserializer.java index c8945685d1a4..3697bc4b6fc7 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageDeserializer.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageDeserializer.java @@ -1,11 +1,11 @@ /* - * Copyright 2015 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,30 +17,31 @@ package com.navercorp.pinpoint.common.server.util; import com.navercorp.pinpoint.common.util.BytesUtils; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.thrift.io.DeserializerFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; import com.navercorp.pinpoint.thrift.util.SerializationUtils; import org.apache.thrift.TBase; import org.apache.thrift.TException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** * @author HyunGil Jeong + * @deprecated Only AgentEventBo.version is 0 */ public class AgentEventMessageDeserializer { - private final List deserializerFactoryList; + private final List> deserializerFactoryList; - public AgentEventMessageDeserializer(DeserializerFactory deserializerFactory) { - List deserializerFactoryList = new ArrayList(1); - deserializerFactoryList.add(deserializerFactory); - - this.deserializerFactoryList = deserializerFactoryList; + public AgentEventMessageDeserializer(DeserializerFactory deserializerFactory) { + this.deserializerFactoryList = Collections.singletonList(deserializerFactory); } - public AgentEventMessageDeserializer(List deserializerFactoryList) { + public AgentEventMessageDeserializer(List> deserializerFactoryList) { this.deserializerFactoryList = deserializerFactoryList; } @@ -53,9 +54,10 @@ public Object deserialize(AgentEventType agentEventType, byte[] eventBody) throw return null; } if (TBase.class.isAssignableFrom(eventMessageType)) { - for (DeserializerFactory deserializerFactory : deserializerFactoryList) { + for (DeserializerFactory deserializerFactory : deserializerFactoryList) { try { - return SerializationUtils.deserialize(eventBody, deserializerFactory); + Message> deserialize = SerializationUtils.deserialize(eventBody, deserializerFactory); + return deserialize.getData(); } catch (TException e) { // ignore } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageDeserializerV1.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageDeserializerV1.java new file mode 100644 index 000000000000..b88277dc41e2 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageDeserializerV1.java @@ -0,0 +1,141 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.util; + +import com.navercorp.pinpoint.common.buffer.Buffer; +import com.navercorp.pinpoint.common.buffer.FixedBuffer; +import com.navercorp.pinpoint.common.server.bo.event.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.event.MonitorInfoBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadDumpBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadState; +import com.navercorp.pinpoint.common.util.BytesUtils; +import com.navercorp.pinpoint.thrift.dto.TDeadlock; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author jaehong.kim + * AgentEventBo.version is 1 + */ +public class AgentEventMessageDeserializerV1 { + + public Object deserialize(AgentEventType agentEventType, byte[] eventBody) throws UnsupportedEncodingException { + if (agentEventType == null) { + throw new NullPointerException("agentEventType must not be null"); + } + Class eventMessageType = agentEventType.getMessageType(); + if (eventMessageType == Void.class) { + return null; + } + + if (TDeadlock.class.isAssignableFrom(eventMessageType)) { + return deserializeDeadlockBo(eventBody); + } else if (String.class.isAssignableFrom(eventMessageType)) { + return BytesUtils.toString(eventBody); + } + throw new UnsupportedEncodingException("Unsupported event message type [" + eventMessageType.getName() + "]"); + } + + private DeadlockBo deserializeDeadlockBo(final byte[] eventBody) { + final Buffer buffer = new FixedBuffer(eventBody); + + final int deadlockedThreadCount = buffer.readInt(); + final int threadDumpBoListSize = buffer.readVInt(); + final List threadDumpBoList = new ArrayList<>(threadDumpBoListSize); + if (threadDumpBoListSize > 0) { + threadDumpBoList.add(readThreadDumpBo(buffer)); + } + + final DeadlockBo deadlockBo = new DeadlockBo(); + deadlockBo.setDeadlockedThreadCount(deadlockedThreadCount); + deadlockBo.setThreadDumpBoList(threadDumpBoList); + return deadlockBo; + } + + private ThreadDumpBo readThreadDumpBo(final Buffer buffer) { + final String threadName = buffer.readPrefixedString(); + final long threadId = buffer.readLong(); + final long blockedTime = buffer.readLong(); + final long blockedCount = buffer.readLong(); + final long waitedTime = buffer.readLong(); + final long waitedCount = buffer.readLong(); + final String lockName = buffer.readPrefixedString(); + final long lockOwnerId = buffer.readLong(); + final String lockOwnerName = buffer.readPrefixedString(); + final boolean inNative = buffer.readBoolean(); + final boolean suspended = buffer.readBoolean(); + final int threadStateValue = buffer.readInt(); + + final int stackTraceListSize = buffer.readVInt(); + final List stackTraceList = new ArrayList<>(stackTraceListSize); + if (stackTraceListSize > 0) { + for (int i = 0; i < stackTraceListSize; i++) { + final String string = buffer.readPrefixedString(); + stackTraceList.add(string); + } + } + + final int lockedMonitorListSize = buffer.readVInt(); + final List monitorInfoBoList = new ArrayList<>(lockedMonitorListSize); + if (lockedMonitorListSize > 0) { + for (int i = 0; i < lockedMonitorListSize; i++) { + final MonitorInfoBo monitorInfoBo = readMonitorInfoBo(buffer); + monitorInfoBoList.add(monitorInfoBo); + } + } + + final int lockedSynchronizerListSize = buffer.readVInt(); + final List lockedSynchronizerList = new ArrayList<>(lockedSynchronizerListSize); + if (lockedSynchronizerListSize > 0) { + for (int i = 0; i < lockedSynchronizerListSize; i++) { + final String string = buffer.readPrefixedString(); + lockedSynchronizerList.add(string); + } + } + + final ThreadDumpBo threadDumpBo = new ThreadDumpBo(); + threadDumpBo.setThreadName(threadName); + threadDumpBo.setThreadId(threadId); + threadDumpBo.setBlockedTime(blockedTime); + threadDumpBo.setBlockedCount(blockedCount); + threadDumpBo.setWaitedTime(waitedTime); + threadDumpBo.setWaitedCount(waitedCount); + threadDumpBo.setLockName(lockName); + threadDumpBo.setLockOwnerId(lockOwnerId); + threadDumpBo.setLockOwnerName(lockOwnerName); + threadDumpBo.setInNative(inNative); + threadDumpBo.setSuspended(suspended); + threadDumpBo.setThreadState(ThreadState.findByValue(threadStateValue)); + threadDumpBo.setStackTraceList(stackTraceList); + threadDumpBo.setLockedMonitorInfoList(monitorInfoBoList); + threadDumpBo.setLockedSynchronizerList(lockedSynchronizerList); + + return threadDumpBo; + } + + private MonitorInfoBo readMonitorInfoBo(final Buffer buffer) { + final int stackDepth = buffer.readInt(); + final String stackFrame = buffer.readPrefixedString(); + + final MonitorInfoBo monitorInfoBo = new MonitorInfoBo(); + monitorInfoBo.setStackDepth(stackDepth); + monitorInfoBo.setStackFrame(stackFrame); + return monitorInfoBo; + } +} \ No newline at end of file diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializer.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializer.java index 5f4d638d941b..1e22bbaa53b1 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializer.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializer.java @@ -27,6 +27,7 @@ /** * @author HyunGil Jeong + * @deprecated Only AgentEventBo.version is 0 */ public class AgentEventMessageSerializer { diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializerV1.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializerV1.java new file mode 100644 index 000000000000..7bb04b8ba234 --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializerV1.java @@ -0,0 +1,99 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.util; + +import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; +import com.navercorp.pinpoint.common.buffer.Buffer; +import com.navercorp.pinpoint.common.server.bo.event.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.event.MonitorInfoBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadDumpBo; + +/** + * @author jaehong.kim + * AgentEventBo.version is 1 + */ +public class AgentEventMessageSerializerV1 { + + public byte[] serialize(AgentEventType agentEventType, Object eventMessage) { + if (agentEventType == null) { + throw new NullPointerException("agentEventType must not be null"); + } + + if (eventMessage instanceof DeadlockBo) { + return serializeDeadlockBo((DeadlockBo) eventMessage); + } + + throw new IllegalArgumentException("Unsupported event message type [" + eventMessage.getClass().getName() + "]"); + } + + private byte[] serializeDeadlockBo(final DeadlockBo deadlockBo) { + final Buffer buffer = new AutomaticBuffer(); + buffer.putInt(deadlockBo.getDeadlockedThreadCount()); + // Put ThreadDumpBoList + final int threadDumpBoListSize = deadlockBo.getThreadDumpBoList() == null ? 0 : deadlockBo.getThreadDumpBoList().size(); + buffer.putVInt(threadDumpBoListSize); + if (threadDumpBoListSize > 0) { + for (ThreadDumpBo threadDumpBo : deadlockBo.getThreadDumpBoList()) { + putThreadDumpBo(buffer, threadDumpBo); + } + } + return buffer.getBuffer(); + } + + private void putThreadDumpBo(final Buffer buffer, final ThreadDumpBo threadDumpBo) { + buffer.putPrefixedString(threadDumpBo.getThreadName()); + buffer.putLong(threadDumpBo.getThreadId()); + buffer.putLong(threadDumpBo.getBlockedTime()); + buffer.putLong(threadDumpBo.getBlockedCount()); + buffer.putLong(threadDumpBo.getWaitedTime()); + buffer.putLong(threadDumpBo.getWaitedCount()); + buffer.putPrefixedString(threadDumpBo.getLockName()); + buffer.putLong(threadDumpBo.getLockOwnerId()); + buffer.putPrefixedString(threadDumpBo.getLockOwnerName()); + buffer.putBoolean(threadDumpBo.isInNative()); + buffer.putBoolean(threadDumpBo.isSuspended()); + buffer.putInt(threadDumpBo.getThreadState().getValue()); + final int stackTraceSize = threadDumpBo.getStackTraceList() == null ? 0 : threadDumpBo.getStackTraceList().size(); + buffer.putVInt(stackTraceSize); + if (stackTraceSize > 0) { + for (String string : threadDumpBo.getStackTraceList()) { + buffer.putPrefixedString(string); + } + } + + final int lockedMonitorListSize = threadDumpBo.getLockedMonitorInfoList() == null ? 0 : threadDumpBo.getLockedMonitorInfoList().size(); + buffer.putVInt(lockedMonitorListSize); + if (lockedMonitorListSize > 0) { + for (MonitorInfoBo monitorInfoBo : threadDumpBo.getLockedMonitorInfoList()) { + putMonitorInfoBo(buffer, monitorInfoBo); + } + } + + final int lockedSynchronizerListSize = threadDumpBo.getLockedSynchronizerList() == null ? 0 : threadDumpBo.getLockedSynchronizerList().size(); + buffer.putVInt(lockedSynchronizerListSize); + if (lockedSynchronizerListSize > 0) { + for (String string : threadDumpBo.getLockedSynchronizerList()) { + buffer.putPrefixedString(string); + } + } + } + + private void putMonitorInfoBo(final Buffer buffer, final MonitorInfoBo monitorInfoBo) { + buffer.putInt(monitorInfoBo.getStackDepth()); + buffer.putPrefixedString(monitorInfoBo.getStackFrame()); + } +} \ No newline at end of file diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/InetAddressUtils.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/InetAddressUtils.java index bc53213aa40d..06306f811cf7 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/InetAddressUtils.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/InetAddressUtils.java @@ -52,7 +52,7 @@ public static List toInetAddressList(List addressList) { public static InetAddress[] toInetAddressArray(List addressList) { final List inetList = InetAddressUtils.toInetAddressList(addressList); - return inetList.toArray(new InetAddress[inetList.size()]); + return inetList.toArray(new InetAddress[0]); } } diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/ServerTraceMetadataLoaderService.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/ServerTraceMetadataLoaderService.java new file mode 100644 index 000000000000..3a63f0f62afc --- /dev/null +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/ServerTraceMetadataLoaderService.java @@ -0,0 +1,72 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.util; + +import com.navercorp.pinpoint.common.plugin.Plugin; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.common.plugin.ServerPluginLoader; +import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.ServiceTypeInfo; +import com.navercorp.pinpoint.common.trace.TraceMetadataLoader; +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ClassUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ServerTraceMetadataLoaderService implements TraceMetadataLoaderService { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final TraceMetadataLoader loader; + + public ServerTraceMetadataLoaderService(CommonLoggerFactory commonLoggerFactory) { + this(ClassUtils.getDefaultClassLoader(), commonLoggerFactory); + } + + public ServerTraceMetadataLoaderService(ClassLoader classLoader, CommonLoggerFactory commonLoggerFactory) { + Assert.requireNonNull(classLoader, "classLoader must not be null"); + Assert.requireNonNull(commonLoggerFactory, "commonLoggerFactory must not be null"); + + PluginLoader pluginLoader = new ServerPluginLoader(classLoader); + List> traceMetadataProvider = pluginLoader.load(TraceMetadataProvider.class); + + List traceMetadataProviderList = new ArrayList(); + for (Plugin plugin : traceMetadataProvider) { + traceMetadataProviderList.addAll(plugin.getInstanceList()); + } + + this.loader = new TraceMetadataLoader(commonLoggerFactory); + loader.load(traceMetadataProviderList); + } + + @Override + public List getServiceTypeInfos() { + return loader.getServiceTypeInfos(); + } + + @Override + public List getAnnotationKeys() { + return loader.getAnnotationKeys(); + } +} diff --git a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/SpanUtils.java b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/SpanUtils.java index 85af2741620c..667c15a1aa00 100644 --- a/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/SpanUtils.java +++ b/commons-server/src/main/java/com/navercorp/pinpoint/common/server/util/SpanUtils.java @@ -20,13 +20,10 @@ import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; import com.navercorp.pinpoint.common.buffer.Buffer; -import com.navercorp.pinpoint.common.server.bo.BasicSpan; +import com.navercorp.pinpoint.common.server.bo.SpanBo; import com.navercorp.pinpoint.common.util.BytesUtils; import com.navercorp.pinpoint.common.util.TimeUtils; import com.navercorp.pinpoint.common.util.TransactionId; -import com.navercorp.pinpoint.common.util.TransactionIdUtils; -import com.navercorp.pinpoint.thrift.dto.TSpan; -import com.navercorp.pinpoint.thrift.dto.TSpanChunk; /** * @author emeroad @@ -35,36 +32,27 @@ public final class SpanUtils { private SpanUtils() { } - @Deprecated - public static byte[] getAgentIdTraceIndexRowKey(String agentId, long timestamp) { - if (agentId == null) { - throw new IllegalArgumentException("agentId must not null"); - } - final byte[] bAgentId = BytesUtils.toBytes(agentId); - return RowKeyUtils.concatFixedByteAndLong(bAgentId, AGENT_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp)); - } - public static byte[] getApplicationTraceIndexRowKey(String applicationName, long timestamp) { if (applicationName == null) { - throw new IllegalArgumentException("agentId must not null"); + throw new IllegalArgumentException("applicationName must not null"); } final byte[] bApplicationName = BytesUtils.toBytes(applicationName); - return RowKeyUtils.concatFixedByteAndLong(bApplicationName, AGENT_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp)); + return RowKeyUtils.concatFixedByteAndLong(bApplicationName, APPLICATION_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp)); } - public static byte[] getTraceIndexRowKey(byte[] agentId, long timestamp) { - if (agentId == null) { - throw new NullPointerException("agentId must not be null"); + public static byte[] getApplicationTraceIndexRowKey(byte[] applicationName, long timestamp) { + if (applicationName == null) { + throw new NullPointerException("applicationName must not be null"); } - return RowKeyUtils.concatFixedByteAndLong(agentId, AGENT_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp)); + return RowKeyUtils.concatFixedByteAndLong(applicationName, APPLICATION_NAME_MAX_LEN, TimeUtils.reverseTimeMillis(timestamp)); } - public static byte[] getVarTransactionId(TSpan span) { + public static byte[] getVarTransactionId(SpanBo span) { if (span == null) { throw new NullPointerException("span must not be null"); } - final byte[] transactionIdBytes = span.getTransactionId(); - TransactionId transactionId = TransactionIdUtils.parseTransactionId(transactionIdBytes); + + final TransactionId transactionId = span.getTransactionId(); String agentId = transactionId.getAgentId(); if (agentId == null) { agentId = span.getAgentId(); @@ -76,42 +64,4 @@ public static byte[] getVarTransactionId(TSpan span) { buffer.putVLong(transactionId.getTransactionSequence()); return buffer.getBuffer(); } - - @Deprecated - public static byte[] getTransactionId(TSpan span) { - if (span == null) { - throw new NullPointerException("span must not be null"); - } - final byte[] transactionIdBytes = span.getTransactionId(); - TransactionId transactionId = TransactionIdUtils.parseTransactionId(transactionIdBytes); - String agentId = transactionId.getAgentId(); - if (agentId == null) { - agentId = span.getAgentId(); - } - return BytesUtils.stringLongLongToBytes(agentId, AGENT_NAME_MAX_LEN, transactionId.getAgentStartTime(), transactionId.getTransactionSequence()); - - } - - @Deprecated - public static byte[] getTransactionId(TSpanChunk spanChunk) { - if (spanChunk == null) { - throw new NullPointerException("spanChunk must not be null"); - } - final byte[] transactionIdBytes = spanChunk.getTransactionId(); - final TransactionId transactionId = TransactionIdUtils.parseTransactionId(transactionIdBytes); - String agentId = transactionId.getAgentId(); - if (agentId == null) { - agentId = spanChunk.getAgentId(); - } - return BytesUtils.stringLongLongToBytes(agentId, AGENT_NAME_MAX_LEN, transactionId.getAgentStartTime(), transactionId.getTransactionSequence()); - } - - @Deprecated - public static byte[] getTransactionId(BasicSpan basicSpan) { - if (basicSpan == null) { - throw new NullPointerException("basicSpan must not be null"); - } - TransactionId transactionId = basicSpan.getTransactionId(); - return BytesUtils.stringLongLongToBytes(transactionId.getAgentId(), AGENT_NAME_MAX_LEN, transactionId.getAgentStartTime(), transactionId.getTransactionSequence()); - } } diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/RandomTSpan.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/RandomTSpan.java index 0c7fcd8aca74..1b0bfd3fbe82 100644 --- a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/RandomTSpan.java +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/RandomTSpan.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.common.server.bo; import com.navercorp.pinpoint.common.util.TransactionIdUtils; @@ -96,7 +112,7 @@ public TSpanEvent randomTSpanEvent(short sequence) { tSpanEvent.setSequence(sequence); tSpanEvent.setStartElapsed(RandomUtils.nextInt(0, 1000)); tSpanEvent.setEndElapsed(RandomUtils.nextInt(0, 1000)); - tSpanEvent.setRpc(RandomStringUtils.random(10)); +// tSpanEvent.setRpc(RandomStringUtils.random(10)); // Database (2000 ~ 2899) tSpanEvent.setServiceType((short) RandomUtils.nextInt(2000, 2889)); tSpanEvent.setEndPoint(RandomStringUtils.random(10)); diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/SpanFactoryAssert.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/SpanFactoryAssert.java index f6df3bf7df08..d0b7fc605740 100644 --- a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/SpanFactoryAssert.java +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/SpanFactoryAssert.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.common.server.bo; import com.navercorp.pinpoint.common.util.TransactionId; @@ -141,15 +157,15 @@ public void assertSpanChunk(TSpanChunk tSpanChunk, SpanChunkBo spanChunkBo) { private void assertSpanEventList(List spanEventBoList, List spanEventList) { Assert.assertEquals(CollectionUtils.isEmpty(spanEventBoList), CollectionUtils.isEmpty(spanEventList)); if (CollectionUtils.isNotEmpty(spanEventBoList)) { - Map spanEventBoMap = new HashMap(); + Map spanEventBoMap = new HashMap(); for (int i = 0; i < spanEventBoList.size(); i++) { SpanEventBo spanEventBo = spanEventBoList.get(i); - spanEventBoMap.put((long)spanEventBo.getSequence(), spanEventBo); + spanEventBoMap.put((int)spanEventBo.getSequence(), spanEventBo); } for (int i = 0; i < spanEventList.size(); i++) { TSpanEvent tSpanEvent = spanEventList.get(i); - SpanEventBo spanEventBo = spanEventBoMap.get((long) tSpanEvent.getSequence()); + SpanEventBo spanEventBo = spanEventBoMap.get((int) tSpanEvent.getSequence()); Assert.assertNotNull(spanEventBo); assertSpanEvent(tSpanEvent, spanEventBo); } diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/TestAgentStatFactory.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/TestAgentStatFactory.java index a469d8abb15f..1a570733ce7f 100644 --- a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/TestAgentStatFactory.java +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/TestAgentStatFactory.java @@ -17,16 +17,7 @@ package com.navercorp.pinpoint.common.server.bo.codec.stat; import com.navercorp.pinpoint.common.server.bo.JvmGcType; -import com.navercorp.pinpoint.common.server.bo.stat.ActiveTraceBo; -import com.navercorp.pinpoint.common.server.bo.stat.ActiveTraceHistogram; -import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; -import com.navercorp.pinpoint.common.server.bo.stat.DataSourceBo; -import com.navercorp.pinpoint.common.server.bo.stat.DataSourceListBo; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; -import com.navercorp.pinpoint.common.server.bo.stat.JvmGcBo; -import com.navercorp.pinpoint.common.server.bo.stat.JvmGcDetailedBo; -import com.navercorp.pinpoint.common.server.bo.stat.ResponseTimeBo; -import com.navercorp.pinpoint.common.server.bo.stat.TransactionBo; +import com.navercorp.pinpoint.common.server.bo.stat.*; import com.navercorp.pinpoint.common.trace.ServiceType; import org.apache.commons.lang3.RandomUtils; @@ -285,26 +276,26 @@ public static List createResponseTimeBos(String agentId, long st return responseTimeBos; } - public static List createDeadlockBos(String agentId, long startTimestamp, long initialTimestamp) { + public static List createDeadlockBos(String agentId, long startTimestamp, long initialTimestamp) { final int numValues = RandomUtils.nextInt(1, MAX_NUM_TEST_VALUES); return createDeadlockBos(agentId, startTimestamp, initialTimestamp, numValues); } - public static List createDeadlockBos(String agentId, long startTimestamp, long initialTimestamp, int numValues) { - List deadlockBos = new ArrayList(numValues); + public static List createDeadlockBos(String agentId, long startTimestamp, long initialTimestamp, int numValues) { + List deadlockThreadCountBos = new ArrayList(numValues); List startTimestamps = createStartTimestamps(startTimestamp, numValues); List timestamps = createTimestamps(initialTimestamp, numValues); List deadlockCounts = TestAgentStatDataPointFactory.INTEGER.createRandomValues(0, 1000, numValues); for (int i = 0; i < numValues; i++) { - DeadlockBo deadlockBo = new DeadlockBo(); - deadlockBo.setAgentId(agentId); - deadlockBo.setStartTimestamp(startTimestamps.get(i)); - deadlockBo.setTimestamp(timestamps.get(i)); - deadlockBo.setDeadlockedThreadCount(deadlockCounts.get(i)); + DeadlockThreadCountBo deadlockThreadCountBo = new DeadlockThreadCountBo(); + deadlockThreadCountBo.setAgentId(agentId); + deadlockThreadCountBo.setStartTimestamp(startTimestamps.get(i)); + deadlockThreadCountBo.setTimestamp(timestamps.get(i)); + deadlockThreadCountBo.setDeadlockedThreadCount(deadlockCounts.get(i)); - deadlockBos.add(deadlockBo); + deadlockThreadCountBos.add(deadlockThreadCountBo); } - return deadlockBos; + return deadlockThreadCountBos; } private static final int MIN_VALUE_OF_MAX_CONNECTION_SIZE = 20; @@ -354,7 +345,55 @@ private static DataSourceListBo createDataSourceListBo(String agentId, long star return dataSourceListBo; } + public static List createFileDescriptorBos(String agentId, long startTimestamp, long initialTimestamp) { + final int numValues = RandomUtils.nextInt(1, MAX_NUM_TEST_VALUES); + return createFileDescriptorBos(agentId, startTimestamp, initialTimestamp, numValues); + } + + public static List createFileDescriptorBos(String agentId, long startTimestamp, long initialTimestamp, int numValues) { + List fileDescriptorBos = new ArrayList(numValues); + List startTimestamps = createStartTimestamps(startTimestamp, numValues); + List timestamps = createTimestamps(initialTimestamp, numValues); + List openFileDescriptors = TestAgentStatDataPointFactory.LONG.createRandomValues(1L, 10000L, numValues); + for (int i = 0; i < numValues; i++) { + FileDescriptorBo fileDescriptorBo = new FileDescriptorBo(); + fileDescriptorBo.setStartTimestamp(startTimestamps.get(i)); + fileDescriptorBo.setAgentId(agentId); + fileDescriptorBo.setTimestamp(timestamps.get(i)); + fileDescriptorBo.setOpenFileDescriptorCount(openFileDescriptors.get(i)); + fileDescriptorBos.add(fileDescriptorBo); + } + return fileDescriptorBos; + } + public static List createDirectBufferBos(String agentId, long startTimestamp, long initialTimestamp) { + final int numValues = RandomUtils.nextInt(1, MAX_NUM_TEST_VALUES); + return createDirectBufferBos(agentId, startTimestamp, initialTimestamp, numValues); + } + + public static List createDirectBufferBos(String agentId, long startTimestamp, long initialTimestamp, int numValues) { + List directBufferBos = new ArrayList(numValues); + List startTimestamps = createStartTimestamps(startTimestamp, numValues); + List timestamps = createTimestamps(initialTimestamp, numValues); + List directBuffers1 = TestAgentStatDataPointFactory.LONG.createRandomValues(1L, 10000L, numValues); + List directBuffers2 = TestAgentStatDataPointFactory.LONG.createRandomValues(1L, 10000L, numValues); + List directBuffers3 = TestAgentStatDataPointFactory.LONG.createRandomValues(1L, 10000L, numValues); + List directBuffers4 = TestAgentStatDataPointFactory.LONG.createRandomValues(1L, 10000L, numValues); + + for (int i = 0; i < numValues; i++) { + DirectBufferBo directBufferBo = new DirectBufferBo(); + directBufferBo.setStartTimestamp(startTimestamps.get(i)); + directBufferBo.setAgentId(agentId); + directBufferBo.setTimestamp(timestamps.get(i)); + directBufferBo.setDirectCount(directBuffers1.get(i)); + directBufferBo.setDirectMemoryUsed(directBuffers2.get(i)); + directBufferBo.setMappedCount(directBuffers3.get(i)); + directBufferBo.setMappedMemoryUsed(directBuffers4.get(i)); + + directBufferBos.add(directBufferBo); + } + return directBufferBos; + } private static List createStartTimestamps(long startTimestamp, int numValues) { return TestAgentStatDataPointFactory.LONG.createConstantValues(startTimestamp, startTimestamp, numValues); } @@ -377,4 +416,6 @@ private static List createRandomPercentageValues(int numValues) { } return values; } + + } diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferCodecTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferCodecTest.java new file mode 100644 index 000000000000..2bce90376672 --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/DirectBufferCodecTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat.join; + +import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; +import com.navercorp.pinpoint.common.buffer.Buffer; +import com.navercorp.pinpoint.common.buffer.FixedBuffer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatDataPointCodec; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatUtils; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatDecodingContext; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinDirectBufferBo; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Roy Kim + */ +public class DirectBufferCodecTest { + + @Test + public void encodeAndDecodeTest(){ + final String id = "test_app"; + final long currentTime = new Date().getTime(); + final AgentStatDataPointCodec agentStatDataPointCodec = new AgentStatDataPointCodec(); + final DirectBufferCodec directBufferCodec = new DirectBufferCodec(agentStatDataPointCodec); + final Buffer encodedValueBuffer = new AutomaticBuffer(); + final List joinDirectBufferBoList = createJoinDirectBufferBoList(currentTime); + encodedValueBuffer.putByte(directBufferCodec.getVersion()); + directBufferCodec.encodeValues(encodedValueBuffer, joinDirectBufferBoList); + + final Buffer valueBuffer = new FixedBuffer(encodedValueBuffer.getBuffer());; + final long baseTimestamp = AgentStatUtils.getBaseTimestamp(currentTime); + final long timestampDelta = currentTime - baseTimestamp; + final ApplicationStatDecodingContext decodingContext = new ApplicationStatDecodingContext(); + decodingContext.setApplicationId(id); + decodingContext.setBaseTimestamp(baseTimestamp); + decodingContext.setTimestampDelta(timestampDelta); + + assertEquals(valueBuffer.readByte(), directBufferCodec.getVersion()); + List decodedJoinDirectBufferBoList = directBufferCodec.decodeValues(valueBuffer, decodingContext); + for (int i = 0; i < decodedJoinDirectBufferBoList.size(); i++) { + assertTrue(decodedJoinDirectBufferBoList.get(i).equals(joinDirectBufferBoList.get(i))); + } + } + + private List createJoinDirectBufferBoList(long currentTime) { + final String id = "test_app"; + final List joinDirectBufferBoList = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo1 = new JoinDirectBufferBo(id, 80, 1000, "agent1_1", 30, "agent1_2", 80, 1000, "agent1_1", 30, "agent1_2", 80, 1000, "agent1_1", 30, "agent1_2", 80, 1000, "agent1_1", 30, "agent1_2", currentTime); + JoinDirectBufferBo joinDirectBufferBo2 = new JoinDirectBufferBo(id, 70, 900, "agent2_1", 20, "agent2_2", 70, 900, "agent2_1", 20, "agent2_2", 70, 900, "agent2_1", 20, "agent2_2", 70, 900, "agent2_1", 20, "agent2_2", currentTime + 5000); + JoinDirectBufferBo joinDirectBufferBo4 = new JoinDirectBufferBo(id, 60, 800, "agent4_1", 15, "agent4_2", 60, 800, "agent4_1", 15, "agent4_2", 60, 800, "agent4_1", 15, "agent4_2", 60, 800, "agent4_1", 15, "agent4_2", currentTime + 15000); + JoinDirectBufferBo joinDirectBufferBo3 = new JoinDirectBufferBo(id, 50, 700, "agent3_1", 10, "agent3_2", 50, 700, "agent3_1", 10, "agent3_2", 50, 700, "agent3_1", 10, "agent3_2", 50, 700, "agent3_1", 10, "agent3_2", currentTime + 10000); + JoinDirectBufferBo joinDirectBufferBo5 = new JoinDirectBufferBo(id, 40, 600, "agent5_1", 5, "agent5_2", 40, 600, "agent5_1", 5, "agent5_2", 40, 600, "agent5_1", 5, "agent5_2", 40, 600, "agent5_1", 5, "agent5_2", currentTime + 20000); + joinDirectBufferBoList.add(joinDirectBufferBo1); + joinDirectBufferBoList.add(joinDirectBufferBo2); + joinDirectBufferBoList.add(joinDirectBufferBo3); + joinDirectBufferBoList.add(joinDirectBufferBo4); + joinDirectBufferBoList.add(joinDirectBufferBo5); + return joinDirectBufferBoList; + } + +} \ No newline at end of file diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorCodecTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorCodecTest.java new file mode 100644 index 000000000000..ae02332f0ce2 --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/join/FileDescriptorCodecTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat.join; + +import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; +import com.navercorp.pinpoint.common.buffer.Buffer; +import com.navercorp.pinpoint.common.buffer.FixedBuffer; +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatDataPointCodec; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatUtils; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatDecodingContext; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinFileDescriptorBo; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Roy Kim + */ +public class FileDescriptorCodecTest { + + @Test + public void encodeAndDecodeTest(){ + final String id = "test_app"; + final long currentTime = new Date().getTime(); + final AgentStatDataPointCodec agentStatDataPointCodec = new AgentStatDataPointCodec(); + final FileDescriptorCodec fileDescriptorCodec = new FileDescriptorCodec(agentStatDataPointCodec); + final Buffer encodedValueBuffer = new AutomaticBuffer(); + final List joinFileDescriptorBoList = createJoinFileDescriptorBoList(currentTime); + encodedValueBuffer.putByte(fileDescriptorCodec.getVersion()); + fileDescriptorCodec.encodeValues(encodedValueBuffer, joinFileDescriptorBoList); + + final Buffer valueBuffer = new FixedBuffer(encodedValueBuffer.getBuffer());; + final long baseTimestamp = AgentStatUtils.getBaseTimestamp(currentTime); + final long timestampDelta = currentTime - baseTimestamp; + final ApplicationStatDecodingContext decodingContext = new ApplicationStatDecodingContext(); + decodingContext.setApplicationId(id); + decodingContext.setBaseTimestamp(baseTimestamp); + decodingContext.setTimestampDelta(timestampDelta); + + assertEquals(valueBuffer.readByte(), fileDescriptorCodec.getVersion()); + List decodedJoinFileDescriptorBoList = fileDescriptorCodec.decodeValues(valueBuffer, decodingContext); + for (int i = 0; i < decodedJoinFileDescriptorBoList.size(); i++) { + assertTrue(decodedJoinFileDescriptorBoList.get(i).equals(joinFileDescriptorBoList.get(i))); + } + } + + private List createJoinFileDescriptorBoList(long currentTime) { + final String id = "test_app"; + final List joinFileDescriptorBoList = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo1 = new JoinFileDescriptorBo(id, 80, 1000, "agent1_1", 30, "agent1_2", currentTime); + JoinFileDescriptorBo joinFileDescriptorBo2 = new JoinFileDescriptorBo(id, 70, 900, "agent2_1", 20, "agent2_2", currentTime + 5000); + JoinFileDescriptorBo joinFileDescriptorBo4 = new JoinFileDescriptorBo(id, 60, 800, "agent4_1", 15, "agent4_2", currentTime + 15000); + JoinFileDescriptorBo joinFileDescriptorBo3 = new JoinFileDescriptorBo(id, 50, 700, "agent3_1", 10, "agent3_2", currentTime + 10000); + JoinFileDescriptorBo joinFileDescriptorBo5 = new JoinFileDescriptorBo(id, 40, 600, "agent5_1", 5, "agent5_2", currentTime + 20000); + joinFileDescriptorBoList.add(joinFileDescriptorBo1); + joinFileDescriptorBoList.add(joinFileDescriptorBo2); + joinFileDescriptorBoList.add(joinFileDescriptorBo3); + joinFileDescriptorBoList.add(joinFileDescriptorBo4); + joinFileDescriptorBoList.add(joinFileDescriptorBo5); + return joinFileDescriptorBoList; + } + +} \ No newline at end of file diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DeadlockCodecV2Test.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DeadlockCodecV2Test.java index 55a427dc7ed0..c24254676595 100644 --- a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DeadlockCodecV2Test.java +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DeadlockCodecV2Test.java @@ -19,7 +19,7 @@ import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatCodec; import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatCodecTestBase; import com.navercorp.pinpoint.common.server.bo.codec.stat.TestAgentStatFactory; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import org.junit.Assert; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -33,23 +33,23 @@ */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext-test.xml") -public class DeadlockCodecV2Test extends AgentStatCodecTestBase { +public class DeadlockCodecV2Test extends AgentStatCodecTestBase { @Autowired private DeadlockCodecV2 deadlockCodecV2; @Override - protected List createAgentStats(String agentId, long startTimestamp, long initialTimestamp) { + protected List createAgentStats(String agentId, long startTimestamp, long initialTimestamp) { return TestAgentStatFactory.createDeadlockBos(agentId, startTimestamp, initialTimestamp); } @Override - protected AgentStatCodec getCodec() { + protected AgentStatCodec getCodec() { return deadlockCodecV2; } @Override - protected void verify(DeadlockBo expected, DeadlockBo actual) { + protected void verify(DeadlockThreadCountBo expected, DeadlockThreadCountBo actual) { Assert.assertEquals("agentId", expected.getAgentId(), actual.getAgentId()); Assert.assertEquals("startTimestamp", expected.getStartTimestamp(), actual.getStartTimestamp()); Assert.assertEquals("timestamp", expected.getTimestamp(), actual.getTimestamp()); diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DirectBufferCodecV2Test.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DirectBufferCodecV2Test.java new file mode 100644 index 000000000000..f6a954964439 --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/DirectBufferCodecV2Test.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat.v2; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatCodecTestBase; +import com.navercorp.pinpoint.common.server.bo.codec.stat.TestAgentStatFactory; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import org.junit.Assert; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.List; + +/** + * @author Roy Kim + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:applicationContext-test.xml") +public class DirectBufferCodecV2Test extends AgentStatCodecTestBase { + + @Autowired + private DirectBufferCodecV2 directBufferCodecV2; + + @Override + protected List createAgentStats(String agentId, long startTimestamp, long initialTimestamp) { + return TestAgentStatFactory.createDirectBufferBos(agentId, startTimestamp, initialTimestamp); + } + + @Override + protected AgentStatCodec getCodec() { + return directBufferCodecV2; + } + + @Override + protected void verify(DirectBufferBo expected, DirectBufferBo actual) { + Assert.assertEquals("agentId", expected.getAgentId(), actual.getAgentId()); + Assert.assertEquals("startTimestamp", expected.getStartTimestamp(), actual.getStartTimestamp()); + Assert.assertEquals("timestamp", expected.getTimestamp(), actual.getTimestamp()); + Assert.assertEquals("agentStatType", expected.getAgentStatType(), actual.getAgentStatType()); + Assert.assertEquals("directCount", expected.getDirectCount(), actual.getDirectCount()); + Assert.assertEquals("directMemoryUsed", expected.getDirectMemoryUsed(), actual.getDirectMemoryUsed()); + Assert.assertEquals("mappedCount", expected.getMappedCount(), actual.getMappedCount()); + Assert.assertEquals("mappedMemoryUsed", expected.getMappedMemoryUsed(), actual.getMappedMemoryUsed()); + } +} diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/FileDescriptorCodecV2Test.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/FileDescriptorCodecV2Test.java new file mode 100644 index 000000000000..dfaa8289b1e3 --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/codec/stat/v2/FileDescriptorCodecV2Test.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.codec.stat.v2; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatCodec; +import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatCodecTestBase; +import com.navercorp.pinpoint.common.server.bo.codec.stat.TestAgentStatFactory; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatUtils; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import org.junit.Assert; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.List; + +/** + * @author Roy Kim + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:applicationContext-test.xml") +public class FileDescriptorCodecV2Test extends AgentStatCodecTestBase { + + @Autowired + private FileDescriptorCodecV2 fileDescriptorCodecV2; + + @Override + protected List createAgentStats(String agentId, long startTimestamp, long initialTimestamp) { + return TestAgentStatFactory.createFileDescriptorBos(agentId, startTimestamp, initialTimestamp); + } + + @Override + protected AgentStatCodec getCodec() { + return fileDescriptorCodecV2; + } + + @Override + protected void verify(FileDescriptorBo expected, FileDescriptorBo actual) { + Assert.assertEquals("agentId", expected.getAgentId(), actual.getAgentId()); + Assert.assertEquals("startTimestamp", expected.getStartTimestamp(), actual.getStartTimestamp()); + Assert.assertEquals("timestamp", expected.getTimestamp(), actual.getTimestamp()); + Assert.assertEquals("agentStatType", expected.getAgentStatType(), actual.getAgentStatType()); + Assert.assertEquals("openFileDescriptor", expected.getOpenFileDescriptorCount(), actual.getOpenFileDescriptorCount()); + } +} diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanEncoderTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanEncoderTest.java index 20665959ee91..1a8b118acd5e 100644 --- a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanEncoderTest.java +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/SpanEncoderTest.java @@ -157,8 +157,8 @@ private void assertSpan(SpanBo spanBo) { decodingContext.setCollectorAcceptedTime(spanBo.getCollectorAcceptTime()); SpanBo decode = (SpanBo) spanDecoder.decode(qualifier, column, decodingContext); - - logger.debug("span dump \noriginal spanBo:{} \ndecode spanBo:{} ", spanBo, decode); + // TODO Check CI log + // logger.debug("span dump \noriginal spanBo:{} \ndecode spanBo:{} ", spanBo, decode); List notSerializedField = Lists.newArrayList("parentApplicationId", "parentApplicationServiceType"); List excludeField = Lists.newArrayList("annotationBoList", "spanEventBoList"); @@ -185,8 +185,8 @@ private void assertSpanChunk(SpanChunkBo spanChunkBo) { decodingContext.setCollectorAcceptedTime(spanChunkBo.getCollectorAcceptTime()); SpanChunkBo decode = (SpanChunkBo) spanDecoder.decode(qualifier, column, decodingContext); - - logger.debug("spanChunk dump \noriginal spanChunkBo:{} \ndecode spanChunkBo:{} ", spanChunkBo, decode); + // TODO Check CI log + // logger.debug("spanChunk dump \noriginal spanChunkBo:{} \ndecode spanChunkBo:{} ", spanChunkBo, decode); List notSerializedField = Lists.newArrayList("endPoint", "serviceType", "applicationServiceType"); List excludeField = Lists.newArrayList("spanEventBoList"); diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/bitfield/SpanEventBitFieldTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/bitfield/SpanEventBitFieldTest.java index a0607fc110ed..b800e6f1fd6c 100644 --- a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/bitfield/SpanEventBitFieldTest.java +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/serializer/trace/v2/bitfield/SpanEventBitFieldTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield; import com.google.common.collect.Lists; @@ -35,9 +51,6 @@ public void testRpc_first() throws Exception { spanEventBo.setRpc("Rpc"); SpanEventBitField bitField = SpanEventBitField.buildFirst(spanEventBo); - Assert.assertTrue(bitField.isSetRpc()); - - bitField.setRpc(false); Assert.assertFalse(bitField.isSetRpc()); } diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinApplicationStatBoTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinApplicationStatBoTest.java index 44d787e89bf3..990adc262e1c 100644 --- a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinApplicationStatBoTest.java +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinApplicationStatBoTest.java @@ -1127,6 +1127,432 @@ private List createJoinDataSourceListBoList(String id, lon return joinDataSourceListBoList; } + + @Test + public void joinApplicationStatBoByTimeSlice13Test() { + final long currentTime = 1487149800000L; // 18:10:00 15 2 2017 + List joinApplicationStatBoList = new ArrayList(); + joinApplicationStatBoList.add(createJoinApplicationStatBo7("id1", currentTime, 10)); + joinApplicationStatBoList.add(createJoinApplicationStatBo7("id2", currentTime + 1000, -40)); + joinApplicationStatBoList.add(createJoinApplicationStatBo7("id3", currentTime + 2000, -30)); + joinApplicationStatBoList.add(createJoinApplicationStatBo7("id4", currentTime + 3000, 40)); + joinApplicationStatBoList.add(createJoinApplicationStatBo7("id5", currentTime + 4000, -50)); + JoinApplicationStatBo resultJoinApplicationStatBo = JoinApplicationStatBo.joinApplicationStatBoByTimeSlice(joinApplicationStatBoList); + List joinFileDescriptorBoList = resultJoinApplicationStatBo.getJoinFileDescriptorBoList(); + Collections.sort(joinFileDescriptorBoList, new ComparatorImpl7()); + assertJoinFileDescriptorBoList(joinFileDescriptorBoList); + } + @Test + public void joinApplicationStatBoByTimeSlice14Test() { + List joinApplicationStatBoList = new ArrayList(); + + List joinFileDescriptorBoList1 = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo1_1 = new JoinFileDescriptorBo("agent1", 440, 700, "agent1", 300, "agent1", 1498462545000L); + JoinFileDescriptorBo joinFileDescriptorBo1_2 = new JoinFileDescriptorBo("agent1", 330, 400, "agent1", 100, "agent1", 1498462550000L); + JoinFileDescriptorBo joinFileDescriptorBo1_3 = new JoinFileDescriptorBo("agent1", 550, 600, "agent1", 70, "agent1", 1498462555000L); + joinFileDescriptorBoList1.add(joinFileDescriptorBo1_1); + joinFileDescriptorBoList1.add(joinFileDescriptorBo1_2); + joinFileDescriptorBoList1.add(joinFileDescriptorBo1_3); + JoinApplicationStatBo joinApplicationStatBo1 = new JoinApplicationStatBo(); + joinApplicationStatBo1.setId("test_app"); + joinApplicationStatBo1.setJoinFileDescriptorBoList(joinFileDescriptorBoList1); + joinApplicationStatBo1.setTimestamp(1498462545000L); + joinApplicationStatBoList.add(joinApplicationStatBo1); + + List joinFileDescriptorBoList2 = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo2_1 = new JoinFileDescriptorBo("agent1", 330, 700, "agent1", 300, "agent1", 1498462545000L); + JoinFileDescriptorBo joinFileDescriptorBo2_2 = new JoinFileDescriptorBo("agent1", 220, 400, "agent1", 100, "agent1", 1498462550000L); + JoinFileDescriptorBo joinFileDescriptorBo2_3 = new JoinFileDescriptorBo("agent1", 110, 600, "agent1", 70, "agent1", 1498462555000L); + JoinFileDescriptorBo joinFileDescriptorBo2_4 = new JoinFileDescriptorBo("agent1", 770, 600, "agent1", 70, "agent1", 1498462560000L); + joinFileDescriptorBoList2.add(joinFileDescriptorBo2_1); + joinFileDescriptorBoList2.add(joinFileDescriptorBo2_2); + joinFileDescriptorBoList2.add(joinFileDescriptorBo2_3); + joinFileDescriptorBoList2.add(joinFileDescriptorBo2_4); + JoinApplicationStatBo joinApplicationStatBo2 = new JoinApplicationStatBo(); + joinApplicationStatBo2.setId("test_app"); + joinApplicationStatBo2.setJoinFileDescriptorBoList(joinFileDescriptorBoList2); + joinApplicationStatBo2.setTimestamp(1498462545000L); + joinApplicationStatBoList.add(joinApplicationStatBo2); + + List joinFileDescriptorBoList3 = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo3_1 = new JoinFileDescriptorBo("agent1", 220, 700, "agent1", 300, "agent1", 1498462545000L); + JoinFileDescriptorBo joinFileDescriptorBo3_2 = new JoinFileDescriptorBo("agent1", 110, 400, "agent1", 100, "agent1", 1498462550000L); + JoinFileDescriptorBo joinFileDescriptorBo3_3 = new JoinFileDescriptorBo("agent1", 880, 600, "agent1", 70, "agent1", 1498462565000L); + joinFileDescriptorBoList3.add(joinFileDescriptorBo3_1); + joinFileDescriptorBoList3.add(joinFileDescriptorBo3_2); + joinFileDescriptorBoList3.add(joinFileDescriptorBo3_3); + JoinApplicationStatBo joinApplicationStatBo3 = new JoinApplicationStatBo(); + joinApplicationStatBo3.setId("test_app"); + joinApplicationStatBo3.setJoinFileDescriptorBoList(joinFileDescriptorBoList3); + joinApplicationStatBo3.setTimestamp(1498462545000L); + joinApplicationStatBoList.add(joinApplicationStatBo3); + + + JoinApplicationStatBo joinApplicationStatBo = JoinApplicationStatBo.joinApplicationStatBoByTimeSlice(joinApplicationStatBoList); + assertEquals(joinApplicationStatBo.getId(), "test_app"); + assertEquals(joinApplicationStatBo.getTimestamp(), 1498462545000L); + List joinFileDescriptorBoList = joinApplicationStatBo.getJoinFileDescriptorBoList(); + Collections.sort(joinFileDescriptorBoList, new ComparatorImpl7()); + + assertEquals(joinFileDescriptorBoList.size(), 5); + assertEquals(joinFileDescriptorBoList.get(0).getAvgOpenFDCount(), 330,0); + assertEquals(joinFileDescriptorBoList.get(1).getAvgOpenFDCount(), 220,0); + assertEquals(joinFileDescriptorBoList.get(2).getAvgOpenFDCount(), 330,0); + assertEquals(joinFileDescriptorBoList.get(3).getAvgOpenFDCount(), 770,0); + assertEquals(joinFileDescriptorBoList.get(4).getAvgOpenFDCount(), 880,0); + } + + private class ComparatorImpl7 implements Comparator { + @Override + public int compare(JoinFileDescriptorBo bo1, JoinFileDescriptorBo bo2) { + return bo1.getTimestamp() < bo2.getTimestamp() ? -1 : 1; + } + } + + private void assertJoinFileDescriptorBoList(List joinFileDescriptorBoList) { + assertEquals(joinFileDescriptorBoList.size(), 5); + JoinFileDescriptorBo joinFileDescriptorBo1 = joinFileDescriptorBoList.get(0); + assertEquals(joinFileDescriptorBo1.getId(), "id1"); + assertEquals(joinFileDescriptorBo1.getTimestamp(), 1487149800000L); + assertEquals(joinFileDescriptorBo1.getAvgOpenFDCount(), 486, 0); + assertEquals(joinFileDescriptorBo1.getMinOpenFDCount(), 220, 0); + assertEquals(joinFileDescriptorBo1.getMinOpenFDCountAgentId(), "id5_2"); + assertEquals(joinFileDescriptorBo1.getMaxOpenFDCount(), 910, 0); + assertEquals(joinFileDescriptorBo1.getMaxOpenFDCountAgentId(), "id4_1"); + + JoinFileDescriptorBo joinFileDescriptorBo2 = joinFileDescriptorBoList.get(1); + assertEquals(joinFileDescriptorBo2.getId(), "id1"); + assertEquals(joinFileDescriptorBo2.getTimestamp(), 1487149805000L); + assertEquals(joinFileDescriptorBo2.getAvgOpenFDCount(), 386, 0); + assertEquals(joinFileDescriptorBo2.getMinOpenFDCount(), 350, 0); + assertEquals(joinFileDescriptorBo2.getMinOpenFDCountAgentId(), "id5_2"); + assertEquals(joinFileDescriptorBo2.getMaxOpenFDCount(), 810, 0); + assertEquals(joinFileDescriptorBo2.getMaxOpenFDCountAgentId(), "id4_1"); + + JoinFileDescriptorBo joinFileDescriptorBo3 = joinFileDescriptorBoList.get(2); + assertEquals(joinFileDescriptorBo3.getId(), "id1"); + assertEquals(joinFileDescriptorBo3.getTimestamp(), 1487149810000L); + assertEquals(joinFileDescriptorBo3.getAvgOpenFDCount(), 286, 0); + assertEquals(joinFileDescriptorBo3.getMinOpenFDCount(), 220, 0); + assertEquals(joinFileDescriptorBo3.getMinOpenFDCountAgentId(), "id5_2"); + assertEquals(joinFileDescriptorBo3.getMaxOpenFDCount(), 710, 0); + assertEquals(joinFileDescriptorBo3.getMaxOpenFDCountAgentId(), "id4_1"); + + JoinFileDescriptorBo joinFileDescriptorBo4 = joinFileDescriptorBoList.get(3); + assertEquals(joinFileDescriptorBo4.getId(), "id1"); + assertEquals(joinFileDescriptorBo4.getTimestamp(), 1487149815000L); + assertEquals(joinFileDescriptorBo4.getAvgOpenFDCount(), 186, 0); + assertEquals(joinFileDescriptorBo4.getMinOpenFDCount(), 120, 0); + assertEquals(joinFileDescriptorBo4.getMinOpenFDCountAgentId(), "id5_2"); + assertEquals(joinFileDescriptorBo4.getMaxOpenFDCount(), 610, 0); + assertEquals(joinFileDescriptorBo4.getMaxOpenFDCountAgentId(), "id4_1"); + + JoinFileDescriptorBo joinFileDescriptorBo5 = joinFileDescriptorBoList.get(4); + assertEquals(joinFileDescriptorBo5.getId(), "id1"); + assertEquals(joinFileDescriptorBo5.getTimestamp(), 1487149820000L); + assertEquals(joinFileDescriptorBo5.getAvgOpenFDCount(), 86, 0); + assertEquals(joinFileDescriptorBo5.getMinOpenFDCount(), 20, 0); + assertEquals(joinFileDescriptorBo5.getMinOpenFDCountAgentId(), "id5_2"); + assertEquals(joinFileDescriptorBo5.getMaxOpenFDCount(), 930, 0); + assertEquals(joinFileDescriptorBo5.getMaxOpenFDCountAgentId(), "id4_1"); + } + + private JoinApplicationStatBo createJoinApplicationStatBo7(final String id, final long timestamp, final int plus) { + final JoinApplicationStatBo joinApplicationStatBo = new JoinApplicationStatBo(); + joinApplicationStatBo.setId(id); + joinApplicationStatBo.setJoinFileDescriptorBoList(createJoinFileDescriptorBoList(id, timestamp, plus)); + joinApplicationStatBo.setTimestamp(timestamp); + joinApplicationStatBo.setStatType(StatType.APP_STST); + return joinApplicationStatBo; + } + + private List createJoinFileDescriptorBoList(final String id, final long currentTime, int plus) { + final List joinFileDescriptorBoList = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo1 = new JoinFileDescriptorBo(id, 500 + plus, 870 + plus, id + "_1", 270 + plus, id + "_2", currentTime); + JoinFileDescriptorBo joinFileDescriptorBo2 = new JoinFileDescriptorBo(id, 400 + plus, 770 + plus, id + "_1", 400 + plus, id + "_2", currentTime + 5000); + JoinFileDescriptorBo joinFileDescriptorBo3 = new JoinFileDescriptorBo(id, 300 + plus, 670 + plus, id + "_1", 270 + plus, id + "_2", currentTime + 10000); + JoinFileDescriptorBo joinFileDescriptorBo4 = new JoinFileDescriptorBo(id, 200 + plus, 570 + plus, id + "_1", 170 + plus, id + "_2", currentTime + 15000); + JoinFileDescriptorBo joinFileDescriptorBo5 = new JoinFileDescriptorBo(id, 100 + plus, 890 + plus, id + "_1", 70 + plus, id + "_2", currentTime + 20000); + + joinFileDescriptorBoList.add(joinFileDescriptorBo1); + joinFileDescriptorBoList.add(joinFileDescriptorBo2); + joinFileDescriptorBoList.add(joinFileDescriptorBo3); + joinFileDescriptorBoList.add(joinFileDescriptorBo4); + joinFileDescriptorBoList.add(joinFileDescriptorBo5); + + return joinFileDescriptorBoList; + } + + @Test + public void joinApplicationStatBoByTimeSlice15Test() { + final long currentTime = 1487149800000L; // 18:10:00 15 2 2017 + List joinApplicationStatBoList = new ArrayList(); + joinApplicationStatBoList.add(createJoinApplicationStatBo8("id1", currentTime, 10)); + joinApplicationStatBoList.add(createJoinApplicationStatBo8("id2", currentTime + 1000, -40)); + joinApplicationStatBoList.add(createJoinApplicationStatBo8("id3", currentTime + 2000, -30)); + joinApplicationStatBoList.add(createJoinApplicationStatBo8("id4", currentTime + 3000, 40)); + joinApplicationStatBoList.add(createJoinApplicationStatBo8("id5", currentTime + 4000, -50)); + JoinApplicationStatBo resultJoinApplicationStatBo = JoinApplicationStatBo.joinApplicationStatBoByTimeSlice(joinApplicationStatBoList); + List joinDirectBufferBoList = resultJoinApplicationStatBo.getJoinDirectBufferBoList(); + Collections.sort(joinDirectBufferBoList, new ComparatorImpl8()); + assertJoinDirectBufferBoList(joinDirectBufferBoList); + } + @Test + public void joinApplicationStatBoByTimeSlice16Test() { + List joinApplicationStatBoList = new ArrayList(); + + List joinDirectBufferBoList1 = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo1_1 = new JoinDirectBufferBo("agent1", 440, 700, "agent1", 300, "agent1", 440, 700, "agent1", 300, "agent1", 440, 700, "agent1", 300, "agent1", 440, 700, "agent1", 300, "agent1", 1498462545000L); + JoinDirectBufferBo joinDirectBufferBo1_2 = new JoinDirectBufferBo("agent1", 330, 400, "agent1", 100, "agent1", 330, 400, "agent1", 100, "agent1", 330, 400, "agent1", 100, "agent1", 330, 400, "agent1", 100, "agent1", 1498462550000L); + JoinDirectBufferBo joinDirectBufferBo1_3 = new JoinDirectBufferBo("agent1", 550, 600, "agent1", 70, "agent1", 550, 600, "agent1", 70, "agent1", 550, 600, "agent1", 70, "agent1", 550, 600, "agent1", 70, "agent1", 1498462555000L); + joinDirectBufferBoList1.add(joinDirectBufferBo1_1); + joinDirectBufferBoList1.add(joinDirectBufferBo1_2); + joinDirectBufferBoList1.add(joinDirectBufferBo1_3); + JoinApplicationStatBo joinApplicationStatBo1 = new JoinApplicationStatBo(); + joinApplicationStatBo1.setId("test_app"); + joinApplicationStatBo1.setJoinDirectBufferBoList(joinDirectBufferBoList1); + joinApplicationStatBo1.setTimestamp(1498462545000L); + joinApplicationStatBoList.add(joinApplicationStatBo1); + + List joinDirectBufferBoList2 = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo2_1 = new JoinDirectBufferBo("agent1", 330, 700, "agent1", 300, "agent1", 330, 700, "agent1", 300, "agent1", 330, 700, "agent1", 300, "agent1", 330, 700, "agent1", 300, "agent1", 1498462545000L); + JoinDirectBufferBo joinDirectBufferBo2_2 = new JoinDirectBufferBo("agent1", 220, 400, "agent1", 100, "agent1", 220, 400, "agent1", 100, "agent1", 220, 400, "agent1", 100, "agent1", 220, 400, "agent1", 100, "agent1", 1498462550000L); + JoinDirectBufferBo joinDirectBufferBo2_3 = new JoinDirectBufferBo("agent1", 110, 600, "agent1", 70, "agent1", 110, 600, "agent1", 70, "agent1", 110, 600, "agent1", 70, "agent1", 110, 600, "agent1", 70, "agent1", 1498462555000L); + JoinDirectBufferBo joinDirectBufferBo2_4 = new JoinDirectBufferBo("agent1", 770, 600, "agent1", 70, "agent1", 770, 600, "agent1", 70, "agent1", 770, 600, "agent1", 70, "agent1", 770, 600, "agent1", 70, "agent1", 1498462560000L); + joinDirectBufferBoList2.add(joinDirectBufferBo2_1); + joinDirectBufferBoList2.add(joinDirectBufferBo2_2); + joinDirectBufferBoList2.add(joinDirectBufferBo2_3); + joinDirectBufferBoList2.add(joinDirectBufferBo2_4); + JoinApplicationStatBo joinApplicationStatBo2 = new JoinApplicationStatBo(); + joinApplicationStatBo2.setId("test_app"); + joinApplicationStatBo2.setJoinDirectBufferBoList(joinDirectBufferBoList2); + joinApplicationStatBo2.setTimestamp(1498462545000L); + joinApplicationStatBoList.add(joinApplicationStatBo2); + + List joinDirectBufferBoList3 = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo3_1 = new JoinDirectBufferBo("agent1", 220, 700, "agent1", 300, "agent1", 220, 700, "agent1", 300, "agent1", 220, 700, "agent1", 300, "agent1", 220, 700, "agent1", 300, "agent1", 1498462545000L); + JoinDirectBufferBo joinDirectBufferBo3_2 = new JoinDirectBufferBo("agent1", 110, 400, "agent1", 100, "agent1", 110, 400, "agent1", 100, "agent1", 110, 400, "agent1", 100, "agent1", 110, 400, "agent1", 100, "agent1", 1498462550000L); + JoinDirectBufferBo joinDirectBufferBo3_3 = new JoinDirectBufferBo("agent1", 880, 600, "agent1", 70, "agent1", 880, 600, "agent1", 70, "agent1", 880, 600, "agent1", 70, "agent1", 880, 600, "agent1", 70, "agent1", 1498462565000L); + joinDirectBufferBoList3.add(joinDirectBufferBo3_1); + joinDirectBufferBoList3.add(joinDirectBufferBo3_2); + joinDirectBufferBoList3.add(joinDirectBufferBo3_3); + JoinApplicationStatBo joinApplicationStatBo3 = new JoinApplicationStatBo(); + joinApplicationStatBo3.setId("test_app"); + joinApplicationStatBo3.setJoinDirectBufferBoList(joinDirectBufferBoList3); + joinApplicationStatBo3.setTimestamp(1498462545000L); + joinApplicationStatBoList.add(joinApplicationStatBo3); + + + JoinApplicationStatBo joinApplicationStatBo = JoinApplicationStatBo.joinApplicationStatBoByTimeSlice(joinApplicationStatBoList); + assertEquals(joinApplicationStatBo.getId(), "test_app"); + assertEquals(joinApplicationStatBo.getTimestamp(), 1498462545000L); + List joinDirectBufferBoList = joinApplicationStatBo.getJoinDirectBufferBoList(); + Collections.sort(joinDirectBufferBoList, new ComparatorImpl8()); + + assertEquals(joinDirectBufferBoList.size(), 5); + assertEquals(joinDirectBufferBoList.get(0).getAvgDirectCount(), 330,0); + assertEquals(joinDirectBufferBoList.get(0).getAvgDirectMemoryUsed(), 330,0); + assertEquals(joinDirectBufferBoList.get(0).getAvgMappedCount(), 330,0); + assertEquals(joinDirectBufferBoList.get(0).getAvgMappedMemoryUsed(), 330,0); + + assertEquals(joinDirectBufferBoList.get(1).getAvgDirectCount(), 220,0); + assertEquals(joinDirectBufferBoList.get(1).getAvgDirectMemoryUsed(), 220,0); + assertEquals(joinDirectBufferBoList.get(1).getAvgMappedCount(), 220,0); + assertEquals(joinDirectBufferBoList.get(1).getAvgMappedMemoryUsed(), 220,0); + + assertEquals(joinDirectBufferBoList.get(2).getAvgDirectCount(), 330,0); + assertEquals(joinDirectBufferBoList.get(2).getAvgDirectMemoryUsed(), 330,0); + assertEquals(joinDirectBufferBoList.get(2).getAvgMappedCount(), 330,0); + assertEquals(joinDirectBufferBoList.get(2).getAvgMappedMemoryUsed(), 330,0); + + assertEquals(joinDirectBufferBoList.get(3).getAvgDirectCount(), 770,0); + assertEquals(joinDirectBufferBoList.get(3).getAvgDirectMemoryUsed(), 770,0); + assertEquals(joinDirectBufferBoList.get(3).getAvgMappedCount(), 770,0); + assertEquals(joinDirectBufferBoList.get(3).getAvgMappedMemoryUsed(), 770,0); + + assertEquals(joinDirectBufferBoList.get(4).getAvgDirectCount(), 880,0); + assertEquals(joinDirectBufferBoList.get(4).getAvgDirectMemoryUsed(), 880,0); + assertEquals(joinDirectBufferBoList.get(4).getAvgMappedCount(), 880,0); + assertEquals(joinDirectBufferBoList.get(4).getAvgMappedMemoryUsed(), 880,0); + } + + private class ComparatorImpl8 implements Comparator { + @Override + public int compare(JoinDirectBufferBo bo1, JoinDirectBufferBo bo2) { + return bo1.getTimestamp() < bo2.getTimestamp() ? -1 : 1; + } + } + + private void assertJoinDirectBufferBoList(List joinDirectBufferBoList) { + assertEquals(joinDirectBufferBoList.size(), 5); + JoinDirectBufferBo joinDirectBufferBo1 = joinDirectBufferBoList.get(0); + assertEquals(joinDirectBufferBo1.getId(), "id1"); + //1 + assertEquals(joinDirectBufferBo1.getTimestamp(), 1487149800000L); + assertEquals(joinDirectBufferBo1.getAvgDirectCount(), 486, 0); + assertEquals(joinDirectBufferBo1.getMinDirectCount(), 220, 0); + assertEquals(joinDirectBufferBo1.getMinDirectCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo1.getMaxDirectCount(), 910, 0); + assertEquals(joinDirectBufferBo1.getMaxDirectCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo1.getAvgDirectMemoryUsed(), 486, 0); + assertEquals(joinDirectBufferBo1.getMinDirectMemoryUsed(), 220, 0); + assertEquals(joinDirectBufferBo1.getMinDirectMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo1.getMaxDirectMemoryUsed(), 910, 0); + assertEquals(joinDirectBufferBo1.getMaxDirectMemoryUsedAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo1.getAvgMappedCount(), 486, 0); + assertEquals(joinDirectBufferBo1.getMinMappedCount(), 220, 0); + assertEquals(joinDirectBufferBo1.getMinMappedCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo1.getMaxMappedCount(), 910, 0); + assertEquals(joinDirectBufferBo1.getMaxMappedCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo1.getAvgMappedMemoryUsed(), 486, 0); + assertEquals(joinDirectBufferBo1.getMinMappedMemoryUsed(), 220, 0); + assertEquals(joinDirectBufferBo1.getMinMappedMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo1.getMaxMappedMemoryUsed(), 910, 0); + assertEquals(joinDirectBufferBo1.getMaxMappedMemoryUsedAgentId(), "id4_1"); + + //2 + JoinDirectBufferBo joinDirectBufferBo2 = joinDirectBufferBoList.get(1); + assertEquals(joinDirectBufferBo2.getId(), "id1"); + assertEquals(joinDirectBufferBo2.getTimestamp(), 1487149805000L); + assertEquals(joinDirectBufferBo2.getAvgDirectCount(), 386, 0); + assertEquals(joinDirectBufferBo2.getMinDirectCount(), 350, 0); + assertEquals(joinDirectBufferBo2.getMinDirectCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo2.getMaxDirectCount(), 810, 0); + assertEquals(joinDirectBufferBo2.getMaxDirectCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo2.getAvgDirectMemoryUsed(), 386, 0); + assertEquals(joinDirectBufferBo2.getMinDirectMemoryUsed(), 350, 0); + assertEquals(joinDirectBufferBo2.getMinDirectMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo2.getMaxDirectMemoryUsed(), 810, 0); + assertEquals(joinDirectBufferBo2.getMaxDirectMemoryUsedAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo2.getAvgMappedCount(), 386, 0); + assertEquals(joinDirectBufferBo2.getMinMappedCount(), 350, 0); + assertEquals(joinDirectBufferBo2.getMinMappedCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo2.getMaxMappedCount(), 810, 0); + assertEquals(joinDirectBufferBo2.getMaxMappedCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo2.getAvgMappedMemoryUsed(), 386, 0); + assertEquals(joinDirectBufferBo2.getMinMappedMemoryUsed(), 350, 0); + assertEquals(joinDirectBufferBo2.getMinMappedMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo2.getMaxMappedMemoryUsed(), 810, 0); + assertEquals(joinDirectBufferBo2.getMaxMappedMemoryUsedAgentId(), "id4_1"); + + //3 + JoinDirectBufferBo joinDirectBufferBo3 = joinDirectBufferBoList.get(2); + assertEquals(joinDirectBufferBo3.getId(), "id1"); + assertEquals(joinDirectBufferBo3.getTimestamp(), 1487149810000L); + assertEquals(joinDirectBufferBo3.getAvgDirectCount(), 286, 0); + assertEquals(joinDirectBufferBo3.getMinDirectCount(), 220, 0); + assertEquals(joinDirectBufferBo3.getMinDirectCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo3.getMaxDirectCount(), 710, 0); + assertEquals(joinDirectBufferBo3.getMaxDirectCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo3.getAvgDirectMemoryUsed(), 286, 0); + assertEquals(joinDirectBufferBo3.getMinDirectMemoryUsed(), 220, 0); + assertEquals(joinDirectBufferBo3.getMinDirectMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo3.getMaxDirectMemoryUsed(), 710, 0); + assertEquals(joinDirectBufferBo3.getMaxDirectMemoryUsedAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo3.getAvgMappedCount(), 286, 0); + assertEquals(joinDirectBufferBo3.getMinMappedCount(), 220, 0); + assertEquals(joinDirectBufferBo3.getMinMappedCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo3.getMaxMappedCount(), 710, 0); + assertEquals(joinDirectBufferBo3.getMaxMappedCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo3.getAvgMappedMemoryUsed(), 286, 0); + assertEquals(joinDirectBufferBo3.getMinMappedMemoryUsed(), 220, 0); + assertEquals(joinDirectBufferBo3.getMinMappedMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo3.getMaxMappedMemoryUsed(), 710, 0); + assertEquals(joinDirectBufferBo3.getMaxMappedMemoryUsedAgentId(), "id4_1"); + + //4 + JoinDirectBufferBo joinDirectBufferBo4 = joinDirectBufferBoList.get(3); + assertEquals(joinDirectBufferBo4.getId(), "id1"); + assertEquals(joinDirectBufferBo4.getTimestamp(), 1487149815000L); + assertEquals(joinDirectBufferBo4.getAvgDirectCount(), 186, 0); + assertEquals(joinDirectBufferBo4.getMinDirectCount(), 120, 0); + assertEquals(joinDirectBufferBo4.getMinDirectCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo4.getMaxDirectCount(), 610, 0); + assertEquals(joinDirectBufferBo4.getMaxDirectCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo4.getAvgDirectMemoryUsed(), 186, 0); + assertEquals(joinDirectBufferBo4.getMinDirectMemoryUsed(), 120, 0); + assertEquals(joinDirectBufferBo4.getMinDirectMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo4.getMaxDirectMemoryUsed(), 610, 0); + assertEquals(joinDirectBufferBo4.getMaxDirectMemoryUsedAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo4.getAvgMappedCount(), 186, 0); + assertEquals(joinDirectBufferBo4.getMinMappedCount(), 120, 0); + assertEquals(joinDirectBufferBo4.getMinMappedCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo4.getMaxMappedCount(), 610, 0); + assertEquals(joinDirectBufferBo4.getMaxMappedCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo4.getAvgMappedMemoryUsed(), 186, 0); + assertEquals(joinDirectBufferBo4.getMinMappedMemoryUsed(), 120, 0); + assertEquals(joinDirectBufferBo4.getMinMappedMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo4.getMaxMappedMemoryUsed(), 610, 0); + assertEquals(joinDirectBufferBo4.getMaxMappedMemoryUsedAgentId(), "id4_1"); + + //5 + JoinDirectBufferBo joinDirectBufferBo5 = joinDirectBufferBoList.get(4); + assertEquals(joinDirectBufferBo5.getId(), "id1"); + assertEquals(joinDirectBufferBo5.getTimestamp(), 1487149820000L); + assertEquals(joinDirectBufferBo5.getAvgDirectCount(), 86, 0); + assertEquals(joinDirectBufferBo5.getMinDirectCount(), 20, 0); + assertEquals(joinDirectBufferBo5.getMinDirectCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo5.getMaxDirectCount(), 930, 0); + assertEquals(joinDirectBufferBo5.getMaxDirectCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo5.getAvgDirectMemoryUsed(), 86, 0); + assertEquals(joinDirectBufferBo5.getMinDirectMemoryUsed(), 20, 0); + assertEquals(joinDirectBufferBo5.getMinDirectMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo5.getMaxDirectMemoryUsed(), 930, 0); + assertEquals(joinDirectBufferBo5.getMaxDirectMemoryUsedAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo5.getAvgMappedCount(), 86, 0); + assertEquals(joinDirectBufferBo5.getMinMappedCount(), 20, 0); + assertEquals(joinDirectBufferBo5.getMinMappedCountAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo5.getMaxMappedCount(), 930, 0); + assertEquals(joinDirectBufferBo5.getMaxMappedCountAgentId(), "id4_1"); + + assertEquals(joinDirectBufferBo5.getAvgMappedMemoryUsed(), 86, 0); + assertEquals(joinDirectBufferBo5.getMinMappedMemoryUsed(), 20, 0); + assertEquals(joinDirectBufferBo5.getMinMappedMemoryUsedAgentId(), "id5_2"); + assertEquals(joinDirectBufferBo5.getMaxMappedMemoryUsed(), 930, 0); + assertEquals(joinDirectBufferBo5.getMaxMappedMemoryUsedAgentId(), "id4_1"); + + } + + private JoinApplicationStatBo createJoinApplicationStatBo8(final String id, final long timestamp, final int plus) { + final JoinApplicationStatBo joinApplicationStatBo = new JoinApplicationStatBo(); + joinApplicationStatBo.setId(id); + joinApplicationStatBo.setJoinDirectBufferBoList(createJoinDirectBufferBoList(id, timestamp, plus)); + joinApplicationStatBo.setTimestamp(timestamp); + joinApplicationStatBo.setStatType(StatType.APP_STST); + return joinApplicationStatBo; + } + + private List createJoinDirectBufferBoList(final String id, final long currentTime, int plus) { + final List joinDirectBufferBoList = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo1 = new JoinDirectBufferBo(id, 500 + plus, 870 + plus, id + "_1", 270 + plus, id + "_2", 500 + plus, 870 + plus, id + "_1", 270 + plus, id + "_2", 500 + plus, 870 + plus, id + "_1", 270 + plus, id + "_2", 500 + plus, 870 + plus, id + "_1", 270 + plus, id + "_2", currentTime); + JoinDirectBufferBo joinDirectBufferBo2 = new JoinDirectBufferBo(id, 400 + plus, 770 + plus, id + "_1", 400 + plus, id + "_2", 400 + plus, 770 + plus, id + "_1", 400 + plus, id + "_2", 400 + plus, 770 + plus, id + "_1", 400 + plus, id + "_2", 400 + plus, 770 + plus, id + "_1", 400 + plus, id + "_2", currentTime + 5000); + JoinDirectBufferBo joinDirectBufferBo3 = new JoinDirectBufferBo(id, 300 + plus, 670 + plus, id + "_1", 270 + plus, id + "_2", 300 + plus, 670 + plus, id + "_1", 270 + plus, id + "_2", 300 + plus, 670 + plus, id + "_1", 270 + plus, id + "_2", 300 + plus, 670 + plus, id + "_1", 270 + plus, id + "_2", currentTime + 10000); + JoinDirectBufferBo joinDirectBufferBo4 = new JoinDirectBufferBo(id, 200 + plus, 570 + plus, id + "_1", 170 + plus, id + "_2", 200 + plus, 570 + plus, id + "_1", 170 + plus, id + "_2", 200 + plus, 570 + plus, id + "_1", 170 + plus, id + "_2", 200 + plus, 570 + plus, id + "_1", 170 + plus, id + "_2", currentTime + 15000); + JoinDirectBufferBo joinDirectBufferBo5 = new JoinDirectBufferBo(id, 100 + plus, 890 + plus, id + "_1", 70 + plus, id + "_2", 100 + plus, 890 + plus, id + "_1", 70 + plus, id + "_2", 100 + plus, 890 + plus, id + "_1", 70 + plus, id + "_2", 100 + plus, 890 + plus, id + "_1", 70 + plus, id + "_2", currentTime + 20000); + + joinDirectBufferBoList.add(joinDirectBufferBo1); + joinDirectBufferBoList.add(joinDirectBufferBo2); + joinDirectBufferBoList.add(joinDirectBufferBo3); + joinDirectBufferBoList.add(joinDirectBufferBo4); + joinDirectBufferBoList.add(joinDirectBufferBo5); + + return joinDirectBufferBoList; + } + @Test public void createJoinApplicationStatBoTest() { JoinAgentStatBo joinAgentStatBo = new JoinAgentStatBo(); @@ -1231,6 +1657,51 @@ public void createJoinApplicationStatBoTest() { joinDataSourceListBoList.add(joinDataSourceListBo5); joinAgentStatBo.setJoinDataSourceListBoList(joinDataSourceListBoList); + List joinFileDescriptorBoList = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo1 = new JoinFileDescriptorBo("agent1", 44, 70, "agent1", 30, "agent1", 1498462565000L); + JoinFileDescriptorBo joinFileDescriptorBo2 = new JoinFileDescriptorBo("agent1", 33, 40, "agent1", 10, "agent1", 1498462570000L); + JoinFileDescriptorBo joinFileDescriptorBo3 = new JoinFileDescriptorBo("agent1", 55, 60, "agent1", 7, "agent1", 1498462575000L); + JoinFileDescriptorBo joinFileDescriptorBo4 = new JoinFileDescriptorBo("agent1", 11, 80, "agent1", 8, "agent1", 1498462580000L); + JoinFileDescriptorBo joinFileDescriptorBo5 = new JoinFileDescriptorBo("agent1", 22, 70, "agent1", 12, "agent1", 1498462585000L); + joinFileDescriptorBoList.add(joinFileDescriptorBo1); + joinFileDescriptorBoList.add(joinFileDescriptorBo2); + joinFileDescriptorBoList.add(joinFileDescriptorBo3); + joinFileDescriptorBoList.add(joinFileDescriptorBo4); + joinFileDescriptorBoList.add(joinFileDescriptorBo5); + joinAgentStatBo.setJoinFileDescriptorBoList(joinFileDescriptorBoList); + + List joinDirectBufferBoList = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo1 = new JoinDirectBufferBo("agent1", 44, 70, "agent1", 30, "agent1" + , 44, 70, "agent1", 30, "agent1" + , 44, 70, "agent1", 30, "agent1" + , 44, 70, "agent1", 30, "agent1" + , 1498462565000L); + JoinDirectBufferBo joinDirectBufferBo2 = new JoinDirectBufferBo("agent2", 33, 40, "agent2", 10, "agent2" + , 33, 40, "agent2", 10, "agent2" + , 33, 40, "agent2", 10, "agent2" + , 33, 40, "agent2", 10, "agent2" + , 1498462570000L); + JoinDirectBufferBo joinDirectBufferBo3 = new JoinDirectBufferBo("agent3", 55, 60, "agent3", 7, "agent3" + , 55, 60, "agent3", 7, "agent3" + , 55, 60, "agent3", 7, "agent3" + , 55, 60, "agent3", 7, "agent3" + , 1498462575000L); + JoinDirectBufferBo joinDirectBufferBo4 = new JoinDirectBufferBo("agent4", 11, 80, "agent4", 8, "agent4" + , 11, 80, "agent4", 8, "agent4" + , 11, 80, "agent4", 8, "agent4" + , 11, 80, "agent4", 8, "agent4" + , 1498462580000L); + JoinDirectBufferBo joinDirectBufferBo5 = new JoinDirectBufferBo("agent5", 22, 70, "agent5", 12, "agent5" + , 22, 70, "agent5", 12, "agent5" + , 22, 70, "agent5", 12, "agent5" + , 22, 70, "agent5", 12, "agent5" + , 1498462585000L); + joinDirectBufferBoList.add(joinDirectBufferBo1); + joinDirectBufferBoList.add(joinDirectBufferBo2); + joinDirectBufferBoList.add(joinDirectBufferBo3); + joinDirectBufferBoList.add(joinDirectBufferBo4); + joinDirectBufferBoList.add(joinDirectBufferBo5); + joinAgentStatBo.setJoinDirectBufferBoList(joinDirectBufferBoList); List joinApplicationStatBoList = JoinApplicationStatBo.createJoinApplicationStatBo("test_app", joinAgentStatBo, 60000); assertEquals(joinApplicationStatBoList.size(), 1); @@ -1242,6 +1713,7 @@ public void createJoinApplicationStatBoTest() { assertEquals(joinApplicationStatBo.getJoinActiveTraceBoList().size(), 5); assertEquals(joinApplicationStatBo.getJoinResponseTimeBoList().size(), 5); assertEquals(joinApplicationStatBo.getJoinDataSourceListBoList().size(), 5); + assertEquals(joinApplicationStatBo.getJoinFileDescriptorBoList().size(), 5); } @Test @@ -1277,7 +1749,7 @@ public void createJoinApplicationStatBo2Test() { List joinTransactionBoList = new ArrayList(); JoinTransactionBo joinTransactionBo1 = new JoinTransactionBo("agent1", 5000, 150, 20, "agent1", 230, "agent1", 1498462545000L); - JoinTransactionBo joinTransactionBo2 = new JoinTransactionBo("agent2", 5000, 300, 10, "agent2", 400, "agent2", 1498462550000L); + JoinTransactionBo joinTransactionBo2 = new JoinTransactionBo("agent2", 5000, 300, 10, "agent2", 400, "agent1", 1498462550000L); JoinTransactionBo joinTransactionBo3 = new JoinTransactionBo("agent3", 5000, 30, 5, "agent3", 100, "agent3", 1498462555000L); JoinTransactionBo joinTransactionBo4 = new JoinTransactionBo("agent4", 5000, 30, 5, "agent4", 100, "agent4", 1498462560000L); JoinTransactionBo joinTransactionBo5 = new JoinTransactionBo("agent5", 5000, 30, 5, "agent5", 100, "agent5", 1498462565000L); @@ -1348,6 +1820,52 @@ public void createJoinApplicationStatBo2Test() { joinDataSourceListBoList.add(joinDataSourceListBo5); joinAgentStatBo.setJoinDataSourceListBoList(joinDataSourceListBoList); + List joinFileDescriptorBoList = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo1 = new JoinFileDescriptorBo("agent1", 44, 70, "agent1", 30, "agent1", 1498462545000L); + JoinFileDescriptorBo joinFileDescriptorBo2 = new JoinFileDescriptorBo("agent1", 33, 40, "agent1", 10, "agent1", 1498462550000L); + JoinFileDescriptorBo joinFileDescriptorBo3 = new JoinFileDescriptorBo("agent1", 55, 60, "agent1", 7, "agent1", 1498462555000L); + JoinFileDescriptorBo joinFileDescriptorBo4 = new JoinFileDescriptorBo("agent1", 11, 80, "agent1", 8, "agent1", 1498462560000L); + JoinFileDescriptorBo joinFileDescriptorBo5 = new JoinFileDescriptorBo("agent1", 22, 70, "agent1", 12, "agent1", 1498462565000L); + joinFileDescriptorBoList.add(joinFileDescriptorBo1); + joinFileDescriptorBoList.add(joinFileDescriptorBo2); + joinFileDescriptorBoList.add(joinFileDescriptorBo3); + joinFileDescriptorBoList.add(joinFileDescriptorBo4); + joinFileDescriptorBoList.add(joinFileDescriptorBo5); + joinAgentStatBo.setJoinFileDescriptorBoList(joinFileDescriptorBoList); + + List joinDirectBufferBoList = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo1 = new JoinDirectBufferBo("agent1", 44, 70, "agent1", 30, "agent1" + , 44, 70, "agent1", 30, "agent1" + , 44, 70, "agent1", 30, "agent1" + , 44, 70, "agent1", 30, "agent1" + , 1498462545000L); + JoinDirectBufferBo joinDirectBufferBo2 = new JoinDirectBufferBo("agent1", 33, 40, "agent1", 10, "agent1" + , 33, 40, "agent1", 10, "agent1" + , 33, 40, "agent1", 10, "agent1" + , 33, 40, "agent1", 10, "agent1" + , 1498462550000L); + JoinDirectBufferBo joinDirectBufferBo3 = new JoinDirectBufferBo("agent1", 55, 60, "agent1", 7, "agent1" + , 55, 60, "agent1", 7, "agent1" + , 55, 60, "agent1", 7, "agent1" + , 55, 60, "agent1", 7, "agent1" + , 1498462555000L); + JoinDirectBufferBo joinDirectBufferBo4 = new JoinDirectBufferBo("agent1", 11, 80, "agent1", 8, "agent1" + , 11, 80, "agent1", 8, "agent1" + , 11, 80, "agent1", 8, "agent1" + , 11, 80, "agent1", 8, "agent1" + , 1498462560000L); + JoinDirectBufferBo joinDirectBufferBo5 = new JoinDirectBufferBo("agent1", 22, 70, "agent1", 12, "agent1" + , 22, 70, "agent1", 12, "agent1" + , 22, 70, "agent1", 12, "agent1" + , 22, 70, "agent1", 12, "agent1" + , 1498462565000L); + joinDirectBufferBoList.add(joinDirectBufferBo1); + joinDirectBufferBoList.add(joinDirectBufferBo2); + joinDirectBufferBoList.add(joinDirectBufferBo3); + joinDirectBufferBoList.add(joinDirectBufferBo4); + joinDirectBufferBoList.add(joinDirectBufferBo5); + joinAgentStatBo.setJoinDirectBufferBoList(joinDirectBufferBoList); + List joinApplicationStatBoList = JoinApplicationStatBo.createJoinApplicationStatBo("test_app", joinAgentStatBo, 60000); assertEquals(joinApplicationStatBoList.size(), 2); for (JoinApplicationStatBo joinApplicationStatBo : joinApplicationStatBoList) { @@ -1359,6 +1877,8 @@ public void createJoinApplicationStatBo2Test() { assertEquals(joinApplicationStatBo.getJoinActiveTraceBoList().size(), 2); assertEquals(joinApplicationStatBo.getJoinResponseTimeBoList().size(), 2); assertEquals(joinApplicationStatBo.getJoinDataSourceListBoList().size(), 2); + assertEquals(joinApplicationStatBo.getJoinFileDescriptorBoList().size(), 2); + assertEquals(joinApplicationStatBo.getJoinDirectBufferBoList().size(), 2); } else if (joinApplicationStatBo.getTimestamp() == 1498462500000L) { assertEquals(joinApplicationStatBo.getJoinCpuLoadBoList().size(), 3); assertEquals(joinApplicationStatBo.getJoinMemoryBoList().size(), 3); @@ -1366,6 +1886,8 @@ public void createJoinApplicationStatBo2Test() { assertEquals(joinApplicationStatBo.getJoinActiveTraceBoList().size(), 3); assertEquals(joinApplicationStatBo.getJoinResponseTimeBoList().size(), 3); assertEquals(joinApplicationStatBo.getJoinDataSourceListBoList().size(), 3); + assertEquals(joinApplicationStatBo.getJoinFileDescriptorBoList().size(), 3); + assertEquals(joinApplicationStatBo.getJoinDirectBufferBoList().size(), 3); } else { fail(); } @@ -1476,6 +1998,52 @@ public void createJoinApplicationStatBo3Test() { joinDataSourceListBoList.add(joinDataSourceListBo5); joinAgentStatBo.setJoinDataSourceListBoList(joinDataSourceListBoList); + List joinFileDescriptorBoList = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo1 = new JoinFileDescriptorBo("agent1", 44, 70, "agent1", 30, "agent1", 1498462545000L); + JoinFileDescriptorBo joinFileDescriptorBo2 = new JoinFileDescriptorBo("agent1", 33, 40, "agent1", 10, "agent1", 1498462550000L); + JoinFileDescriptorBo joinFileDescriptorBo3 = new JoinFileDescriptorBo("agent1", 55, 60, "agent1", 7, "agent1", 1498462555000L); + JoinFileDescriptorBo joinFileDescriptorBo4 = new JoinFileDescriptorBo("agent1", 11, 80, "agent1", 8, "agent1", 1498462560000L); + JoinFileDescriptorBo joinFileDescriptorBo5 = new JoinFileDescriptorBo("agent1", 22, 70, "agent1", 12, "agent1", 1498462565000L); + joinFileDescriptorBoList.add(joinFileDescriptorBo1); + joinFileDescriptorBoList.add(joinFileDescriptorBo2); + joinFileDescriptorBoList.add(joinFileDescriptorBo3); + joinFileDescriptorBoList.add(joinFileDescriptorBo4); + joinFileDescriptorBoList.add(joinFileDescriptorBo5); + joinAgentStatBo.setJoinFileDescriptorBoList(joinFileDescriptorBoList); + + List joinDirectBufferBoList = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo1 = new JoinDirectBufferBo("agent1", 44, 70, "agent1", 30, "agent1" + , 44, 70, "agent1", 30, "agent1" + , 44, 70, "agent1", 30, "agent1" + , 44, 70, "agent1", 30, "agent1" + , 1498462545000L); + JoinDirectBufferBo joinDirectBufferBo2 = new JoinDirectBufferBo("agent1", 33, 40, "agent1", 10, "agent1" + , 33, 40, "agent1", 10, "agent1" + , 33, 40, "agent1", 10, "agent1" + , 33, 40, "agent1", 10, "agent1" + , 1498462550000L); + JoinDirectBufferBo joinDirectBufferBo3 = new JoinDirectBufferBo("agent1", 55, 60, "agent1", 7, "agent1" + , 55, 60, "agent1", 7, "agent1" + , 55, 60, "agent1", 7, "agent1" + , 55, 60, "agent1", 7, "agent1" + , 1498462555000L); + JoinDirectBufferBo joinDirectBufferBo4 = new JoinDirectBufferBo("agent1", 11, 80, "agent1", 8, "agent1" + , 11, 80, "agent1", 8, "agent1" + , 11, 80, "agent1", 8, "agent1" + , 11, 80, "agent1", 8, "agent1" + , 1498462560000L); + JoinDirectBufferBo joinDirectBufferBo5 = new JoinDirectBufferBo("agent1", 22, 70, "agent1", 12, "agent1" + , 22, 70, "agent1", 12, "agent1" + , 22, 70, "agent1", 12, "agent1" + , 22, 70, "agent1", 12, "agent1" + , 1498462565000L); + joinDirectBufferBoList.add(joinDirectBufferBo1); + joinDirectBufferBoList.add(joinDirectBufferBo2); + joinDirectBufferBoList.add(joinDirectBufferBo3); + joinDirectBufferBoList.add(joinDirectBufferBo4); + joinDirectBufferBoList.add(joinDirectBufferBo5); + joinAgentStatBo.setJoinDirectBufferBoList(joinDirectBufferBoList); + List joinApplicationStatBoList = JoinApplicationStatBo.createJoinApplicationStatBo("test_app", joinAgentStatBo, 10000); assertEquals(joinApplicationStatBoList.size(), 3); for (JoinApplicationStatBo joinApplicationStatBo : joinApplicationStatBoList) { @@ -1487,6 +2055,8 @@ public void createJoinApplicationStatBo3Test() { assertEquals(joinApplicationStatBo.getJoinActiveTraceBoList().size(), 2); assertEquals(joinApplicationStatBo.getJoinResponseTimeBoList().size(), 2); assertEquals(joinApplicationStatBo.getJoinDataSourceListBoList().size(), 2); + assertEquals(joinApplicationStatBo.getJoinFileDescriptorBoList().size(), 2); + assertEquals(joinApplicationStatBo.getJoinDirectBufferBoList().size(), 2); } else if (joinApplicationStatBo.getTimestamp() == 1498462540000L) { assertEquals(joinApplicationStatBo.getJoinCpuLoadBoList().size(), 1); assertEquals(joinApplicationStatBo.getJoinMemoryBoList().size(), 1); @@ -1494,6 +2064,8 @@ public void createJoinApplicationStatBo3Test() { assertEquals(joinApplicationStatBo.getJoinActiveTraceBoList().size(), 1); assertEquals(joinApplicationStatBo.getJoinResponseTimeBoList().size(), 1); assertEquals(joinApplicationStatBo.getJoinDataSourceListBoList().size(), 1); + assertEquals(joinApplicationStatBo.getJoinFileDescriptorBoList().size(), 1); + assertEquals(joinApplicationStatBo.getJoinDirectBufferBoList().size(), 1); } else if (joinApplicationStatBo.getTimestamp() == 1498462550000L) { assertEquals(joinApplicationStatBo.getJoinCpuLoadBoList().size(), 2); assertEquals(joinApplicationStatBo.getJoinMemoryBoList().size(), 2); @@ -1501,6 +2073,8 @@ public void createJoinApplicationStatBo3Test() { assertEquals(joinApplicationStatBo.getJoinActiveTraceBoList().size(), 2); assertEquals(joinApplicationStatBo.getJoinResponseTimeBoList().size(), 2); assertEquals(joinApplicationStatBo.getJoinDataSourceListBoList().size(), 2); + assertEquals(joinApplicationStatBo.getJoinFileDescriptorBoList().size(), 2); + assertEquals(joinApplicationStatBo.getJoinDirectBufferBoList().size(), 2); } else { fail(); } diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDirectBufferBoTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDirectBufferBoTest.java new file mode 100644 index 000000000000..9fb6ca85a9fb --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinDirectBufferBoTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.stat.join; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author minwoo.jung + */ +public class JoinDirectBufferBoTest { + @Test + public void joinDirectBufferBoList() throws Exception { + List joinDirectBufferBoList = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo1 = new JoinDirectBufferBo("agent1", 33, 70, "agent1", 30, "agent1" + , 33, 70, "agent1", 30, "agent1" + , 33, 70, "agent1", 30, "agent1" + , 33, 70, "agent1", 30, "agent1" + , 1496988667231L); + JoinDirectBufferBo joinDirectBufferBo2 = new JoinDirectBufferBo("agent2", 33, 40, "agent2", 10, "agent2" + , 33, 40, "agent2", 10, "agent2" + , 33, 40, "agent2", 10, "agent2" + , 33, 40, "agent2", 10, "agent2" + , 1496988667231L); + JoinDirectBufferBo joinDirectBufferBo3 = new JoinDirectBufferBo("agent3", 54, 60, "agent3", 7, "agent3" + , 54, 60, "agent3", 7, "agent3" + , 54, 60, "agent3", 7, "agent3" + , 54, 60, "agent3", 7, "agent3" + , 1496988667231L); + JoinDirectBufferBo joinDirectBufferBo4 = new JoinDirectBufferBo("agent4", 11, 80, "agent4", 8, "agent4" + , 11, 80, "agent4", 8, "agent4" + , 11, 80, "agent4", 8, "agent4" + , 11, 80, "agent4", 8, "agent4" + , 1496988667231L); + JoinDirectBufferBo joinDirectBufferBo5 = new JoinDirectBufferBo("agent5", 22, 70, "agent5", 12, "agent5" + , 22, 70, "agent5", 12, "agent5" + , 22, 70, "agent5", 12, "agent5" + , 22, 70, "agent5", 12, "agent5" + , 1496988667231L); + + joinDirectBufferBoList.add(joinDirectBufferBo1); + joinDirectBufferBoList.add(joinDirectBufferBo2); + joinDirectBufferBoList.add(joinDirectBufferBo3); + joinDirectBufferBoList.add(joinDirectBufferBo4); + joinDirectBufferBoList.add(joinDirectBufferBo5); + + JoinDirectBufferBo joinDirectBufferBo = JoinDirectBufferBo.joinDirectBufferBoList(joinDirectBufferBoList, 1496988667231L); + assertEquals(joinDirectBufferBo.getId(), "agent1"); + assertEquals(joinDirectBufferBo.getTimestamp(), 1496988667231L); + assertEquals(joinDirectBufferBo.getAvgDirectCount(), 30, 0); + assertEquals(joinDirectBufferBo.getMinDirectCount(), 7, 0); + assertEquals(joinDirectBufferBo.getMinDirectCountAgentId(), "agent3"); + assertEquals(joinDirectBufferBo.getMaxDirectCount(), 80, 0); + assertEquals(joinDirectBufferBo.getMaxDirectCountAgentId(), "agent4"); + + assertEquals(joinDirectBufferBo.getAvgDirectMemoryUsed(), 30, 0); + assertEquals(joinDirectBufferBo.getMinDirectMemoryUsed(), 7, 0); + assertEquals(joinDirectBufferBo.getMinDirectMemoryUsedAgentId(), "agent3"); + assertEquals(joinDirectBufferBo.getMaxDirectMemoryUsed(), 80, 0); + assertEquals(joinDirectBufferBo.getMaxDirectMemoryUsedAgentId(), "agent4"); + + assertEquals(joinDirectBufferBo.getAvgMappedCount(), 30, 0); + assertEquals(joinDirectBufferBo.getMinMappedCount(), 7, 0); + assertEquals(joinDirectBufferBo.getMinMappedCountAgentId(), "agent3"); + assertEquals(joinDirectBufferBo.getMaxMappedCount(), 80, 0); + assertEquals(joinDirectBufferBo.getMaxMappedCountAgentId(), "agent4"); + + assertEquals(joinDirectBufferBo.getAvgMappedMemoryUsed(), 30, 0); + assertEquals(joinDirectBufferBo.getMinMappedMemoryUsed(), 7, 0); + assertEquals(joinDirectBufferBo.getMinMappedMemoryUsedAgentId(), "agent3"); + assertEquals(joinDirectBufferBo.getMaxMappedMemoryUsed(), 80, 0); + assertEquals(joinDirectBufferBo.getMaxMappedMemoryUsedAgentId(), "agent4"); + } + + @Test + public void joinDirectBufferBo2List() { + List joinDirectBufferBoList = new ArrayList(); + JoinDirectBufferBo joinDirectBufferBo = JoinDirectBufferBo.joinDirectBufferBoList(joinDirectBufferBoList, 1496988667231L); + assertEquals(joinDirectBufferBo, JoinDirectBufferBo.EMPTY_JOIN_DIRECT_BUFFER_BO); + } +} \ No newline at end of file diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinFileDescriptorBoTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinFileDescriptorBoTest.java new file mode 100644 index 000000000000..eab449aab38b --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/bo/stat/join/JoinFileDescriptorBoTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.bo.stat.join; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author minwoo.jung + */ +public class JoinFileDescriptorBoTest { + @Test + public void joinFileDescriptorBoList() throws Exception { + List joinFileDescriptorBoList = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo1 = new JoinFileDescriptorBo("agent1", 33, 70, "agent1", 30, "agent1", 1496988667231L); + JoinFileDescriptorBo joinFileDescriptorBo2 = new JoinFileDescriptorBo("agent2", 33, 40, "agent2", 10, "agent2", 1496988667231L); + JoinFileDescriptorBo joinFileDescriptorBo3 = new JoinFileDescriptorBo("agent3", 54, 60, "agent3", 7, "agent3", 1496988667231L); + JoinFileDescriptorBo joinFileDescriptorBo4 = new JoinFileDescriptorBo("agent4", 11, 80, "agent4", 8, "agent4", 1496988667231L); + JoinFileDescriptorBo joinFileDescriptorBo5 = new JoinFileDescriptorBo("agent5", 22, 70, "agent5", 12, "agent5", 1496988667231L); + joinFileDescriptorBoList.add(joinFileDescriptorBo1); + joinFileDescriptorBoList.add(joinFileDescriptorBo2); + joinFileDescriptorBoList.add(joinFileDescriptorBo3); + joinFileDescriptorBoList.add(joinFileDescriptorBo4); + joinFileDescriptorBoList.add(joinFileDescriptorBo5); + + JoinFileDescriptorBo joinFileDescriptorBo = JoinFileDescriptorBo.joinFileDescriptorBoList(joinFileDescriptorBoList, 1496988667231L); + assertEquals(joinFileDescriptorBo.getId(), "agent1"); + assertEquals(joinFileDescriptorBo.getTimestamp(), 1496988667231L); + assertEquals(joinFileDescriptorBo.getAvgOpenFDCount(), 30, 0); + assertEquals(joinFileDescriptorBo.getMinOpenFDCount(), 7, 0); + assertEquals(joinFileDescriptorBo.getMinOpenFDCountAgentId(), "agent3"); + assertEquals(joinFileDescriptorBo.getMaxOpenFDCount(), 80, 0); + assertEquals(joinFileDescriptorBo.getMaxOpenFDCountAgentId(), "agent4"); + } + + @Test + public void joinFileDescriptorBo2List() { + List joinFileDescriptorBoList = new ArrayList(); + JoinFileDescriptorBo joinFileDescriptorBo = JoinFileDescriptorBo.joinFileDescriptorBoList(joinFileDescriptorBoList, 1496988667231L); + assertEquals(joinFileDescriptorBo, JoinFileDescriptorBo.EMPTY_JOIN_FILE_DESCRIPTOR_BO); + } +} \ No newline at end of file diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ConnectionTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ConnectionTest.java new file mode 100644 index 000000000000..980758b7fd75 --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/ConnectionTest.java @@ -0,0 +1,203 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper; + +import com.navercorp.pinpoint.common.server.util.TestAwaitTaskUtils; +import com.navercorp.pinpoint.common.server.util.TestAwaitUtils; +import org.apache.curator.test.TestingServer; +import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.ZooKeeper; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.SocketUtils; + +/** + * This test compares the connection status of Curator and Zookeeper. + * + * @author Taejin Koo + */ +public class ConnectionTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionTest.class); + + private static TestAwaitUtils AWAIT_UTILS = new TestAwaitUtils(100, 3000); + + private static int zookeeperPort; + private static TestingServer ts = null; + + @BeforeClass + public static void setUp() throws Exception { + zookeeperPort = SocketUtils.findAvailableTcpPort(); + ts = createTestingServer(); + } + + private static TestingServer createTestingServer() throws Exception { + return new TestingServer(zookeeperPort); + } + + @AfterClass + public static void tearDown() throws Exception { + if (ts != null) { + ts.stop(); + ts.close(); + } + } + + // If the Instance of ZookeeperServer is changed, Zookeeper will not automatically reconnect. + @Test + public void zookeeperExpiredTest() throws Exception { + ZooKeeper zookeeper = new ZooKeeper(ts.getConnectString(), 5000, null); + + try { + boolean pass = awaitState(zookeeper, ZooKeeper.States.CONNECTED); + Assert.assertTrue(pass); + + ts.restart(); + pass = awaitState(zookeeper, ZooKeeper.States.CONNECTED); + Assert.assertTrue(pass); + + ts.stop(); + ts.close(); + + pass = awaitState(zookeeper, ZooKeeper.States.CONNECTING); + Assert.assertTrue(pass); + + ts = createTestingServer(); + + pass = awaitState(zookeeper, ZooKeeper.States.CONNECTED); + Assert.assertFalse(pass); + } finally { + if (zookeeper != null) { + zookeeper.close(); + } + } + } + + // If the Instance of ZookeeperServer is changed, Zookeeper will not automatically reconnect. + @Test + public void zookeeperReconnectTest() throws Exception { + ZooKeeper zookeeper = new ZooKeeper(ts.getConnectString(), 5000, null); + + try { + boolean pass = awaitState(zookeeper, ZooKeeper.States.CONNECTED); + Assert.assertTrue(pass); + + ts.restart(); + pass = awaitState(zookeeper, ZooKeeper.States.CONNECTED); + Assert.assertTrue(pass); + } finally { + if (zookeeper != null) { + zookeeper.close(); + } + } + } + + private boolean awaitState(ZooKeeper zookeeper, ZooKeeper.States expectedState) { + return AWAIT_UTILS.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + ZooKeeper.States state = zookeeper.getState(); + return state == expectedState; + } + }); + } + + // Even if the Instance of the ZookeeperServer changes, the Curator will automatically reconnect. + @Test + public void curatorExpiredTest() throws Exception { + CuratorZookeeperClient curatorZookeeperClient = new CuratorZookeeperClient(ts.getConnectString(), 5000, new LoggingZookeeperEventWatcher()); + try { + curatorZookeeperClient.connect(); + + boolean pass = awaitState(curatorZookeeperClient, true); + Assert.assertTrue(pass); + + ts.restart(); + + pass = awaitState(curatorZookeeperClient, true); + Assert.assertTrue(pass); + + ts.stop(); + ts.close(); + + pass = awaitState(curatorZookeeperClient, false); + Assert.assertTrue(pass); + + ts = createTestingServer(); + + pass = awaitState(curatorZookeeperClient, true); + Assert.assertTrue(pass); + } finally { + if (curatorZookeeperClient != null) { + curatorZookeeperClient.close(); + } + } + } + + @Test + public void curatorReconnectTest() throws Exception { + CuratorZookeeperClient curatorZookeeperClient = new CuratorZookeeperClient(ts.getConnectString(), 5000, new LoggingZookeeperEventWatcher()); + + try { + curatorZookeeperClient.connect(); + + boolean pass = awaitState(curatorZookeeperClient, true); + Assert.assertTrue(pass); + + ts.restart(); + pass = awaitState(curatorZookeeperClient, true); + Assert.assertTrue(pass); + } finally { + if (curatorZookeeperClient != null) { + curatorZookeeperClient.close(); + } + } + } + + private boolean awaitState(CuratorZookeeperClient curatorZookeeperClient, boolean expectedConnected) { + return AWAIT_UTILS.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return curatorZookeeperClient.isConnected() == expectedConnected; + } + }); + } + + private static class LoggingZookeeperEventWatcher implements ZookeeperEventWatcher { + @Override + public boolean handleConnected() { + LOGGER.info("handleConnected()"); + return true; + } + + @Override + public boolean handleDisconnected() { + LOGGER.info("handleDisconnected()"); + return true; + } + + @Override + public void process(WatchedEvent watchedEvent) { + LOGGER.info("process:{}", watchedEvent); + } + } + +} diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/CuratorZookeeperClientTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/CuratorZookeeperClientTest.java new file mode 100644 index 000000000000..43161febb50a --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/cluster/zookeeper/CuratorZookeeperClientTest.java @@ -0,0 +1,278 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.cluster.zookeeper; + +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.BadOperationException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.PinpointZookeeperException; +import com.navercorp.pinpoint.common.server.util.TestAwaitTaskUtils; +import com.navercorp.pinpoint.common.server.util.TestAwaitUtils; +import org.apache.curator.test.TestingServer; +import org.apache.curator.utils.ZKPaths; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.ZooDefs; +import org.apache.zookeeper.ZooKeeper; +import org.apache.zookeeper.data.Stat; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.SocketUtils; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Taejin Koo + */ +public class CuratorZookeeperClientTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(CuratorZookeeperClientTest.class); + + private static TestAwaitUtils AWAIT_UTILS = new TestAwaitUtils(100, 3000); + + private static TestingServer ts = null; + private static EventHoldingZookeeperEventWatcher eventHoldingZookeeperEventWatcher; + private static CuratorZookeeperClient curatorZookeeperClient; + + private static final String PARENT_PATH = "/a/b/c/"; + + private static final AtomicInteger TEST_NODE_ID = new AtomicInteger(); + + @BeforeClass + public static void setUpClass() throws Exception { + int availablePort = SocketUtils.findAvailableTcpPort(); + ts = new TestingServer(availablePort); + + eventHoldingZookeeperEventWatcher = new EventHoldingZookeeperEventWatcher(); + curatorZookeeperClient = createCuratorZookeeperClient(ts.getConnectString(), eventHoldingZookeeperEventWatcher); + curatorZookeeperClient.createPath(PARENT_PATH); + } + + @Before + public void setUp() throws Exception { + List nodeList = curatorZookeeperClient.getChildNodeList(PARENT_PATH, false); + for (String node : nodeList) { + String fullPath = ZKPaths.makePath(PARENT_PATH, node); + curatorZookeeperClient.delete(fullPath); + } + eventHoldingZookeeperEventWatcher.eventClear(); + } + + private static CuratorZookeeperClient createCuratorZookeeperClient(String connectString, EventHoldingZookeeperEventWatcher zookeeperEventWatcher) throws IOException { + CuratorZookeeperClient curatorZookeeperClient = new CuratorZookeeperClient(connectString, 3000, zookeeperEventWatcher); + curatorZookeeperClient.connect(); + curatorZookeeperClient.connect(); + return curatorZookeeperClient; + } + + @AfterClass + public static void tearDownClass() throws Exception { + try { + if (curatorZookeeperClient != null) { + curatorZookeeperClient.close(); + } + } catch (Exception e) { + // skip + } + + if (ts != null) { + ts.stop(); + ts.close(); + } + } + + @Test + public void createAndDeleteTest() throws Exception { + ZooKeeper zooKeeper = createZookeeper(); + try { + String message = createTestMessage(); + String testNodePath = createTestNodePath(); + + curatorZookeeperClient.createPath(testNodePath); + curatorZookeeperClient.createNode(testNodePath, message.getBytes()); + + byte[] result = curatorZookeeperClient.getData(testNodePath); + Assert.assertEquals(message, new String(result)); + + curatorZookeeperClient.delete(testNodePath); + + Assert.assertFalse(isExistNode(zooKeeper, testNodePath)); + } finally { + if (zooKeeper != null) { + zooKeeper.close(); + } + } + } + + @Test(expected = BadOperationException.class) + public void alreadyExistNodeCreateTest() throws Exception { + ZooKeeper zooKeeper = createZookeeper(); + try { + String message = createTestMessage(); + String testNodePath = createTestNodePath(); + + curatorZookeeperClient.createNode(testNodePath, message.getBytes()); + Assert.assertTrue(isExistNode(zooKeeper, testNodePath)); + + curatorZookeeperClient.createNode(testNodePath, "test".getBytes()); + } finally { + if (zooKeeper != null) { + zooKeeper.close(); + } + } + } + + @Test + public void getTest() throws Exception { + ZooKeeper zooKeeper = createZookeeper(); + try { + String testNodePath = createTestNodePath(); + + curatorZookeeperClient.createNode(testNodePath, "".getBytes()); + Assert.assertTrue(isExistNode(zooKeeper, testNodePath)); + + curatorZookeeperClient.getData(testNodePath, true); + + String message = createTestMessage(); + zooKeeper.setData(testNodePath, message.getBytes(), -1); + assertGetWatchedEvent(testNodePath, message); + + message = createTestMessage(); + curatorZookeeperClient.createOrSetNode(testNodePath, message.getBytes()); + assertGetWatchedEvent(testNodePath, message); + } finally { + if (zooKeeper != null) { + zooKeeper.close(); + } + } + } + + private void assertGetWatchedEvent(String path, String message) throws PinpointZookeeperException { + boolean await = AWAIT_UTILS.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return eventHoldingZookeeperEventWatcher.getLastWatchedEvent() != null; + } + }); + Assert.assertTrue(await); + + WatchedEvent lastWatchedEvent = eventHoldingZookeeperEventWatcher.getLastWatchedEvent(); + Assert.assertEquals(Watcher.Event.EventType.NodeDataChanged, lastWatchedEvent.getType()); + + byte[] result = curatorZookeeperClient.getData(path); + Assert.assertEquals(message, new String(result)); + } + + @Test + public void getChildrenTest() throws Exception { + ZooKeeper zooKeeper = createZookeeper(); + try { + String message = createTestMessage(); + String testNodePath = createTestNodePath(); + + ZKPaths.PathAndNode pathAndNode = ZKPaths.getPathAndNode(testNodePath); + + List childrenNode = curatorZookeeperClient.getChildNodeList(pathAndNode.getPath(), true); + Assert.assertTrue(childrenNode.isEmpty()); + + zooKeeper.create(testNodePath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); + + boolean await = AWAIT_UTILS.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return eventHoldingZookeeperEventWatcher.getLastWatchedEvent() != null; + } + }); + Assert.assertTrue(await); + + WatchedEvent lastWatchedEvent = eventHoldingZookeeperEventWatcher.getLastWatchedEvent(); + Assert.assertEquals(Watcher.Event.EventType.NodeChildrenChanged, lastWatchedEvent.getType()); + + childrenNode = curatorZookeeperClient.getChildNodeList(pathAndNode.getPath(), false); + Assert.assertTrue(!childrenNode.isEmpty()); + } finally { + if (zooKeeper != null) { + zooKeeper.close(); + } + } + } + + private ZooKeeper createZookeeper() throws IOException { + ZooKeeper zooKeeper = new ZooKeeper(ts.getConnectString(), 3000, new Watcher() { + @Override + public void process(WatchedEvent watchedEvent) { + LOGGER.info("ZooKeeper process:{}", watchedEvent); + } + }); + + return zooKeeper; + } + + private boolean isExistNode(ZooKeeper zooKeeper, String path) throws KeeperException, InterruptedException { + Stat isExists = zooKeeper.exists(path, false); + return isExists != null; + } + + private static String createTestMessage() { + return "message-" + TEST_NODE_ID.incrementAndGet(); + } + + private static String createTestNodePath() { + return PARENT_PATH + "test-" + TEST_NODE_ID.incrementAndGet(); + } + + private static class EventHoldingZookeeperEventWatcher implements ZookeeperEventWatcher { + + private WatchedEvent watchedEvent; + + @Override + public boolean handleConnected() { + return true; + } + + @Override + public boolean handleDisconnected() { + return true; + } + + @Override + public void process(WatchedEvent watchedEvent) { + synchronized (this) { + LOGGER.info("process() event:{}", watchedEvent); + this.watchedEvent = watchedEvent; + } + } + + synchronized WatchedEvent getLastWatchedEvent() { + return watchedEvent; + } + + void eventClear() { + synchronized (this) { + watchedEvent = null; + } + } + } + +} diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerDesTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerDesTest.java index fe780471f10a..b33b19055550 100644 --- a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerDesTest.java +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerDesTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,6 +17,7 @@ package com.navercorp.pinpoint.common.server.util; import com.navercorp.pinpoint.common.util.ThreadMXBeanUtils; +import com.navercorp.pinpoint.io.util.TypeLocator; import com.navercorp.pinpoint.thrift.dto.command.TCommandThreadDumpResponse; import com.navercorp.pinpoint.thrift.dto.command.TMonitorInfo; import com.navercorp.pinpoint.thrift.dto.command.TThreadDump; @@ -28,6 +29,7 @@ import com.navercorp.pinpoint.thrift.io.SerializerFactory; import com.navercorp.pinpoint.thrift.io.TCommandRegistry; import com.navercorp.pinpoint.thrift.io.TCommandType; +import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; import org.junit.Test; @@ -36,7 +38,7 @@ import java.lang.management.LockInfo; import java.lang.management.MonitorInfo; import java.lang.management.ThreadInfo; -import java.util.Arrays; +import java.util.Collections; import static org.junit.Assert.assertEquals; @@ -46,14 +48,14 @@ public class AgentEventMessageSerDesTest { private final TProtocolFactory protocolFactory = new TCompactProtocol.Factory(); - private final TCommandRegistry commandTbaseRegistry = new TCommandRegistry(Arrays.asList(TCommandType.THREAD_DUMP_RESPONSE)); + private final TypeLocator> commandTbaseRegistry = TCommandRegistry.build(Collections.singletonList(TCommandType.THREAD_DUMP_RESPONSE)); private final SerializerFactory serializerFactory = new HeaderTBaseSerializerFactory(true, HeaderTBaseSerializerFactory.DEFAULT_STREAM_SIZE, true, this.protocolFactory, this.commandTbaseRegistry); private final DeserializerFactory deserializerFactory = new HeaderTBaseDeserializerFactory(this.protocolFactory, this.commandTbaseRegistry); - private final AgentEventMessageSerializer serializer = new AgentEventMessageSerializer(Arrays.asList(serializerFactory)); + private final AgentEventMessageSerializer serializer = new AgentEventMessageSerializer(Collections.singletonList(serializerFactory)); private final AgentEventMessageDeserializer deserializer = new AgentEventMessageDeserializer(deserializerFactory); @Test diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializerV1Test.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializerV1Test.java new file mode 100644 index 000000000000..3920e616c6b3 --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/AgentEventMessageSerializerV1Test.java @@ -0,0 +1,116 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.util; + +import com.navercorp.pinpoint.common.server.bo.event.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.event.MonitorInfoBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadDumpBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadState; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * @author jaehong.kim + */ +public class AgentEventMessageSerializerV1Test { + + @Test + public void serialize() throws Exception { + AgentEventMessageSerializerV1 serializer = new AgentEventMessageSerializerV1(); + // Mock + final DeadlockBo deadlockBo = new DeadlockBo(); + deadlockBo.setDeadlockedThreadCount(1); + List threadDumpBoList = new ArrayList<>(); + ThreadDumpBo threadDumpBo = new ThreadDumpBo(); + threadDumpBo.setThreadName("threadName"); + threadDumpBo.setThreadId(0); + threadDumpBo.setBlockedTime(1); + threadDumpBo.setBlockedCount(2); + threadDumpBo.setWaitedTime(3); + threadDumpBo.setWaitedCount(4); + threadDumpBo.setLockName("lockName"); + threadDumpBo.setLockOwnerId(5); + threadDumpBo.setLockOwnerName("lockOwnerName"); + threadDumpBo.setInNative(Boolean.TRUE); + threadDumpBo.setSuspended(Boolean.FALSE); + threadDumpBo.setThreadState(ThreadState.RUNNABLE); + threadDumpBo.setStackTraceList(Arrays.asList("foo", "bar")); + + List monitorInfoBoList = new ArrayList<>(); + MonitorInfoBo monitorInfoBo = new MonitorInfoBo(); + monitorInfoBo.setStackDepth(9); + monitorInfoBo.setStackFrame("Frame"); + monitorInfoBoList.add(monitorInfoBo); + threadDumpBo.setLockedMonitorInfoList(monitorInfoBoList); + threadDumpBo.setLockedSynchronizerList(Arrays.asList("foo", "bar")); + + threadDumpBoList.add(threadDumpBo); + deadlockBo.setThreadDumpBoList(threadDumpBoList); + + byte[] bytes = serializer.serialize(AgentEventType.AGENT_DEADLOCK_DETECTED, deadlockBo); + + // deserialize + AgentEventMessageDeserializerV1 deserializer = new AgentEventMessageDeserializerV1(); + Object object = deserializer.deserialize(AgentEventType.AGENT_DEADLOCK_DETECTED, bytes); + if (false == (object instanceof DeadlockBo)) { + fail("Failed to deserialize, expected object is DeadlockBo"); + } + DeadlockBo result = (DeadlockBo) object; + assertEquals(1, result.getDeadlockedThreadCount()); + assertEquals(1, result.getThreadDumpBoList().size()); + assertThreadDumpBo(threadDumpBo, result.getThreadDumpBoList().get(0)); + } + + private void assertThreadDumpBo(ThreadDumpBo expectedThreadDumpBo, ThreadDumpBo threadDumpBo) { + assertEquals(expectedThreadDumpBo.getThreadName(), threadDumpBo.getThreadName()); + assertEquals(expectedThreadDumpBo.getThreadId(), threadDumpBo.getThreadId()); + assertEquals(expectedThreadDumpBo.getBlockedTime(), threadDumpBo.getBlockedTime()); + assertEquals(expectedThreadDumpBo.getBlockedCount(), threadDumpBo.getBlockedCount()); + assertEquals(expectedThreadDumpBo.getWaitedTime(), threadDumpBo.getWaitedTime()); + assertEquals(expectedThreadDumpBo.getWaitedCount(), threadDumpBo.getWaitedCount()); + assertEquals(expectedThreadDumpBo.getLockName(), threadDumpBo.getLockName()); + assertEquals(expectedThreadDumpBo.getLockOwnerId(), threadDumpBo.getLockOwnerId()); + assertEquals(expectedThreadDumpBo.getLockOwnerName(), threadDumpBo.getLockOwnerName()); + assertEquals(expectedThreadDumpBo.isInNative(), threadDumpBo.isInNative()); + assertEquals(expectedThreadDumpBo.isSuspended(), threadDumpBo.isSuspended()); + assertEquals(expectedThreadDumpBo.getThreadState().getValue(), threadDumpBo.getThreadState().getValue()); + assertEquals(expectedThreadDumpBo.getStackTraceList().size(), threadDumpBo.getStackTraceList().size()); + for (int i = 0; i < expectedThreadDumpBo.getStackTraceList().size(); i++) { + final String expectedStackTrace = expectedThreadDumpBo.getStackTraceList().get(i); + final String stackTrace = threadDumpBo.getStackTraceList().get(i); + assertEquals(expectedStackTrace, stackTrace); + } + assertEquals(expectedThreadDumpBo.getLockedMonitorInfoList().size(), threadDumpBo.getLockedMonitorInfoList().size()); + for (int i = 0; i < expectedThreadDumpBo.getLockedMonitorInfoList().size(); i++) { + final MonitorInfoBo expectedMonitorInfoBo = expectedThreadDumpBo.getLockedMonitorInfoList().get(i); + final MonitorInfoBo monitorInfoBo = threadDumpBo.getLockedMonitorInfoList().get(i); + assertEquals(expectedMonitorInfoBo.getStackDepth(), monitorInfoBo.getStackDepth()); + assertEquals(expectedMonitorInfoBo.getStackFrame(), monitorInfoBo.getStackFrame()); + } + assertEquals(expectedThreadDumpBo.getLockedSynchronizerList().size(), threadDumpBo.getLockedSynchronizerList().size()); + for (int i = 0; i < expectedThreadDumpBo.getLockedSynchronizerList().size(); i++) { + final String expectedLockedSynchronizer = expectedThreadDumpBo.getLockedSynchronizerList().get(i); + final String lockedSynchronizer = threadDumpBo.getLockedSynchronizerList().get(i); + assertEquals(expectedLockedSynchronizer, lockedSynchronizer); + } + } +} \ No newline at end of file diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/SpanUtilsTest.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/SpanUtilsTest.java index de46906729f5..e89fddbdf82f 100644 --- a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/SpanUtilsTest.java +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/SpanUtilsTest.java @@ -20,11 +20,8 @@ import com.google.common.primitives.Longs; import com.navercorp.pinpoint.common.PinpointConstants; -import com.navercorp.pinpoint.common.server.bo.SpanBo; -import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.TraceRowKeyDecoderV2; import com.navercorp.pinpoint.common.util.BytesUtils; import com.navercorp.pinpoint.common.util.TimeUtils; -import com.navercorp.pinpoint.common.util.TransactionId; import com.navercorp.pinpoint.thrift.dto.TSpan; import org.junit.Assert; @@ -35,71 +32,57 @@ */ public class SpanUtilsTest { @Test - public void testGetTraceIndexRowKeyWhiteSpace() throws Exception { - String agentId = "test test"; + public void testGetTraceIndexRowKeyWhiteSpace() { + String applicationName = "test test"; long time = System.currentTimeMillis(); - check(agentId, time); + check(applicationName, time); } @Test - public void testGetTraceIndexRowKey1() throws Exception { - String agentId = "test"; + public void testGetTraceIndexRowKey1() { + String applicationName = "test"; long time = System.currentTimeMillis(); - check(agentId, time); + check(applicationName, time); } @Test - public void testGetTraceIndexRowKey2() throws Exception { - String agentId = ""; - for (int i = 0; i < PinpointConstants.AGENT_NAME_MAX_LEN; i++) { - agentId += "1"; + public void testGetTraceIndexRowKey2() { + String applicationName = ""; + for (int i = 0; i < PinpointConstants.APPLICATION_NAME_MAX_LEN; i++) { + applicationName += "1"; } long time = System.currentTimeMillis(); - check(agentId, time); + check(applicationName, time); } @Test - public void testGetTraceIndexRowKey3() throws Exception { - String agentId = ""; - for (int i = 0; i < PinpointConstants.AGENT_NAME_MAX_LEN + 1; i++) { - agentId += "1"; + public void testGetTraceIndexRowKey3() { + String applicationName = ""; + for (int i = 0; i < PinpointConstants.APPLICATION_NAME_MAX_LEN + 1; i++) { + applicationName += "1"; } long time = System.currentTimeMillis(); try { - check(agentId, time); + check(applicationName, time); Assert.fail("error"); } catch (IndexOutOfBoundsException ignore) { } } - private void check(String agentId0, long l1) { + private void check(String applicationName, long l1) { TSpan span = new TSpan(); - span.setAgentId(agentId0); + span.setApplicationName(applicationName); span.setStartTime(l1); - byte[] traceIndexRowKey = SpanUtils.getAgentIdTraceIndexRowKey(span.getAgentId(), span.getStartTime()); + byte[] traceIndexRowKey = SpanUtils.getApplicationTraceIndexRowKey(span.getApplicationName(), span.getStartTime()); - String agentId = BytesUtils.toString(traceIndexRowKey, 0, PinpointConstants.AGENT_NAME_MAX_LEN).trim(); - Assert.assertEquals(agentId0, agentId); + String agentId = BytesUtils.toString(traceIndexRowKey, 0, PinpointConstants.APPLICATION_NAME_MAX_LEN).trim(); + Assert.assertEquals(applicationName, agentId); - long time = Longs.fromByteArray(Arrays.copyOfRange(traceIndexRowKey, PinpointConstants.AGENT_NAME_MAX_LEN, PinpointConstants.AGENT_NAME_MAX_LEN + 8)); + long time = Longs.fromByteArray(Arrays.copyOfRange(traceIndexRowKey, PinpointConstants.APPLICATION_NAME_MAX_LEN, PinpointConstants.APPLICATION_NAME_MAX_LEN + 8)); time = TimeUtils.recoveryTimeMillis(time); Assert.assertEquals(time, l1); } - - @Test - public void testGetTransactionId_BasicSpan() { - SpanBo spanBo = new SpanBo(); - TransactionId spanTransactionId = new TransactionId("traceAgentId", System.currentTimeMillis(), 1111); - spanBo.setTransactionId(spanTransactionId); - - byte[] transactionIdRowkey = SpanUtils.getTransactionId(spanBo); - - TraceRowKeyDecoderV2 decoder = new TraceRowKeyDecoderV2(); - TransactionId transactionId = decoder.readTransactionId(transactionIdRowkey); - - Assert.assertEquals(transactionId, spanBo.getTransactionId()); - } } diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/TestAwaitTaskUtils.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/TestAwaitTaskUtils.java new file mode 100644 index 000000000000..63cb050cb35c --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/TestAwaitTaskUtils.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.util; + +/** + * @author Taejin Koo + */ +public interface TestAwaitTaskUtils { + + boolean checkCompleted(); + +} diff --git a/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/TestAwaitUtils.java b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/TestAwaitUtils.java new file mode 100644 index 000000000000..8423999a886d --- /dev/null +++ b/commons-server/src/test/java/com/navercorp/pinpoint/common/server/util/TestAwaitUtils.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.server.util; + +import com.navercorp.pinpoint.common.util.StopWatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Taejin Koo + */ +public class TestAwaitUtils { + + private final static Logger LOGGER = LoggerFactory.getLogger(TestAwaitUtils.class); + + private final long waitUnitTime; + private final long maxWaitTime; + + public TestAwaitUtils(long waitUnitTime, long maxWaitTime) { + this.waitUnitTime = waitUnitTime; + this.maxWaitTime = maxWaitTime; + } + + public boolean await(TestAwaitTaskUtils awaitTaskUtils) { + return await(awaitTaskUtils, waitUnitTime, maxWaitTime); + } + + public static boolean await(TestAwaitTaskUtils awaitTaskUtils, long waitUnitTime, long maxWaitTime) { + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + while (true) { + try { + if (awaitTaskUtils.checkCompleted()) { + return true; + } + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + + try { + Thread.sleep(waitUnitTime); + } catch (InterruptedException e) { + } + + if (stopWatch.stop() > maxWaitTime) { + return false; + } + } + } + +} diff --git a/commons/clover.license b/commons/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/commons/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-commons @@ -12,19 +12,6 @@ jar - - com.navercorp.pinpoint - pinpoint-thrift - provided - - - - - org.apache.thrift - libthrift - true - - diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/Version.java b/commons/src/main/java/com/navercorp/pinpoint/common/Version.java index 57dd947f9390..69c4a838a343 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/Version.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/Version.java @@ -1,4 +1,4 @@ package com.navercorp.pinpoint.common; public final class Version { - public static final String VERSION = "1.7.2-SNAPSHOT"; + public static final String VERSION = "1.8.1-SNAPSHOT"; } \ No newline at end of file diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/DirClassPathPlugin.java b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/DirClassPathPlugin.java new file mode 100644 index 000000000000..7c5103bd9424 --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/DirClassPathPlugin.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.plugin; + +import com.navercorp.pinpoint.common.util.Assert; + +import java.net.URL; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DirClassPathPlugin implements Plugin { + private final URL pluginUrl; + + private final List instanceList; + private final List packageList; + + public DirClassPathPlugin(URL pluginUrl, List instanceList, List packageList) { + this.pluginUrl = Assert.requireNonNull(pluginUrl, "plugin must not be null"); + this.instanceList = Assert.requireNonNull(instanceList, "instanceList must not be null"); + this.packageList = Assert.requireNonNull(packageList, "packageList must not be null"); + } + + @Override + public URL getURL() { + return pluginUrl; + } + + @Override + public List getInstanceList() { + return instanceList; + } + + @Override + public List getPackageList() { + return packageList; + } + + + @Override + public String toString() { + return "DirClassPathPlugin{" + + "pluginUrl=" + pluginUrl + + ", instanceList=" + instanceList + + ", packageList=" + packageList + + '}'; + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/JarFileUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/JarFileUtils.java new file mode 100644 index 000000000000..b2fc009ba51e --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/JarFileUtils.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.plugin; + + +import java.io.IOException; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class JarFileUtils { + + private JarFileUtils() { + } + + public static String getManifestValue(JarFile jarFile, String key, String defaultValue) { + final Manifest manifest = getManifest(jarFile); + if (manifest == null) { + return defaultValue; + } + + final Attributes attributes = manifest.getMainAttributes(); + final String value = attributes.getValue(key); + if (value == null) { + return defaultValue; + } + return value; + } + + + public static Manifest getManifest(JarFile pluginJarFile) { + try { + return pluginJarFile.getManifest(); + } catch (IOException ex) { + return null; + } + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/JarPlugin.java b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/JarPlugin.java new file mode 100644 index 000000000000..65106a786814 --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/JarPlugin.java @@ -0,0 +1,71 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.plugin; + +import com.navercorp.pinpoint.common.util.Assert; + +import java.net.URL; +import java.util.List; +import java.util.jar.JarFile; + +/** + * @author Woonduk Kang(emeroad) + */ +public class JarPlugin implements Plugin { + private final URL pluginUrl; + private final JarFile pluginJarFIle; + + private final List instanceList; + private final List packageList; + + public JarPlugin(URL pluginUrl, JarFile pluginJarFIle, List instanceList, List packageList) { + this.pluginUrl = Assert.requireNonNull(pluginUrl, "plugin must not be null"); + this.pluginJarFIle = Assert.requireNonNull(pluginJarFIle, "pluginJar must not be null"); + this.instanceList = Assert.requireNonNull(instanceList, "instanceList must not be null"); + this.packageList = Assert.requireNonNull(packageList, "packageList must not be null"); + } + + @Override + public URL getURL() { + return pluginUrl; + } + + @Override + public List getInstanceList() { + return instanceList; + } + + @Override + public List getPackageList() { + return packageList; + } + + + public JarFile getJarFile() { + return pluginJarFIle; + } + + @Override + public String toString() { + return "Plugin{" + + "pluginUrl=" + pluginUrl + + ", pluginJarFIle=" + pluginJarFIle + + ", instanceList=" + instanceList + + ", packageList=" + packageList + + '}'; + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/Plugin.java b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/Plugin.java new file mode 100644 index 000000000000..db20bb78917f --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/Plugin.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.plugin; + +import java.net.URL; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface Plugin { + URL getURL(); + + List getInstanceList(); + + List getPackageList(); +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/PluginLoader.java b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/PluginLoader.java index d5e4e572bf69..5dcdb5503717 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/PluginLoader.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/PluginLoader.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,57 +16,13 @@ package com.navercorp.pinpoint.common.plugin; -import java.net.URL; -import java.net.URLClassLoader; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; import java.util.List; -import java.util.ServiceLoader; /** - * TODO Loading all plugins with a single class loader could cause class collisions. - * Also, with current implementation, plugins can use dependencies by putting them in the plugin directory too. - * But it can lead to dependency collision between plugins because they are loaded by a single class loader. - * - * How can we prevent this? - * A ClassLoader per plugin could do it but then we have to create "N of target class loader" x "N of plugin" class loaders. - * It seems too much. For now, Just leave it as it is. - * - * - * @author Jongho Moon - * @author emeroad - * - * @param + * @author Woonduk Kang(emeroad) */ -public class PluginLoader { - private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); - - public static List load(Class serviceType, URL[] urls) { - URLClassLoader classLoader = createPluginClassLoader(urls, ClassLoader.getSystemClassLoader()); - return load(serviceType, classLoader); - } +public interface PluginLoader { - private static PluginLoaderClassLoader createPluginClassLoader(final URL[] urls, final ClassLoader parent) { - if (SECURITY_MANAGER != null) { - return AccessController.doPrivileged(new PrivilegedAction() { - public PluginLoaderClassLoader run() { - return new PluginLoaderClassLoader(urls, parent); - } - }); - } else { - return new PluginLoaderClassLoader(urls, parent); - } - } - - public static List load(Class serviceType, ClassLoader classLoader) { - ServiceLoader serviceLoader = ServiceLoader.load(serviceType, classLoader); - - List plugins = new ArrayList(); - for (T plugin : serviceLoader) { - plugins.add(serviceType.cast(plugin)); - } + List> load(Class serviceType); - return plugins; - } } diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/PluginLoaderClassLoader.java b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/PluginLoaderClassLoader.java deleted file mode 100644 index 31c9cf00f2e6..000000000000 --- a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/PluginLoaderClassLoader.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.common.plugin; - -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLStreamHandlerFactory; - -/** - * @author emeroad - */ -public class PluginLoaderClassLoader extends URLClassLoader { -// for debug -// private final String loaderName - - public PluginLoaderClassLoader(URL[] urls, ClassLoader parent) { - super(urls, parent); - } - - public PluginLoaderClassLoader(URL[] urls) { - super(urls); - } - - public PluginLoaderClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { - super(urls, parent, factory); - } - - @Override - protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - // for debug - return super.loadClass(name, resolve); - } -} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/plugin/ServerPluginLoader.java b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/ServerPluginLoader.java new file mode 100644 index 000000000000..52a420ff7824 --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/plugin/ServerPluginLoader.java @@ -0,0 +1,83 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.plugin; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.ServiceLoader; +import java.util.jar.JarFile; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ServerPluginLoader implements PluginLoader { + + private final ClassLoader classLoader; + + public ServerPluginLoader(ClassLoader classLoader) { + this.classLoader = Assert.requireNonNull(classLoader, "classLoader must not be null"); + } + + @Override + public List> load(Class serviceType) { + Assert.requireNonNull(serviceType, "serviceType must not be null"); + + List> pluginList = new ArrayList>(); + ServiceLoader serviceLoader = ServiceLoader.load(serviceType, classLoader); + + for (T plugin : serviceLoader) { + Plugin simple = newPlugin(plugin); + pluginList.add(simple); + } + + return pluginList; + } + + private Plugin newPlugin(T plugin) { + final URL pluginURL = CodeSourceUtils.getCodeLocation(plugin.getClass()); + if (pluginURL == null) { + throw new IllegalStateException("pluginURL not found plugin:" + plugin.getClass()); + } + + final File file = new File(pluginURL.getFile()); + if (file.isDirectory()) { + return new DirClassPathPlugin(pluginURL, Collections.singletonList(plugin), Collections.emptyList()); + } + + if (file.getName().endsWith(".jar")) { + JarFile jarFile = toJarFile(file); + return new JarPlugin(pluginURL, jarFile, Collections.singletonList(plugin), Collections.emptyList()); + } + throw new IllegalArgumentException("unknown plugin " + pluginURL); + } + + + private JarFile toJarFile(File file) { + try { + return new JarFile(file); + } catch (IOException e) { + throw new RuntimeException("jarFile create fail " + e.getMessage(), e); + } + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultAnnotationKeyRegistryService.java b/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultAnnotationKeyRegistryService.java index 1375c91ac3b5..bd1e93dab8ac 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultAnnotationKeyRegistryService.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultAnnotationKeyRegistryService.java @@ -18,10 +18,10 @@ import com.navercorp.pinpoint.common.trace.AnnotationKey; import com.navercorp.pinpoint.common.trace.AnnotationKeyRegistry; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.common.util.logger.CommonLogger; import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; import com.navercorp.pinpoint.common.util.StaticFieldLookUp; -import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; import java.util.List; @@ -35,20 +35,12 @@ public class DefaultAnnotationKeyRegistryService implements AnnotationKeyRegistr private final TraceMetadataLoaderService typeLoaderService; private final AnnotationKeyRegistry registry; - public DefaultAnnotationKeyRegistryService() { - this(new DefaultTraceMetadataLoaderService(), StdoutCommonLoggerFactory.INSTANCE); - } - public DefaultAnnotationKeyRegistryService(TraceMetadataLoaderService typeLoaderService, CommonLoggerFactory commonLogger) { - if (typeLoaderService == null) { - throw new NullPointerException("typeLoaderService must not be null"); - } - if (commonLogger == null) { - throw new NullPointerException("commonLogger must not be null"); - } + Assert.requireNonNull(commonLogger, "commonLogger must not be null"); this.logger = commonLogger.getLogger(DefaultAnnotationKeyRegistryService.class.getName()); - this.typeLoaderService = typeLoaderService; + + this.typeLoaderService = Assert.requireNonNull(typeLoaderService, "typeLoaderService must not be null"); this.registry = buildAnnotationKeyRegistry(); } diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultServiceTypeRegistryService.java b/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultServiceTypeRegistryService.java index 3aa3cc7a1baf..6622014d0939 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultServiceTypeRegistryService.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultServiceTypeRegistryService.java @@ -19,10 +19,10 @@ import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.common.trace.ServiceTypeInfo; import com.navercorp.pinpoint.common.trace.ServiceTypeRegistry; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.common.util.logger.CommonLogger; import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; import com.navercorp.pinpoint.common.util.StaticFieldLookUp; -import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; import java.util.List; @@ -36,20 +36,10 @@ public class DefaultServiceTypeRegistryService implements ServiceTypeRegistrySer private final TraceMetadataLoaderService typeLoaderService; private final ServiceTypeRegistry registry; - public DefaultServiceTypeRegistryService() { - this(new DefaultTraceMetadataLoaderService(), StdoutCommonLoggerFactory.INSTANCE); - } - - public DefaultServiceTypeRegistryService(TraceMetadataLoaderService typeLoaderService, CommonLoggerFactory commonLoggerFactory) { - if (typeLoaderService == null) { - throw new NullPointerException("typeLoaderService must not be null"); - } - if (commonLoggerFactory == null) { - throw new NullPointerException("commonLoggerFactory must not be null"); - } + Assert.requireNonNull(commonLoggerFactory, "commonLoggerFactory must not be null"); this.logger = commonLoggerFactory.getLogger(DefaultServiceTypeRegistryService.class.getName()); - this.typeLoaderService = typeLoaderService; + this.typeLoaderService = Assert.requireNonNull(typeLoaderService, "typeLoaderService must not be null"); this.registry = buildServiceTypeRegistry(); } diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultTraceMetadataLoaderService.java b/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultTraceMetadataLoaderService.java index 0deb24691f83..903e736d3108 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultTraceMetadataLoaderService.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/service/DefaultTraceMetadataLoaderService.java @@ -20,11 +20,9 @@ import com.navercorp.pinpoint.common.trace.ServiceTypeInfo; import com.navercorp.pinpoint.common.trace.TraceMetadataLoader; import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; -import com.navercorp.pinpoint.common.util.ClassLoaderUtils; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; -import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; -import java.net.URL; import java.util.List; /** @@ -34,41 +32,16 @@ public class DefaultTraceMetadataLoaderService implements TraceMetadataLoaderSer private final TraceMetadataLoader loader; - public DefaultTraceMetadataLoaderService() { - this(ClassLoaderUtils.getDefaultClassLoader(), StdoutCommonLoggerFactory.INSTANCE); - } - - public DefaultTraceMetadataLoaderService(CommonLoggerFactory commonLoggerFactory) { - this(ClassLoaderUtils.getDefaultClassLoader(), commonLoggerFactory); - } - - public DefaultTraceMetadataLoaderService(URL[] jarLists, CommonLoggerFactory commonLoggerFactory) { - if (jarLists == null) { - throw new NullPointerException("jarLists must not be null"); - } + public DefaultTraceMetadataLoaderService(List providers, CommonLoggerFactory commonLoggerFactory) { + Assert.requireNonNull(commonLoggerFactory, "commonLoggerFactory must not be null"); this.loader = new TraceMetadataLoader(commonLoggerFactory); - loader.load(jarLists); - } - - public DefaultTraceMetadataLoaderService(List providers, CommonLoggerFactory commonLoggerFactory) { - if (providers == null) { - throw new NullPointerException("providers must not be null"); - } - this.loader = new TraceMetadataLoader(); + Assert.requireNonNull(providers, "providers must not be null"); loader.load(providers); } - public DefaultTraceMetadataLoaderService(ClassLoader classLoader, CommonLoggerFactory commonLoggerFactory) { - if (classLoader == null) { - throw new NullPointerException("classLoader must not be null"); - } - this.loader = new TraceMetadataLoader(commonLoggerFactory); - loader.load(classLoader); - } - @Override public List getServiceTypeInfos() { return loader.getServiceTypeInfos(); diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/trace/AnnotationKey.java b/commons/src/main/java/com/navercorp/pinpoint/common/trace/AnnotationKey.java index 22bd77da12c2..bddb7025526e 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/trace/AnnotationKey.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/trace/AnnotationKey.java @@ -16,11 +16,12 @@ package com.navercorp.pinpoint.common.trace; -import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.*; +import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.ERROR_API_METADATA; +import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET; /** * AnnotationKey sandbox is from 900 to 999. These values will not be assigned to anything. - * + * * * * @@ -48,7 +49,7 @@ * * * - * + * * * * @@ -81,10 +82,6 @@ * * * - * - * - * - * * hystrix.command * hystrix.command.execution * hystrix.command.fallback.cause @@ -94,13 +91,35 @@ * hystrix.thread.pool.key * hystrix.collapser.key * - * - * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * * * + * + * * * * + * * * * @@ -108,8 +127,7 @@ * * *
-1args[0]
-2args[1]
-51ExceptionClass
-100Asynchronous Invocation
-9999UNKNOWN
12API
13API_METADATA
14RETURN_DATA
82thrift.result
90dubbo.args
91dubbo.result
130rabbitmq.properties
131rabbitmq.body
132rabbitmq.properties
133rabbitmq.body
110
111
112
117
118
120netty.address
200cxf.operation
201cxf.args
130rabbitmq.properties
131rabbitmq.body
132rabbitmq.properties
133rabbitmq.body
150mongo.json.data
151mongo.collection.info
152mongo.collection.option
153mongo.json
154mongo.json.bindvalue
160grpc.status
200cxf.operation
201cxf.args
203cxf.address
204cxf.response.code
205cxf.encoding
206cxf.http.method
207cxf.content.type
208cxf.headers
209cxf.messages
210cxf.payload
300PROXY_HTTP_HEADER
310REDIS.IO
320hbase.client.params
923marker.message
9000gson.json.length
9001jackson.json.length
9002json-lib.json.length
9003fastjson.json.length
10015API-TAG
10000010API-METADATA-ERROR
10000011API-METADATA-AGENT-INFO-NOT-FOUND
10000013API-METADATA-NOT-FOUND
10000014API-METADATA-DID-COLLSION
- * - * + * * @author netspider * @author emeroad * @author Jongho Moon @@ -120,12 +138,12 @@ public interface AnnotationKey { String getName(); int getCode(); - + boolean isErrorApiMetadata(); boolean isViewInRecordSet(); - + // because of using variable-length encoding, // a small number should be used mainly for data contained in network packets and a big number for internal used code. @@ -141,7 +159,7 @@ public interface AnnotationKey { AnnotationKey API_METADATA = AnnotationKeyFactory.of(13, "API-METADATA"); AnnotationKey RETURN_DATA = AnnotationKeyFactory.of(14, "RETURN_DATA", VIEW_IN_RECORD_SET); AnnotationKey API_TAG = AnnotationKeyFactory.of(10015, "API-TAG"); - + // when you don't know the correct cause of errors. AnnotationKey ERROR_API_METADATA_ERROR = AnnotationKeyFactory.of(10000010, "API-METADATA-ERROR", ERROR_API_METADATA); // when agentInfo not found diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/trace/ServiceType.java b/commons/src/main/java/com/navercorp/pinpoint/common/trace/ServiceType.java index fc38bc79be94..c866e946891d 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/trace/ServiceType.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/trace/ServiceType.java @@ -52,12 +52,24 @@ * 1051VERTX_INTERNAL * 1052VERTX_HTTP_SERVER * 1053VERTX_HTTP_SERVER_INTERNAL + * 1060WEBSPHERE + * 1061WEBSPHERE_METHOD + * 1070WEBLOGIC + * 1071WEBLOGIC_METHOD + * 1080RESERVED + * 1081RESERVED * 1100THRIFT_SERVER * 1101THRIFT_SERVER_INTERNAL * 1110DUBBO_PROVIDER + * 1120UNDERTOW + * 1121UNDERTOW_METHOD + * 1130GRPC_SERVER * * 1500PHP * 1501PHP_METHOD + * 1620OPENWHISK_INTERNAL + * 1621OPENWHISK_CONTROLLER + * 1622OPENWHISK_INVOKER * * * @@ -85,6 +97,8 @@ * 2501POSTGRESQL_EXECUTE_QUERY * 2600CASSANDRA * 2601CASSANDRA_EXECUTE_QUERY + * 2700COUCHDB + * 2701COUCHDB_EXECUTE_QUERY * * *

Database Sandbox (2900 ~ 2999)

@@ -100,8 +114,10 @@ * 5010GSON * 5011JACKSON * 5012JSON-LIB + * 5013FASTJSON * 5050SPRING * 5051SPRING_MVC + * 5052SPRING_ASYNC * 5061RESERVED * 5071SPRING_BEAN * 5500IBATIS @@ -110,6 +126,7 @@ * 6050DBCP * 6052DBCP2 * 6060HIKARICP + * 6062DRUID * 6500RXJAVA * 7010USER_INCLUDE * @@ -131,6 +148,12 @@ * 8300RABBITMQ * 8310ACTIVEMQ_CLIENT * 8311ACTIVEMQ_CLIENT_INTERNAL + * 8660KAFKA_CLIENT + * 8661KAFKA_CLIENT_INTERNAL + * 8800HBASE_CLIENT + * 8801HBASE_CLIENT_ADMIN + * 8802HBASE_CLIENT_TABLE + * 8803HBASE_ASYNC_CLIENT * *

Cache Library Sandbox (8900 ~ 8999) Histogram type: Fast

* @@ -149,7 +172,11 @@ * 9059OK_HTTP_CLIENT_INTERNAL * 9060RESERVED * 9070RESERVED - * 9080APACHE_CXF_CLIENT + * 9080APACHE_CXF_CLIENT + * 9081APACHE_CXF_SERVICE_INVOKER + * 9082APACHE_CXF_MESSAGE_SENDER + * 9083APACHE_CXF_LOGGING_IN + * 9084APACHE_CXF_LOGGING_OUT * 9100THRIFT_CLIENT * 9101THRIFT_CLIENT_INTERNAL * 9110DUBBO_CONSUMER @@ -160,6 +187,10 @@ * 9150NETTY * 9151NETTY_INTERNAL * 9152NETTY_HTTP + * 9160GRPC + * 9161GRPC_INTERNAL + * 9162GRPC_SERVER_INTERNAL + * 9622OPENWHISK_CLIENT * * *

RPC Sandbox (9900 ~ 9999)

@@ -236,11 +267,11 @@ public interface ServiceType { ServiceType UNAUTHORIZED = of(1007, "UNAUTHORIZED", RECORD_STATISTICS); // Added for php agent. - @Deprecated - ServiceType PHP = ServiceTypeFactory.of(1500, "PHP", RECORD_STATISTICS); + //@Deprecated + //ServiceType PHP = ServiceTypeFactory.of(1500, "PHP", RECORD_STATISTICS); // Added for php agent. - @Deprecated - ServiceType PHP_METHOD = ServiceTypeFactory.of(1501, "PHP_METHOD"); + //@Deprecated + //ServiceType PHP_METHOD = ServiceTypeFactory.of(1501, "PHP_METHOD"); /** @@ -253,6 +284,7 @@ public interface ServiceType { // Internal method // FIXME it's not clear to put internal method here. but do that for now. ServiceType INTERNAL_METHOD = of(5000, "INTERNAL_METHOD"); + ServiceType SERVLET = of(5004, "SERVLET"); // Spring framework diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/trace/TraceMetadataLoader.java b/commons/src/main/java/com/navercorp/pinpoint/common/trace/TraceMetadataLoader.java index eee28c4016eb..61f788d27d00 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/trace/TraceMetadataLoader.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/trace/TraceMetadataLoader.java @@ -14,7 +14,6 @@ */ package com.navercorp.pinpoint.common.trace; -import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -23,10 +22,8 @@ import java.util.Map; -import com.navercorp.pinpoint.common.plugin.PluginLoader; import com.navercorp.pinpoint.common.util.logger.CommonLogger; import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; -import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; /** * @author Jongho Moon @@ -42,9 +39,6 @@ public class TraceMetadataLoader { private final List annotationKeys = new ArrayList(); private final AnnotationKeyChecker annotationKeyChecker = new AnnotationKeyChecker(); - public TraceMetadataLoader() { - this(StdoutCommonLoggerFactory.INSTANCE); - } public TraceMetadataLoader(CommonLoggerFactory loggerFactory) { if (loggerFactory == null) { @@ -53,24 +47,7 @@ public TraceMetadataLoader(CommonLoggerFactory loggerFactory) { this.logger = loggerFactory.getLogger(TraceMetadataLoader.class.getName()); } - public void load(URL[] urls) { - if (urls == null) { - throw new NullPointerException("urls must not be null"); - } - - List providers = PluginLoader.load(TraceMetadataProvider.class, urls); - load(providers); - } - - public void load(ClassLoader loader) { - if (loader == null) { - throw new NullPointerException("loader must not be null"); - } - List providers = PluginLoader.load(TraceMetadataProvider.class, loader); - load(providers); - } - public void load(List providers) { if (providers == null) { throw new NullPointerException("providers must not be null"); diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/ClassLoaderUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/ClassLoaderUtils.java index 376c35620532..021de4bb7a40 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/ClassLoaderUtils.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/ClassLoaderUtils.java @@ -33,17 +33,22 @@ public ClassLoader getClassLoader() { private static final ClassLoader BOOT_CLASS_LOADER; static { - SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader(); - if (SYSTEM_CLASS_LOADER != null) { - EXT_CLASS_LOADER = SYSTEM_CLASS_LOADER.getParent(); - } else { - EXT_CLASS_LOADER = null; - } - if (EXT_CLASS_LOADER != null) { - BOOT_CLASS_LOADER = EXT_CLASS_LOADER.getParent(); - } else { - BOOT_CLASS_LOADER = null; + BOOT_CLASS_LOADER = Object.class.getClassLoader(); + // SystemClassLoader can be changed by "java.system.class.loader" + // https://docs.oracle.com/javase/8/docs/api/java/lang/ClassLoader.html + // If the system property "java.system.class.loader" is defined when this method is first invoked + // then the value of that property is taken to be the name of a class that will be returned as the system class loader. + final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + EXT_CLASS_LOADER = findChildClassLoader(BOOT_CLASS_LOADER, systemClassLoader); + SYSTEM_CLASS_LOADER = findChildClassLoader(EXT_CLASS_LOADER, systemClassLoader); + } + + private static ClassLoader findChildClassLoader(ClassLoader parent, ClassLoader searchTarget) { + ClassLoader prev = searchTarget; + while (parent != prev.getParent()) { + prev = prev.getParent(); } + return prev; } private ClassLoaderUtils() { diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/ClassUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/ClassUtils.java index 53ca7ff47e16..26cff285b5ed 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/ClassUtils.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/ClassUtils.java @@ -21,7 +21,6 @@ */ public final class ClassUtils { - private static final Object CLASS_NOT_LOADED = null; private static final char PACKAGE_SEPARATOR = '.'; private ClassUtils() { @@ -40,25 +39,31 @@ public static boolean isLoaded(String name, ClassLoader classLoader) { classLoaderToUse = ClassLoaderUtils.getDefaultClassLoader(); } try { - return (classLoaderToUse.loadClass(name) != CLASS_NOT_LOADED); + classLoaderToUse.loadClass(name); + return true; } catch (ClassNotFoundException ignore) { - // Swallow + return false; } - return false; } - - public static String getPackageName(String fqcn) { + + public static String getPackageName(String fqcn, char packageSeparator, String defaultValue) { if (fqcn == null) { throw new IllegalArgumentException("fully-qualified class name must not be null"); } - final int lastPackageSeparatorIndex = fqcn.lastIndexOf(PACKAGE_SEPARATOR); + final int lastPackageSeparatorIndex = fqcn.lastIndexOf(packageSeparator); if (lastPackageSeparatorIndex == -1) { - return ""; + return defaultValue; } return fqcn.substring(0, lastPackageSeparatorIndex); } - // convert "." based name to "/" based internal name. + public static String getPackageName(String fqcn) { + return getPackageName(fqcn, PACKAGE_SEPARATOR, ""); + } + + /** + * convert "." based name to "/" based internal name. + */ public static String toInternalName(final String className) { if (className == null) { throw new IllegalArgumentException("class name must not be null"); diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/CodeSourceUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/CodeSourceUtils.java new file mode 100644 index 000000000000..76e62f33a576 --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/CodeSourceUtils.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +import java.net.URL; +import java.security.CodeSource; +import java.security.ProtectionDomain; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class CodeSourceUtils { + private CodeSourceUtils() { + } + + public static URL getCodeLocation(Class clazz) { + if (clazz == null) { + throw new NullPointerException("clazz must not be null"); + } + final ProtectionDomain protectionDomain = clazz.getProtectionDomain(); + return getCodeLocation(protectionDomain); + } + + + public static URL getCodeLocation(ProtectionDomain protectionDomain) { + if (protectionDomain == null) { + return null; + } + + final CodeSource codeSource = protectionDomain.getCodeSource(); + if (codeSource == null) { + return null; + } + return codeSource.getLocation(); + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultApiDescription.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultApiDescription.java index 77110a9dd2d0..3862903dafa7 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultApiDescription.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultApiDescription.java @@ -23,11 +23,7 @@ public String getSimpleClassName() { } public String getPackageNameName() { - int packageNameIndex = className.lastIndexOf('.'); - if (packageNameIndex == -1) { - return ""; - } - return className.substring(0, packageNameIndex); + return ClassUtils.getPackageName(className); } public void setMethodName(String methodName) { diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultSqlParser.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultSqlParser.java index 2e42fe6b0d39..de74a2949c1c 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultSqlParser.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/DefaultSqlParser.java @@ -473,11 +473,7 @@ public String combineBindValues(String sql, List bindValues) { return sql; } - final Queue bindValueQueue = new LinkedList(); - for(String value : bindValues) { - // trim - bindValueQueue.add(value.trim()); - } + final Queue bindValueQueue = new LinkedList(bindValues); final int length = sql.length(); final StringBuilder result = new StringBuilder(length + 16); diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/IOUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/IOUtils.java new file mode 100644 index 000000000000..04ff45848a17 --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/IOUtils.java @@ -0,0 +1,113 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.DatagramSocket; +import java.net.Socket; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class IOUtils { + + public static final int DEFAULT_BUFFER_SIZE = 4096; + public static final int EOF = -1; + + private IOUtils() { + } + + public static byte[] toByteArray(final InputStream inputStream) throws IOException { + return toByteArray(inputStream, DEFAULT_BUFFER_SIZE, true); + } + + public static byte[] toByteArray(final InputStream inputStream, boolean close) throws IOException { + return toByteArray(inputStream, DEFAULT_BUFFER_SIZE, close); + } + + public static byte[] toByteArray(final InputStream inputStream, int bufferSize, boolean close) throws IOException { + if (inputStream == null) { + throw new NullPointerException("inputStream must not be null"); + } + if (bufferSize < 0) { + throw new IllegalArgumentException("negative bufferSize"); + } + + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + final byte[] buffer = new byte[bufferSize]; + copy(inputStream, outputStream, buffer); + outputStream.flush(); + return outputStream.toByteArray(); + } finally { + if (close) { + closeQuietly(inputStream); + } + } + } + + public static void copy(InputStream inputStream, OutputStream outputStream, byte[] buffer) throws IOException { + int readCount; + while ((readCount = inputStream.read(buffer, 0, buffer.length)) != EOF) { + outputStream.write(buffer, 0, readCount); + } + } + + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException ignore) { + // skip + } + } + } + + public static void close(Closeable closeable) throws IOException { + if (closeable != null) { + closeable.close(); + } + } + + public static void closeQuietly(Socket socket) { + if (socket != null) { + try { + socket.close(); + } catch (IOException ignore) { + // skip + } + } + } + + public static void close(Socket socket) throws IOException { + if (socket != null) { + socket.close(); + } + } + + public static void closeQuietly(DatagramSocket datagramSocket) { + if (datagramSocket != null) { + datagramSocket.close(); + } + } + + +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/JvmType.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/JvmType.java index 25fe3e7b3bd9..2537eb561172 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/JvmType.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/JvmType.java @@ -16,17 +16,23 @@ package com.navercorp.pinpoint.common.util; +import java.util.EnumSet; + /** * @author HyunGil Jeong */ public enum JvmType { UNKNOWN(null), - IBM("IBM"), + // ibm-j9 java.vm.name=IBM J9 VM; + // openj9 java.vm.name=Eclipse OpenJ9 VM + IBM("J9"), OPENJDK("OpenJDK"), ORACLE("HotSpot"); private final String inclusiveString; + private static final EnumSet JVM_TYPE = EnumSet.allOf(JvmType.class); + JvmType(String inclusiveString) { this.inclusiveString = inclusiveString; } @@ -36,7 +42,7 @@ public static JvmType fromVendor(String vendorName) { return UNKNOWN; } final String vendorNameTrimmed = vendorName.trim(); - for (JvmType jvmType : JvmType.values()) { + for (JvmType jvmType : JVM_TYPE) { if (jvmType.toString().equalsIgnoreCase(vendorNameTrimmed)) { return jvmType; } @@ -48,10 +54,11 @@ public static JvmType fromVmName(String vmName) { if (vmName == null) { return UNKNOWN; } - for (JvmType jvmType : JvmType.values()) { + for (JvmType jvmType : JVM_TYPE) { if (jvmType.inclusiveString == null) { continue; - } else if (vmName.contains(jvmType.inclusiveString)) { + } + if (vmName.contains(jvmType.inclusiveString)) { return jvmType; } } diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/JvmVersion.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/JvmVersion.java index 65e88a0615e4..a176b189d8f3 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/JvmVersion.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/JvmVersion.java @@ -25,10 +25,18 @@ * @author hyungil.jeong */ public enum JvmVersion { + JAVA_1(1.1f, 45), + JAVA_2(1.2f, 46), + JAVA_3(1.3f, 47), + JAVA_4(1.4f, 48), JAVA_5(1.5f, 49), JAVA_6(1.6f, 50), JAVA_7(1.7f, 51), JAVA_8(1.8f, 52), + JAVA_9(9.0f, 53), + JAVA_10(10.0f, 54), + JAVA_11(11.0f, 55), + JAVA_RECENT(99.0f, 99), UNSUPPORTED(-1, -1); private final float version; @@ -59,22 +67,17 @@ public static JvmVersion getFromVersion(String javaVersion) { } } - /** - * @deprecated Since 1.7.0. Use {@link JvmVersion#getFromVersion(float)} - */ - @Deprecated - public static JvmVersion getFromVersion(double javaVersion) { - return getFromVersion((float)javaVersion); - } - public static JvmVersion getFromVersion(float javaVersion) { for (JvmVersion version : JVM_VERSION) { if (Float.compare(version.version, javaVersion) == 0) { return version; - } } - return JvmVersion.UNSUPPORTED; + if (JAVA_1.version > javaVersion) { + return UNSUPPORTED; + } else { + return JAVA_RECENT; + } } @@ -89,7 +92,11 @@ private static IntHashMap toClassVersionMap() { public static JvmVersion getFromClassVersion(int classVersion) { final JvmVersion jvmVersion = CLASS_VERSION_MAP.get(classVersion); if (jvmVersion == null) { - return JvmVersion.UNSUPPORTED; + if (JAVA_1.classVersion > classVersion) { + return JvmVersion.UNSUPPORTED; + } else { + return JAVA_RECENT; + } } return jvmVersion; diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/MapUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/MapUtils.java new file mode 100644 index 000000000000..a3b66069d038 --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/MapUtils.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +import java.util.Map; + +/** + * @since 1.7.2 + * @author Woonduk Kang(emeroad) + */ +public final class MapUtils { + + private MapUtils() { + } + + public static boolean isEmpty(final Map map) { + return map == null || map.isEmpty(); + } + + + public static boolean hasLength(final Map map) { + return map != null && !map.isEmpty(); + } + + public static int nullSafeSize(final Map map) { + return nullSafeSize(map, 0); + } + + public static int nullSafeSize(final Map map, final int nullValue) { + if (map == null) { + return nullValue; + } + return map.size(); + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/NetUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/NetUtils.java index 9305bc64fbca..ade274310b0c 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/NetUtils.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/NetUtils.java @@ -16,13 +16,13 @@ package com.navercorp.pinpoint.common.util; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; + import java.net.Inet4Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketException; -import java.net.URI; -import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; @@ -36,32 +36,77 @@ public final class NetUtils { public static final String LOOPBACK_ADDRESS_V4 = "127.0.0.1"; + + private static final HostAndPortFactory inetSocketAddressFactory = new HostAndPortFactory() { + @Override + public InetSocketAddress newInstance(String host, int port) { + if (!HostAndPort.isValidPort(port)) { + return null; + } + return new InetSocketAddress(host, port); + } + }; + private NetUtils() { } public static List toInetSocketAddressLIst(List addressList) { - List inetSocketAddressList = new ArrayList(); + return toHostAndPortLIst(addressList, inetSocketAddressFactory); + } + + public interface HostAndPortFactory { + T newInstance(String host, int port); + } + + public static List toHostAndPortLIst(List addressList, HostAndPortFactory hostAndPortFactory) { + if (CollectionUtils.isEmpty(addressList)) { + return Collections.emptyList(); + } + final List hostAndPortList = new ArrayList(addressList.size()); for (String address : addressList) { - InetSocketAddress inetSocketAddress = toInetSocketAddress(address); - if (inetSocketAddress != null) { - inetSocketAddressList.add(inetSocketAddress); + final T hostAndPort = parseHostAndPort(address, hostAndPortFactory); + if (hostAndPort != null) { + hostAndPortList.add(hostAndPort); } } - - return inetSocketAddressList; + return hostAndPortList; } + public static InetSocketAddress toInetSocketAddress(String address) { - try { - URI uri = new URI("pinpoint://" + address); + return parseHostAndPort(address, inetSocketAddressFactory); + } - return new InetSocketAddress(uri.getHost(), uri.getPort()); - } catch (URISyntaxException ignore) { - // skip + public static T parseHostAndPort(String address, HostAndPortFactory hostAndPortFactory) { + if (StringUtils.isEmpty(address)) { + return null; } + Assert.requireNonNull(hostAndPortFactory, "hostAndPortFactory must not be null"); - return null; + final int hostIndex = address.indexOf(':'); + if (hostIndex == -1) { + return null; + } + final String host = address.substring(0, hostIndex); + final String portString = address.substring(hostIndex +1, address.length()); + final int port = parseInteger(portString, HostAndPort.NO_PORT); + return hostAndPortFactory.newInstance(host, port); + } + + /** + * TODO duplicate code + * com.navercorp.pinpoint.bootstrap.util.NumberUtils.parseInteger(); + */ + private static int parseInteger(String str, int defaultInt) { + if (str == null) { + return defaultInt; + } + try { + return Integer.parseInt(str); + } catch (NumberFormatException e) { + return defaultInt; + } } public static String getLocalV4Ip() { @@ -82,7 +127,6 @@ public static String getLocalV4Ip() { * If no network interfaces can be found on this machine, returns an empty List. */ public static List getLocalV4IpList() { - List result = new ArrayList(); Enumeration interfaces = null; try { @@ -95,6 +139,7 @@ public static List getLocalV4IpList() { return Collections.emptyList(); } + List result = new ArrayList(); while (interfaces.hasMoreElements()) { NetworkInterface current = interfaces.nextElement(); if (isSkipIp(current)) { @@ -131,30 +176,25 @@ private static boolean isSkipIp(NetworkInterface networkInterface) { public static boolean validationIpPortV4FormatAddress(String address) { - try { - int splitIndex = address.indexOf(':'); - if (splitIndex == -1 || splitIndex + 1 >= address.length()) { - return false; - } - - String ip = address.substring(0, splitIndex); - - if (!validationIpV4FormatAddress(ip)) { - return false; - } + final int splitIndex = address.indexOf(':'); + if (splitIndex == -1 || splitIndex + 1 >= address.length()) { + return false; + } - String port = address.substring(splitIndex + 1, address.length()); - if (Integer.parseInt(port) > 65535) { - return false; - } + final String ip = address.substring(0, splitIndex); + if (!validationIpV4FormatAddress(ip)) { + return false; + } - return true; - } catch (Exception ignore) { - //skip + final String portString = address.substring(splitIndex + 1, address.length()); + final int port = parseInteger(portString, HostAndPort.NO_PORT); + if (!HostAndPort.isValidPort(port)) { + return false; } - return false; + return true; + } public static boolean validationIpV4FormatAddress(String address) { diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/OsType.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/OsType.java new file mode 100644 index 000000000000..e761426fe53b --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/OsType.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +import java.util.EnumSet; + +/** + * @author Roy Kim + */ +public enum OsType { + UNKNOWN(null), + WINDOW("Window"), + MAC("Mac"), + LINUX("Linux"), + SOLARIS("Solaris"), + AIX("AIX"), + HP_UX("HP-UX"), + BSD("BSD"); + + public String getInclusiveString() { + return inclusiveString; + } + + private final String inclusiveString; + + private static EnumSet OS_TYPE = EnumSet.allOf(OsType.class); + + OsType(String inclusiveString) { + this.inclusiveString = inclusiveString; + } + + public static OsType fromVendor(String vendorName) { + if (vendorName == null) { + return UNKNOWN; + } + final String vendorNameTrimmed = vendorName.trim(); + for (OsType osType : OS_TYPE) { + if (osType.toString().equalsIgnoreCase(vendorNameTrimmed)) { + return osType; + } + } + return UNKNOWN; + } + + public static OsType fromOsName(String osName) { + if (osName == null) { + return UNKNOWN; + } + for (OsType osType : OS_TYPE) { + if (osType.inclusiveString == null) { + continue; + } + if (osName.toLowerCase().contains(osType.inclusiveString.toLowerCase())) { + return osType; + } + } + return UNKNOWN; + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/OsUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/OsUtils.java new file mode 100644 index 000000000000..2b078026cf81 --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/OsUtils.java @@ -0,0 +1,41 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +/** + * @author Roy Kim + */ +public final class OsUtils { + + private static final OsType OS_TYPE = getType0(); + + private OsUtils() { + } + + public static OsType getType() { + return OS_TYPE; + } + + public static String getSystemProperty(SystemPropertyKey systemPropertyKey) { + return System.getProperty(systemPropertyKey.getKey(), ""); + } + + private static OsType getType0() { + String OsName = getSystemProperty(SystemPropertyKey.OS_NAME); + return OsType.fromOsName(OsName); + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/PropertyUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/PropertyUtils.java index f5c308c41b2f..8f107fc02ccf 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/PropertyUtils.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/PropertyUtils.java @@ -98,20 +98,10 @@ public static Properties loadProperty(Properties properties, InputStreamFactory reader = new InputStreamReader(in, encoding); properties.load(reader); } finally { - close(reader); - close(in); + IOUtils.closeQuietly(reader); + IOUtils.closeQuietly(in); } return properties; } - private static void close(Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (IOException ignore) { - // skip - } - } - } - } diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/StringStringValue.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/StringStringValue.java new file mode 100644 index 000000000000..247521010b83 --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/StringStringValue.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +/** + * @author Roy Kim + */ +public class StringStringValue { + private String stringValue1; + private String stringValue2; + + public StringStringValue(String stringValue1, String stringValue2) { + this.stringValue1 = stringValue1; + this.stringValue2 = stringValue2; + } + + public String getStringValue1() { + return stringValue1; + } + + public String getStringValue2() { + return stringValue2; + } + + @Override + public String toString() { + return "StringStringValue{" + + "stringValue1='" + stringValue1 + '\'' + + ", stringValue2='" + stringValue2 + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StringStringValue that = (StringStringValue) o; + return stringValue1.equals(that.getStringValue1()) && + stringValue2.equals(that.getStringValue2()); + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/StringUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/StringUtils.java index e952388fd52b..27f1d84d2aa6 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/StringUtils.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/StringUtils.java @@ -28,6 +28,8 @@ public final class StringUtils { private static final String NULL_STRING = "null"; + private static final int INDEX_NOT_FOUND = -1; + private StringUtils() { } @@ -175,4 +177,89 @@ public static List tokenizeToStringList(final String str, final String d } return tokens; } + + /** + * Apache Commons Lang StringUtils + * + *

Replaces all occurrences of a String within another String.

+ * + *

A {@code null} reference passed to this method is a no-op.

+ * + *
+     * StringUtils.replace(null, *, *)        = null
+     * StringUtils.replace("", *, *)          = ""
+     * StringUtils.replace("any", null, *)    = "any"
+     * StringUtils.replace("any", *, null)    = "any"
+     * StringUtils.replace("any", "", *)      = "any"
+     * StringUtils.replace("aba", "a", null)  = "aba"
+     * StringUtils.replace("aba", "a", "")    = "b"
+     * StringUtils.replace("aba", "a", "z")   = "zbz"
+     * 
+ * + * @see #replace(String text, String searchString, String replacement, int max) + * @param text text to search and replace in, may be null + * @param searchString the String to search for, may be null + * @param replacement the String to replace it with, may be null + * @return the text with any replacements processed, + * {@code null} if null String input + */ + public static String replace(String text, String searchString, String replacement) { + return replace(text, searchString, replacement, -1); + } + + /** + * Apache Commons Lang StringUtils + * + *

Replaces a String with another String inside a larger String, + * for the first {@code max} values of the search String.

+ * + *

A {@code null} reference passed to this method is a no-op.

+ * + *
+     * StringUtils.replace(null, *, *, *)         = null
+     * StringUtils.replace("", *, *, *)           = ""
+     * StringUtils.replace("any", null, *, *)     = "any"
+     * StringUtils.replace("any", *, null, *)     = "any"
+     * StringUtils.replace("any", "", *, *)       = "any"
+     * StringUtils.replace("any", *, *, 0)        = "any"
+     * StringUtils.replace("abaa", "a", null, -1) = "abaa"
+     * StringUtils.replace("abaa", "a", "", -1)   = "b"
+     * StringUtils.replace("abaa", "a", "z", 0)   = "abaa"
+     * StringUtils.replace("abaa", "a", "z", 1)   = "zbaa"
+     * StringUtils.replace("abaa", "a", "z", 2)   = "zbza"
+     * StringUtils.replace("abaa", "a", "z", -1)  = "zbzz"
+     * 
+ * + * @param text text to search and replace in, may be null + * @param searchString the String to search for, may be null + * @param replacement the String to replace it with, may be null + * @param max maximum number of values to replace, or {@code -1} if no maximum + * @return the text with any replacements processed, + * {@code null} if null String input + */ + public static String replace(String text, String searchString, String replacement, int max) { + if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) { + return text; + } + int start = 0; + int end = text.indexOf(searchString, start); + if (end == INDEX_NOT_FOUND) { + return text; + } + int replLength = searchString.length(); + int increase = replacement.length() - replLength; + increase = increase < 0 ? 0 : increase; + increase *= max < 0 ? 16 : max > 64 ? 64 : max; + StringBuilder buf = new StringBuilder(text.length() + increase); + while (end != INDEX_NOT_FOUND) { + buf.append(text.substring(start, end)).append(replacement); + start = end + replLength; + if (--max == 0) { + break; + } + end = text.indexOf(searchString, start); + } + buf.append(text.substring(start)); + return buf.toString(); + } } diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/SystemPropertyKey.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/SystemPropertyKey.java index e44922f4872b..7e2e146d2ce2 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/SystemPropertyKey.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/SystemPropertyKey.java @@ -30,7 +30,8 @@ public enum SystemPropertyKey { JAVA_VM_VERSION("java.vm.version"), JAVA_VM_INFO("java.vm.info"), JAVA_VM_SPECIFICATION_VERSION("java.vm.specification.version"), - SUN_JAVA_COMMAND("sun.java.command"); // May be unsupported depending on the JVM. + SUN_JAVA_COMMAND("sun.java.command"), // May be unsupported depending on the JVM. + OS_NAME("os.name"); private final String key; diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/apache/IntHashMapUtils.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/apache/IntHashMapUtils.java index 84eed2049891..8a1ba9bbc3e9 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/apache/IntHashMapUtils.java +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/apache/IntHashMapUtils.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -36,4 +36,15 @@ public static IntHashMap copy(Map target) { } return copyMap; } + + public static IntHashMap copyShortMap(Map target) { + if (target == null) { + throw new NullPointerException("target must not be null"); + } + final IntHashMap copyMap = new IntHashMap(); + for (Map.Entry entry : target.entrySet()) { + copyMap.put(entry.getKey(), entry.getValue()); + } + return copyMap; + } } diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/AnnotationKeyTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/AnnotationKeyTest.java index 3ce2088cb2fa..ac02e0c1c211 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/AnnotationKeyTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/AnnotationKeyTest.java @@ -16,19 +16,26 @@ package com.navercorp.pinpoint.common; +import com.navercorp.pinpoint.common.plugin.PluginLoader; import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; import com.navercorp.pinpoint.common.service.DefaultTraceMetadataLoaderService; import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; import com.navercorp.pinpoint.common.util.AnnotationKeyUtils; +import com.navercorp.pinpoint.common.util.ClassLoaderUtils; +import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; +import java.util.List; + /** * @author emeroad */ @@ -38,8 +45,9 @@ public class AnnotationKeyTest { @Test public void getCode() { - TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(); - AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(typeLoaderService, StdoutCommonLoggerFactory.INSTANCE); + CommonLoggerFactory loggerFactory = StdoutCommonLoggerFactory.INSTANCE; + TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(Collections.emptyList(), loggerFactory); + AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(typeLoaderService, loggerFactory); AnnotationKey annotationKey = annotationKeyRegistryService.findAnnotationKey(AnnotationKey.API.getCode()); Assert.assertEquals(annotationKey, AnnotationKey.API); @@ -74,7 +82,9 @@ public void isCachedArgsToArgs() { @Test public void testValueOf() { - AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(); + CommonLoggerFactory loggerFactory = StdoutCommonLoggerFactory.INSTANCE; + TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(Collections.emptyList(), loggerFactory); + AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(typeLoaderService, loggerFactory); annotationKeyRegistryService.findAnnotationKeyByName(AnnotationKey.ARGS0.getName()); AnnotationKey valueof = annotationKeyRegistryService.findAnnotationKeyByName(AnnotationKey.ARGS0.getName()); diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeInitializerTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeInitializerTest.java index e97192808a7f..3b56f8245969 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeInitializerTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeInitializerTest.java @@ -91,7 +91,7 @@ public void testDuplicated() { new TestProvider(new ServiceType[0], TEST_KEYS) ); - TraceMetadataLoader loader = new TraceMetadataLoader(); + TraceMetadataLoader loader = new TraceMetadataLoader(StdoutCommonLoggerFactory.INSTANCE); loader.load(providers); } @@ -102,7 +102,7 @@ public void testDuplicated2() { new TestProvider(TEST_TYPES, new AnnotationKey[0]) ); - TraceMetadataLoader loader = new TraceMetadataLoader(); + TraceMetadataLoader loader = new TraceMetadataLoader(StdoutCommonLoggerFactory.INSTANCE); loader.load(providers); } @@ -113,7 +113,7 @@ public void testDuplicated3() { new TestProvider(TEST_TYPES, new AnnotationKey[0]) ); - TraceMetadataLoader loader = new TraceMetadataLoader(); + TraceMetadataLoader loader = new TraceMetadataLoader(StdoutCommonLoggerFactory.INSTANCE); loader.load(providers); } @@ -145,7 +145,6 @@ public void testDuplicatedWithDefault3() { TraceMetadataLoaderService loaderService = new DefaultTraceMetadataLoaderService(providers, loggerFactory); AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(loaderService, loggerFactory); - } diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeTest.java index acee40e1a2be..7edd7963f0ef 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/ServiceTypeTest.java @@ -16,8 +16,16 @@ package com.navercorp.pinpoint.common; +import java.util.Collections; import java.util.List; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.common.service.DefaultTraceMetadataLoaderService; +import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.util.ClassLoaderUtils; +import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; +import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; @@ -31,12 +39,16 @@ public class ServiceTypeTest { @Test public void findDesc() { - DefaultServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(); + CommonLoggerFactory loggerFactory = StdoutCommonLoggerFactory.INSTANCE; + + List providers = Collections.emptyList(); + TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(providers, loggerFactory); + DefaultServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(typeLoaderService, loggerFactory); String desc = "UNKNOWN_DB"; List serviceTypeList = serviceTypeRegistryService.findDesc(desc); boolean find = false; for (ServiceType serviceType : serviceTypeList) { - if(serviceType.getDesc().equals(desc)) { + if (serviceType.getDesc().equals(desc)) { find = true; } } diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/BytesUtilsTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/BytesUtilsTest.java index 264738830d75..f8eb5b349ed0 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/util/BytesUtilsTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/BytesUtilsTest.java @@ -23,9 +23,6 @@ import com.navercorp.pinpoint.common.buffer.Buffer; import com.navercorp.pinpoint.common.buffer.FixedBuffer; -import org.apache.thrift.TException; -import org.apache.thrift.protocol.TCompactProtocol; -import org.apache.thrift.transport.TMemoryBuffer; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; @@ -148,22 +145,7 @@ private void testEncodingDecodingZigZag(int value) { Assert.assertEquals(value, decode); } - @Test - public void compactProtocolVint() throws TException { - TMemoryBuffer tMemoryBuffer = writeVInt32(BytesUtils.zigzagToInt(64)); - logger.trace("length:{}", tMemoryBuffer.length()); - - TMemoryBuffer tMemoryBuffer2 = writeVInt32(64); - logger.trace("length:{}", tMemoryBuffer2.length()); - } - - private TMemoryBuffer writeVInt32(int i) throws TException { - TMemoryBuffer tMemoryBuffer = new TMemoryBuffer(10); - TCompactProtocol tCompactProtocol = new TCompactProtocol(tMemoryBuffer); - tCompactProtocol.writeI32(i); - return tMemoryBuffer; - } @Test public void testWriteBytes1() { diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/ClassLoaderUtilsTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/ClassLoaderUtilsTest.java index 380e9b38160b..1a0620024c01 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/util/ClassLoaderUtilsTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/ClassLoaderUtilsTest.java @@ -92,4 +92,20 @@ public void append() throws Exception { String log = ClassLoaderUtils.dumpStandardClassLoader(); logger.debug("StandardClassLoader dump:{}", log); } + + @Test + public void dumpStandardClassLoader() { + String jvmClassLoader = ClassLoaderUtils.dumpStandardClassLoader(); + logger.debug("{}", jvmClassLoader); + } + + @Test + public void test() { + Assert.assertTrue(ClassLoaderUtils.isJvmClassLoader(ClassLoader.getSystemClassLoader())); + Assert.assertTrue(ClassLoaderUtils.isJvmClassLoader(ClassLoader.getSystemClassLoader().getParent())); + Assert.assertTrue(ClassLoaderUtils.isJvmClassLoader(Object.class.getClassLoader())); + + Assert.assertFalse(ClassLoaderUtils.isJvmClassLoader(new URLClassLoader(new URL[0]))); + + } } \ No newline at end of file diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/CodeSourceUtilsTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/CodeSourceUtilsTest.java new file mode 100644 index 000000000000..fbce8659a0f1 --- /dev/null +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/CodeSourceUtilsTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URL; + +/** + * @author Woonduk Kang(emeroad) + */ +public class CodeSourceUtilsTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void getLocationTest() { + + URL location = CodeSourceUtils.getCodeLocation(Logger.class); + logger.debug("url:{}", location); + + logger.debug("protocol:{}", location.getProtocol()); + + logger.debug("path:{}", location.getPath()); + logger.debug("file:{}", location.getFile()); + + } +} \ No newline at end of file diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/CollectionUtilsTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/CollectionUtilsTest.java index 5bf524e28452..eca01fe24246 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/util/CollectionUtilsTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/CollectionUtilsTest.java @@ -30,7 +30,7 @@ public class CollectionUtilsTest { @Test - public void nullSafeSize() throws Exception { + public void nullSafeSize() { Assert.assertEquals(CollectionUtils.nullSafeSize(Lists.newArrayList(123)), 1); Assert.assertEquals(CollectionUtils.nullSafeSize(Collections.emptyList()), 0); @@ -38,20 +38,20 @@ public void nullSafeSize() throws Exception { } @Test - public void nullSafeSize_nullValue() throws Exception { + public void nullSafeSize_nullValue() { Assert.assertEquals(CollectionUtils.nullSafeSize(null, -1), -1); } @Test - public void isEmpty() throws Exception { + public void isEmpty() { Assert.assertTrue(CollectionUtils.isEmpty(null)); Assert.assertTrue(CollectionUtils.isEmpty(Collections.emptyList())); } @Test - public void isNotEmpty() throws Exception { - Assert.assertFalse(CollectionUtils.hasLength(Collections.emptyList())); + public void isNotEmpty() { Assert.assertFalse(CollectionUtils.hasLength(null)); + Assert.assertFalse(CollectionUtils.hasLength(Collections.emptyList())); } } \ No newline at end of file diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/DefaultSqlParserTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/DefaultSqlParserTest.java index 07608b8b107e..92696b8dd3de 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/util/DefaultSqlParserTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/DefaultSqlParserTest.java @@ -262,8 +262,8 @@ public void combineBindValue() { Assert.assertEquals(expected, result); sql = "select * from table a = ? and b=? and c=? and d=?"; - expected = "select * from table a = '1' and b='50' and c='foo' and d='11'"; - bindValues = parameterParser.parseOutputParameter("1, 50, foo, 11"); + expected = "select * from table a = '1' and b='50' and c=' foo ' and d='11'"; + bindValues = parameterParser.parseOutputParameter("1,50, foo ,11"); result = sqlParser.combineBindValues(sql, bindValues); Assert.assertEquals(expected, result); @@ -279,6 +279,7 @@ public void combineBindValue() { result = sqlParser.combineBindValues(sql, bindValues); Assert.assertEquals(expected, result); + // check comment sql = "/** comment ? */ select * from table id = ?"; expected = "/** comment ? */ select * from table id = 'foo,bar'"; bindValues = parameterParser.parseOutputParameter("foo,,bar"); diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/JvmVersionTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/JvmVersionTest.java index 4e2a18b036ac..b3728d0966e5 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/util/JvmVersionTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/JvmVersionTest.java @@ -20,8 +20,11 @@ import static com.navercorp.pinpoint.common.util.JvmVersion.*; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import com.navercorp.pinpoint.common.util.JvmVersion; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; /** * @author hyungil.jeong @@ -35,30 +38,60 @@ public void testOnOrAfter() { assertFalse(JAVA_5.onOrAfter(JAVA_6)); assertFalse(JAVA_5.onOrAfter(JAVA_7)); assertFalse(JAVA_5.onOrAfter(JAVA_8)); + assertFalse(JAVA_5.onOrAfter(JAVA_9)); + assertFalse(JAVA_5.onOrAfter(JAVA_10)); assertFalse(JAVA_5.onOrAfter(UNSUPPORTED)); // JDK 6 assertTrue(JAVA_6.onOrAfter(JAVA_5)); assertTrue(JAVA_6.onOrAfter(JAVA_6)); assertFalse(JAVA_6.onOrAfter(JAVA_7)); assertFalse(JAVA_6.onOrAfter(JAVA_8)); + assertFalse(JAVA_6.onOrAfter(JAVA_9)); + assertFalse(JAVA_6.onOrAfter(JAVA_10)); assertFalse(JAVA_6.onOrAfter(UNSUPPORTED)); // JDK 7 assertTrue(JAVA_7.onOrAfter(JAVA_5)); assertTrue(JAVA_7.onOrAfter(JAVA_6)); assertTrue(JAVA_7.onOrAfter(JAVA_7)); assertFalse(JAVA_7.onOrAfter(JAVA_8)); + assertFalse(JAVA_7.onOrAfter(JAVA_9)); + assertFalse(JAVA_7.onOrAfter(JAVA_10)); assertFalse(JAVA_7.onOrAfter(UNSUPPORTED)); // JDK 8 assertTrue(JAVA_8.onOrAfter(JAVA_5)); assertTrue(JAVA_8.onOrAfter(JAVA_6)); assertTrue(JAVA_8.onOrAfter(JAVA_7)); assertTrue(JAVA_8.onOrAfter(JAVA_8)); + assertFalse(JAVA_8.onOrAfter(JAVA_9)); + assertFalse(JAVA_8.onOrAfter(JAVA_10)); assertFalse(JAVA_8.onOrAfter(UNSUPPORTED)); + // JDK 9 + assertTrue(JAVA_9.onOrAfter(JAVA_5)); + assertTrue(JAVA_9.onOrAfter(JAVA_6)); + assertTrue(JAVA_9.onOrAfter(JAVA_7)); + assertTrue(JAVA_9.onOrAfter(JAVA_8)); + assertTrue(JAVA_9.onOrAfter(JAVA_9)); + assertFalse(JAVA_9.onOrAfter(JAVA_10)); + assertFalse(JAVA_9.onOrAfter(UNSUPPORTED)); + + assertTrue(JAVA_10.onOrAfter(JAVA_5)); + assertTrue(JAVA_10.onOrAfter(JAVA_6)); + assertTrue(JAVA_10.onOrAfter(JAVA_7)); + assertTrue(JAVA_10.onOrAfter(JAVA_8)); + assertTrue(JAVA_10.onOrAfter(JAVA_9)); + assertTrue(JAVA_10.onOrAfter(JAVA_10)); + assertFalse(JAVA_10.onOrAfter(JAVA_RECENT)); + assertFalse(JAVA_10.onOrAfter(UNSUPPORTED)); + + assertTrue(JAVA_RECENT.onOrAfter(JAVA_11)); + // Unsupported assertFalse(UNSUPPORTED.onOrAfter(JAVA_5)); assertFalse(UNSUPPORTED.onOrAfter(JAVA_6)); assertFalse(UNSUPPORTED.onOrAfter(JAVA_7)); assertFalse(UNSUPPORTED.onOrAfter(JAVA_8)); + assertFalse(UNSUPPORTED.onOrAfter(JAVA_9)); + assertFalse(UNSUPPORTED.onOrAfter(JAVA_10)); assertFalse(UNSUPPORTED.onOrAfter(UNSUPPORTED)); } @@ -66,56 +99,82 @@ public void testOnOrAfter() { public void testGetFromDoubleVersion() { // JDK 5 final JvmVersion java_5 = JvmVersion.getFromVersion(1.5f); - assertSame(java_5, JAVA_5); + assertSame(JAVA_5, java_5); // JDK 6 final JvmVersion java_6 = JvmVersion.getFromVersion(1.6f); - assertSame(java_6, JAVA_6); + assertSame(JAVA_6, java_6); // JDK 7 final JvmVersion java_7 = JvmVersion.getFromVersion(1.7f); - assertSame(java_7, JAVA_7); + assertSame(JAVA_7, java_7); // JDK 8 final JvmVersion java_8 = JvmVersion.getFromVersion(1.8f); - assertSame(java_8, JAVA_8); + assertSame(JAVA_8, java_8); + // JDK 9 + final JvmVersion java_9 = JvmVersion.getFromVersion(9f); + assertSame(JAVA_9, java_9); + // JDK 10 + final JvmVersion java_10 = JvmVersion.getFromVersion(10f); + assertSame(JAVA_10, java_10); + } + + @Test + public void testGetFromDoubleVersion_exceptional_case() { // Unsupported final JvmVersion java_unsupported = JvmVersion.getFromVersion(0.9f); - assertSame(java_unsupported, UNSUPPORTED); + assertSame(UNSUPPORTED, java_unsupported); + + // new version + final JvmVersion java20 = JvmVersion.getFromVersion(20.f); + assertSame(JAVA_RECENT, java20); } @Test public void testGetFromStringVersion() { // JDK 5 final JvmVersion java_5 = JvmVersion.getFromVersion("1.5"); - assertSame(java_5, JAVA_5); + assertSame(JAVA_5, java_5); // JDK 6 final JvmVersion java_6 = JvmVersion.getFromVersion("1.6"); - assertSame(java_6, JAVA_6); + assertSame(JAVA_6, java_6); // JDK 7 final JvmVersion java_7 = JvmVersion.getFromVersion("1.7"); - assertSame(java_7, JAVA_7); + assertSame(JAVA_7, java_7); // JDK 8 final JvmVersion java_8 = JvmVersion.getFromVersion("1.8"); - assertSame(java_8, JAVA_8); + assertSame(JAVA_8, java_8); + // JDK 9 + final JvmVersion java_9 = JvmVersion.getFromVersion("9"); + assertSame(JAVA_9, java_9); + // JDK 10 + final JvmVersion java_10 = JvmVersion.getFromVersion("10"); + assertSame(JAVA_10, java_10); // Unsupported final JvmVersion java_unsupported = JvmVersion.getFromVersion("abc"); - assertSame(java_unsupported, UNSUPPORTED); + assertSame(UNSUPPORTED, java_unsupported); } @Test public void testGetFromClassVersion() { // JDK 5 final JvmVersion java_5 = JvmVersion.getFromClassVersion(49); - assertSame(java_5, JAVA_5); + assertSame(JAVA_5, java_5); // JDK 6 final JvmVersion java_6 = JvmVersion.getFromClassVersion(50); - assertSame(java_6, JAVA_6); + assertSame(JAVA_6, java_6); // JDK 7 final JvmVersion java_7 = JvmVersion.getFromClassVersion(51); - assertSame(java_7, JAVA_7); + assertSame(JAVA_7, java_7); // JDK 8 final JvmVersion java_8 = JvmVersion.getFromClassVersion(52); - assertSame(java_8, JAVA_8); + assertSame(JAVA_8, java_8); + // JDK 9 + final JvmVersion java_9 = JvmVersion.getFromClassVersion(53); + assertSame(JAVA_9, java_9); + // JDK 10 + final JvmVersion java_10 = JvmVersion.getFromClassVersion(54); + assertSame(JAVA_10, java_10); // Unsupported final JvmVersion java_unsupported = JvmVersion.getFromClassVersion(-1); - assertSame(java_unsupported, UNSUPPORTED); + assertSame(UNSUPPORTED, java_unsupported); } } diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/MapUtilsTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/MapUtilsTest.java new file mode 100644 index 000000000000..9def572d80b7 --- /dev/null +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/MapUtilsTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; + +/** + * @author Woonduk Kang(emeroad) + */ +public class MapUtilsTest { + + @Test + public void isEmpty() { + Assert.assertTrue(MapUtils.isEmpty(null)); + Assert.assertTrue(MapUtils.isEmpty(Collections.emptyMap())); + } + + @Test + public void isNotEmpty() { + Assert.assertFalse(MapUtils.hasLength(null)); + Assert.assertFalse(MapUtils.hasLength(Collections.emptyMap())); + } +} \ No newline at end of file diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/NetUtilsTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/NetUtilsTest.java new file mode 100644 index 000000000000..95d1ad9158ea --- /dev/null +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/NetUtilsTest.java @@ -0,0 +1,32 @@ +package com.navercorp.pinpoint.common.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.net.InetSocketAddress; + +/** + * @author Woonduk Kang(emeroad) + */ +public class NetUtilsTest { + + @Test + public void toInetSocketAddress() { + InetSocketAddress inetSocketAddress = NetUtils.toInetSocketAddress("192.168.0.1:8081"); + Assert.assertEquals(inetSocketAddress.getHostName(), "192.168.0.1"); + Assert.assertEquals(inetSocketAddress.getPort(), 8081); + } + + @Test + public void toInetSocketAddress_miss_port1() { + InetSocketAddress inetSocketAddress = NetUtils.toInetSocketAddress("192.168.0.1"); + Assert.assertNull(inetSocketAddress); + } + + @Test + public void toInetSocketAddress_miss_port2() { + InetSocketAddress inetSocketAddress = NetUtils.toInetSocketAddress("192.168.0.1:"); + Assert.assertNull(inetSocketAddress); + } + +} \ No newline at end of file diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/OsTypeTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/OsTypeTest.java new file mode 100644 index 000000000000..24c879befe93 --- /dev/null +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/OsTypeTest.java @@ -0,0 +1,109 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.EnumSet; + +/** + * @author Roy Kim + */ +public class OsTypeTest { + + @Test + public void fromVendorNullParameter() { + OsType actualType = OsType.fromVendor(null); + Assert.assertSame(OsType.UNKNOWN, actualType); + } + + @Test + public void fromVendorEmptyParameter() { + OsType actualType = OsType.fromVendor(""); + Assert.assertSame(OsType.UNKNOWN, actualType); + } + + @Test + public void fromVendorValidParameter() { + Assert.assertSame(OsType.WINDOW, OsType.fromVendor("window")); + Assert.assertSame(OsType.MAC, OsType.fromVendor("mac")); + Assert.assertSame(OsType.LINUX, OsType.fromVendor("linux")); + Assert.assertSame(OsType.SOLARIS, OsType.fromVendor("SOLARIS")); + Assert.assertSame(OsType.AIX, OsType.fromVendor("aix")); + Assert.assertSame(OsType.HP_UX, OsType.fromVendor("HP_Ux")); + Assert.assertSame(OsType.BSD, OsType.fromVendor("bsd")); + } + + @Test + public void fromVendorInvalidParameter() { + Assert.assertSame(OsType.UNKNOWN, OsType.fromVendor("Some Invalid Parameter")); + } + + @Test + public void fromOsNameNullParameter() { + OsType actualType = OsType.fromOsName(null); + Assert.assertSame(OsType.UNKNOWN, actualType); + } + + @Test + public void fromOsNameEmptyParameter() { + OsType actualType = OsType.fromOsName(""); + Assert.assertSame(OsType.UNKNOWN, actualType); + } + + @Test + public void fromOsNameValidParameter() { + final String windowOsName = "Windows 2000"; + final String macOsName = "Mac OS X"; + final String linuxOsName = "Linux"; + final String solarisOsName = "Solaris"; + final String hpOsName = "HP-Ux"; + Assert.assertSame(OsType.WINDOW, OsType.fromOsName(windowOsName)); + Assert.assertSame(OsType.MAC, OsType.fromOsName(macOsName)); + Assert.assertSame(OsType.LINUX, OsType.fromOsName(linuxOsName)); + Assert.assertSame(OsType.SOLARIS, OsType.fromOsName(solarisOsName)); + Assert.assertSame(OsType.HP_UX, OsType.fromOsName(hpOsName)); + } + + @Test + public void fromOsNameInvalidParameter() { + Assert.assertSame(OsType.UNKNOWN, OsType.fromOsName("Some Invalid Parameter")); + } + + @Test + public void testInvalidOSName() { + + EnumSet OS_TYPE = EnumSet.allOf(OsType.class); + + for (OsType osType : OS_TYPE) { + for (OsType osType2 : OS_TYPE) { + if (osType.equals(osType2)) { + continue; + } + if (osType == OsType.UNKNOWN || osType2 == OsType.UNKNOWN) { + continue; + } + + if(osType.getInclusiveString().toLowerCase().contains(osType2.getInclusiveString().toLowerCase())) { + Assert.fail("May cause duplicate Os types, check list of OsType"); + } + } + } + } +} + diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/OsUtilsTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/OsUtilsTest.java new file mode 100644 index 000000000000..229c9838640d --- /dev/null +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/OsUtilsTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Roy Kim + */ +public class OsUtilsTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void getType() throws Exception { + OsType type = OsUtils.getType(); + logger.debug("type:{}", type); + } + + +} \ No newline at end of file diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/OutputParameterParserTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/OutputParameterParserTest.java index 9676bed235cd..9812bbc889a1 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/util/OutputParameterParserTest.java +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/OutputParameterParserTest.java @@ -51,7 +51,7 @@ private void assertOutputParameter(String outputParam, String... params) { List result = parser.parseOutputParameter(outputParam); logger.debug("parseResult:{}", result); try { - Assert.assertArrayEquals(result.toArray(new String[result.size()]), params); + Assert.assertArrayEquals(result.toArray(new String[0]), params); } catch (AssertionError e) { logger.warn("parseResult:{}", result); logger.warn("params:{}", (Object[]) params); diff --git a/commons/src/test/resources/test-hbase.properties b/commons/src/test/resources/test-hbase.properties index b13d4350650d..d02794873086 100644 --- a/commons/src/test/resources/test-hbase.properties +++ b/commons/src/test/resources/test-hbase.properties @@ -1,3 +1,6 @@ hbase.client.host=localhost hbase.client.port=2181 -hbase.htable.threads.max=32 \ No newline at end of file +hbase.htable.threads.max=32 + +# hbase namespace to use default:default +hbase.namespace=default \ No newline at end of file diff --git a/doc/additional-plugins.md b/doc/additional-plugins.md new file mode 100755 index 000000000000..8bb52b536e9f --- /dev/null +++ b/doc/additional-plugins.md @@ -0,0 +1,22 @@ +--- +title: Additional Plugins +keywords: plugins, plugin, plug +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: additionalplugins.html +disqus: false +--- + +## Third-party agents/plugins + +There may be agents, and plugins that are being developed and managed by other individuals/organizations. + +Below include agents and plugins that are not merged into this repository. +Take a look at them if you are interested and would like to help out. +* Agents + * NodeJS agent - https://github.com/peaksnail/pinpoint-node-agent +* Plugins + * Websphere - https://github.com/sjmittal/pinpoint/tree/cpu_monitoring_fix/plugins/websphere + * RocketMQ - https://github.com/ruizlake/pinpoint/tree/master/plugins/rocketmq + +If you are working on an agent or a plugin and want to add it to this list, please feel free to [contact us](mailto:roy.kim@navercorp.com) anytime. diff --git a/doc/alarm.md b/doc/alarm.md index 84071c427d34..ececd8f8344a 100644 --- a/doc/alarm.md +++ b/doc/alarm.md @@ -1,3 +1,12 @@ +--- +title: Setting Alarm +keywords: alarm +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: alarm.html +disqus: false +--- + [English](#alarm) | [한글](#alarm-1) # Alarm @@ -8,51 +17,62 @@ These conditions are (by default) checked every 3 minutes by a background batch ## 1. User Guide 1) Configuration menu -![alarm_figure01.gif](img/alarm/alarm_figure01.gif) +![alarm_figure01.gif](images/alarm/alarm_figure01.gif) 2) Registering users -![alarm_figure02.gif](img/alarm/alarm_figure02.gif) +![alarm_figure02.gif](images/alarm/alarm_figure02.gif) 3) Creating user groups -![alarm_figure03.gif](img/alarm/alarm_figure03.gif) +![alarm_figure03.gif](images/alarm/alarm_figure03.gif) 4) Adding users to user group -![alarm_figure04.gif](img/alarm/alarm_figure04.gif) +![alarm_figure04.gif](images/alarm/alarm_figure04.gif) 5) Setting alarm rules -![alarm_figure05.gif](img/alarm/alarm_figure05.gif) +![alarm_figure05.gif](images/alarm/alarm_figure05.gif) **Alarm Rules** ``` SLOW COUNT - Triggered when the number of slow requests sent by the application exceeds the configured threshold. + Triggered when the number of slow requests sent to the application exceeds the configured threshold. SLOW RATE - Triggered when the percentage(%) of slow requests sent by the application exceeds the configured threshold. + Triggered when the percentage(%) of slow requests sent to the application exceeds the configured threshold. ERROR COUNT - Triggered when the number of failed requests sent by the application exceeds the configured threshold. + Triggered when the number of failed requests sent to the application exceeds the configured threshold. ERROR RATE - Triggered when the percentage(%) of failed requests sent by the application exceeds the configured threshold. + Triggered when the percentage(%) of failed requests sent to the application exceeds the configured threshold. TOTAL COUNT - Triggered when the number of all requests sent by the application exceeds the configured threshold. + Triggered when the number of all requests sent to the application exceeds the configured threshold. SLOW COUNT TO CALLEE - Triggered when the number of slow requests sent to the application exceeds the configured threshold. + Triggered when the number of slow requests sent by the application exceeds the configured threshold. + You must specify the domain or the address(ip, port) in the configuration UI's "Note..." box + ex) www.naver.com, 127.0.0.1:8080 SLOW RATE TO CALLEE - Triggered when the percentage(%) of slow requests sent to the application exceeds the configured threshold. + Triggered when the percentage(%) of slow requests sent by the application exceeds the configured threshold. + You must specify the domain or the address(ip, port) in the configuration UI's "Note..." box + ex) www.naver.com, 127.0.0.1:8080 ERROR COUNT TO CALLEE - Triggered when the number of failed requests sent to the application exceeds the configured threshold. + Triggered when the number of failed requests sent by the application exceeds the configured threshold. + You must specify the domain or the address(ip, port) in the configuration UI's "Note..." box + ex) www.naver.com, 127.0.0.1:8080 ERROR RATE TO CALLEE - Triggered when the percentage(%) of failed requests sent to the application exceeds the configured threshold. + Triggered when the percentage(%) of failed requests sent by the application exceeds the configured threshold. + You must specify the domain or the address(ip, port) in the configuration UI's "Note..." box + ex) www.naver.com, 127.0.0.1:8080 TOTAL COUNT TO CALLEE - Triggered when the number of all requests sent to the application exceeds the configured threshold. + Triggered when the number of all requests sent by the application exceeds the configured threshold. + You must specify the domain or the address(ip, port) in the configuration UI's "Note..." box + ex) www.naver.com, 127.0.0.1:8080 + HEAP USAGE RATE Triggered when the application's heap usage(%) exceeds the configured threshold. @@ -137,26 +157,26 @@ jdbc.url=jdbc:mysql://localhost:13306/pinpoint?characterEncoding=UTF-8 jdbc.username=admin jdbc.password=admin ``` -Create tables by running *[CreateTableStatement-mysql.sql](../web/src/main/resources/sql/CreateTableStatement-mysql.sql)*, and *[SpringBatchJobRepositorySchema-mysql.sql](../web/src/main/resources/sql/SpringBatchJobRepositorySchema-mysql.sql)*. +Create tables by running *[CreateTableStatement-mysql.sql](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/sql/CreateTableStatement-mysql.sql)*, and *[SpringBatchJobRepositorySchema-mysql.sql](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/sql/SpringBatchJobRepositorySchema-mysql.sql)*. ### 4) Others -**1) You may start the alarm batch in a separate process** - Simply start the spring batch job using the *[applicationContext-alarmJob.xml](../web/src/main/resources/batch/applicationContext-alarmJob.xml)* file inside the Pinpoint-web module. +**1) You may start the alarm batch in a separate process** - Simply start the spring batch job using the *[applicationContext-alarmJob.xml](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/batch/applicationContext-alarmJob.xml)* file inside the Pinpoint-web module. -**2) You may change the batch execution period by modifying the cron expression in *[applicationContext-batch-schedule.xml](../web/src/main/resources/batch/applicationContext-batch-schedule.xml)* file** +**2) You may change the batch execution period by modifying the cron expression in *[applicationContext-batch-schedule.xml](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/batch/applicationContext-batch-schedule.xml)* file** ``` ``` -**3) Ways to improve alarm batch performance** - The alarm batch was designed to run concurrently. If you have a lot of applications with alarms registered, you may increase the size of the executor's thread pool by modifying `pool-size` in *[applicationContext-batch.xml](../web/src/main/resources/batch/applicationContext-batch.xml)* file. +**3) Ways to improve alarm batch performance** - The alarm batch was designed to run concurrently. If you have a lot of applications with alarms registered, you may increase the size of the executor's thread pool by modifying `pool-size` in *[applicationContext-batch.xml](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/batch/applicationContext-batch.xml)* file. Note that increasing this value will result in higher resource usage. ``` ``` -If there are a lot of alarms registered to applications, you may set the `alarmStep` registered in *[applicationContext-batch.xml](../web/src/main/resources/batch/applicationContext-batch.xml)* file to run concurrently. +If there are a lot of alarms registered to applications, you may set the `alarmStep` registered in *[applicationContext-batch.xml](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/batch/applicationContext-batch.xml)* file to run concurrently. ``` @@ -170,8 +190,8 @@ If there are a lot of alarms registered to applications, you may set the `alarmS Pinpoint Web uses Mysql to persist users, user groups, and alarm configurations.
However Quickstart uses MockDAO to reduce memory usage.
Therefore if you want to use Mysql for Quickstart, please refer to Pinpoint Web's [applicationContext-dao-config.xml -](../web/src/main/resources/applicationContext-dao-config.xml -), [jdbc.properties](../web/src/main/resources/jdbc.properties). +](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/applicationContext-dao-config.xml +), [jdbc.properties](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/jdbc.properties). --- @@ -185,54 +205,62 @@ alarm batch는 기본적으로 3분에 한번씩 동작이 된다. 최근 5분 ## 1. Alarm 기능 사용 방법 1) 설정 화면으로 이동 -![alarm_figure01.gif](img/alarm/alarm_figure01.gif) +![alarm_figure01.gif](images/alarm/alarm_figure01.gif) 2) user를 등록 -![alarm_figure02.gif](img/alarm/alarm_figure02.gif) +![alarm_figure02.gif](images/alarm/alarm_figure02.gif) 3) userGroup을 생성 -![alarm_figure03.gif](img/alarm/alarm_figure03.gif) +![alarm_figure03.gif](images/alarm/alarm_figure03.gif) 4) userGroup에 member를 등록 -![alarm_figure04.gif](img/alarm/alarm_figure04.gif) +![alarm_figure04.gif](images/alarm/alarm_figure04.gif) 5) alarm rule을 등록 -![alarm_figure05.gif](img/alarm/alarm_figure05.gif) +![alarm_figure05.gif](images/alarm/alarm_figure05.gif) alarm rule에 대한 설명은 아래를 참고하시오. ``` + SLOW COUNT - application 내에서 외부서버를 호출한 요청 중 slow 호출의 개수가 임계치를 초과한 경우 알람이 전송된다. - + 외부에서 application을 호출한 요청 중에 외부서버로 응답을 늦게 준 요청의 개수가 임계치를 초과한 경우 알람이 전송된다. + SLOW RATE - application 내에서 외부서버를 호출한 요청 중 slow 호출의 비율(%)이 임계치를 초과한 경우 알람이 전송된다. + 외부에서 application을 호출한 요청 중에 외부서버로 응답을 늦게 준 요청의 비율(%)이 임계치를 초과한 경우 알람이 전송된다. ERROR COUNT - application 내에서 외부서버를 호출한 요청 중 error 가 발생한 호출의 개수가 임계치를 초과한 경우 알람이 전송된다. + 외부에서 application을 호출한 요청 중에 에러가 발생한 요청의 개수가 임계치를 초과한 경우 알람이 전송된다. ERROR RATE - application 내에서 외부서버를 호출한 요청 중 error 가 발생한 호출의 비율이 임계치를 초과한 경우 알람이 전송된다. + 외부에서 application을 호출한 요청 중에 에러가 발생한 요청의 비율(%)이 임계치를 초과한 경우 알람이 전송된다. TOTAL COUNT - application 내에서 외부서버를 호출한 요청의 개수가 임계치를 초과한 경우 알람이 전송된다. + 외부에서 application을 호출한 요청 개수가 임계치를 초과한 경우 알람이 전송된다. SLOW COUNT TO CALLEE - 외부에서 application을 호출한 요청 중에 외부서버로 응답을 늦게 준 요청의 개수가 임계치를 초과한 경우 알람이 전송된다. - + application 내에서 외부서버를 호출한 요청 중 slow 호출의 개수가 임계치를 초과한 경우 알람이 전송된다. + 설정 화면의 Note 항목에 외부서버의 도메인 이나 주소(ip, port)를 입력해야 합니다. ex) naver.com, 127.0.0.1:8080 + SLOW RATE TO CALLEE - 외부에서 application을 호출한 요청 중에 외부서버로 응답을 늦게 준 요청의 비율(%)이 임계치를 초과한 경우 알람이 전송된다. + application 내에서 외부서버를 호출한 요청 중 slow 호출의 비율(%)이 임계치를 초과한 경우 알람이 전송된다. + 설정 화면의 Note 항목에 외부서버의 도메인 이나 주소(ip, port)를 입력해야 합니다. ex) naver.com, 127.0.0.1:8080 ERROR COUNT TO CALLEE - 외부에서 application을 호출한 요청 중에 에러가 발생한 요청의 개수가 임계치를 초과한 경우 알람이 전송된다. + application 내에서 외부서버를 호출한 요청 중 error 가 발생한 호출의 개수가 임계치를 초과한 경우 알람이 전송된다. + 설정 화면의 Note 항목에 외부서버의 도메인 이나 주소(ip, port)를 입력해야 합니다. ex) naver.com, 127.0.0.1:8080 ERROR RATE TO CALLEE - 외부에서 application을 호출한 요청 중에 에러가 발생한 요청의 비율(%)이 임계치를 초과한 경우 알람이 전송된다. + application 내에서 외부서버를 호출한 요청 중 error 가 발생한 호출의 비율이 임계치를 초과한 경우 알람이 전송된다. + 설정 화면의 Note 항목에 외부서버의 도메인 이나 주소(ip, port)를 입력해야 합니다. ex) naver.com, 127.0.0.1:8080 TOTAL COUNT TO CALLEE - 외부에서 application을 호출한 요청 개수가 임계치를 초과한 경우 알람이 전송된다. + application 내에서 외부서버를 호출한 요청의 개수가 임계치를 초과한 경우 알람이 전송된다. + 설정 화면의 Note 항목에 외부서버의 도메인 이나 주소(ip, port)를 입력해야 합니다. ex) naver.com, 127.0.0.1:8080 HEAP USAGE RATE heap의 사용률이 임계치를 초과한 경우 알람이 전송된다. + 설정 화면의 Note 항목에 외부서버의 도메인 이나 주소(ip, port)를 입력해야 합니다. JVM CPU USAGE RATE applicaiton의 CPU 사용률이 임계치를 초과한 경우 알람이 전송된다. + 설정 화면의 Note 항목에 외부서버의 도메인 이나 주소(ip, port)를 입력해야 합니다. DATASOURCE CONNECTION USAGE RATE applicaiton의 DataSource내의 Connection 사용률이 임계치를 초과한 경우 알람이 전송된다. @@ -320,14 +348,14 @@ jdbc.url=jdbc:mysql://localhost:13306/pinpoint?characterEncoding=UTF-8 jdbc.username=admin jdbc.password=admin ``` -필요한 table 생성 - *[CreateTableStatement-mysql.sql](../web/src/main/resources/sql/CreateTableStatement-mysql.sql)*, *[SpringBatchJobReositorySchema-mysql.sql](../web/src/main/resources/sql/SpringBatchJobRepositorySchema-mysql.sql)* +필요한 table 생성 - *[CreateTableStatement-mysql.sql](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/sql/CreateTableStatement-mysql.sql)*, *[SpringBatchJobReositorySchema-mysql.sql](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/sql/SpringBatchJobRepositorySchema-mysql.sql)* ## 3. 기타 **1) alarm batch를 별도 프로세스로 실행하는 것도 가능하다.** -pinpoint-web 프로젝트의 *[applicationContext-alarmJob.xml](../web/src/main/resources/batch/applicationContext-alarmJob.xml)* 파일을 이용해서 spring batch job을 실행하면 된다. +pinpoint-web 프로젝트의 *[applicationContext-alarmJob.xml](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/batch/applicationContext-alarmJob.xml)* 파일을 이용해서 spring batch job을 실행하면 된다. 실행 방법은 대한 구체적인 방법은 spirng batch 메뉴얼을 참고하자. -**2) batch의 동작 주기를 조정하고 싶다면 *[applicationContext-batch-schedule.xml](../web/src/main/resources/batch/applicationContext-batch-schedule.xml)* 파일의 cron expression을 수정하면 된다.** +**2) batch의 동작 주기를 조정하고 싶다면 *[applicationContext-batch-schedule.xml](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/batch/applicationContext-batch-schedule.xml)* 파일의 cron expression을 수정하면 된다.** ``` @@ -338,12 +366,12 @@ pinpoint-web 프로젝트의 *[applicationContext-alarmJob.xml](../web/src/main/ alarm batch 성능 튜닝을 위해서 병렬로 동작이 가능하도록 구현을 해놨다. 그래서 아래에서 언급된 조건에 해당하는 경우 설정값을 조정한다면 성능을 향상 시킬수 있다. 단 병렬성을 높이면 리소스의 사용률이 높아지는것은 감안해야한다. -alarm이 등록된 application의 개수가 많다면 *[applicationContext-batch.xml](../web/src/main/resources/batch/applicationContext-batch.xml)* 파일의 poolTaskExecutorForPartition의 pool size를 늘려주면 된다. +alarm이 등록된 application의 개수가 많다면 *[applicationContext-batch.xml](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/batch/applicationContext-batch.xml)* 파일의 poolTaskExecutorForPartition의 pool size를 늘려주면 된다. ``` ``` -application 각각마다 등록된 alarm의 개수가 많다면 *[applicationContext-batch.xml](../web/src/main/resources/batch/applicationContext-batch.xml)* 파일에 선언된 alarmStep이 병렬로 동작되도록 설정하면 된다. +application 각각마다 등록된 alarm의 개수가 많다면 *[applicationContext-batch.xml](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/batch/applicationContext-batch.xml)* 파일에 선언된 alarmStep이 병렬로 동작되도록 설정하면 된다. ``` @@ -356,5 +384,5 @@ application 각각마다 등록된 alarm의 개수가 많다면 *[applicationCon **4) quickstart web을 사용한다면.** pinpoint web은 mockDAO를 사용하기 때문에 pinpont web의 설정들을 참고해서 기능을 사용해야한다. [applicationContext-dao-config.xml -](../web/src/main/resources/applicationContext-dao-config.xml -), [jdbc.properties](../web/src/main/resources/jdbc.properties). +](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/applicationContext-dao-config.xml +), [jdbc.properties](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/jdbc.properties). diff --git a/doc/application-inspector.md b/doc/application-inspector.md index d3582416d802..227051aff443 100644 --- a/doc/application-inspector.md +++ b/doc/application-inspector.md @@ -1,3 +1,12 @@ +--- +title: How to use Application Inspector +keywords: inspector, how, how-to +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: applicationinspector.html +disqus: false +--- + [English](#application-inspector) | [한글](#application-inspector-1) # Application Inspector @@ -8,31 +17,31 @@ Application inspector provides an aggregate view of all the agent's resource dat To access application inspector, click on the application inspector menu on the left side of the screen. - 1 : application inspector menu, 2 : application stat data -![inspector_view.jpg](img/applicationInspector/inspector_view.jpg) +![inspector_view.jpg](images/applicationInspector/inspector_view.jpg) The Heap Usage chart above for example, shows the average(Avg), smallest(Min), greatest(Max) heap usage of the agents registered under the same application name along with the id of the agent that had the smallest/greatest heap usage at a certain point in time. The application inspector also provides other statistics found in the agent inspector in a similar fashion. -![graph.jpg](img/applicationInspector/graph.jpg) +![graph.jpg](images/applicationInspector/graph.jpg) Application inspector requires [flink](https://flink.apache.org) and [zookeeper](https://zookeeper.apache.org/). Please read on for more detail. ## 2. Architecture -![execute_flow.jpg](img/applicationInspector/execute_flow.jpg) +![execute_flow.jpg](images/applicationInspector/execute_flow.jpg) **A.** Run a streaming job on [flink](https://flink.apache.org). **B.** The taskmanager server is registered to zookeeper as a data node once the job starts. -**C.** The collector obtains the flink server info from zookeeper to create a tcp connection with it and starts sending agent data. -**D.** The flink server aggregates data sent by the collector and stores them into hbase. +**C.** The Collector obtains the flink server info from zookeeper to create a tcp connection with it and starts sending agent data. +**D.** The flink server aggregates data sent by the Collector and stores them into hbase. ## 3. Configuration -In order to enable application inspector, you will need to do the following and run pinpoint. +In order to enable application inspector, you will need to do the following and run Pinpoint. **A.** Create **ApplicationStatAggre** table (refer to [create table script](https://github.com/naver/pinpoint/tree/master/hbase/scripts)), which stores application stat data. -**B.** Configure zookeeper address in [pinpoint-flink.properties](https://github.com/naver/pinpoint/blob/master/flink/src/main/resources/pinpoint-flink.properties) which will be used to store flink's taskmanager server information. +**B.** Configure zookeeper address in [Pinpoint-flink.properties](https://github.com/naver/pinpoint/blob/master/flink/src/main/resources/pinpoint-flink.properties) which will be used to store flink's taskmanager server information. ```properties flink.cluster.enable=true flink.cluster.zookeeper.address=YOUR_ZOOKEEPER_ADDRESS @@ -41,7 +50,7 @@ In order to enable application inspector, you will need to do the following and flink.cluster.tcp.port=19994 ``` -**C.** Configure job execution type and the number of listeners to receive data from the collector in [pinpoint-flink.properties](https://github.com/naver/pinpoint/blob/master/flink/src/main/resources/pinpoint-flink.properties). +**C.** Configure job execution type and the number of listeners to receive data from the Collector in [Pinpoint-flink.properties](https://github.com/naver/pinpoint/blob/master/flink/src/main/resources/pinpoint-flink.properties). * If you are running a flink cluster, set *flink.StreamExecutionEnvironment* to **server**, and *flink.sourceFunction.Parallel* to the number of task manager servers. * If you are running flink as a standalone, set *flink.StreamExecutionEnvironment* to **local**, and *flink.sourceFunction.Parallel* to **1**. ```properties @@ -55,11 +64,11 @@ In order to enable application inspector, you will need to do the following and hbase.client.port=2181 ``` -**E.** Build [pinpoint-flink](https://github.com/naver/pinpoint/tree/master/flink) and run the streaming job file created under *target* directory on the flink server. +**E.** Build [Pinpoint-flink](https://github.com/naver/pinpoint/tree/master/flink) and run the streaming job file created under *target* directory on the flink server. - The name of the streaming job is `pinpoint-flink-job.2.0.jar`. - For details on how to run the job, please refer to the [flink website](https://flink.apache.org). -**F.** Configure zookeeper address in [pinpoint-collector.properties](https://github.com/naver/pinpoint/blob/master/collector/src/main/resources/pinpoint-collector.properties) so that the collector can connect to the flink server. +**F.** Configure zookeeper address in [Pinpoint-Collector.properties](https://github.com/naver/pinpoint/blob/master/collector/src/main/resources/pinpoint-collector.properties) so that the Collector can connect to the flink server. ```properties flink.cluster.enable=true flink.cluster.zookeeper.address=YOUR_ZOOKEEPER_ADDRESS @@ -73,7 +82,7 @@ In order to enable application inspector, you will need to do the following and ## 4. Monitoring Streaming Jobs -There is a batch job that monitors how pinpoint streaming jobs are running. To enable this batch job, configure the following files for *pinpoint-web*. +There is a batch job that monitors how Pinpoint streaming jobs are running. To enable this batch job, configure the following files for *Pinpoint-web*. **batch.properties** ```properties @@ -105,11 +114,11 @@ application inspector 기능은 agent들의 리소스 데이터(stat : cpu, memo inspector 화면 왼쪽 메뉴의 링크를 클릭하면 application inspector 버튼을 클릭하고 데이터를 볼 수 있다. - 1 : application inspector menu, 2: application stat data -![inspector_view.jpg](img/applicationInspector/inspector_view.jpg) +![inspector_view.jpg](images/applicationInspector/inspector_view.jpg) 예를들면 A라는 application에 포함된 agent들의 heap 사용량을 모아서 heap 사용량 평균값 , heap 사용량의 평균값, heap 사용량이 가장 높은 agentid와 사용량, heap 사용량이 가장 적은 agentid와 사용량을 보여준다. 이외에도 agent inspector 에서 제공하는 다른 데이터들도 집계하여 application inspector에서 제공한다. -![graph.jpg](img/applicationInspector/graph.jpg) +![graph.jpg](images/applicationInspector/graph.jpg) application inspector 기능을 동작시키기 위해서는 [flink](https://flink.apache.org)와 [zookeeper](https://zookeeper.apache.org/)가 필요하고, 기능의 동작 구조와 구성 및 설정 방법을 아래 설명한다. @@ -118,22 +127,22 @@ application inspector 기능을 동작시키기 위해서는 [flink](https://fli application inspector 기능의 동작 및 구조를 그림과 함께 보자. -![execute_flow.jpg](img/applicationInspector/execute_flow.jpg) +![execute_flow.jpg](images/applicationInspector/execute_flow.jpg) **A.** [flink](https://flink.apache.org)에 streaming job을 실행시킨다. **B.** job이 실행되면 taskmanager 서버의 정보가 zookeeper의 데이터 노드로 등록이 된다. -**C.** collector는 zookeeper에서 flink 서버의 정보를 가져와서 flink 서버와 tcp 연결을 맺고 agent stat 데이터를 전송한다. +**C.** Collector는 zookeeper에서 flink 서버의 정보를 가져와서 flink 서버와 tcp 연결을 맺고 agent stat 데이터를 전송한다. **D.** flink 서버에서는 agent 데이터를 집계하여 통계 데이터를 hbase에 저장한다. ## 3. 기능 실행 방법 -application inspector 기능을 실행하기 위해서 아래와 같이 설정을 변경하고 pinpoint를 실행해야 한다. +application inspector 기능을 실행하기 위해서 아래와 같이 설정을 변경하고 Pinpoint를 실행해야 한다. **A.** [테이블 생성 스크립트를 참조](https://github.com/naver/pinpoint/tree/master/hbase/scripts)하여 application 통계 데이터를 저장하는 **ApplicationStatAggre** 테이블을 생성한다. -**B.** flink 프로젝트 설정파일([pinpoint-flink.properties](https://github.com/naver/pinpoint/blob/master/flink/src/main/resources/pinpoint-flink.properties))에 taskmanager 서버 정보를 저장하는 zookeeper 주소를 설정한다. +**B.** flink 프로젝트 설정파일([Pinpoint-flink.properties](https://github.com/naver/pinpoint/blob/master/flink/src/main/resources/pinpoint-flink.properties))에 taskmanager 서버 정보를 저장하는 zookeeper 주소를 설정한다. ```properties flink.cluster.enable=true flink.cluster.zookeeper.address=YOUR_ZOOKEEPER_ADDRESS @@ -142,7 +151,7 @@ application inspector 기능을 실행하기 위해서 아래와 같이 설정 flink.cluster.tcp.port=19994 ``` -**C.** flink 프로젝트 설정파일([pinpoint-flink.properties](https://github.com/naver/pinpoint/blob/master/flink/src/main/resources/pinpoint-flink.properties))에 job의 실행 방법과 collector에서 데이터를 받는 listener의 개수를 설정한다. +**C.** flink 프로젝트 설정파일([Pinpoint-flink.properties](https://github.com/naver/pinpoint/blob/master/flink/src/main/resources/pinpoint-flink.properties))에 job의 실행 방법과 Collector에서 데이터를 받는 listener의 개수를 설정한다. - flink를 cluster로 구축해서 사용한다면 *flink.StreamExecutionEnvironment*에는 **server**를 설정하고 *flink.sourceFunction.Parallel*에는 task manager 서버의 개수만큼 설정한다. - flink를 Standalone 형태로 실행한다면 *flink.StreamExecutionEnvironment*에는 **local**을 설정하고 *flink.sourceFunction.Parallel*에는 **1**을 설정하면 된다. @@ -161,7 +170,7 @@ application inspector 기능을 실행하기 위해서 아래와 같이 설정 - streaming job 파일 이름은 `pinpoint-flink-job.2.0.jar` 이다. - 실행방법은 [flink 사이트](https://flink.apache.org)를 참조한다. -**F.** collector에서 flink와 연결을 맺을 수 있도록 설정파일([pinpoint-collector.porperties](https://github.com/naver/pinpoint/blob/master/collector/src/main/resources/pinpoint-collector.properties))에 zookeeper 주소를 설정한다. +**F.** Collector에서 flink와 연결을 맺을 수 있도록 설정파일([Pinpoint-Collector.porperties](https://github.com/naver/pinpoint/blob/master/collector/src/main/resources/pinpoint-collector.properties))에 zookeeper 주소를 설정한다. ```properties flink.cluster.enable=true flink.cluster.zookeeper.address=YOUR_ZOOKEEPER_ADDRESS @@ -175,8 +184,8 @@ application inspector 기능을 실행하기 위해서 아래와 같이 설정 ## 4. streaming job 동작 확인 모니터링 batch -pinpoint streaming job이 실행되고 있는지 확인하는 batch job이 있다. -batch job을 동작 시키고 싶다면 pinpoint web 프로젝트의 설정 파일을 수정하면 된다. +Pinpoint streaming job이 실행되고 있는지 확인하는 batch job이 있다. +batch job을 동작 시키고 싶다면 Pinpoint web 프로젝트의 설정 파일을 수정하면 된다. **batch.properties** ```properties diff --git a/doc/compatibilityHbase.md b/doc/compatibilityHbase.md new file mode 100755 index 000000000000..ebcdf14fa60a --- /dev/null +++ b/doc/compatibilityHbase.md @@ -0,0 +1,8 @@ +Pinpoint Version | HBase 0.94.x | HBase 0.98.x | HBase 1.0.x | HBase 1.2.x +---------------- | ------------ | ------------ | ----------- | ----------- +1.0.x | yes | no | no | no +1.1.x | no | not tested | yes | not tested +1.5.x | no | not tested | yes | not tested +1.6.x | no | not tested | not tested | yes +1.7.x | no | not tested | not tested | yes +1.8.x | no | not tested | not tested | yes diff --git a/doc/compatibilityJava.md b/doc/compatibilityJava.md new file mode 100755 index 000000000000..36f0a2a5188b --- /dev/null +++ b/doc/compatibilityJava.md @@ -0,0 +1,8 @@ +Pinpoint Version | Agent | Collector | Web +---------------- | ----- | --------- | --- +1.0.x | 6-8 | 6+ | 6+ +1.1.x | 6-8 | 7+ | 7+ +1.5.x | 6-8 | 7+ | 7+ +1.6.x | 6-8 | 7+ | 7+ +1.7.x | 6-8 | 8+ | 8+ +1.8.x | 6-8
9+(Experimental) | 8+ | 8+ \ No newline at end of file diff --git a/doc/compatibilityPinpoint.md b/doc/compatibilityPinpoint.md new file mode 100755 index 000000000000..e15ec678822b --- /dev/null +++ b/doc/compatibilityPinpoint.md @@ -0,0 +1,8 @@ +Agent Version | Collector 1.0.x | Collector 1.1.x | Collector 1.5.x | Collector 1.6.x | Collector 1.7.x | Collector 1.8.x +------------- | --------------- | --------------- | --------------- | --------------- | --------------- | --------------- +1.0.x | yes | yes | yes | yes | yes | yes +1.1.x | not tested | yes | yes | yes | yes | yes +1.5.x | no | no | yes | yes | yes | yes +1.6.x | no | no | not tested | yes | yes | yes +1.7.x | no | no | no | no | yes | yes +1.8.x | no | no | no | no | no | yes \ No newline at end of file diff --git a/doc/contribution.md b/doc/contribution.md new file mode 100755 index 000000000000..de326a60621e --- /dev/null +++ b/doc/contribution.md @@ -0,0 +1,95 @@ +--- +title: Contribution +keywords: help +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: contribution.html +disqus: false +--- + +Thank you very much for choosing to share your contribution with us. Please read this page to help yourself to the contribution. + +Before making first pull-request, please make sure you've signed the [Contributor License Agreement](http://goo.gl/forms/A6Bp2LRoG3). This isn't a copyright - it gives us (Naver) permission to use and redistribute your code as part of the project. + +## Making Pull Requests +Apart from trivial fixes such as typo or formatting, all pull requests should have a corresponding issue associated with them. It is always helpful to know what people are working on, and different (often better) ideas may pop up while discussing them. +Please keep these in mind before you create a pull request: +* Every new java file must have a copy of the license comment. You may copy this from an existing file. +* Make sure you've tested your code thoroughly. For plugins, please try your best to include integration tests if possible. +* Before submitting your code, make sure any changes introduced by your code does not break the build, or any tests. +* Clean up your commit log into logical chunks of work to make it easier for us to figure out what and why you've changed something. (`git rebase -i` helps) +* Please try best to keep your code updated against the master branch before creating a pull request. +* Make sure you create the pull request against our master branch. +* If you've created your own plugin, please take a look at [plugin contribution guideline](#plugin-contribution-guideline) + + +## Plugin Contribution Guideline +We welcome your plugin contribution. +Currently, we would love to see additional tracing support for libraries such as [Storm](https://storm.apache.org "Apache Storm"), [HBase](http://hbase.apache.org "Apache HBase"), as well as profiler support for additional languages (.NET, C++). + +### Technical Guide +**For technical guides for developing plug-in,** take a look at our [plugin development guide](./plugindevguide.html "Pinpoint Plugin Development Guide"), along with [plugin samples](https://github.com/naver/pinpoint-plugin-sample "Pinpoint Plugin Samples project") project to get an idea of how we do instrumentation. The samples will provide you with example codes to help you get started. + +### Contributing Plugin +If you want to contribute your plugin, it has to satisfy the following requirements: + +1. Configuration key names must start with `profiler.[pluginName]`. +2. At least 1 plugin integration test. + +Once your plugin is complete, please open an issue to contribute the plugin as below: + +``` +Title: [Target Library Name] Plugin Contribution + +Link: Plugin Repository URL +Target: Target Library Name +Supported Version: +Description: Simple description about the target library and/or target library homepage URL + +ServiceTypes: List of service type names and codes the plugin adds +Annotations: List of annotation key names and codes the plugin adds +Configurations: List of configuration keys and description the plugin adds. +``` + +Our team will review the plugin, and your plugin repository will be linked at the third-party plugin list page if everything checks out. If the plugin is for a widely used library, and if we feel confident that we can continuously provide support for it, you may be asked to send us a PR. Should you choose to accept it, your plugin will be merged to the Pinpoint repository. + +As much as we'd love to merge all the plugins to the source repository, we do not have the man power to manage all of them, yet. We are a very small team, and we certainly are not experts in all of the target libraries. We feel that it would be better to not merge a plugin if we are not confident in our ability to provide continuous support for it. + +To send a PR, you have to modify your plugin like this: + +* Fork Pinpoint repository +* Copy your plugin under /plugins directory +* Set parent pom +``` + + com.navercorp.pinpoint + pom + ../.. + Current Version + +``` +* Add your plugin to plugins/pom.xml as a sub-module and a dependency. +* Copy your plugin integration tests under /agent/src/test directory. +* Add your configurations to /agent/src/main/resources/*.config files. +* Insert following license header to all java source files. +``` +/* + * Copyright 2016 Pinpoint contributors and NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +``` + +If you do not want to be bothered with a PR, you may choose to tell us to do it ourselves. However, please note that your contribution will not visible through git history or the Github profile. + + diff --git a/doc/dev-architecture.md b/doc/dev-architecture.md index 2540534a3633..69aac83d39ee 100644 --- a/doc/dev-architecture.md +++ b/doc/dev-architecture.md @@ -2,7 +2,7 @@ Pinpoint is comprised of 3 main components (Agent, Collector, Web UI), and a HBase storage. -![Pinpoint Architecture](img/pinpoint-architecture.png) +![Pinpoint Architecture](images/pinpoint-architecture.png) ## Components diff --git a/doc/dev-collector.md b/doc/dev-collector.md deleted file mode 100644 index 8684137f4202..000000000000 --- a/doc/dev-collector.md +++ /dev/null @@ -1 +0,0 @@ -# Collector Development - WIP diff --git a/doc/dev-profiler.md b/doc/dev-profiler.md deleted file mode 100644 index b8f2b1795c2d..000000000000 --- a/doc/dev-profiler.md +++ /dev/null @@ -1 +0,0 @@ -# Profiler Development - WIP diff --git a/doc/dev-web.md b/doc/dev-web.md deleted file mode 100644 index 384c0c2f131d..000000000000 --- a/doc/dev-web.md +++ /dev/null @@ -1 +0,0 @@ -# Web Development - WIP diff --git a/doc/docker.md b/doc/docker.md new file mode 100755 index 000000000000..dc39bffb7b55 --- /dev/null +++ b/doc/docker.md @@ -0,0 +1,15 @@ +--- +title: Pinpoint on Docker +keywords: docker pinpoint, pinpoint install +last_updated: May 14, 2018 +sidebar: mydoc_sidebar +permalink: docker.html +disqus: false +--- + +## Want to install Pinpoint inside docker? + +We've create docker files to support docker. +Installing Pinpoint with these docker files will take approximately 10min. to check out the features of Pinpoint. + +Visit [Official Pinpoint-Docker repository](https://github.com/naver/pinpoint-docker) for more information. \ No newline at end of file diff --git a/doc/faq.md b/doc/faq.md new file mode 100755 index 000000000000..c8419fbe0568 --- /dev/null +++ b/doc/faq.md @@ -0,0 +1,64 @@ +--- +title: FAQ +sidebar: mydoc_sidebar +keywords: faq, question, answer, frequently asked questions, FAQ, question and answer +last_updated: Feb 1, 2018 +permalink: faq.html +toc: false +disqus: false +--- + +For any other questions, please use the [user group](https://groups.google.com/forum/#!forum/pinpoint_user) + +### How do I get the call stack view? +Click on a server node, which will populate the scatter chart on the right. This chart shows all succeeded/failed requests that went through the server. If there are any requests that spike your interest, simply **drag on the scatter chart** to select them. This will bring up the call stack view containing the requests you've selected. + +### How do I change agent's log level? +You can change the log level by modifying the agent's *log4j.xml* located in *PINPOINT_AGENT/lib* directory. + +### Why is only the first/some of the requests traced? +There is a sampling rate option in the agent's pinpoint.config file (profiler.sampling.rate). +The agent's release binary has this value set to 20, which tells the agent to sample 1 trace every 20 transactions. +Changing this value to 1 will allow you to trace every transaction. + +### Request count in the Scatter Chart is different from the ones in Response Summary chart. Why is this? +The Scatter Chart data have a second granularity, so the requests counted here can be differentiated by a second interval. +On the other hand, the Server Map, Response Summary, and Load Chart data are stored in a minute granularity (the collector aggregates these in memory and flushes them every minute due to performance reasons). +For example, if the data is queried from 10:00:30 to 10:05:30, the Scatter Chart will show the requests counted between 10:00:30 and 10:05:30, whereas the server map, response summary, and load chart will show the requests counted between 10:00:00 and 10:05:59. + +### How do I delete application name and/or agent id from HBase? +Application names and agent ids, once registered, stay in HBase until their TTL expires (default 1year). +You may however delete them proactively using [admin APIs](https://github.com/naver/pinpoint/blob/master/web/src/main/java/com/navercorp/pinpoint/web/controller/AdminController.java) once they are no longer used. +* Remove application name - `/admin/removeApplicationName.pinpoint?applicationName=$APPLICATION_NAME&password=$PASSWORD` +* Remove agent id - `/admin/removeAgentId.pinpoint?applicationName=$APPLICATION_NAME&agentId=$AGENT_ID&password=$PASSWORD` +Note that the value for the password parameter is what you defined `admin.password` property in *pinpoint-web.properties*. Leaving this blank will allow you to call admin APIs without the password parameter. + +### What are the criteria for the application name? +Pinpoint's applicationName doesn't support special characters. such as @,#,$,%,*. +Pinpoint's applicationName only supports [a-zA-Z0-9], '.', '-', '_' characters. + +### HBase is taking up too much space, which data should I delete first? +Hbase is very scalable so you can always add more region servers if you're running out of space. Shortening the TTL values, especially for **AgentStatV2** and **TraceV2**, can also help (though you might have to wait for a major compaction before space is reclaimed). For details on how to major compact, please refer to [this](https://github.com/naver/pinpoint/blob/master/hbase/scripts/hbase-major-compact-htable.hbase) script. + +However, if you **must** make space asap, data in **AgentStatV2** and **TraceV2** tables are probably the safest to delete. You will lose agent statistic data (inspector view) and call stack data (transaction view), but deleting these will not break anything. + +Note that deleting ***MetaData** tables will result in **-METADATA-NOT-FOUND* being displayed in the call stack and the only way to "fix" this is to restart all the agents, so it is generally a good idea to leave these tables alone. + +### My custom jar application is not being traced. Help! +Pinpoint Agent need an entry point to start off a new trace for a transaction. This is usually done by various WAS plugins (such as Tomcat, Jetty, etc) in which a new trace is started when they receive an RPC request. +For custom jar applications, you need to set this manually as the Agent does not have knowledge of when and where to start a trace. +You can set this by configuring `profiler.entrypoint` in *pinpoint.config* file. + +### Building is failing after new release. Help! +Please remember to run the command `mvn clean verify -DskipTests=true` if you've used a previous version before. + +### How to set java runtime option when using atlassian OSGi +`-Datlassian.org.osgi.framework.bootdelegation=sun.,com.sun.,com.navercorp.*,org.apache.xerces.*` + +### Why do I see UI send requests to http://www.google-analytics.com/collect? +Pinpoint Web module has google analytics attached which tracks the number and the order of button clicks in the Server Map, Transaction List, and the Inspector View. +This data is used to better understand how users interact with the Web UI which gives us valuable information on improving Pinpoint Web's user experience. To disable this for any reason, set following option to false in pinpoint-web.properties for your web instance. +``` +config.sendUsage=false +``` + diff --git a/doc/history.md b/doc/history.md new file mode 100755 index 000000000000..c2878586360b --- /dev/null +++ b/doc/history.md @@ -0,0 +1,29 @@ +--- +title: History +keywords: history +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: history.html +disqus: false +--- + +Pinpoint is a platform that analyzes large-scale distributed systems and provides a solution to handle large collections of trace data. It has been developed since July 2012 and was launched as an open-source project on January 9, 2015. + +This article introduces Pinpoint; it describes what motivated us to start this project, which technologies are used, and how the Pinpoint Agent can be optimized. + +> 本文的中文翻译版本 [请见这里](https://github.com/skyao/leaning-pinpoint/blob/master/design/technical_overview.md) + +## Motivation to Get Started & Pinpoint Characteristics + +Compared to nowadays, the number of Internet users was relatively small and the architecture of Internet services was less complex. Web services were generally configured using a 2-tier (web server and database) or 3-tier (web server, application server, and database) architecture. However, today, supporting a large number of concurrent connections is required and functionalities and services should be organically integrated as the Internet has grown, resulting in much more complex combinations of the software stack. That is n-tier architecture more than 3 tiers has become more widespread. A service-oriented architecture (SOA) or the [microservices](http://en.wikipedia.org/wiki/Microservices) architecture is now a reality. + +The system's complexity has consequently increased. The more complex it is, the more difficult you solve problems such as system failure or performance issues. For example, Finding solutions in a 3-tier system is far less complicated. You only need to analyze 3 main components; a web server, an application server, and a database where the number of servers is small. While, if a problem occurs in an n-tier architecture, a large number of components and servers should be investigated. Another problem is that it is difficult to see the big picture only with an analysis of individual components; a low visibility issue is raised. The higher the degree of system complexity is, the longer it takes time to find out the reasons. Even worse, probability increases in which we may not even find them at all. + +Such problems have occurred in the systems at NAVER. A variety of tools like Application Performance Management (APM) were used but they were not enough to handle the problems effectively; so we finally ended up developing a new tracing platform for n-tier architecture, which can provide solutions to systems with an n-tier architecture. + +Pinpoint, began development in July 2012 and was launched as an open-source project in January 2015, is an n-tier architecture tracing platform for large-scale distributed systems. The characteristics of Pinpoint are as follows: +* Distributed transaction tracing to trace messages across distributed applications +* Automatically detecting the application topology that helps you to figure out the configurations of an application +* Horizontal scalability to support large-scale server group +* Providing code-level visibility to easily identify points of failure and bottlenecks +* Adding a new functionality without code modifications, using the bytecode instrumentation technique diff --git a/doc/http-status-code-failure.md b/doc/http-status-code-failure.md index 161e00df2939..e40d69746129 100644 --- a/doc/http-status-code-failure.md +++ b/doc/http-status-code-failure.md @@ -1,6 +1,15 @@ +--- +title: Marking Transaction as Fail +keywords: http, code fail, failure, http status +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: httpstatuscodefailure.html +disqus: false +--- + # HTTP Status Code with Request Failure. -![overview](img/http-status-code-failure-overview.png) +![overview](images/http-status-code-failure-overview.png) ## Pinpoint Configuration diff --git a/doc/img/alarm/alarm_figure01.gif b/doc/images/alarm/alarm_figure01.gif similarity index 100% rename from doc/img/alarm/alarm_figure01.gif rename to doc/images/alarm/alarm_figure01.gif diff --git a/doc/img/alarm/alarm_figure02.gif b/doc/images/alarm/alarm_figure02.gif similarity index 100% rename from doc/img/alarm/alarm_figure02.gif rename to doc/images/alarm/alarm_figure02.gif diff --git a/doc/img/alarm/alarm_figure03.gif b/doc/images/alarm/alarm_figure03.gif similarity index 100% rename from doc/img/alarm/alarm_figure03.gif rename to doc/images/alarm/alarm_figure03.gif diff --git a/doc/img/alarm/alarm_figure04.gif b/doc/images/alarm/alarm_figure04.gif similarity index 100% rename from doc/img/alarm/alarm_figure04.gif rename to doc/images/alarm/alarm_figure04.gif diff --git a/doc/img/alarm/alarm_figure05.gif b/doc/images/alarm/alarm_figure05.gif similarity index 100% rename from doc/img/alarm/alarm_figure05.gif rename to doc/images/alarm/alarm_figure05.gif diff --git a/doc/img/applicationInspector/execute_flow.jpg b/doc/images/applicationInspector/execute_flow.jpg similarity index 100% rename from doc/img/applicationInspector/execute_flow.jpg rename to doc/images/applicationInspector/execute_flow.jpg diff --git a/doc/img/applicationInspector/graph.jpg b/doc/images/applicationInspector/graph.jpg similarity index 100% rename from doc/img/applicationInspector/graph.jpg rename to doc/images/applicationInspector/graph.jpg diff --git a/doc/img/applicationInspector/inspector_view.jpg b/doc/images/applicationInspector/inspector_view.jpg similarity index 100% rename from doc/img/applicationInspector/inspector_view.jpg rename to doc/images/applicationInspector/inspector_view.jpg diff --git a/doc/img/http-status-code-failure-overview.png b/doc/images/http-status-code-failure-overview.png similarity index 100% rename from doc/img/http-status-code-failure-overview.png rename to doc/images/http-status-code-failure-overview.png diff --git a/doc/img/per-request_feature_1.jpg b/doc/images/per-request_feature_1.jpg similarity index 100% rename from doc/img/per-request_feature_1.jpg rename to doc/images/per-request_feature_1.jpg diff --git a/doc/img/per-request_feature_2.jpg b/doc/images/per-request_feature_2.jpg similarity index 100% rename from doc/img/per-request_feature_2.jpg rename to doc/images/per-request_feature_2.jpg diff --git a/doc/img/pinpoint-architecture.png b/doc/images/pinpoint-architecture.png similarity index 100% rename from doc/img/pinpoint-architecture.png rename to doc/images/pinpoint-architecture.png diff --git a/doc/img/proxy-http-header-overview.png b/doc/images/proxy-http-header-overview.png similarity index 100% rename from doc/img/proxy-http-header-overview.png rename to doc/images/proxy-http-header-overview.png diff --git a/doc/img/ss_call-stack.png b/doc/images/ss_call-stack.png similarity index 100% rename from doc/img/ss_call-stack.png rename to doc/images/ss_call-stack.png diff --git a/doc/img/ss_inspector.png b/doc/images/ss_inspector.png similarity index 100% rename from doc/img/ss_inspector.png rename to doc/images/ss_inspector.png diff --git a/doc/img/ss_quickstart-collector-log.png b/doc/images/ss_quickstart-collector-log.png similarity index 100% rename from doc/img/ss_quickstart-collector-log.png rename to doc/images/ss_quickstart-collector-log.png diff --git a/doc/img/ss_quickstart-testapp-log.png b/doc/images/ss_quickstart-testapp-log.png similarity index 100% rename from doc/img/ss_quickstart-testapp-log.png rename to doc/images/ss_quickstart-testapp-log.png diff --git a/doc/img/ss_quickstart-web-log.png b/doc/images/ss_quickstart-web-log.png similarity index 100% rename from doc/img/ss_quickstart-web-log.png rename to doc/images/ss_quickstart-web-log.png diff --git a/doc/img/ss_server-map.png b/doc/images/ss_server-map.png similarity index 100% rename from doc/img/ss_server-map.png rename to doc/images/ss_server-map.png diff --git a/doc/img/td_figure1.png b/doc/images/td_figure1.png similarity index 100% rename from doc/img/td_figure1.png rename to doc/images/td_figure1.png diff --git a/doc/img/td_figure2.png b/doc/images/td_figure2.png similarity index 100% rename from doc/img/td_figure2.png rename to doc/images/td_figure2.png diff --git a/doc/img/td_figure3.png b/doc/images/td_figure3.png similarity index 100% rename from doc/img/td_figure3.png rename to doc/images/td_figure3.png diff --git a/doc/img/td_figure4.png b/doc/images/td_figure4.png similarity index 100% rename from doc/img/td_figure4.png rename to doc/images/td_figure4.png diff --git a/doc/img/td_figure5.png b/doc/images/td_figure5.png similarity index 100% rename from doc/img/td_figure5.png rename to doc/images/td_figure5.png diff --git a/doc/img/td_figure6.png b/doc/images/td_figure6.png similarity index 100% rename from doc/img/td_figure6.png rename to doc/images/td_figure6.png diff --git a/doc/images/ui.png b/doc/images/ui.png new file mode 100644 index 000000000000..8c1364a480a9 Binary files /dev/null and b/doc/images/ui.png differ diff --git a/doc/installation.md b/doc/installation.md index a32ea9c772cb..3c355aa51347 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -1,105 +1,103 @@ -# Installation -In order to set up your very own Pinpoint instance, you need to run these components: +--- +title: Installation +keywords: pinpoint, pinpoint homepage, install, start, installation +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: installation.html +disqus: false +--- + +To set up your very own Pinpoint instance you can either **download the build results** from our [**latest release**](https://github.com/naver/pinpoint/releases/latest), or manually build from your Git clone. +In order to run your own Pinpoint instance, you will need to run below components: * **HBase** (for storage) * **Pinpoint Collector** (deployed on a web container) * **Pinpoint Web** (deployed on a web container) * **Pinpoint Agent** (attached to a java application for profiling) -To try out a simple quickstart project, please refer to the [quick-start guide](../quickstart/README.md). +To try out a simple quickstart project, please refer to the [quick-start guide](./quickstart.html). -## Quick Overview -1. HBase ([details](#hbase)) +## Quick Overview of Installation +1. HBase ([details](#1-hbase)) 1. Set up HBase cluster - [Apache HBase](http://hbase.apache.org) 2. Create HBase Schemas - feed `/scripts/hbase-create.hbase` to hbase shell. -2. Build Pinpoint (Optional) - You do not need to build from source to use Pinpoint (binaries [here](https://github.com/naver/pinpoint/releases)). +2. Build Pinpoint (Optional)([details](#2-building-pinpoint-optional)) - No need if you use the binaries.([here](https://github.com/naver/pinpoint/releases)). 1. Clone Pinpoint - `git clone $PINPOINT_GIT_REPOSITORY` - 2. Set JAVA_HOME environment variable to JDK 7+ home directory. + 2. Set JAVA_HOME environment variable to JDK 8 home directory. 3. Set JAVA_6_HOME environment variable to JDK 6 home directory (1.6.0_45 recommended). 4. Set JAVA_7_HOME environment variable to JDK 7 home directory (1.7.0_80 recommended). 5. Set JAVA_8_HOME environment variable to JDK 8 home directory. - 6. Run `./mvnw clean install -Dmaven.test.skip=true` (or `./mvnw.cmd` for Windows) -3. Pinpoint Collector ([details](#pinpoint-collector)) + 6. Set JAVA_9_HOME environment variable to JDK 9 home directory. + 7. Run `./mvnw clean install -DskipTests=true` (or `./mvnw.cmd` for Windows) +3. Pinpoint Collector ([details](#3-pinpoint-collector)) 1. Deploy *pinpoint-collector-$VERSION.war* to a web container. 2. Configure *pinpoint-collector.properties*, *hbase.properties*. 3. Start container. -4. Pinpoint Web ([details](#pinpoint-web)) +4. Pinpoint Web ([details](#4-pinpoint-web)) 1. Deploy *pinpoint-web-$VERSION.war* to a web container as a ROOT application. 2. Configure *pinpoint-web.properties*, *hbase.properties*. 3. Start container. -5. Pinpoint Agent ([details](#pinpoint-agent)) +5. Pinpoint Agent ([details](#5-pinpoint-agent)) 1. Extract/move *pinpoint-agent/* to a convenient location (`$AGENT_PATH`). 2. Set `-javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar` JVM argument to attach the agent to a java application. 3. Set `-Dpinpoint.agentId` and `-Dpinpoint.applicationName` command-line arguments. 4. Launch java application with the options above. -## HBase +## 1. HBase Pinpoint uses HBase as its storage backend for the Collector and the Web. To set up your own cluster, take a look at the [HBase website](http://hbase.apache.org) for instructions. The HBase compatibility table is given below: -Pinpoint Version | HBase 0.94.x | HBase 0.98.x | HBase 1.0.x | HBase 1.1.x | HBase 1.2.x ----------------- | ------------ | ------------ | ----------- | ----------- | ----------- -1.0.x | yes | no | no | no | no -1.1.x | no | not tested | yes | not tested | not tested -1.5.x | no | not tested | yes | not tested | not tested -1.6.x | no | not tested | not tested | not tested | yes -1.7.x | no | not tested | not tested | not tested | yes +{% include_relative compatibilityHbase.md %} Once you have HBase up and running, make sure the Collector and the Web are configured properly and are able to connect to HBase. -### Creating Schemas -There are 2 scripts available to create tables for Pinpoint: *hbase-create.hbase*, and *hbase-create-snappy.hbase*. Use *hbase-create-snappy.hbase* for snappy compression (requires [snappy](http://code.google.com/p/snappy)), otherwise use *hbase-create.hbase* instead. +### Creating Schemas for HBase +There are 2 scripts available to create tables for Pinpoint: *hbase-create.hbase*, and *hbase-create-snappy.hbase*. Use *hbase-create-snappy.hbase* for snappy compression (requires [snappy](http://google.github.io/snappy/)), otherwise use *hbase-create.hbase* instead. To run these scripts, feed them into the HBase shell like below: `$HBASE_HOME/bin/hbase shell hbase-create.hbase` -See [here](../hbase/scripts/ "Pinpoint HBase scripts") for a complete list of scripts. +See [here](https://github.com/naver/pinpoint/tree/master/hbase/scripts "Pinpoint HBase scripts") for a complete list of scripts. -## Building Pinpoint +## 2. Building Pinpoint (Optional) There are two options: -1. Download the build results from our [**latest release**](https://github.com/naver/pinpoint/releases/latest) and skip the building. **Recommended.** +1. Download the build results from our [**latest release**](https://github.com/naver/pinpoint/releases/latest) and skip building process.**(Recommended)** 2. Build Pinpoint manually from the Git clone. In order to do so, the following **requirements** must be met: - * JDK 6 installed - * JDK 7 installed - * JDK 8 installed - * JAVA_HOME environment variable set to JDK 7+ home directory. - * JAVA_6_HOME environment variable set to JDK 6 home directory (1.6.0_45 recommended). - * JAVA_7_HOME environment variable set to JDK 7 home directory (1.7.0_80 recommended). + * JDK 6 installed ([jdk1.6.0_45](http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-419409.html#jdk-6u45-oth-JPR) recommended) + * JDK 7 installed ([jdk1.7.0_80](http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html#jdk-7u80-oth-JPR) recommended) + * JDK 8 installed + * JDK 9 installed + * JAVA_HOME environment variable set to JDK 8 home directory. + * JAVA_6_HOME environment variable set to JDK 6 home directory. + * JAVA_7_HOME environment variable set to JDK 7 home directory. * JAVA_8_HOME environment variable set to JDK 8 home directory. - - JDK 7+ and JAVA_7_HOME, JAVA_8_HOME environment variable are required to build **profiler-optional**. For more information about the optional package, please take a look [here](../profiler-optional/README.md). + * JAVA_9_HOME environment variable set to JDK 9 home directory. Additionally, the required Java version to run each Pinpoint component is given below: - Pinpoint Version | Agent | Collector | Web - ---------------- | ----- | --------- | --- - 1.0.x | 6-8 | 6+ | 6+ - 1.1.x | 6-8 | 7+ | 7+ - 1.5.x | 6-8 | 7+ | 7+ - 1.6.x | 6-8 | 7+ | 7+ - 1.7.x | 6-8 | 8+ | 8+ - + {% include_relative compatibilityPinpoint.md %} + Once the above requirements are met, simply run the command below (you may need to add permission for **mvnw** so that it can be executed) : - `./mvnw install -Dmaven.test.skip=true` + `./mvnw install -DskipTests=true` The default agent built this way will have log level set to DEBUG by default. If you're building an agent for release and need a higher log level, you can set maven profile to *release* when building : - `./mvnw install -Prelease -Dmaven.test.skip=true` + `./mvnw install -Prelease -DskipTests=true` The guide will refer to the full path of the pinpoint home directory as `$PINPOINT_PATH`. Regardless of your method, you should end up with the files and directories mentioned in the following sections. -## Pinpoint Collector +## 3. Pinpoint Collector You should have the following **war** file that can be deployed to a web container. *pinpoint-collector-$VERSION.war* @@ -122,20 +120,24 @@ There are 2 configuration files available for Pinpoint Collector: *pinpoint-coll These files are located under `WEB-INF/classes/` inside the war file. -You may take a look at the default configuration files here: [pinpoint-collector.properties](../collector/src/main/resources/pinpoint-collector.properties), [hbase.properties](../collector/src/main/resources/hbase.properties) +You may take a look at the default configuration files here: [pinpoint-collector.properties](https://github.com/naver/pinpoint/blob/master/collector/src/main/resources/pinpoint-collector.properties), [hbase.properties](https://github.com/naver/pinpoint/blob/master/collector/src/main/resources/hbase.properties) -## Pinpoint Web +## 4. Pinpoint Web You should have the following **war** file that can be deployed to a web container. *pinpoint-web-$VERSION.war* The path to this file should look like *$PINPOINT_PATH/web/target/pinpoint-web-$VERSION.war* if you built it manually. +Pinpoint Web Supported Browsers: + +* Chrome + ### Installation Since Pinpoint Web is packaged as a deployable war file, you may deploy them to a web container as you would any other web applications. The web module must also be deployed as a ROOT application. ### Configuration -Similar to the collector, Pinpoint Web has configuration files related to installation: *pinpoint-web.properties*, and *hbase.properties*. +Similar to the Collector, Pinpoint Web has configuration files related to installation: *pinpoint-web.properties*, and *hbase.properties*. Make sure you check the following configuration options : @@ -145,9 +147,9 @@ Make sure you check the following configuration options : These files are located under `WEB-INF/classes/` inside the war file. -You may take a look at the default configuration files here: [pinpoint-web.properties](../web/src/main/resources/pinpoint-web.properties), [hbase.properties](../web/src/main/resources/hbase.properties) +You may take a look at the default configuration files here: [pinpoint-web.properties](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/pinpoint-web.properties), [hbase.properties](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/hbase.properties) -## Pinpoint Agent +## 5. Pinpoint Agent If downloaded, unzip the Pinpoint Agent file. You should have a **pinpoint-agent** directory with the layout below : ``` @@ -177,6 +179,10 @@ You may move/extract the contents of **pinpoint-agent** directory to any locatio > Note that you may change the agent's log level by modifying the *log4j.xml* located in the *lib* directory above. +Agent compatibility to Collector table: + +{% include_relative compatibilityJava.md %} + ### Installation Pinpoint Agent runs as a java agent attached to an application to be profiled (such as Tomcat). @@ -212,7 +218,7 @@ Some application servers require additional configuration and/or may have caveat There are various configuration options for Pinpoint Agent available in *$AGENT_PATH/pinpoint.config*. -Most of these options are self explanatory, but the most important configuration options you must check are **collector ip address**, and the **TCP/UDP ports**. These values are required for the agent to establish connection to the *Collector* and function correctly. +Most of these options are self explanatory, but the most important configuration options you must check are **Collector ip address**, and the **TCP/UDP ports**. These values are required for the agent to establish connection to the *Collector* and function correctly. Set these values appropriately in *pinpoint.config*: @@ -221,13 +227,13 @@ Set these values appropriately in *pinpoint.config*: * `profiler.collector.stat.port` (collector's *collector.udpStatListenPort* - default: 9995) * `profiler.collector.span.port` (collector's *collector.udpSpanListenPort* - default: 9996) -You may take a look at the default *pinpoint.config* file [here](../agent/src/main/resources/pinpoint.config "pinpoint.config") along with all the available configuration options. +You may take a look at the default *pinpoint.config* file [here](https://github.com/naver/pinpoint/blob/master/agent/src/main/resources/pinpoint-real-env-lowoverhead-sample.config "pinpoint.config") along with all the available configuration options. ## Miscellaneous -### Routing web requests to agents +### Routing Web requests to Agents -Starting from 1.5.0, Pinpoint can send requests from the web to agents directly via the collector (and vice-versa). To make this possible, we use Zookeeper to co-ordinate the communication channels established between agents and collectors, and those between collectors and web instances. With this addition, real-time communication (for things like active thread count monitoring) is now possible. +Starting from 1.5.0, Pinpoint can send requests from the Web to Agents directly via the Collector (and vice-versa). To make this possible, we use Zookeeper to co-ordinate the communication channels established between Agents and Collectors, and those between Collectors and Web instances. With this addition, real-time communication (for things like active thread count monitoring) is now possible. We typically use the Zookeeper instance provided by the HBase backend so no additional Zookeeper configuration is required. Related configuration options are shown below. @@ -244,3 +250,4 @@ We typically use the Zookeeper instance provided by the HBase backend so no addi * `cluster.zookeeper.sessiontimeout` * `cluster.zookeeper.retry.interval` * `cluster.connect.address` + diff --git a/doc/main.md b/doc/main.md new file mode 100755 index 000000000000..5475eafa33fd --- /dev/null +++ b/doc/main.md @@ -0,0 +1,62 @@ +--- +title: "Pinpoint 1.8.1" +keywords: pinpoint release, 1.8.1 +permalink: main.html +sidebar: mydoc_sidebar +--- + +[Check out updates on lastest stable release](https://naver.github.io/pinpoint/1.8.0/main.html) + +## What's Next in 1.8.1? + + +### Pinpoint Plugin + +- Started to support MongoDB + +### Pinpoint Agent + + +### Pinpoint Collector + + +### Pinpoint Web + + +### Pinpoint Flink + + + +### Upgrade consideration + +HBase compatibility table: + +{% include_relative compatibilityHbase.md %} + +Agent compatibility to Collector table: + +{% include_relative compatibilityPinpoint.md %} + +Agent compatibility to Collector table: + +{% include_relative compatibilityJava.md %} + +### Full List of Supported Modules + +* JDK 6+ +* Tomcat 6/7/8, [Jetty 8/9](https://github.com/naver/pinpoint/tree/master/plugins/jetty), [JBoss EAP 6](https://github.com/naver/pinpoint/tree/master/plugins/jboss), +[Resin 4](https://github.com/naver/pinpoint/tree/master/plugins/resin), [Websphere 6/7/8](https://github.com/naver/pinpoint/tree/master/plugins/websphere), +WebLogic +- asynchronous communication supported +* [Vertx 3.3/3.4/3.5](https://github.com/naver/pinpoint/tree/master/plugins/vertx), Undertow +* Spring, Spring Boot (Embedded Tomcat, Jetty), Spring asynchronous communication +* Apache HTTP Client 3.x/4.x, JDK HttpConnector, GoogleHttpClient, OkHttpClient, NingAsyncHttpClient, Akka-http +* Thrift Client, Thrift Service, DUBBO PROVIDER, DUBBO CONSUMER, Kafka +* ActiveMQ, RabbitMQ +* MySQL, Oracle, MSSQL, CUBRID,POSTGRESQL, MARIA +* Arcus, Memcached, Redis, CASSANDRA +* iBATIS, MyBatis +* DBCP, DBCP2, HIKARICP +* gson, Jackson, Json Lib +* log4j, Logback + diff --git a/doc/overview.md b/doc/overview.md new file mode 100755 index 000000000000..6c8bb14b7a9b --- /dev/null +++ b/doc/overview.md @@ -0,0 +1,30 @@ +--- +title: Overview +keywords: overview, architecture +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: overview.html +disqus: false +--- + + +## Overview +Services nowadays often consist of many different components, communicating amongst themselves as well as making API calls to external services. How each and every transaction gets executed is often left as a blackbox. Pinpoint traces transaction flows between these components and provides a clear view to identify problem areas and potential bottlenecks.
+ + +* **ServerMap** - Understand the topology of any distributed systems by visualizing how their components are interconnected. Clicking on a node reveals details about the component, such as its current status, and transaction count. +* **Realtime Active Thread Chart** - Monitor active threads inside applications in real-time. +* **Request/Response Scatter Chart** - Visualize request count and response patterns over time to identify potential problems. Transactions can be selected for additional detail by **dragging over the chart**. + + ![Server Map](images/ss_server-map.png) + +* **CallStack** - Gain code-level visibility to every transaction in a distributed environment, identifying bottlenecks and points of failure in a single view. + + ![Call Stack](images/ss_call-stack.png) + +* **Inspector** - View additional details on the application such as CPU usage, Memory/Garbage Collection, TPS, and JVM arguments. + + ![Inspector](images/ss_inspector.png) + +## Architecture +![Pinpoint Architecture](images/pinpoint-architecture.png) diff --git a/doc/per-request_feature_guide.md b/doc/per-request_feature_guide.md index 701deb704f62..6731d35e4d45 100644 --- a/doc/per-request_feature_guide.md +++ b/doc/per-request_feature_guide.md @@ -1,3 +1,12 @@ +--- +title: Separate Logging Per Request +keywords: history +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: perrequestfeatureguide.html +disqus: false +--- + # ENGLISH GUIDE ## Per-request logging @@ -106,7 +115,7 @@ ex) With Pinpoint ``` The transactionId printed in the log message is the same as the transactionId in Pinpoint Web’s Transaction List view. -![per-request_feature_1.jpg](img/per-request_feature_1.jpg) +![per-request_feature_1.jpg](images/per-request_feature_1.jpg) ### 2. How to configure @@ -258,7 +267,7 @@ public class AppenderInterceptor implements AroundInterceptor0 { ``` If those are correctly configured, the buttons are added in the transaction list view. -![per-request_feature_2.jpg](img/per-request_feature_2.jpg) +![per-request_feature_2.jpg](images/per-request_feature_2.jpg) For details in how the log buttons are generated, please refer to Pinpoint Web’s BusinessTransactionController and ScatterChartController. @@ -270,18 +279,18 @@ For details in how the log buttons are generated, please refer to Pinpoint Web ### 1. 기능 설명 -Pinpoint에서는 log message를 request 단위로 구분할 수 있도록 log message 에 추가정보를 저장 해준다. +Pinpoint에서는 log message를 request 단위로 구분할 수 있도록 log message 에 추가정보를 저장해준다. 다수의 요청을 처리하는 tomcat을 사용할 경우 로그 파일을 보면 시간순으로 출력된 로그를 확인할 수 있다. 그러나 동시에 요청된 다수의 request 각각에 대한 로그를 구분 해서 볼 수 없다. -예를 들어 로그에서 exception message가 출력됐을때 그 exception이 발생한 request의 모든 log를 확인 하기 힘들다. +예를 들어 로그에서 exception message가 출력됐을 때 그 exception이 발생한 request의 모든 log를 확인하기 힘들다. -Pinpoint는 로그 메세지 마다 request와 연관된 정보(transactionId, spanId)를 MDC에 넣어줘서 request 단위로 log message를 구분할 수 있도록 해준다. -로그에 출력된 transactionId는 pinpoint web의 transaction List 화면에 출려된 transactionId와 일치한다. +Pinpoint는 log message 마다 request와 연관된 정보(transactionId, spanId)를 MDC에 넣어줘서 request 단위로 log message를 구분할 수 있도록 해준다. +로그에 출력된 transactionId는 pinpoint web의 transaction List 화면에 출력된 transactionId와 일치한다. 구체적으로 예를 들어보자. -Pinpoint를 사용하지 않았을때 exception이 발생했을 경우 로그 메시지를 살펴 보자. -요청된 다수의 request 각각을 구분하여 로그를 확인 할 수가 없다. +Pinpoint를 사용하지 않았을 때 exception이 발생했을 경우 로그 메시지를 살펴 보자. +요청된 다수의 request 각각을 구분하여 로그를 확인할 수가 없다. ex) Without Pinpoint ``` @@ -376,13 +385,13 @@ ex) With Pinpoint ``` 로그메시지에 출력된 transactionId는 Pinpoint web의 transactionlist의 transactionId와 일치한다. -![per-request_feature_1.jpg](img/per-request_feature_1.jpg) +![per-request_feature_1.jpg](images/per-request_feature_1.jpg) ### 2. 설정 방법 **2-1 Pinpoint agent 설정** -Pinpoint를 사용하려면 Pinpoint agent 설정파일(Pinpoint.config)의 logging 설정 값을 true로 변경해야한다. +Pinpoint를 사용하려면 Pinpoint agent 설정파일(Pinpoint.config)의 logging 설정 값을 true로 변경해야 한다. 사용하는 logging 라이브러리에 해당하는 설정값만 true로 변경하면 된다. 아래 설정에 대한 예시가 있다. @@ -499,7 +508,7 @@ log.button.name=log **step 3** pinpoint 1.5 이후 버전부터 log 기록 여부에 따라 log 버튼의 활성화가 결정되도록 개선 됐기 때문에 당신이 사용하는 logging appender의 로깅 메소드에 logging 여부를 저장하는 interceptor를 추가하는 플러그인을 개발해야 한다. -플러그인 개발 방법은 다음 링크를 참고하면 된다([Link](https://github.com/naver/pinpoint-plugin-sample)). interceptor 로직이 추가되야 하는 위치는 appender class 내에 LoggingEvent 객체의 데이터를 이용하여 로깅을 하는 메소드다. +플러그인 개발 방법은 다음 링크를 참고하면 된다([Link](https://github.com/naver/pinpoint-plugin-sample)). interceptor 로직이 추가돼야 하는 위치는 appender class 내에 LoggingEvent 객체의 데이터를 이용하여 로깅을 하는 메소드다. 아래는 interceptor 예제이다. ``` public class AppenderInterceptor implements AroundInterceptor0 { @@ -530,5 +539,5 @@ public class AppenderInterceptor implements AroundInterceptor0 { 위와 같이 설정 및 구현을 추가하고 pinpoint web을 동작시키면 아래와 같이 버튼이 추가 된다. -![per-request_feature_2.jpg](img/per-request_feature_2.jpg) +![per-request_feature_2.jpg](images/per-request_feature_2.jpg) 로그 버튼을 생성해주는 과정을 보시려면, Pinpoint Web의 BusinessTransactionController 와 ScatterChartController class를 참고하세요. diff --git a/doc/pinpoint-in-action.md b/doc/pinpoint-in-action.md new file mode 100755 index 000000000000..c273fcc44375 --- /dev/null +++ b/doc/pinpoint-in-action.md @@ -0,0 +1,22 @@ +--- +title: Powered by Pinpoint +keywords: pinpoint, used, working, use, inuse +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: pinpointinaction.html +disqus: false +--- + +Pinpoint is used globally. Currently top 3 countries using Pinpoint are China, Korea, USA. + +## Sites using Pinpoint + +* XLGAMES (http://www.xlgames.com) +* NAVER (www.naver.com) +* NHN Entertainment +* Coupang (www.coupang.com) +* SKPlanet(www.skplanet.com) +* Pikicast (www.pikicast.com) +* ... and much more companies + +If you want(or don't want) your company's title to be added in the list, feel free to contact us anytime. \ No newline at end of file diff --git a/doc/plugin-dev-guide.md b/doc/plugin-dev-guide.md new file mode 100755 index 000000000000..bc7223cdfa2e --- /dev/null +++ b/doc/plugin-dev-guide.md @@ -0,0 +1,271 @@ +--- +title: Plugin Developer Guide +keywords: plugin, plug-in, plug +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: plugindevguide.html +disqus: false +--- + +You can write Pinpoint profiler plugins to extend profiling target coverage. It is highly advisable to look into the trace data recorded by pinpoint plugins before jumping into plugin development. + + * There is a [fast auto pinpoint agent plugin generate tool](https://github.com/bbossgroups/pinpoint-plugin-generate) from a 3rd party for creating a simple plug-in, if you'd like to check out. + +## I. Trace Data +In Pinpoint, a transaction consists of a group of `Spans`. Each `Span` represents a trace of a single logical node where the transaction had gone through. + +To aid in visualization, let's suppose that there is a system like below. The *FrontEnd* server receives requests from users, then sends request to the *BackEnd* server, which queries a DB. Among these nodes, let's assume only the *FrontEnd* and *BackEnd* servers are profiled by the Pinpoint Agent. + +![trace](https://cloud.githubusercontent.com/assets/8037461/13870778/0073df06-ed22-11e5-97a3-ebe116186947.jpg) + + +When a request arrives at the *FrontEnd* server, Pinpoint Agent generates a new transaction id and creates a `Span` with it. To handle the request, the *FrontEnd* server then invokes the *BackEnd* server. At this point, Pinpoint Agent injects the transaction id (plus a few other values for propagation) into the invocation message. When the *BackEnd* server receives this message, it extracts the transaction id (and the other values) from the message and creates a new `Span` with them. Resulting, all `Spans` in a single transaction share the same transaction id. + +A `Span` records important method invocations and their related data(arguments, return value, etc) before encapsulating them as `SpanEvents` in a call stack like representation. The `Span` itself and each of its `SpanEvents` represents a method invocation. + +`Span` and `SpanEvent` have many fields, but most of them are handled internally by Pinpoint Agent and most plugin developers doesn't need to concern about them. But For the fields, and information that must be handled by the plugin developers is as follow. + + +## II. Pinpoint Plugin Structure +Pinpoint plugin consists of `TraceMetadataProvider` and `ProfilerPlugin` implementations. `TraceMetadataProvider` implementation provides `ServiceType` and `AnnotationKey` to Pinpoint Agent, Web and Collector. `ProfilerPlugin` implementations are used by Pinpoint Agent to transform target classes to record trace data. + +Plugins are deployed as jar files. Pinpoint Agent searches `TraceMetadataProvider` and `ProfilerPlugin` implementations using `ServiceLoader` from the `plugin` directory, while Web and Collector look into `WEB-INF/lib` directory. `ServiceLoader` requires provider configuration file located in `META-INF/services`, so you must put the following files in the plugin jar file. + +* META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin +* META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider + +Here is a [template plugin project](https://github.com/naver/pinpoint-plugin-template). You can start creating your own plugin withgae0 this template. + + +### 1. TraceMetadataProvider +`TraceMetadataProvider` implementations provide `ServiceTypes` and `AnnotationKeys`. + +#### 1.1 ServiceType + +Every `Span` and `SpanEvent` contains a `ServiceType`. The `ServiceType` represents which library the traced method belongs to, as well as how the `Span` and `SpanEvent` should be handled. + +Below table shows `ServiceType`'s properties. + +property | description +--- | --- +name | name of the `ServiceType`. Must be unique +code | short type code value of the `ServiceType`. Must be unique +desc | description +properties | properties + +The `ServiceType` code must use a value from its appropriate category. Below table shows the categories and the ranges. + +category | range +--- | --- +Internal Use | 0 ~ 999 +Server | 1000 ~ 1999 +DB Client | 2000 ~ 2999 +Cache Client | 8000 ~ 8999 +RPC Client | 9000 ~ 9999 +Others | 5000 ~ 7999 + + +`ServiceType` code must be unique. Therefore, if you are writing a plugin that will be shared publicly, **you must** contact the Pinpoint dev. team to get a `ServiceType` code assigned. If your plugin is for private use, you may freely pick a value for `ServiceType` code from the table below. + +category | range +--- | --- +Server | 1900 ~ 1999 +DB client | 2900 ~ 2999 +Cache client | 8900 ~ 8999 +RPC client | 9900 ~ 9999 +Others | 7500 ~ 7999 + + +`ServiceTypes` can have the following properties. + +property | description +--- | --- +TERMINAL | This `Span` or `SpanEvent` invokes a remote node but the target node is not traceable with Pinpoint +INCLUDE_DESTINATION_ID | This `Span` or `SpanEvent` records a `destination id` and remote server is not a traceable type. +RECORD_STATISTICS | Pinpoint Collector should collect execution time statistics of this `Span` or `SpanEvent` + + +#### 1.2 AnnotationKey +You can annotate Spans or SpanEvents with more information. An `Annotation` is a key-value pair where the key is an `AnnotationKey` type and the value is a primitive type, String or a byte[]. There are pre-defined `AnnotationKeys` for commonly used annotation types, but you can define your own keys in `TraceMetadataProvider` if these are not enough. + + +property | description +--- | --- +name | Name of the `AnnotationKey` +code | int type code value of the `AnnotationKey`. Must be unique. +properties | properties + +If your public plugin is going to add a new `AnnotationKey`, you must contact the Pinpoint dev. team to get an `AnnotationKey` code assigned. If your plugin is for private use, you may pick a value between 900 to 999 safely to use as `AnnotationKey` code. + +The table below shows the `AnnotationKey` properties. + +property | description +--- | --- +VIEW_IN_RECORD_SET | Show this annotation in transaction call tree. +ERROR_API_METADATA | This property is not for plugins. + + +#### Example +You can find `TraceMetadataProvider` sample [here](https://github.com/naver/pinpoint-plugin-sample/blob/master/plugin/src/main/java/com/navercorp/pinpoint/plugin/sample/SampleTraceMetadataProvider.java). + +You may also pass `AnnotationKeyMatcher` with the `ServiceType` (`TraceMetadata.addServiceType(ServiceType, AnnotationKeyMatcher`) in the sample code). If you pass an `AnnotationKeyMatcher` this way, matching annotations will be displayed as representative annotation when the `ServiceType`'s `Span` or `SpanEvent` is displayed in the transaction call tree. + + + +### 2. ProfilerPlugin +`ProfilerPlugin` modifies target library classes to collect trace data. + +`ProfilerPlugin` works in the order of following steps: + +1. Pinpoint Agent is started when the JVM starts. +2. Pinpoint Agent loads all plugins under `plugin` directory. +3. Pinpoint Agent invokes `ProfilerPlugin.setup(ProfilerPluginSetupContext)` for each loaded plugin. +4. In the `setup` method, the plugin defines classes that should be transformed and registers a `TransformerCallback`. +5. Target application start. +6. Every time a class is loaded, Pinpoint Agent looks up for the `TransformerCallback` registered for the class. +7. If a `TransformerCallback` is registered, the Agent invokes its `doInTransform` method. +8. `TransformerCallback` modifies the target class' byte code. (e.g. add interceptors, add fields, etc.) +9. The modified byte code is returned to the JVM, and the class is loaded with the returned byte code. +10. Application continues running. +11. When a modified method is invoked, the injected interceptor's `before` and `after` methods are invoked. +12. The interceptor records the trace data. + +The most important points of consideration boils down to i) figuring out which methods are interesting enough to warrant tracing. ii) injecting interceptors to actually trace these methods. +These interceptors are used to extract, store and pass trace data around before they are sent off to the Collector. Interceptors may even cooperate with each other, sharing context between them. Plugins may also aid in tracing by adding getters or even custom fields to the target class so that the interceptors may access them during execution. [Pinpoint plugin sample](https://github.com/naver/pinpoint-plugin-sample) shows you how the `TransformerCallback` modifies classes and what the injected interceptors do to trace methods. + +We will now describe what interceptors must do to trace different kinds of methods. + +#### 2.1 Plain method +*Plain method* refers to anything that is not a top-level method of a node, or is not related to remote or asynchronous invocation. [Sample 2](https://github.com/naver/pinpoint-plugin-sample/tree/master/plugin/src/main/java/com/navercorp/pinpoint/plugin/sample/_02_Injecting_Custom_Interceptor) shows you how to trace these plain methods. + +#### 2.2 Top level method of a node +*Top level method of a node* is a method in which its interceptor begins a new trace in a node. These methods are typically acceptors for RPCs, and the trace is recorded as a `Span` with `ServiceType` categorized as a server. + +How the `Span` is recorded depends on whether the transaction has already begun at any previous nodes. + +##### 2.2.1 New transaction +If the current node is the first one that is recording the transaction, you must issue a new transaction id and record it. `TraceContext.newTraceObject()` will handle this task automatically, so you will simply need to invoke it. + +##### 2.2.2 Continue Transaction +If the request came from another node traced by a Pinpoint Agent, then the transaction will already have a transaction id issued; and you will have to record the data below to the `Span`. (Most of these data are sent from the previous node, usually packed in the request message) + +name | description +--- | --- +transactionId | Transaction ID +parentSpanId | Span ID of the previous node +parentApplicationName | Application name of the previous node +parentApplicationType | Application type of the previous node +rpc | Procedure name (Optional) +endPoint | Server(current node) address +remoteAddr | Client address +acceptorHost | Server address that the client used + +Pinpoint finds caller-callee relation between nodes using *acceptorHost*. In most cases, *acceptorHost* is identical to *endPoint*. However, the address which client sent the request to, may sometimes be different from the address the server received the request (proxy). To handle such cases, you have to record the actual address the client used to send the request to as *acceptorHost*. Normally, the client plugin will have added this address into the request message along with the transaction data. + +Moreover, you must also use the span id issued and sent by the previous node. + +Sometimes, the previous node marks the transaction not to be traced. In this case, you must not trace the transaction. + +As you can see, the client plugin have to pass many data to the server plugin. How to do it is protocol dependent. + +You can find an example of top-level method server interceptor [here](https://github.com/naver/pinpoint-plugin-sample/tree/master/plugin/src/main/java/com/navercorp/pinpoint/plugin/sample/_14_RPC_Server). + +#### 2.3 Methods invoking a remote node + +An interceptor of a method that invokes a remote node has to record the following data: + +name | description +--- | --- +endPoint | Target server address +destinationId | Logical name of the target +rpc | Invoking target procedure name (optional) +nextSpanId | Span id that will be used by next node's span (If next node is traceable by Pinpoint) + + +Whether or not the next node is traceable by Pinpoint affects how the interceptor is implemented. The term "traceable" here is about possibility. For example, a HTTP client's next node is a HTTP server. Pinpoint does not trace all HTTP servers, but it is possible to trace them (and there already are HTTP server plugins). In this case, the HTTP client's next node is traceable. On the other hand, MySQL JDBC's next node, a MySQL database server, is not traceable. + +##### 2.3.1 If the next node is traceable +If the next node is traceable, the interceptor must propagate the following data to the next node. How to pass them is protocol dependent, and in worst cases may be impossible to pass them at all. + +name | description +--- | --- +transactionId | Transaction ID +parentApplicationName | Application name of current node +parentApplicationType | Application type of current node +parentSpanId | Span id of trace at current node +nextSpanId | Span id that will be used by the next node's span (same value with nextSpanId of above table) + +Pinpoint finds out caller-callee relation by matching *destinationId* of client trace and *acceptorHost* of server trace. Therefore the client plugin has to record *destinationId* and the server plugin has to record *acceptorHost* with the same value. If server cannot acquire the value by itself, client plugin has to pass it to server. + +The interceptor's recorded `ServiceType` must be from the RPC client category. + +You can find an example for these interceptors [here](https://github.com/naver/pinpoint-plugin-sample/tree/master/plugin/src/main/java/com/navercorp/pinpoint/plugin/sample/_13_RPC_Client). + +##### 2.3.2 If the next node is not traceable +If the next node is not traceable, your `ServiceType` must have the `TERMINAL` property. + +If you want to record the *destinationId*, it must also have the `INCLUDE_DESTINATION_ID` property. If you record *destinationId*, server map will show a node per destinationId even if they have same *endPoint*. + +Also, the `ServiceType` must be a DB client or Cache client category. Note that you do not need to concern yourself about the terms "DB" or "Cache", as any plugin tracing a client library with non-traceable target server may use them. The only difference between "DB" and "Cache" is the time range of the response time histogram ("Cache" having smaller intervals for the histogram). + + +#### 2.4 Asynchronous task + +Trace objects are bound to the thread that first created them via **ThreadLocal** and whenever the execution crosses a thread boundary, trace objects are *lost* to the new thread. Therefore, in order to trace tasks across thread boundaries, you must take care of passing the current trace context over to the new thread. This is done by injecting an **AsyncContext** into an object shared by both the invocation thread and the execution thread. +The invocation thread creates an **AsyncContext** from the current trace, and injects it into an object that will be passed over to the execution thread. The execution thread then retrieves the **AsyncContext** from the object, creates a new trace out of it and binds it to it's own **ThreadLocal**. +You must therefore create interceptors for two methods : i) one that initiates the task (invocation thread), and ii) the other that actually handles the task (execution thread). + +The initiating method's interceptor has to issue an **AsyncContext** and pass it to the handling method. How to pass this value depends on the target library. In worst cases, you may not be able to pass it at all. + +The handling method's interceptor must then continue the trace using the propagated **AsyncContext** and bind it to it's own thread. However, it is very strongly recommended that you simply extend the **AsyncContextSpanEventSimpleAroundInterceptor** so that you do not have to handle this manually. + +Keep in mind that since the shared object must be able have **AsyncContext** injected into it, you have to add a field using `AsyncContextAccessor` during it's class transformation. +You can find an example for tracing asynchronous tasks [here](https://github.com/naver/pinpoint-plugin-sample/tree/master/plugin/src/main/java/com/navercorp/pinpoint/plugin/sample/_12_Asynchronous_Trace). + +#### 2.5 Case Study: HTTP +HTTP client is an example of _a method invoking a remote node_ (client), and HTTP server is an example of a _top level method of a node_ (server). As mentioned before, client plugins must have a way to pass transaction data to server plugins to continue the trace. Note that the implementation is protocol dependent, and [HttpMethodBaseExecuteMethodInterceptor](https://github.com/naver/pinpoint/blob/master/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/interceptor/HttpMethodBaseExecuteMethodInterceptor.java) of [HttpClient3 plugin](https://github.com/naver/pinpoint/tree/master/plugins/httpclient3) and [StandardHostValveInvokeInterceptor](https://github.com/naver/pinpoint/blob/master/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/StandardHostValveInvokeInterceptor.java) of [Tomcat plugin](https://github.com/naver/pinpoint/tree/master/plugins/tomcat) show a working example of this for HTTP: + +1. Pass transaction data as HTTP headers. You can find header names [here](https://github.com/naver/pinpoint/blob/master/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/context/Header.java) +2. Client plugin records `IP:PORT` of the server as `destinationId`. +3. Client plugin passes `destinationId` value to server as `Header.HTTP_HOST` header. +4. Server plugin records `Header.HTTP_HOST` header value as `acceptorHost`. + +One more thing you have to remember is that all the clients and servers using the same protocol must pass the transaction data in the same way to ensure compatibility. So if you are writing a plugin of some other HTTP client or server, your plugin has to record and pass transaction data as described above. + +### 3. Plugin Integration Test +You can run plugin integration tests (`mvn integration-test`) with [PinointPluginTestSuite](https://github.com/naver/pinpoint/blob/master/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestSuite.java), which is a *JUnit Runner*. It downloads all the required dependencies from maven repositories and launches a new JVM with the Pinpoint Agent and the aforementioned dependencies. The JUnit tests are executed in this JVM. + +To run the plugin integration test, it needs a complete agent distribution - which is why integration tests are in the *plugin-sample-agent* module and why they are run in **integration-test phase**. + +For the actual integration test, you will want to first invoke the method you are tracing, and then use [PluginTestVerifier](https://github.com/naver/pinpoint/blob/master/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/test/PluginTestVerifier.java) to check if the trace data is correctly recorded. + + +#### 3.1 Test Dependency +`PinointPluginTestSuite` doesn't use the project's dependencies (configured in pom.xml). It uses the dependencies that are listed by `@Dependency` annotation. This way, you may test multiple versions of the target library using the same test class. + +Dependencies are declared as following. You may specify versions or version ranges for a dependency library. +``` +@Dependency({"some.group:some-artifact:1.0", "another.group:another-artifact:2.1-RELEASE"}) +@Dependency({"some.group:some-artifact:[1.0,)"}) +@Dependency({"some.group:some-artifact:[1.0,1.9]"}) +@Dependency({"some.group:some-artifact:[1.0],[2.1],[3.2])"}) +``` +`PinointPluginTestSuite` by default searches the local repository and maven central repository. You may also add your own repositories by using the `@Repository` annotation. + +#### 3.2 Jvm Version +You can specify the JVM version for a test using `@JvmVersion`. If `@JvmVersion` is not present, JVM at `java.home property` will be used. + +#### 3.3 Application Test +`PinpointPluginTestSuite` is not for applications that has to be launched by its own main class. You can extend [AbstractPinpointPluginTestSuite](https://github.com/naver/pinpoint/blob/master/test/src/main/java/com/navercorp/pinpoint/test/plugin/AbstractPinpointPluginTestSuite.java) and related types to test such applications. + + +### 4. Adding Images + +If you're developing a plugin for applications, you need to add images so the server map can render the corresponding node. The plugin jar itself cannot provide these image files and for now, you will have to add the image files to the web module manually. + +First, put the PNG files to following directories: + +* web/src/main/webapp/images/icons (25x25) +* web/src/main/webapp/images/servermap (80x40) + +Then, add `ServiceType` name and the image file name to `htIcons` in *web/src/main/webapp/components/server-map2/jquery.ServerMap2.js*. diff --git a/doc/proxy-http-header.md b/doc/proxy-http-header.md index fbc8a3216cfb..676d713c6cb9 100644 --- a/doc/proxy-http-header.md +++ b/doc/proxy-http-header.md @@ -1,7 +1,16 @@ +--- +title: Monitoring Proxy Server +keywords: proxy, http, header +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: proxyhttpheader.html +disqus: false +--- + # Proxy monitoring using HTTP headers It is used to know the elapsed time between proxy and WAS. -![overview](img/proxy-http-header-overview.png) +![overview](images/proxy-http-header-overview.png) ## Pinpoint Configuration diff --git a/doc/quickstart.md b/doc/quickstart.md new file mode 100755 index 000000000000..6274b6599f84 --- /dev/null +++ b/doc/quickstart.md @@ -0,0 +1,106 @@ +--- +title: Quick Start Guide +keywords: start, begin, quickstart, quick +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: quickstart.html +disqus: false +--- + +If you are using docker, [Take a look at pinpoint docker](./docker.html) which is the easiest way to look around. + +You may run a sample Pinpoint instance in your own machine by running four simple scripts for each components: Collector, Web, Sample TestApp, HBase. + +Once the components are running, you should be able to visit http://localhost:28080 to view the Pinpoint Web UI, and http://localhost:28081 to generate transactions on the Sample TestApp. + +Pinpoint is comprised of 3 main components (Collector, Web, Agent), and uses HBase as its storage. Collector and Web are packaged as simple WAR files, and the Agent is packaged so that it may be attached to applications as a java agent. + +Pinpoint QuickStart provides a sample TestApp for the Agent to attach itself to, and launches all three components using [Tomcat Maven Plugin](http://tomcat.apache.org/maven-plugin.html). + +## Requirements +In order to build Pinpoint, the following requirements must be met: + +* JDK 6 installed ([jdk1.6.0_45](http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-419409.html#jdk-6u45-oth-JPR) recommended) +* JDK 7 installed ([jdk1.7.0_80](http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html#jdk-7u80-oth-JPR) recommended) +* JDK 8 installed +* JDK 9 installed +* JAVA_HOME environment variable set to JDK 8 home directory. +* JAVA_6_HOME environment variable set to JDK 6 home directory. +* JAVA_7_HOME environment variable set to JDK 7 home directory. +* JAVA_8_HOME environment variable set to JDK 8 home directory. +* JAVA_9_HOME environment variable set to JDK 9 home directory. + +QuickStart supports Linux, OSX, and Windows. + + +## Starting +Download Pinpoint with `git clone https://github.com/naver/pinpoint.git` or [download](https://github.com/naver/pinpoint/archive/master.zip) the project as a zip file and unzip. + +Install Pinpoint by running `./mvnw install -DskipTests=true` + +### Install & Start HBase + +The following script downloads HBase standalone from [Apache download site](http://apache.mirror.cdnetworks.com/hbase/). + +> **For Windows**, you'll have to download HBase manually from [Apache download site](http://apache.mirror.cdnetworks.com/hbase/). +> +> Download `HBase-1.0.3-bin.tar.gz` and unzip it. +> +> Rename the directory to `hbase` so that the final HBase directory looks like `quickstart\hbase\hbase`. +> +> Also note that you should run the scripts below by their corresponding `.cmd` files. + +**Download & Start** - Run `quickstart/bin/start-hbase.sh` + +**Initialize Tables** - Run `quickstart/bin/init-hbase.sh` + +### Start Pinpoint Daemons + +**Collector** - Run `quickstart/bin/start-collector.sh` + +**TestApp** - Run `quickstart/bin/start-testapp.sh` + +**Web UI** - Run `quickstart/bin/start-web.sh` + + +Once the startup scripts are completed, the last 10 lines of the Tomcat log are tailed to the console: + + +**Collector** + +![Collector quick start successful](images/ss_quickstart-collector-log.png) + +**TestApp** + +![TestApp quick start successful](images/ss_quickstart-testapp-log.png) + +**Web UI** + +![Web quick start successful](images/ss_quickstart-web-log.png) + +### Check Status +Once HBase and the 3 daemons are running, you may visit the following addresses to test out your very own Pinpoint instance. + +* Web UI - http://localhost:28080 +* TestApp - http://localhost:28081 + +You can feed trace data to Pinpoint using the TestApp UI, and check them using Pinpoint Web UI. TestApp registers itself as *test-agent* under *TESTAPP*. + + +## Stopping + +**Web UI** - Run `quickstart/bin/stop-web.sh` + +**TestApp** - Run `quickstart/bin/stop-testapp.sh` + +**Collector** - Run `quickstart/bin/stop-collector.sh` + +**HBase** - Run `quickstart/bin/stop-hbase.sh` + +## Extra + +Pinpoint Web uses Mysql to persist users, user groups, and alarm configurations.
+However Quickstart uses MockDAO to reduce memory usage.
+Therefore if you want to use Mysql for Quickstart, please refer to Pinpoint Web's [applicationContext-dao-config.xml](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/applicationContext-dao-config.xml), [jdbc.properties](https://github.com/naver/pinpoint/blob/master/web/src/main/resources/jdbc.properties). + +Additionally, if you would like to enable alerts, you need to implement additional logic. Please ref this [link](./alarm.html) diff --git a/doc/resources.md b/doc/resources.md new file mode 100755 index 000000000000..8dadaa9f8c18 --- /dev/null +++ b/doc/resources.md @@ -0,0 +1,33 @@ +--- +title: Resources +keywords: resources, other sites +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: resources.html +disqus: false +--- + +If you have created informative posts on pinpoint and want the link to be added. +Feel free to contact us anytime. We are glad to add more links. + +## Resources (KOREAN) +* 유용한 자료를 작성하셨다면 공유부탁드립니다!!! +* [Pinpoint 개발자가 작성한 Pinpoint 기술문서 (helloworld.naver.com)](http://helloworld.naver.com/helloworld/1194202) +* [소개 및 설치 가이드 (prompt blog)](http://dev2.prompt.co.kr/33) +* [Pinpoint 사용 경험 (barney blog)](https://www.barney.pe.kr/naver-pinpoint/) +* [설치 가이드 동영상 강좌 1 (okjsp 대표 허광남님)](https://www.youtube.com/watch?v=hrvKaEaDEGs) +* [설치 가이드 동영상 강좌 2 (okjsp 대표 허광남님)](https://www.youtube.com/watch?v=fliKPGHGXK4) +* [AWS Ubuntu 14.04 설치 가이드 (lky1001 blog)](http://lky1001.tistory.com/132) + +## Resources (ENGLISH) +* Anyone who would like to share any document are always welcome +* [Technical Overview of Pinpoint](https://github.com/naver/pinpoint/wiki/Technical-Overview-Of-Pinpoint) +* [Official Docker Repository](https://github.com/naver/pinpoint-docker) +* [Using Pinpoint with Docker](http://yous.be/2015/05/05/using-pinpoint-with-docker/) ([@yous](https://github.com/yous)) +* [Another docker deployment using docker-compose.yml](https://github.com/minyk/docker-pinpoint) ([@minyk](https://github.com/minyk)) +* [Notes on Jetty Plugin for Pinpoint](https://github.com/cijung/Docs/blob/master/JettyPluginNotes.md) ([@cijung](https://github.com/cijung)) + +## Resources (中文) +* [Pinpoint学习笔记](http://skyao.gitbooks.io/leaning-pinpoint/):中文资料收集整理和更重要的-中文翻译! +* [Pinpoint - 应用性能管理(APM)平台实践之部署篇](https://sconts.com/11) +* [开源APM工具Pinpoint线上部署](https://www.iqarr.com/2018/02/04/java/pinpoint/pinpoint-deploy/) \ No newline at end of file diff --git a/doc/roadmap.md b/doc/roadmap.md new file mode 100755 index 000000000000..2b86d705e716 --- /dev/null +++ b/doc/roadmap.md @@ -0,0 +1,45 @@ +--- +title: Roadmap +keywords: roadmap, future +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: roadmap.html +disqus: false +--- + +## 2017 Roadmap +* Server Map Enhancement + * Performance + * Improve query speed through parallelism via asynchronous I/O operation, and code optimization + * Change/introduce a new data structure more suitable for dealing with a large number of agents + * Realtime + * Improve realtime update/rendering + * Support grouping of multiple applications +* Scatter Chart Enhancement + * Introduce grouping by type of errors (db access fail, rpc fail, cache access fail, etc) +* Statistics/Aggregation + * Introduce realtime data pipeline (Apache Flink) for statistics and data aggregation + * Application-level min/max statistics and response time histograms + * Statistics by request URLs +* Agent + * Active thread dump + * Collect DataSource information + * Improve asynchronous trace support + * Add vert.x support + * Introduce agent trace data format v2 + * Type optimization & compressed format + * Protocol buffer 3 + * Improve interceptor and thread local lookup performance + * Introduce adapters for different interceptor types/patterns + * Adaptive sampling + * Adaptive callstack tracing + * Discard relatively insignificant method invocations + * Combine multiple highly similar/identical callstacks when sending them over the wire + * Ability to store stack traces + * Introduce log-level histograms +* UI/Usability + * Improve performance + * Migrate to AngularJS 2 + * Improve personalized configuration for users +* HBase + * Data store optimization - Reduce rowkey sizes \ No newline at end of file diff --git a/doc/scripts/deployGitPage.sh b/doc/scripts/deployGitPage.sh new file mode 100644 index 000000000000..fa23435c4df8 --- /dev/null +++ b/doc/scripts/deployGitPage.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +set -e # exit with nonzero exit code if anything fails + +if [[ $TRAVIS_BRANCH == "master" && $TRAVIS_PULL_REQUEST == "false" ]]; then + +echo "Starting to update gh-pages\n" + +#copy data we're interested in to other place +cp -R doc $HOME/doc + +#go to home and setup git +cd $HOME +git config --global user.email "sungwook0115.kim@gmail.com" +git config --global user.name "RoySRose" + +#using token clone gh-pages branch +git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/naver/pinpoint.git gh-pages > /dev/null + +#go into directory and copy data we're interested in to that directory +cd gh-pages +cp -Rf $HOME/doc/*.md ./pages +cp -Rf $HOME/doc/images/* ./images + +#add, commit and push files +git add -f . +git commit -m "Auto commit by TRAVIS $TRAVIS_BUILD_NUMBER" + +git push -fq origin gh-pages > /dev/null + +echo "Done updating gh-pages\n" + +else + echo "Skipped updating gh-pages, because build is not triggered from the master branch." +fi; \ No newline at end of file diff --git a/doc/techdetail.md b/doc/techdetail.md new file mode 100755 index 000000000000..8724f9c656a8 --- /dev/null +++ b/doc/techdetail.md @@ -0,0 +1,259 @@ +--- +title: Technical Details +keywords: tech, technology +last_updated: Feb 1, 2018 +sidebar: mydoc_sidebar +permalink: techdetail.html +disqus: false +--- + + +In this article, we describe the Pinpoint's techniques such as transaction tracing and bytecode instrumentation. And we explain the optimization method applied to Pinpoint Agent, which modifies bytecode and record performance data. + +## Distributed Transaction Tracing, Modeled after Google's Dapper + +Pinpoint traces distributed requests in a single transaction, modeled after Google's Dapper. + +### How Distributed Transaction Tracing Works in Google's Dapper + +The purpose of a distributed tracing system is to identify relationships between Node 1 and Node 2 in a distributed system when a message is sent from Node 1 to Node 2 (Figure 1). + +![Figure 1. Message relationship in a distributed system](images/td_figure1.png) + +Figure 1. Message relationship in a distributed system + +The problem is that there is no way to identify relationships between messages. For example, we cannot recognize relationships between N messages sent from Node 1 and N' messages received in Node 2. In other words, when X-th message is sent from Node 1, the X-th message cannot be identified among N' messages received in Node 2. An attempt was made to trace messages at TCP or operating system level. However, implementation complexity was high with low performance because it should be implemented separately for each protocol. In addition, it was difficult to accurately trace messages. + +However, a simple solution to resolve such issues has been implemented in Google's Dapper. The solution is to add application-level tags that can be a link between messages when sending a message. For example, it includes tag information for a message in the HTTP header at an HTTP request and traces the message using this tag. + +> Google's Dapper + +> For more information on Google's Dapper, see "[Dapper, a Large-Scale Distributed Systems Tracing Infrastructure](http://research.google.com/pubs/pub36356.html)." + +Pinpoint is modeled on the tracing technique of Google's Dapper but has been modified to add application-level tag data in the call header to trace distributed transactions at a remote call. The tag data consists of a collection of keys, which is defined as a TraceId. + +### Data Structure in Pinpoint + +In Pinpoint, the core of data structure consists of Spans, Traces, and TraceIds. +* Span: The basic unit of RPC (remote procedure call) tracing; it indicates work processed when an RPC arrives and contains trace data. To ensure the code-level visibility, a Span has children labeled SpanEvent as a data structure. Each Span contains a TraceId. +* Trace: A collection of Spans; it consists of associated RPCs (Spans). Spans in the same trace share the same TransactionId. A Trace is sorted as a hierarchical tree structure through SpanIds and ParentSpanIds. +* TraceId: A collections of keys consisting of TransactionId, SpanId, and ParentSpanId. The TransactionId indicates the message ID, and both the SpanId and the ParentSpanId represent the parent-child relationship of RPCs. + - TransactionId (TxId): The ID of the message sent/received across distributed systems from a single transaction; it must be globally unique across the entire group of servers. + - SpanId: The ID of a job processed when receiving RPC messages; it is generated when an RPC arrives at a node. + - ParentSpanId (pSpanId): The SpanId of the parent span which generated the RPC. If a node is the starting point of a transaction, there will not be a parent span - for these cases, we use a value of -1 to denote that the span is the root span of a transaction. + +> Differences in terms between Google's Dapper and NAVER's Pinpoint + +> The term "TransactionId" in Pinpoint has the same meaning as the term "TraceId" in Google's Dapper and the term "TraceId" in Pinpoint refers to a collection of keys. + +### How TraceId Works +The figure below illustrates the behavior of a TraceId in which RPCs were made 3 times within 4 nodes. + +![Figure 2. Example of a TraceId behavior](images/td_figure2.png) + +Figure 2. Example of a TraceId behavior + +A TransactionId (TxId) represents that three different RPCs are associated with each other as a single transaction in Figure 2. However, a TransactionId itself can't explicitly describe the relationship between RPCs. To identify the relationships between RPCs, a SpanId and a ParentSpanId (pSpanId) are required. Suppose that a node is Tomcat. You can think of a SpanId as a thread which handles HTTP requests. A ParentSpanId indicates the SpainId of a parent that makes RPC calls. + +Pinpoint can find associated n Spans using a TransactionId and can sort them as a hierarchical tree structure using a SpanId and a ParentSpanId. + +A SpanId and a ParentSpanId are 64-bit long integers. A conflict might arise because the number is generated arbitrarily, but considering the range of value from -9223372036854775808 to 9223372036854775807, this is unlikely to happen. If there is a conflict between keys, Pinpoint as well as Google's Dapper lets developers know what happened, instead of resolving the conflict. + +A TransactionId consists of AgentIds, JVM (Java virtual machine) startup time, and SequenceNumbers. + +* AgentId: A user-created ID when JVM starts; it must be globally unique across the entire group of servers where Pinpoint has been installed. The easiest way to make it unique is to use a hostname ($HOSTNAME) because the hostname is not duplicate in general. If you need to run multiple JVMs within the server group, add a postfix to the hostname to avoid duplicates. +* JVM startup time: Required to guarantee a unique SequenceNumber which starts with zero. This value is used to prevent ID conflicts when a user creates duplicate AgentId by mistake. +* SequenceNumber: ID issued by the Pinpoint Agent, with sequentially increasing numbers that start with zero; it is issued per message. + +Dapper and [Zipkin](https://github.com/twitter/zipkin), a distributed systems tracing platform at Twitter, generate random TraceIds (TransactionIds in Pinpoint) and consider conflict situations as a normal case. However, we wanted to avoid this conflict as much as possible in Pinpoint. We had two available options for this; one with a method in which the amount of data is small but the probability of conflict is high; the other is a method in which the amount of data is large but the probability of conflict is low; We chose the second option. + +There may be a better ways to handle transactions. We came up with several ideas such as key issue by a central key server. But we didn't implement this in the system due to performance issues and network errors. We are still considering issuing keys in bulk as an alternative Solution. So maybe later in the future, such methods can be developed; But for now, a simple method is adopted. In Pinpoint, a TransactionId is regarded as changeable data. + +## Bytecode Instrumentation, Not Requiring Code Modifications + +Earlier, we explained distributed transaction tracing. One way for implementing this is that developers to modify their code by themselves. Allow developers to add tag information when an RPC is made. However, it could be a burden to modify code even though such functionality is useful to developers. + +Twitter's Zipkin provides the functionality of distributed transaction tracing using modified libraries and its container (Finagle). However, it requires the code to be modified if needed. We wanted the functionality to work without code modifications and desired to ensure code-level visibility. To solve such problems, the bytecode instrumentation technique was adopted in Pinpoint. The Pinpoint Agent intervenes code to make RPCs so as to automatically handle tag information. + +### Overcoming Disadvantages of Bytecode Instrumentation + +There are two ways for distributed transaction tracing as below. Bytecode instrumentation is one of an automatic method. +* Manual method: Developers develop code that records data at important points using APIs provided by Pinpoint. +* Automatic method: Developers do not involve code modifications because Pinpoint decides which API is to be intervened and developed. + + +Advantages and disadvantages of each method are as follows: + +Table 1 Advantages and disadvantage of each method + + +Item |Advantage |Disadvantage +---------|----------|------------ +**Manual Tracing** | - Requires less development resources.
- An API can become simpler and consequently the number of bugs can be reduced. |- Developers must modify the code.
- Tracing level is low. +**Automatic Tracing** |- Developers are not required to modify the code.
- More precise data can be collected due to more information in bytecode.|- It would cost 10 times more to develop Pinpoint with automatic method.
- Requires highly competent developers who can instantly recognize the library code to be traced and make decisions on the tracing points.
- Can increase the possibility of a bug due to high-level development skills such as bytecode instrumentation. + +Bytecode instrumentation is a technique that includes high difficulty level and risks. Nevertheless, using this technique has many benefits. + +Although it requires a large number of development resources, it requires almost none for applying the service. For example, the following shows the costs between an automatic method which uses bytecode instrumentation and a manual method which uses libraries (in this context, costs are random numbers assumed for clarity). + +* Automatic method: Total of 100 + - Cost of Pinpoint development: 100 + - Cost of services applied: 0 +* Manual method: Total of 30 + - Cost of Pinpoint development: 20 + - Cost of services applied: 10 + +The data above tells us that a manual method is more cost-effective than an automatic one. However, it will not guarantee the same result for NAVER since we have thousands of services. For example, if we have 10 services which require being modified, the total cost will be calculated as follows: + +* Cost of Pinpoint development 20 + Cost of services applied 10 x 10 services = 120 + +As you can see, the automatic method was more cost-efficient for us. + +We are lucky to have many developers who are highly competent and specialized in Java in the Pinpoint team. Therefore, we believed it was only a matter of time to overcome the technical difficulties in Pinpoint development. + +### The Value of Bytecode Instrumentation + +The reason we chose to implement bytecode instrumentation(Automatic method) is not only those that we have already explained but also the following points. + +#### Hidden API + +If the API is exposed for developers to use. We, as API providers, are restricted to modify the API as we desire. Such a restriction can impose stress on us. + +We may modify an API to correct mistaken design or add new functions. However, if there is a restriction to do this, it would be difficult for us to improve the API. The best answer for solving such a problem is a scalable system design, which is not an easy option as everyone knows. It is almost impossible to create perfect API design as we can't predict the future. + +With bytecode instrumentation, we don't have to worry about the problems caused by exposing the tracing APIs and can continuously improve the design, without considering dependency relationships. For those who are planning to develop their applications using Pinpoint, please note that API can be changed by the Pinpoint developers since improving performance and design is our first priority. + +#### Easy to Enable or Disable + +The disadvantage of using bytecode instrumentation is that it could affect your applications when a problem occurs in the profiling section of a library or Pinpoint itself. However, you can easily solve it by just disabling the Pinpoint since you don't have to change any code. + +You can easily enable Pinpoint for your applications by adding the three lines (associated with the configuration of the Pinpoint Agent) below into your JVM startup script: + + -javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar + -Dpinpoint.agentId= + -Dpinpoint.applicationName= + +If any problem occurs due to Pinpoint, you can just delete the configuration data in the JVM startup script. + +### How Bytecode Instrumentation Works + +Since bytecode instrumentation technique has to deal with Java bytecode, it tends to increase the risk of development while it decreases productivity. In addition, developers are prone to make mistakes. In Pinpoint, we improved productivity and accessibility by abstraction with the interceptor. Pinpoint injects necessary codes to track distributed transactions and performance information by intervening application code at class loading time. This increases performance since tracking codes are directly injected into the application code. + +![Figure 3. Behavior of bytecode instrumentation](images/td_figure3.png) + +Figure 3. Basic principle of bytecode instrumentation + +In Pinpoint, the API intercepting part and data recording part are separated. Interceptor is injected into the method that we'd like to track and calls before() and after() methods where data recording is taken care of. Through bytecode instrumentation, Pinpoint Agent can record data only from the necessary method which makes the size of profiling data compact. + +## Optimizing Performance of the Pinpoint Agent + +Finally, we will describe how to optimize the performance of Pinpoint Agent. + +### Using Binary Format (Thrift) + +You can increase encoding speed by using a binary format ([Thrift](https://thrift.apache.org/)). Although it is difficult to use and debug, It can improve the efficiency of network usage by reducing the size of data generated. + +### Optimize Recorded Data for Variable-Length Encoding and Format + +If you convert a long integer into a fixed-length string, the data size will be 8 bytes. However, if you use variable-length encoding, the data size can vary from 1 to 10 bytes depending on the size of a given number. To reduce data size, Pinpoint encodes data as a variable-length string through Compact Protocol of Thrift and records data to be optimized for encoding format. Pinpoint Agent reduces data size by converting remaining time based on root method into a vector value. + +> Variable-length encoding + +> For more information on the variable-length encoding, see "[Base 128 Varints](https://developers.google.com/protocol-buffers/docs/encoding#varints)" in Google Developers. + + ![Figure 4. Comparison between fixed-length encoding and variable-length encoding](images/td_figure4.png) + + Figure 4. Comparison between fixed-length encoding and variable-length encoding + +As you can see in Figure 4, you need to measure the time of 6 different points to get information of when three different methods are called and finished(Figure 4); With fixed-length encoding, this process requires 48 bytes (6points × 8bytes). + +Meanwhile, Pinpoint Agent uses variable-length encoding and records the data according to its corresponding format. And calculate time information on other points with the difference(in vector value) based on the start time of the root method. Since vector value is a small number, it consumes a small number of bytes resulting only 13 bytes consumed rather than 48bytes. + +If it takes more time to execute a method, it will increase the number of bytes even though variable-length encoding is used. However, it is still more efficient than fixed-length encoding. + +### Replacing Repeated API Information, SQLs, and Strings with Constant Tables + +We wanted Pinpoint to enable code-level tracing. However, it had a problem in terms of increasing data size. Every time data with a high degree of precision is sent to a server, due to the size of the data it increased network usage. + +To solve such a problem, we adopted a strategy by creating a constant table in a remote HBase server. Since there will be an overload to send data of "method A" to Pinpoint Collector each time, Pinpoint Agent converts "method A" data to an ID and stores this information as a constant table in HBase, and continue tracing data with the ID. When a user retrieves trace data on the Website, the Pinpoint Web searches for the method information of the corresponding ID in the constant table and reorganize them. The same way is used to reduce data size in SQLs or frequently-used strings. + +### Handling Samples for Bulk Requests + +The requests to online portal services which Naver is providing are huge. A single service handles more than 20 billion requests a day. A simple way to trace such request is by expanding network infrastructure and servers as much as needed to suit the number of requests. However, this is not a cost-effective way to handle such situations. + +In Pinpoint, you can collect only sampling data rather than tracking every request. In a development environment where requests are few, every data is collected. While in the production environment where requests are large, only 1~5% out of whole data is collected which is sufficient to analyze the status of entire applications. With sampling, you can minimize network overhead in applications and reduce costs of infrastructure such as networks and servers. + +> Sampling method in Pinpoint + +> Pinpoint supports a Counting sampler, which collects data only for one of 10 requests if it is set to 10. We plan to add new samplers that can collect data more effectively. + +### Minimizing Application Threads Being Aborted Using Asynchronous Data Transfer + +Pinpoint does not interfere with application threads since encoded data or remote messages are transferred asynchronously by another thread. + +#### Transferring Data via UDP + +Unlike Google's Dapper, Pinpoint transfers data through a network to ensure data speed. Sharing network with your service can be an issue when data traffic bursts out. In such situations, the Pinpoint Agent starts to use UDP protocol to give the network connection priority to your service. + +> Note + +> The data transfer APIs can be replaced since it's separated as an interface. It can be changed into an implementation that stores data in a different way, like local files. + +## Example of Pinpoint Applied + +Here is an example of how to get data from your application so that you can comprehensively understand the contents described earlier. + +Figure 5 shows what you can see when you install Pinpoint in TomcatA and TomcatB. You can see the trace data of an individual node as a single transaction, which represents the flow of distributed transaction tracing. + +![Figure 5. Example 1: Pinpoint applied](images/td_figure5.png) + +Figure 5. Example of Pinpoint in action + + +The following describes what Pinpoint does for each method. + +1. Pinpoint Agent issues a TraceId when a request arrives at TomcatA. + - TX_ID: TomcatA^TIME^1 + - SpanId: 10 + - ParentSpanId: -1(Root) + +2. Records data from Spring MVC controllers. + +3. Intervene the calls of HttpClient.execute() method and configure the TraceId in HttpGet. + - Creates a child TraceId. + - TX_ID: TomcatA^TIME^1 -> TomcatA^TIME^1 + - SPAN_ID: 10 -> 20 + - PARENT_SPAN_ID: -1 -> 10 (parent SpanId) + - Configures the child TraceId in the HTTP header. + - HttpGet.setHeader(PINPOINT_TX_ID, "TomcatA^TIME^1") + - HttpGet.setHeader(PINPOINT_SPAN_ID, "20") + - HttpGet.setHeader(PINPOINT_PARENT_SPAN_ID, "10") + +4. Transfer tagged request to TomcatB. + - TomcatB checks the header from the transferred request. + - HttpServletRequest.getHeader(PINPOINT_TX_ID) + - TomcatB becomes a child node as it identifies a TraceId in the header. + - TX_ID: TomcatA^TIME^1 + - SPAN_ID: 20 + - PARENT_SPAN_ID: 10 + +5. Records data from Spring MVC controllers and completes the request. + + ![Figure 6. Example 2: Pinpoint applied ](images/td_figure6.png) + +6. Pinpoint Agent sends trace data to Pinpoint Collector to store it in HBase when the request from TomcatB is completed. + +7. After the HTTP calls from TomcatB is terminated, then the request from TomcatA is complete. The Pinpoint Agent sends trace data to Pinpoint Collector to store it in HBase. + +8. UI reads the trace data from HBase and creates a call stack by sorting trees. + + +## Conclusions + +Pinpoint is another application that runs along with your applications. Using bytecode instrumentation makes Pinpoint seem like that it does not require code modifications. In general, the bytecode instrumentation technique makes applications vulnerable to risks; if a problem occurs in Pinpoint, it will affect your applications as well. But for now, instead of getting rid of such threats, we are focusing on improving performance and design of Pinpoint. Because we think this makes Pinpoint more valuable. So whether or not to use Pinpoint is for you to decide. + +We still have a large amount of work to be done to improve Pinpoint. Despite its incompleteness, Pinpoint was released as an open-source project; we are continuously trying to develop and improve Pinpoint so as to meet your expectations. + +> Written by Woonduk Kang + +> In 2011, I wrote about myself like this—As a developer, I would like to make a software program that users are willing to pay for, like those of Microsoft or Oracle. As Pinpoint was launched as an open-source project, it seems that my dreams somewhat came true. For now, my desire is to make Pinpoint more valuable and attractive to users. \ No newline at end of file diff --git a/doc/troubleshooting_network.md b/doc/troubleshooting_network.md new file mode 100755 index 000000000000..1b7bf3660a51 --- /dev/null +++ b/doc/troubleshooting_network.md @@ -0,0 +1,66 @@ +--- +title: Checking network configuration +keywords: troubleshooting +last_updated: Aug 14, 2018 +sidebar: mydoc_sidebar +permalink: troubleshooting_network.html +disqus: false +--- + +We provide a simple tool that can check your network configurations. +This tool checks the network status between Pinpoint-Agent and Pinpoint-Collector + +### Testing with binary release + +If you have downloaded the build results from our [**latest release**](https://github.com/naver/pinpoint/releases/latest). + +1. Start your collector server +2. With any terminal that you are using, go to *script* folder which is under *pinpoint-agent-VERSION.tar.gz* package that you have downloaded. + +```` +> pwd +/Users/user/Downloads/pinpoint-agent-1.7.2-SNAPSHOT/script +```` +and run *networktest.sh* shell script +```` +> sh networktest.sh +```` + +You will see some CLASSPATH and configuration you have made in the *pinpoint.config* file as below +```` +CLASSPATH=./tools/pinpoint-tools-1.7.2-SNAPSHOT.jar +...Remainder Omitted... +2018-04-10 17:36:30 [INFO ](com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig) profiler.enable=true +2018-04-10 17:36:30 [INFO ](com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig) profiler.instrument.engine=ASM +2018-04-10 17:36:30 [INFO ](com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig) profiler.instrument.matcher.enable=true +...Remainder Omitted... +```` + +And after that, you will see the results. (In this case, collector server was started locally) +If you receive all six SUCCESSes as below, then you are all set and ready to go. + +```` +UDP-STAT:// localhost + => 127.0.0.1:9995 [SUCCESS] + => 0:0:0:0:0:0:0:1:9995 [SUCCESS] + +UDP-SPAN:// localhost + => 127.0.0.1:9996 [SUCCESS] + => 0:0:0:0:0:0:0:1:9996 [SUCCESS] + +TCP:// localhost + => 127.0.0.1:9994 [SUCCESS] + => 0:0:0:0:0:0:0:1:9994 [SUCCESS] +```` + +### Testing with source code + +The idea is basically the same. + +1. Start your collector server +2. Pass the *path* of the pinpoint.config file as a *program argument* and run ***NetworkAvailabilityChecker*** class. +3. (only for under v1.7.2)For the few who gets JNI error while running. Please remove ````provided```` line from pom.xml under *tools* module and try again + +Results should be same as shown above. + + > If you face error for v1.7.3 take a look at this [issue](https://github.com/naver/pinpoint/issues/4668) \ No newline at end of file diff --git a/doc/ui_guide.md b/doc/ui_guide.md new file mode 100644 index 000000000000..393306daa742 --- /dev/null +++ b/doc/ui_guide.md @@ -0,0 +1,63 @@ +--- +title: New UI Guide +sidebar: mydoc_sidebar +tags: +keywords: UI +last_updated: Sep 1, 2018 +permalink: ui_v2.html +toc: false +--- + +## How to test new UI in Development + +Our team is redeveloping the UI with a new design using the latest Angular Framework. +If you want to experience the new UI in advance, +please follow the instructions below. + +* Update the following `RewriteForV2Filter` setting to Spring's `applicationContext-web.xml`. + +```` xml +// applicationContext-web.xml + + + + +```` + +* Add `-Pv2` option when building Maven. +> mvn clean install -Pv2 + // Please note that adding the -Pv2 option may cause longer time to build. + +* URL where you can check + * http://your.domain.name/v2 + +![UI Example](images/ui.png) + +## 새롭게 개발 중인 UI를 테스트 할 수 있는 방법 + +Pinpoint 팀은 새로운 디자인과 최신 Angular Framework 을 이용하여 UI 를 재 개발하고 있습니다. +만약 새로운 UI를 미리 체험하고 싶다면 다음과 같은 설정이 필요합니다. + +* applicationContext-web.xml 의 `contructor-arg` 값을 `true`로 설정합니다. + +```` xml +// applicationContext-web.xml + + + +```` +* Maven 빌드 시 `-Pv2` 옵션을 추가 합니다. +> mvn clean install -Pv2 + // -Pv2 옵션을 추가하면 빌드 타임이 오래 걸릴 수 있는 점을 유의해 주세요. + +* 확인 할 수 있는 URL + * http://your.domain.name/v2 + +![UI Example](images/ui.png) + +* 개발 시 watch & build 실행 방법 +`./web/src/main/webapp/v2/` 에서 `npm install` 후 다음 명령 실행 + +```` +> npm run build:watch +```` \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 34a2541580fc..000000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,88 +0,0 @@ -pinpoint-hbase: - container_name: pinpoint-hbase - hostname: hbase - image: naver/pinpoint-hbase:1.7.2-SNAPSHOT - restart: always - expose: - - "2181" - - "16010" - ports: - - "2181:2181" - - "16010:16010" - -pinpoint-mysql: - container_name: pinpoint-mysql - restart: always - image: mysql:5.7 - ports: - - "13306:3306" - environment: - - MYSQL_ROOT_PASSWORD=root123 - - MYSQL_USER=admin - - MYSQL_PASSWORD=admin - - MYSQL_DATABASE=pinpoint - -pinpoint-collector: - container_name: pinpoint-collector - hostname: collector - image: naver/pinpoint-collector:1.7.2-SNAPSHOT - restart: always - expose: - - "9994" - - "9995" - - "9996" - ports: - - "9994:9994" - - "9995:9995/tcp" - - "9996:9996/tcp" - - "9995:9995/udp" - - "9996:9996/udp" - environment: - HBASE_HOST: hbase - HBASE_PORT: 2181 - COLLECTOR_TCP_PORT: 9994 - COLLECTOR_UDP_STAT_LISTEN_PORT: 9995 - COLLECTOR_UDP_SPAN_LISTEN_PORT: 9996 - CLUSTER_ENABLE: 'true' - CLUSTER_ZOOKEEPER_ADDRESS: hbase - DISABLE_DEBUG: 'true' - links: - - pinpoint-hbase:hbase - -pinpoint-web: - container_name: pinpoint-web - hostname: web - image: naver/pinpoint-web:1.7.2-SNAPSHOT - restart: always - expose: - - "8080" - ports: - - "3080:8080" - environment: - HBASE_HOST: hbase - HBASE_PORT: 2181 - CLUSTER_ENABLE: 'true' - CLUSTER_ZOOKEEPER_ADDRESS: hbase - ADMIN_PASSWORD: admin123 - DISABLE_DEBUG: 'true' - JDBC_DRIVER: com.mysql.jdbc.Driver - JDBC_URL: jdbc:mysql://mysql:3306/pinpoint?characterEncoding=UTF-8 - JDBC_USERNAME: admin - JDBC_PASSWORD: admin - links: - - pinpoint-hbase:hbase - - pinpoint-mysql:mysql - -# only example -#pinpoint-agent: -# image: naver/pinpoint-agent:1.7.2-SNAPSHOT -# net: "none" -# restart: unless-stopped -# volumes: -# - /var/container_data/pinpoint-agent/log:/opt/app/pinpoint-agent/log:rw -# environment: -# COLLECTOR_IP: 192.168.99.100 -# COLLECTOR_TCP_PORT: 9994 -# COLLECTOR_UDP_STAT_LISTEN_PORT: 9995 -# COLLECTOR_UDP_SPAN_LISTEN_PORT: 9996 -# DISABLE_DEBUG: 'true' diff --git a/flink/clover.license b/flink/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/flink/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF - org.apache.flink - flink-hbase - 0.10.2 + org.springframework + spring-context-support + + + net.sf.ehcache + ehcache-core @@ -127,6 +141,18 @@ log4j runtime
+ + io.dropwizard.metrics + metrics-core + + + io.dropwizard.metrics + metrics-jvm + + + io.dropwizard.metrics + metrics-servlets +
@@ -150,7 +176,6 @@ org.apache.maven.plugins maven-compiler-plugin - 3.5.1 ${jdk.version} ${jdk.version} @@ -166,7 +191,7 @@ org.apache.maven.plugins maven-shade-plugin - 2.4.3 + ${plugin.shade.version} build-first @@ -186,28 +211,11 @@ com.navercorp.pinpoint.flink.StatStreamingVer2Job - pinpoint-flink-job-2.0 - - - - build-second - package - - shade - - - - - com.navercorp.pinpoint.flink.SocketServer - - - server-1.0 + pinpoint-flink-job-${project.version} - - \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/Bootstrap.java b/flink/src/main/java/com/navercorp/pinpoint/flink/Bootstrap.java index f0627920283b..f98f3be382e2 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/Bootstrap.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/Bootstrap.java @@ -15,20 +15,22 @@ */ package com.navercorp.pinpoint.flink; +import com.navercorp.pinpoint.collector.receiver.thrift.TCPReceiverBean; import com.navercorp.pinpoint.flink.cluster.FlinkServerRegister; import com.navercorp.pinpoint.flink.config.FlinkConfiguration; import com.navercorp.pinpoint.flink.dao.hbase.*; +import com.navercorp.pinpoint.flink.function.ApplicationStatBoWindowInterceptor; import com.navercorp.pinpoint.flink.process.ApplicationCache; -import com.navercorp.pinpoint.flink.process.TbaseFlatMapper; +import com.navercorp.pinpoint.flink.process.TBaseFlatMapper; +import com.navercorp.pinpoint.flink.process.TBaseFlatMapperInterceptor; import com.navercorp.pinpoint.flink.receiver.AgentStatHandler; -import com.navercorp.pinpoint.flink.receiver.TCPReceiver; import com.navercorp.pinpoint.flink.receiver.TcpDispatchHandler; import com.navercorp.pinpoint.flink.receiver.TcpSourceFunction; +import com.navercorp.pinpoint.flink.vo.RawData; import org.apache.flink.streaming.api.datastream.DataStreamSource; import org.apache.flink.streaming.api.environment.LocalStreamEnvironment; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.api.functions.source.SourceFunction.SourceContext; -import org.apache.thrift.TBase; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; @@ -41,9 +43,9 @@ public class Bootstrap { private final StatisticsDao statisticsDao; - private final ApplicationContext applicationContext; + private final ClassPathXmlApplicationContext applicationContext; - private final TbaseFlatMapper tbaseFlatMapper; + private final TBaseFlatMapper tbaseFlatMapper; private final FlinkConfiguration flinkConfiguration; private final TcpDispatchHandler tcpDispatchHandler; private final TcpSourceFunction tcpSourceFunction; @@ -54,12 +56,16 @@ public class Bootstrap { private final ActiveTraceDao activeTraceDao; private final ResponseTimeDao responseTimeDao; private final DataSourceDao dataSourceDao; + private final FileDescriptorDao fileDescriptorDao; + private final DirectBufferDao directBufferDao; + private final TBaseFlatMapperInterceptor tBaseFlatMapperInterceptor; + private final StatisticsDaoInterceptor statisticsDaoInterceptor; + private final ApplicationStatBoWindowInterceptor applicationStatBoWindowInterceptor; private Bootstrap() { - String[] SPRING_CONFIG_XML = new String[]{"applicationContext-flink.xml", "applicationContext-cache.xml"}; - applicationContext = new ClassPathXmlApplicationContext(SPRING_CONFIG_XML); + applicationContext = new ClassPathXmlApplicationContext("applicationContext-flink.xml"); - tbaseFlatMapper = applicationContext.getBean("tbaseFlatMapper", TbaseFlatMapper.class); + tbaseFlatMapper = applicationContext.getBean("tbaseFlatMapper", TBaseFlatMapper.class); flinkConfiguration = applicationContext.getBean("flinkConfiguration", FlinkConfiguration.class); tcpDispatchHandler = applicationContext.getBean("tcpDispatchHandler", TcpDispatchHandler.class); tcpSourceFunction = applicationContext.getBean("tcpSourceFunction", TcpSourceFunction.class); @@ -71,6 +77,15 @@ private Bootstrap() { activeTraceDao = applicationContext.getBean("activeTraceDao", ActiveTraceDao.class); responseTimeDao = applicationContext.getBean("responseTimeDao", ResponseTimeDao.class); dataSourceDao = applicationContext.getBean("dataSourceDao", DataSourceDao.class); + fileDescriptorDao = applicationContext.getBean("fileDescriptorDao", FileDescriptorDao.class); + directBufferDao = applicationContext.getBean("directBufferDao", DirectBufferDao.class); + tBaseFlatMapperInterceptor = applicationContext.getBean("tBaseFlatMapperInterceptor", TBaseFlatMapperInterceptor.class); + statisticsDaoInterceptor = applicationContext.getBean("statisticsDaoInterceptor", StatisticsDaoInterceptor.class); + applicationStatBoWindowInterceptor = applicationContext.getBean("applicationStatBoWindowInterceptor", ApplicationStatBoWindowInterceptor.class); + } + + public FileDescriptorDao getFileDescriptorDao() { + return fileDescriptorDao; } public static Bootstrap getInstance() { @@ -109,7 +124,11 @@ public DataSourceDao getDataSourceDao() { return dataSourceDao; } - public TbaseFlatMapper getTbaseFlatMapper() { + public DirectBufferDao getDirectBufferDao() { + return directBufferDao; + } + + public TBaseFlatMapper getTbaseFlatMapper() { return tbaseFlatMapper; } @@ -136,7 +155,7 @@ public void setSourceFunctionParallel(DataStreamSource rawData) { rawData.setParallelism(parallel); } - public void setStatHandlerTcpDispatchHandler(SourceContext sourceContext) { + public void setStatHandlerTcpDispatchHandler(SourceContext sourceContext) { AgentStatHandler agentStatHandler = new AgentStatHandler(sourceContext); tcpDispatchHandler.setAgentStatHandler(agentStatHandler); } @@ -145,11 +164,24 @@ public FlinkServerRegister initFlinkServerRegister() { return applicationContext.getBean("flinkServerRegister", FlinkServerRegister.class); } - public TCPReceiver initTcpReceiver() { - return applicationContext.getBean("tcpReceiver", TCPReceiver.class); + public void initTcpReceiver() { + // lazy init + applicationContext.getBean("tcpReceiver", TCPReceiverBean.class); } - public TcpSourceFunction getTcpSourceFuncation() { + public TcpSourceFunction getTcpSourceFunction() { return tcpSourceFunction; } -} + + public TBaseFlatMapperInterceptor getTbaseFlatMapperInterceptor() { + return tBaseFlatMapperInterceptor; + } + + public StatisticsDaoInterceptor getStatisticsDaoInterceptor() { + return statisticsDaoInterceptor; + } + + public ApplicationStatBoWindowInterceptor getApplicationStatBoWindowInterceptor() { + return applicationStatBoWindowInterceptor; + } +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/StatStreamingVer2Job.java b/flink/src/main/java/com/navercorp/pinpoint/flink/StatStreamingVer2Job.java index 0298680c821b..c803149c9c78 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/StatStreamingVer2Job.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/StatStreamingVer2Job.java @@ -25,6 +25,7 @@ import com.navercorp.pinpoint.flink.function.Timestamp; import com.navercorp.pinpoint.flink.function.ApplicationStatBoFliter; import com.navercorp.pinpoint.flink.receiver.TcpSourceFunction; +import com.navercorp.pinpoint.flink.vo.RawData; import org.apache.flink.api.java.tuple.Tuple3; import org.apache.flink.streaming.api.TimeCharacteristic; import org.apache.flink.streaming.api.datastream.DataStream; @@ -33,7 +34,6 @@ import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows; import org.apache.flink.streaming.api.windowing.time.Time; -import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,9 +51,9 @@ public void start() throws Exception { final Bootstrap bootstrap = Bootstrap.getInstance(); // set data source - final TcpSourceFunction tcpSourceFunction = bootstrap.getTcpSourceFuncation(); + final TcpSourceFunction tcpSourceFunction = bootstrap.getTcpSourceFunction(); final StreamExecutionEnvironment env = bootstrap.createStreamExecutionEnvironment(); - DataStreamSource rawData = env.addSource(tcpSourceFunction); + DataStreamSource rawData = env.addSource(tcpSourceFunction); env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); bootstrap.setSourceFunctionParallel(rawData); diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/cluster/FlinkServerRegister.java b/flink/src/main/java/com/navercorp/pinpoint/flink/cluster/FlinkServerRegister.java index b7e79ff75d82..948e77d7b6c3 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/cluster/FlinkServerRegister.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/cluster/FlinkServerRegister.java @@ -15,11 +15,16 @@ */ package com.navercorp.pinpoint.flink.cluster; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.CuratorZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperEventWatcher; import com.navercorp.pinpoint.common.util.NetUtils; import com.navercorp.pinpoint.flink.config.FlinkConfiguration; import com.navercorp.pinpoint.rpc.util.ClassUtils; import com.navercorp.pinpoint.rpc.util.TimerFactory; -import com.navercorp.pinpoint.web.cluster.zookeeper.*; +import com.navercorp.pinpoint.web.cluster.zookeeper.PushZnodeJob; +import com.navercorp.pinpoint.web.cluster.zookeeper.ZookeeperClusterDataManagerHelper; +import org.apache.curator.utils.ZKPaths; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.Watcher.Event.KeeperState; @@ -34,7 +39,6 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; /** @@ -42,12 +46,12 @@ */ public class FlinkServerRegister implements ZookeeperEventWatcher { - private static final String PINPOINT_FLINK_CLUSTER_PATh = "/pinpoint-cluster/flink"; + private static final String PINPOINT_FLINK_CLUSTER_PATH = "/pinpoint-cluster/flink"; private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final AtomicReference job = new AtomicReference<>(); private final ZookeeperClusterDataManagerHelper clusterDataManagerHelper = new ZookeeperClusterDataManagerHelper(); - private final AtomicBoolean connected = new AtomicBoolean(false); + private final String connectAddress; private final int sessionTimeout; private final int retryInterval; @@ -63,7 +67,7 @@ public FlinkServerRegister(FlinkConfiguration flinkConfiguration) { this.connectAddress = flinkConfiguration.getFlinkClusterZookeeperAddress(); this.sessionTimeout = flinkConfiguration.getFlinkClusterSessionTimeout(); this.retryInterval = flinkConfiguration.getFlinkRetryInterval(); - this.zNodeName = getRepresentationLocalV4Ip() +":" + flinkConfiguration.getFlinkClusterTcpPort(); + this.zNodeName = getRepresentationLocalV4Ip() + ":" + flinkConfiguration.getFlinkClusterTcpPort(); } @PostConstruct @@ -74,7 +78,7 @@ public void start() throws Exception { } this.timer = createTimer(); - this.client = new ZookeeperClient(connectAddress, sessionTimeout, this, ZookeeperClient.DEFAULT_RECONNECT_DELAY_WHEN_SESSION_EXPIRED); + this.client = new CuratorZookeeperClient(connectAddress, sessionTimeout, this); this.client.connect(); registerFlinkNode(); @@ -115,7 +119,7 @@ public void stop() { // Retry upon failure (1 min retry period) // not too much overhead, just logging public boolean registerFlinkNode() { - String zNodePath = clusterDataManagerHelper.bindingPathAndZNode(PINPOINT_FLINK_CLUSTER_PATh, zNodeName); + String zNodePath = ZKPaths.makePath(PINPOINT_FLINK_CLUSTER_PATH, zNodeName); logger.info("registerFlinkNode() started. create UniqPath={}.", zNodePath); @@ -147,18 +151,10 @@ public void process(WatchedEvent event) { EventType eventType = event.getType(); String path = event.getPath(); - // when this happens, ephemeral node disappears - // reconnects automatically, and process gets notified for all events - boolean result = false; - if (ZookeeperUtils.isDisconnectedEvent(event)) { - result = handleDisconnected(); - if (state == KeeperState.Expired) { - client.reconnectWhenSessionExpired(); - } - } else if (state == KeeperState.SyncConnected || state == KeeperState.NoSyncConnected) { - if (eventType == EventType.None) { - result = handleConnected(); - } else if (eventType == EventType.NodeChildrenChanged) { + if (state == KeeperState.SyncConnected || state == KeeperState.NoSyncConnected) { + // when this happens, ephemeral node disappears + // reconnects automatically, and process gets notified for all events + if (eventType == EventType.NodeChildrenChanged) { logger.info("zookeeper Event occurs : NodeChildrenChanged event"); } else if (eventType == EventType.NodeDeleted) { logger.info("zookeeper Event occurs : NodeDeleted"); @@ -166,52 +162,36 @@ public void process(WatchedEvent event) { logger.info("zookeeper Event occurs : NodeDataChanged"); } } - - if (result) { - logger.info("Handle Zookeeper Event({}) completed.", event); - } else { - logger.info("Handle Zookeeper Event({}) failed.", event); - } + logger.info("Handle Zookeeper Event({}) completed.", event); } - private boolean handleDisconnected() { - connected.compareAndSet(true, false); + @Override + public boolean handleDisconnected() { return true; } - private boolean handleConnected() { - boolean result = true; - - // is it ok to keep this since previous condition was possibly RUN - boolean changed = connected.compareAndSet(false, true); - if (changed) { - PushFlinkNodeJob job = this.job.get(); - if (job != null) { - if (!clusterDataManagerHelper.pushZnode(client, job)) { - timer.newTimeout(job, job.getRetryInterval(), TimeUnit.MILLISECONDS); - result = false; - } + @Override + public boolean handleConnected() { + PushFlinkNodeJob job = this.job.get(); + if (job != null) { + if (!clusterDataManagerHelper.pushZnode(client, job)) { + timer.newTimeout(job, job.getRetryInterval(), TimeUnit.MILLISECONDS); + return false; } - } else { - result = false; } - - return result; + return true; } - private Timer createTimer() { HashedWheelTimer timer = TimerFactory.createHashedWheelTimer("Pinpoint-Flink-Cluster-Timer", 100, TimeUnit.MILLISECONDS, 512); timer.start(); return timer; } - @Override public boolean isConnected() { - return connected.get(); + return client.isConnected(); } - class PushFlinkNodeJob implements PushZnodeJob { private final String zNodeName; private final byte[] contents; @@ -256,4 +236,5 @@ public String toString() { return ClassUtils.simpleClassName(this) + ", ZNode=" + getZNodePath(); } } + } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/ActiveTraceDao.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/ActiveTraceDao.java index 6226965924c5..a3bf7bbe81bc 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/ActiveTraceDao.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/ActiveTraceDao.java @@ -17,6 +17,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseTemplate2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.join.ActiveTraceSerializer; import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; @@ -40,12 +41,13 @@ public class ActiveTraceDao { private final HbaseTemplate2 hbaseTemplate2; private final ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory; private final ActiveTraceSerializer activeTraceSerializer; - private final TableName APPLICATION_STAT_AGGRE = HBaseTables.APPLICATION_STAT_AGGRE; + private final TableNameProvider tableNameProvider; - public ActiveTraceDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, ActiveTraceSerializer activeTraceSerializer) { + public ActiveTraceDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, ActiveTraceSerializer activeTraceSerializer, TableNameProvider tableNameProvider) { this.hbaseTemplate2 = Objects.requireNonNull(hbaseTemplate2, "hbaseTemplate2 must not be null"); this.applicationStatHbaseOperationFactory = Objects.requireNonNull(applicationStatHbaseOperationFactory, "applicationStatHbaseOperationFactory must not be null"); this.activeTraceSerializer = Objects.requireNonNull(activeTraceSerializer, "activeTraceSerializer must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); } public void insert(String id, long timestamp, List joinActiveTraceBoList, StatType statType) { @@ -54,9 +56,10 @@ public void insert(String id, long timestamp, List joinActiveTraceBo } List activeTracePuts = applicationStatHbaseOperationFactory.createPuts(id, joinActiveTraceBoList, statType, activeTraceSerializer); if (!activeTracePuts.isEmpty()) { - List rejectedPuts = hbaseTemplate2.asyncPut(APPLICATION_STAT_AGGRE, activeTracePuts); + TableName applicationStatAggreTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_STAT_AGGRE_STR); + List rejectedPuts = hbaseTemplate2.asyncPut(applicationStatAggreTableName, activeTracePuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - hbaseTemplate2.put(APPLICATION_STAT_AGGRE, rejectedPuts); + hbaseTemplate2.put(applicationStatAggreTableName, rejectedPuts); } } } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/CpuLoadDao.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/CpuLoadDao.java index 86207dadf027..27df9716d814 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/CpuLoadDao.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/CpuLoadDao.java @@ -17,6 +17,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseTemplate2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.join.CpuLoadSerializer; import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; @@ -40,12 +41,13 @@ public class CpuLoadDao { private final HbaseTemplate2 hbaseTemplate2; private final ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory; private final CpuLoadSerializer cpuLoadSerializer; - private final TableName APPLICATION_STAT_AGGRE = HBaseTables.APPLICATION_STAT_AGGRE; + private final TableNameProvider tableNameProvider; - public CpuLoadDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, CpuLoadSerializer cpuLoadSerializer) { + public CpuLoadDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, CpuLoadSerializer cpuLoadSerializer, TableNameProvider tableNameProvider) { this.hbaseTemplate2 = Objects.requireNonNull(hbaseTemplate2, "hbaseTemplate2 must not be null"); this.applicationStatHbaseOperationFactory = Objects.requireNonNull(applicationStatHbaseOperationFactory, "applicationStatHbaseOperationFactory must not be null"); this.cpuLoadSerializer = Objects.requireNonNull(cpuLoadSerializer, "cpuLoadSerializer must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); } public void insert(String id, long timestamp, List joinCpuLoadBoList, StatType statType) { @@ -54,9 +56,10 @@ public void insert(String id, long timestamp, List joinCpuLoadBoList } List cpuLoadPuts = applicationStatHbaseOperationFactory.createPuts(id, joinCpuLoadBoList, statType, cpuLoadSerializer); if (!cpuLoadPuts.isEmpty()) { - List rejectedPuts = hbaseTemplate2.asyncPut(APPLICATION_STAT_AGGRE, cpuLoadPuts); + TableName applicationStatAggreTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_STAT_AGGRE_STR); + List rejectedPuts = hbaseTemplate2.asyncPut(applicationStatAggreTableName, cpuLoadPuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - hbaseTemplate2.put(APPLICATION_STAT_AGGRE, rejectedPuts); + hbaseTemplate2.put(applicationStatAggreTableName, rejectedPuts); } } } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DataSourceDao.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DataSourceDao.java index 3ba3577b6952..94d16ef6d22f 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DataSourceDao.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DataSourceDao.java @@ -17,6 +17,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseTemplate2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.join.DataSourceSerializer; import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; @@ -40,12 +41,13 @@ public class DataSourceDao { private final HbaseTemplate2 hbaseTemplate2; private final ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory; private final DataSourceSerializer dataSourceSerializer; - private final TableName APPLICATION_STAT_AGGRE = HBaseTables.APPLICATION_STAT_AGGRE; + private final TableNameProvider tableNameProvider; - public DataSourceDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, DataSourceSerializer dataSourceSerializer) { + public DataSourceDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, DataSourceSerializer dataSourceSerializer, TableNameProvider tableNameProvider) { this.hbaseTemplate2 = Objects.requireNonNull(hbaseTemplate2, "hbaseTemplate2 must not be null"); this.applicationStatHbaseOperationFactory = Objects.requireNonNull(applicationStatHbaseOperationFactory, "applicationStatHbaseOperationFactory must not be null"); this.dataSourceSerializer = Objects.requireNonNull(dataSourceSerializer, "dataSourceSerializer must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); } public void insert(String id, long timestamp, List joinResponseTimeBoList, StatType statType) { @@ -54,9 +56,10 @@ public void insert(String id, long timestamp, List joinResponseTimeB } List responseTimePuts = applicationStatHbaseOperationFactory.createPuts(id, joinResponseTimeBoList, statType, dataSourceSerializer); if (!responseTimePuts.isEmpty()) { - List rejectedPuts = hbaseTemplate2.asyncPut(APPLICATION_STAT_AGGRE, responseTimePuts); + TableName applicationStatAggreTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_STAT_AGGRE_STR); + List rejectedPuts = hbaseTemplate2.asyncPut(applicationStatAggreTableName, responseTimePuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - hbaseTemplate2.put(APPLICATION_STAT_AGGRE, rejectedPuts); + hbaseTemplate2.put(applicationStatAggreTableName, rejectedPuts); } } } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DefaultStatisticsDaoInterceptor.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DefaultStatisticsDaoInterceptor.java new file mode 100644 index 000000000000..bb62b4d57537 --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DefaultStatisticsDaoInterceptor.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.dao.hbase; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import org.apache.flink.api.java.tuple.Tuple3; + +/** + * @author minwoo.jung + */ +public class DefaultStatisticsDaoInterceptor implements StatisticsDaoInterceptor { + + @Override + public void before(Tuple3 statData) { + } + + @Override + public void after() { + } +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DirectBufferDao.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DirectBufferDao.java new file mode 100644 index 000000000000..a2501d9b2904 --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/DirectBufferDao.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.dao.hbase; + +import com.navercorp.pinpoint.common.hbase.HBaseTables; +import com.navercorp.pinpoint.common.hbase.HbaseTemplate2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatHbaseOperationFactory; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.join.DirectBufferSerializer; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import com.navercorp.pinpoint.common.server.bo.stat.join.StatType; +import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Put; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.List; +import java.util.Objects; + +/** + * @author Roy Kim + */ +public class DirectBufferDao { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final HbaseTemplate2 hbaseTemplate2; + private final ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory; + private final DirectBufferSerializer directBufferSerializer; + private final TableNameProvider tableNameProvider; + + public DirectBufferDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, DirectBufferSerializer directBufferSerializer, TableNameProvider tableNameProvider) { + this.hbaseTemplate2 = Objects.requireNonNull(hbaseTemplate2, "hbaseTemplate2 must not be null"); + this.applicationStatHbaseOperationFactory = Objects.requireNonNull(applicationStatHbaseOperationFactory, "applicationStatHbaseOperationFactory must not be null"); + this.directBufferSerializer = Objects.requireNonNull(directBufferSerializer, "directBufferSerializer must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); + } + + public void insert(String id, long timestamp, List joinDirectBufferBoList, StatType statType) { + if (logger.isDebugEnabled()) { + logger.debug("[insert] {} : ({})", new Date(timestamp), joinDirectBufferBoList); + } + List directBufferPuts = applicationStatHbaseOperationFactory.createPuts(id, joinDirectBufferBoList, statType, directBufferSerializer); + if (!directBufferPuts.isEmpty()) { + TableName applicationStatAggreTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_STAT_AGGRE_STR); + List rejectedPuts = hbaseTemplate2.asyncPut(applicationStatAggreTableName, directBufferPuts); + if (CollectionUtils.isNotEmpty(rejectedPuts)) { + hbaseTemplate2.put(applicationStatAggreTableName, rejectedPuts); + } + } + } +} diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/FileDescriptorDao.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/FileDescriptorDao.java new file mode 100644 index 000000000000..db89dd8c81b6 --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/FileDescriptorDao.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.dao.hbase; + +import com.navercorp.pinpoint.common.hbase.HBaseTables; +import com.navercorp.pinpoint.common.hbase.HbaseTemplate2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatHbaseOperationFactory; +import com.navercorp.pinpoint.common.server.bo.serializer.stat.join.FileDescriptorSerializer; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import com.navercorp.pinpoint.common.server.bo.stat.join.StatType; +import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Put; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.List; +import java.util.Objects; + +/** + * @author Roy Kim + */ +public class FileDescriptorDao { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final HbaseTemplate2 hbaseTemplate2; + private final ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory; + private final FileDescriptorSerializer fileDescriptorSerializer; + private final TableNameProvider tableNameProvider; + + public FileDescriptorDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, FileDescriptorSerializer fileDescriptorSerializer, TableNameProvider tableNameProvider) { + this.hbaseTemplate2 = Objects.requireNonNull(hbaseTemplate2, "hbaseTemplate2 must not be null"); + this.applicationStatHbaseOperationFactory = Objects.requireNonNull(applicationStatHbaseOperationFactory, "applicationStatHbaseOperationFactory must not be null"); + this.fileDescriptorSerializer = Objects.requireNonNull(fileDescriptorSerializer, "fileDescriptorSerializer must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); + } + + public void insert(String id, long timestamp, List joinFileDescriptorBoList, StatType statType) { + if (logger.isDebugEnabled()) { + logger.debug("[insert] {} : ({})", new Date(timestamp), joinFileDescriptorBoList); + } + List fileDescriptorPuts = applicationStatHbaseOperationFactory.createPuts(id, joinFileDescriptorBoList, statType, fileDescriptorSerializer); + if (!fileDescriptorPuts.isEmpty()) { + TableName applicationStatAggreTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_STAT_AGGRE_STR); + List rejectedPuts = hbaseTemplate2.asyncPut(applicationStatAggreTableName, fileDescriptorPuts); + if (CollectionUtils.isNotEmpty(rejectedPuts)) { + hbaseTemplate2.put(applicationStatAggreTableName, rejectedPuts); + } + } + } +} diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/MemoryDao.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/MemoryDao.java index 564697ef2c68..01e861ec9c9e 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/MemoryDao.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/MemoryDao.java @@ -17,6 +17,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseTemplate2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.join.MemorySerializer; import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; @@ -40,12 +41,13 @@ public class MemoryDao { private final HbaseTemplate2 hbaseTemplate2; private final ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory; private final MemorySerializer memorySerializer; - private final TableName APPLICATION_STAT_AGGRE = HBaseTables.APPLICATION_STAT_AGGRE; + private final TableNameProvider tableNameProvider; - public MemoryDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, MemorySerializer memorySerializer) { + public MemoryDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, MemorySerializer memorySerializer, TableNameProvider tableNameProvider) { this.hbaseTemplate2 = Objects.requireNonNull(hbaseTemplate2, "hbaseTemplate2 must not be null"); this.applicationStatHbaseOperationFactory = Objects.requireNonNull(applicationStatHbaseOperationFactory, "applicationStatHbaseOperationFactory must not be null"); this.memorySerializer = Objects.requireNonNull(memorySerializer, "memorySerializer must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); } public void insert(String id, long timestamp, List joinMemoryBoList, StatType statType) { @@ -54,9 +56,10 @@ public void insert(String id, long timestamp, List joinMemoryBoList, } List memoryPuts = applicationStatHbaseOperationFactory.createPuts(id, joinMemoryBoList, statType, memorySerializer); if (!memoryPuts.isEmpty()) { - List rejectedPuts = hbaseTemplate2.asyncPut(APPLICATION_STAT_AGGRE, memoryPuts); + TableName applicationStatAggreTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_STAT_AGGRE_STR); + List rejectedPuts = hbaseTemplate2.asyncPut(applicationStatAggreTableName, memoryPuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - hbaseTemplate2.put(APPLICATION_STAT_AGGRE, rejectedPuts); + hbaseTemplate2.put(applicationStatAggreTableName, rejectedPuts); } } } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/ResponseTimeDao.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/ResponseTimeDao.java index 70afa9dedd24..8e582f1317a7 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/ResponseTimeDao.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/ResponseTimeDao.java @@ -17,6 +17,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseTemplate2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.join.ResponseTimeSerializer; import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; @@ -40,12 +41,13 @@ public class ResponseTimeDao { private final HbaseTemplate2 hbaseTemplate2; private final ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory; private final ResponseTimeSerializer responseTimeSerializer; - private final TableName APPLICATION_STAT_AGGRE = HBaseTables.APPLICATION_STAT_AGGRE; + private final TableNameProvider tableNameProvider; - public ResponseTimeDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, ResponseTimeSerializer responseTimeSerializer) { + public ResponseTimeDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, ResponseTimeSerializer responseTimeSerializer, TableNameProvider tableNameProvider) { this.hbaseTemplate2 = Objects.requireNonNull(hbaseTemplate2, "hbaseTemplate2 must not be null"); this.applicationStatHbaseOperationFactory = Objects.requireNonNull(applicationStatHbaseOperationFactory, "applicationStatHbaseOperationFactory must not be null"); this.responseTimeSerializer = Objects.requireNonNull(responseTimeSerializer, "responseTimeSerializer must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); } public void insert(String id, long timestamp, List joinResponseTimeBoList, StatType statType) { @@ -54,9 +56,10 @@ public void insert(String id, long timestamp, List joinResponseTimeB } List responseTimePuts = applicationStatHbaseOperationFactory.createPuts(id, joinResponseTimeBoList, statType, responseTimeSerializer); if (!responseTimePuts.isEmpty()) { - List rejectedPuts = hbaseTemplate2.asyncPut(APPLICATION_STAT_AGGRE, responseTimePuts); + TableName applicationStatAggreTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_STAT_AGGRE_STR); + List rejectedPuts = hbaseTemplate2.asyncPut(applicationStatAggreTableName, responseTimePuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - hbaseTemplate2.put(APPLICATION_STAT_AGGRE, rejectedPuts); + hbaseTemplate2.put(applicationStatAggreTableName, rejectedPuts); } } } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/StatisticsDao.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/StatisticsDao.java index bcb69e77d597..a3b54563d0d1 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/StatisticsDao.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/StatisticsDao.java @@ -15,14 +15,15 @@ */ package com.navercorp.pinpoint.flink.dao.hbase; -import com.navercorp.pinpoint.common.hbase.HBaseTables; -import com.navercorp.pinpoint.common.server.bo.stat.join.*; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinAgentStatBo; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinApplicationStatBo; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import com.navercorp.pinpoint.common.server.bo.stat.join.StatType; import com.navercorp.pinpoint.flink.Bootstrap; import org.apache.flink.api.common.io.OutputFormat; import org.apache.flink.api.java.tuple.Tuple3; import org.apache.flink.configuration.Configuration; import org.apache.flink.util.CollectionUtil; -import org.apache.hadoop.hbase.TableName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,13 +38,15 @@ public class StatisticsDao implements OutputFormat statData) throws IOException { - JoinStatBo joinStatBo = (JoinStatBo)statData.f1; - if (joinStatBo instanceof JoinAgentStatBo) { - if (logger.isDebugEnabled()) { - logger.debug("JoinAgentStatBo insert data : {}", joinStatBo); - } - - insertJoinAgentStatBo((JoinAgentStatBo)joinStatBo); - } else if (joinStatBo instanceof JoinApplicationStatBo) { + statisticsDaoInterceptor.before(statData); + + try { + JoinStatBo joinStatBo = (JoinStatBo) statData.f1; + if (joinStatBo instanceof JoinAgentStatBo) { + if (logger.isDebugEnabled()) { + logger.debug("JoinAgentStatBo insert data : {}", joinStatBo); + } + insertJoinAgentStatBo((JoinAgentStatBo) joinStatBo); + } else if (joinStatBo instanceof JoinApplicationStatBo) { // logger.info("JoinApplicationStatBo insert data : " + joinStatBo); - insertJoinApplicationStatBo((JoinApplicationStatBo)joinStatBo); + insertJoinApplicationStatBo((JoinApplicationStatBo) joinStatBo); + } + } finally { + statisticsDaoInterceptor.after(); } - } private void insertJoinApplicationStatBo(JoinApplicationStatBo joinApplicationStatBo) { @@ -88,6 +97,8 @@ private void insertJoinApplicationStatBo(JoinApplicationStatBo joinApplicationSt List joinActiveTraceBoList = castJoinStatBoList(joinApplicationStatBo.getJoinActiveTraceBoList()); List joinResponseTimeBoList = castJoinStatBoList(joinApplicationStatBo.getJoinResponseTimeBoList()); List joinDataSourceBoList = castJoinStatBoList(joinApplicationStatBo.getJoinDataSourceListBoList()); + List joinFileDescriptorBoList = castJoinStatBoList(joinApplicationStatBo.getJoinFileDescriptorBoList()); + List joinDirectBufferBoList = castJoinStatBoList(joinApplicationStatBo.getJoinDirectBufferBoList()); if (joinApplicationStatBo.getStatType() == StatType.APP_STST_AGGRE) { // logger.info("insert application aggre : " + new Date(joinApplicationStatBo.getTimestamp()) + " ("+ joinApplicationStatBo.getApplicationId() + " )"); @@ -100,6 +111,8 @@ private void insertJoinApplicationStatBo(JoinApplicationStatBo joinApplicationSt activeTraceDao.insert(id, timestamp, joinActiveTraceBoList, StatType.APP_ACTIVE_TRACE_COUNT); responseTimeDao.insert(id, timestamp, joinResponseTimeBoList, StatType.APP_RESPONSE_TIME); dataSourceDao.insert(id, timestamp, joinDataSourceBoList, StatType.APP_DATA_SOURCE); + fileDescriptorDao.insert(id, timestamp, joinFileDescriptorBoList, StatType.APP_FILE_DESCRIPTOR); + directBufferDao.insert(id, timestamp, joinDirectBufferBoList, StatType.APP_DIRECT_BUFFER); } } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/StatisticsDaoInterceptor.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/StatisticsDaoInterceptor.java new file mode 100644 index 000000000000..c3069c0fb12a --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/StatisticsDaoInterceptor.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.dao.hbase; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import org.apache.flink.api.java.tuple.Tuple3; + +/** + * @author minwoo.jung + */ +public interface StatisticsDaoInterceptor { + void before(Tuple3 statData); + + void after(); +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/TransactionDao.java b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/TransactionDao.java index 0e18e69bbcfb..4af9aa03a96d 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/TransactionDao.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/dao/hbase/TransactionDao.java @@ -17,6 +17,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseTemplate2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.join.TransactionSerializer; import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; @@ -37,16 +38,16 @@ public class TransactionDao { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private static final TableName APPLICATION_STAT_AGGRE = HBaseTables.APPLICATION_STAT_AGGRE; - private final HbaseTemplate2 hbaseTemplate2; private final ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory; private final TransactionSerializer transactionSerializer; + private final TableNameProvider tableNameProvider; - public TransactionDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, TransactionSerializer transactionSerializer) { + public TransactionDao(HbaseTemplate2 hbaseTemplate2, ApplicationStatHbaseOperationFactory applicationStatHbaseOperationFactory, TransactionSerializer transactionSerializer, TableNameProvider tableNameProvider) { this.hbaseTemplate2 = Objects.requireNonNull(hbaseTemplate2, "hbaseTemplate2 must not be null"); this.applicationStatHbaseOperationFactory = Objects.requireNonNull(applicationStatHbaseOperationFactory, "applicationStatHbaseOperationFactory must not be null"); this.transactionSerializer = Objects.requireNonNull(transactionSerializer, "transactionSerializer must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); } public void insert(String id, long timestamp, List joinTransactionBoList, StatType statType) { @@ -55,9 +56,10 @@ public void insert(String id, long timestamp, List joinTransactionBo } List transactionPuts = applicationStatHbaseOperationFactory.createPuts(id, joinTransactionBoList, statType, transactionSerializer); if (!transactionPuts.isEmpty()) { - List rejectedPuts = hbaseTemplate2.asyncPut(APPLICATION_STAT_AGGRE, transactionPuts); + TableName applicationStatAggreTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_STAT_AGGRE_STR); + List rejectedPuts = hbaseTemplate2.asyncPut(applicationStatAggreTableName, transactionPuts); if (CollectionUtils.isNotEmpty(rejectedPuts)) { - hbaseTemplate2.put(APPLICATION_STAT_AGGRE, rejectedPuts); + hbaseTemplate2.put(applicationStatAggreTableName, rejectedPuts); } } } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoFliter.java b/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoFliter.java index b3518fb94c9d..d3fbf25b83ac 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoFliter.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoFliter.java @@ -22,8 +22,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Date; - /** * @author minwoo.jung */ diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoWindow.java b/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoWindow.java index 17d9c3b30ff3..fb3f0b0bbe12 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoWindow.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoWindow.java @@ -17,8 +17,11 @@ import com.navercorp.pinpoint.common.server.bo.stat.join.JoinApplicationStatBo; import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import com.navercorp.pinpoint.flink.Bootstrap; import org.apache.flink.api.java.tuple.Tuple; import org.apache.flink.api.java.tuple.Tuple3; +import org.apache.flink.configuration.Configuration; +import org.apache.flink.streaming.api.functions.windowing.RichWindowFunction; import org.apache.flink.streaming.api.functions.windowing.WindowFunction; import org.apache.flink.streaming.api.windowing.windows.TimeWindow; import org.apache.flink.util.Collector; @@ -32,14 +35,24 @@ /** * @author minwoo.jung */ -public class ApplicationStatBoWindow implements WindowFunction, Tuple3, Tuple, TimeWindow> { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - +public class ApplicationStatBoWindow extends RichWindowFunction, Tuple3, Tuple, TimeWindow> { public static final int WINDOW_SIZE = 10000; public static final int ALLOWED_LATENESS = 45000; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private transient ApplicationStatBoWindowInterceptor applicationStatBoWindowInterceptor; + + @Override + public void open(Configuration parameters) throws Exception { + applicationStatBoWindowInterceptor = Bootstrap.getInstance().getApplicationStatBoWindowInterceptor(); + + } + @Override public void apply(Tuple tuple, TimeWindow window, Iterable> values, Collector> out) throws Exception { + String tupleKey = (String)tuple.getField(0); + applicationStatBoWindowInterceptor.before(values); try { JoinApplicationStatBo joinApplicationStatBo = join(values); long delayTime = new Date().getTime() - joinApplicationStatBo.getTimestamp(); @@ -65,9 +78,12 @@ public void apply(Tuple tuple, TimeWindow window, Iterable(joinApplicationStatBo.getId(), joinApplicationStatBo, joinApplicationStatBo.getTimestamp())); + Tuple3 resultTuple = applicationStatBoWindowInterceptor.middle(new Tuple3<>(tupleKey, joinApplicationStatBo, joinApplicationStatBo.getTimestamp())); + out.collect(resultTuple); } catch (Exception e) { logger.error("window function error", e); + } finally { + applicationStatBoWindowInterceptor.after(); } } @@ -81,4 +97,4 @@ private JoinApplicationStatBo join(Iterable> va return JoinApplicationStatBo.joinApplicationStatBoByTimeSlice(joinApplicaitonStatBoList); } -} +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoWindowInterceptor.java b/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoWindowInterceptor.java new file mode 100644 index 000000000000..14ca938c48f9 --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/function/ApplicationStatBoWindowInterceptor.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.function; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import org.apache.flink.api.java.tuple.Tuple3; + +/** + * @author minwoo.jung + */ +public interface ApplicationStatBoWindowInterceptor { + void before(Iterable> values); + + Tuple3 middle(Tuple3 value); + + void after(); +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/function/DefaultApplicationStatBoWindowInterceptor.java b/flink/src/main/java/com/navercorp/pinpoint/flink/function/DefaultApplicationStatBoWindowInterceptor.java new file mode 100644 index 000000000000..b06015669259 --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/function/DefaultApplicationStatBoWindowInterceptor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.function; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import org.apache.flink.api.java.tuple.Tuple3; + +/** + * @author minwoo.jung + */ +public class DefaultApplicationStatBoWindowInterceptor implements ApplicationStatBoWindowInterceptor { + @Override + public void before(Iterable> values) { + } + + @Override + public Tuple3 middle(Tuple3 value) { + return value; + } + + @Override + public void after() { + } +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinAgentStatBoMapper.java b/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinAgentStatBoMapper.java index 9bb25f52fcd7..35f30e5e1969 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinAgentStatBoMapper.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinAgentStatBoMapper.java @@ -36,6 +36,8 @@ public class JoinAgentStatBoMapper implements ThriftBoMapper joinActiveTraceBoList = new ArrayList<>(agentStatSize); List joinResponseTimeBoList = new ArrayList<>(agentStatSize); List joinDataSourceListBoList = new ArrayList<>(agentStatSize); + List joinFileDescriptorBoList = new ArrayList<>(agentStatSize); + List joinDirectBufferBoList = new ArrayList<>(agentStatSize); for (TFAgentStat tFAgentStat : tFAgentStatBatch.getAgentStats()) { createAndAddJoinCpuLoadBo(tFAgentStat, joinCpuLoadBoList); @@ -63,6 +67,8 @@ public JoinAgentStatBo map(TFAgentStatBatch tFAgentStatBatch) { createAndAddJoinActiveTraceBo(tFAgentStat, joinActiveTraceBoList); createAndAddJoinResponseTimeBo(tFAgentStat, joinResponseTimeBoList); createAndAddJoinDataSourceListBo(tFAgentStat, joinDataSourceListBoList); + createAndAddJoinFileDescriptorBo(tFAgentStat, joinFileDescriptorBoList); + createAndAddJoinDirectBufferBo(tFAgentStat, joinDirectBufferBoList); } joinAgentStatBo.setJoinCpuLoadBoList(joinCpuLoadBoList); @@ -71,6 +77,8 @@ public JoinAgentStatBo map(TFAgentStatBatch tFAgentStatBatch) { joinAgentStatBo.setJoinActiveTraceBoList(joinActiveTraceBoList); joinAgentStatBo.setJoinResponseTimeBoList(joinResponseTimeBoList); joinAgentStatBo.setJoinDataSourceListBoList(joinDataSourceListBoList); + joinAgentStatBo.setJoinFileDescriptorBoList(joinFileDescriptorBoList); + joinAgentStatBo.setJoinDirectBufferBoList(joinDirectBufferBoList); joinAgentStatBo.setId(tFAgentStatBatch.getAgentId()); joinAgentStatBo.setAgentStartTimestamp(tFAgentStatBatch.getStartTimestamp()); joinAgentStatBo.setTimestamp(getTimeStamp(joinAgentStatBo)); @@ -154,6 +162,18 @@ private long getTimeStamp(JoinAgentStatBo joinAgentStatBo) { return joinDataSourceListBoList.get(0).getTimestamp(); } + List joinFileDescriptorBoList = joinAgentStatBo.getJoinFileDescriptorBoList(); + + if (joinFileDescriptorBoList.size() != 0) { + return joinFileDescriptorBoList.get(0).getTimestamp(); + } + + List joinDirectBufferBoList = joinAgentStatBo.getJoinDirectBufferBoList(); + + if (joinDirectBufferBoList.size() != 0) { + return joinDirectBufferBoList.get(0).getTimestamp(); + } + return Long.MIN_VALUE; } @@ -177,4 +197,23 @@ private void createAndAddJoinMemoryBo(TFAgentStat tFAgentStat, List joinFileDescriptorBoList) { + JoinFileDescriptorBo joinFileDescriptorBo = joinFileDescriptorBoMapper.map(tFAgentStat); + + if (joinFileDescriptorBo == JoinFileDescriptorBo.EMPTY_JOIN_FILE_DESCRIPTOR_BO) { + return; + } + + joinFileDescriptorBoList.add(joinFileDescriptorBo); + } + + public void createAndAddJoinDirectBufferBo(TFAgentStat tFAgentStat, List joinDirectBufferBoList) { + JoinDirectBufferBo joinDirectBufferBo = joinDirectBufferBoMapper.map(tFAgentStat); + + if (joinDirectBufferBo == JoinDirectBufferBo.EMPTY_JOIN_DIRECT_BUFFER_BO) { + return; + } + + joinDirectBufferBoList.add(joinDirectBufferBo); + } } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDataSourceListBoMapper.java b/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDataSourceListBoMapper.java index f2d1e90d725d..2fbe16d86e3a 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDataSourceListBoMapper.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDataSourceListBoMapper.java @@ -41,7 +41,7 @@ public JoinDataSourceListBo map(TFAgentStat tFAgentStat) { } List tFDataSourceList = dataSourceList.getDataSourceList(); - if (tFDataSourceList.size() == 0) { + if (tFDataSourceList.isEmpty()) { return JoinDataSourceListBo.EMPTY_JOIN_DATA_SOURCE_LIST_BO; } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDirectBufferBoMapper.java b/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDirectBufferBoMapper.java new file mode 100644 index 000000000000..bba4e2a9561f --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDirectBufferBoMapper.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.flink.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinDirectBufferBo; +import com.navercorp.pinpoint.flink.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.thrift.dto.flink.TFAgentStat; +import com.navercorp.pinpoint.thrift.dto.flink.TFDirectBuffer; + +/** + * @author Roy Kim + */ +public class JoinDirectBufferBoMapper implements ThriftBoMapper { + + @Override + public JoinDirectBufferBo map(TFAgentStat tFAgentStat) { + if (!tFAgentStat.isSetDirectBuffer()) { + return JoinDirectBufferBo.EMPTY_JOIN_DIRECT_BUFFER_BO; + } + + JoinDirectBufferBo joinDirectBufferBo = new JoinDirectBufferBo(); + + final String agentId = tFAgentStat.getAgentId(); + joinDirectBufferBo.setId(agentId); + joinDirectBufferBo.setTimestamp(tFAgentStat.getTimestamp()); + + TFDirectBuffer tFDirectBuffer = tFAgentStat.getDirectBuffer(); + joinDirectBufferBo.setAvgDirectCount(tFDirectBuffer.getDirectCount()); + joinDirectBufferBo.setMinDirectCountAgentId(agentId); + joinDirectBufferBo.setMinDirectCount(tFDirectBuffer.getDirectCount()); + joinDirectBufferBo.setMaxDirectCountAgentId(agentId); + joinDirectBufferBo.setMaxDirectCount(tFDirectBuffer.getDirectCount()); + + joinDirectBufferBo.setAvgDirectMemoryUsed(tFDirectBuffer.getDirectMemoryUsed()); + joinDirectBufferBo.setMinDirectMemoryUsedAgentId(agentId); + joinDirectBufferBo.setMinDirectMemoryUsed(tFDirectBuffer.getDirectMemoryUsed()); + joinDirectBufferBo.setMaxDirectMemoryUsedAgentId(agentId); + joinDirectBufferBo.setMaxDirectMemoryUsed(tFDirectBuffer.getDirectMemoryUsed()); + + joinDirectBufferBo.setAvgMappedCount(tFDirectBuffer.getMappedCount()); + joinDirectBufferBo.setMinMappedCountAgentId(agentId); + joinDirectBufferBo.setMinMappedCount(tFDirectBuffer.getMappedCount()); + joinDirectBufferBo.setMaxMappedCountAgentId(agentId); + joinDirectBufferBo.setMaxMappedCount(tFDirectBuffer.getMappedCount()); + + joinDirectBufferBo.setAvgMappedMemoryUsed(tFDirectBuffer.getMappedMemoryUsed()); + joinDirectBufferBo.setMinMappedMemoryUsedAgentId(agentId); + joinDirectBufferBo.setMinMappedMemoryUsed(tFDirectBuffer.getMappedMemoryUsed()); + joinDirectBufferBo.setMaxMappedMemoryUsedAgentId(agentId); + joinDirectBufferBo.setMaxMappedMemoryUsed(tFDirectBuffer.getMappedMemoryUsed()); + + return joinDirectBufferBo; + } +} diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinFileDescriptorBoMapper.java b/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinFileDescriptorBoMapper.java new file mode 100644 index 000000000000..5b4546838dab --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinFileDescriptorBoMapper.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.flink.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinFileDescriptorBo; +import com.navercorp.pinpoint.flink.mapper.thrift.ThriftBoMapper; +import com.navercorp.pinpoint.thrift.dto.flink.TFAgentStat; +import com.navercorp.pinpoint.thrift.dto.flink.TFFileDescriptor; + +/** + * @author Roy Kim + */ +public class JoinFileDescriptorBoMapper implements ThriftBoMapper { + + @Override + public JoinFileDescriptorBo map(TFAgentStat tFAgentStat) { + if (!tFAgentStat.isSetFileDescriptor()) { + return JoinFileDescriptorBo.EMPTY_JOIN_FILE_DESCRIPTOR_BO; + } + + JoinFileDescriptorBo joinFileDescriptorBo = new JoinFileDescriptorBo(); + + final String agentId = tFAgentStat.getAgentId(); + joinFileDescriptorBo.setId(agentId); + joinFileDescriptorBo.setTimestamp(tFAgentStat.getTimestamp()); + + TFFileDescriptor tFFileDescriptor = tFAgentStat.getFileDescriptor(); + joinFileDescriptorBo.setAvgOpenFDCount(tFFileDescriptor.getOpenFileDescriptorCount()); + joinFileDescriptorBo.setMinOpenFDCountAgentId(agentId); + joinFileDescriptorBo.setMinOpenFDCount(tFFileDescriptor.getOpenFileDescriptorCount()); + joinFileDescriptorBo.setMaxOpenFDCountAgentId(agentId); + joinFileDescriptorBo.setMaxOpenFDCount(tFFileDescriptor.getOpenFileDescriptorCount()); + + return joinFileDescriptorBo; + } +} diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/process/ApplicationCache.java b/flink/src/main/java/com/navercorp/pinpoint/flink/process/ApplicationCache.java index c24a5930a5fa..ac1aaddbce79 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/process/ApplicationCache.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/process/ApplicationCache.java @@ -17,10 +17,12 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseTemplate2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.util.RowKeyUtils; import com.navercorp.pinpoint.common.util.TimeUtils; import com.navercorp.pinpoint.web.mapper.AgentInfoMapper; import com.navercorp.pinpoint.web.vo.AgentInfo; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; @@ -42,9 +44,11 @@ public class ApplicationCache { private final transient HbaseTemplate2 hbaseTemplate2; + private final transient TableNameProvider tableNameProvider; - public ApplicationCache(HbaseTemplate2 hbaseTemplate2) { + public ApplicationCache(HbaseTemplate2 hbaseTemplate2, TableNameProvider tableNameProvider) { this.hbaseTemplate2 = Objects.requireNonNull(hbaseTemplate2, "hbaseTemplate must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); } @Cacheable(value="applicationId", key=SPEL_KEY) @@ -57,7 +61,8 @@ public String findApplicationId(ApplicationKey application) { get.addColumn(HBaseTables.AGENTINFO_CF_INFO, HBaseTables.AGENTINFO_CF_INFO_IDENTIFIER); AgentInfo agentInfo = null; try { - agentInfo = hbaseTemplate2.get(HBaseTables.AGENTINFO, get, agentInfoMapper); + TableName tableName = tableNameProvider.getTableName(HBaseTables.AGENTINFO_STR); + agentInfo = hbaseTemplate2.get(tableName, get, agentInfoMapper); } catch (Exception e) { logger.error("can't found application id({})", agentId, e); } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/process/DefaultTBaseFlatMapperInterceptor.java b/flink/src/main/java/com/navercorp/pinpoint/flink/process/DefaultTBaseFlatMapperInterceptor.java new file mode 100644 index 000000000000..8fbad50b1d42 --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/process/DefaultTBaseFlatMapperInterceptor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.process; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import com.navercorp.pinpoint.flink.vo.RawData; +import com.navercorp.pinpoint.io.request.ServerRequest; +import org.apache.flink.api.java.tuple.Tuple3; + +import java.util.List; + +/** + * @author minwoo.jung + */ +public class DefaultTBaseFlatMapperInterceptor implements TBaseFlatMapperInterceptor { + + @Override + public void before(RawData rawData) { + } + + @Override + public void after() { + } + + @Override + public List> middle(List> outData) { + return outData; + } +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/process/TBaseFlatMapper.java b/flink/src/main/java/com/navercorp/pinpoint/flink/process/TBaseFlatMapper.java new file mode 100644 index 000000000000..7cdc2f2b69dd --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/process/TBaseFlatMapper.java @@ -0,0 +1,134 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.process; + +import com.navercorp.pinpoint.common.server.bo.stat.join.*; +import com.navercorp.pinpoint.flink.Bootstrap; +import com.navercorp.pinpoint.flink.function.ApplicationStatBoWindow; +import com.navercorp.pinpoint.flink.mapper.thrift.stat.JoinAgentStatBoMapper; +import com.navercorp.pinpoint.flink.vo.RawData; +import com.navercorp.pinpoint.thrift.dto.flink.TFAgentStatBatch; +import org.apache.flink.api.common.functions.RichFlatMapFunction; +import org.apache.flink.api.java.tuple.Tuple3; + +import org.apache.flink.configuration.Configuration; +import org.apache.flink.util.Collector; +import org.apache.thrift.TBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author minwoo.jung + */ +public class TBaseFlatMapper extends RichFlatMapFunction> { + private final static List> EMPTY_LIST = Collections.emptyList(); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private transient JoinAgentStatBoMapper joinAgentStatBoMapper; + private transient ApplicationCache applicationCache; + private transient TBaseFlatMapperInterceptor tBaseFlatMapperInterceptor; + + + public TBaseFlatMapper() { + } + + public TBaseFlatMapper(JoinAgentStatBoMapper joinAgentStatBoMapper, ApplicationCache applicationCache, TBaseFlatMapperInterceptor tBaseFlatMapperInterceptor) { + this.joinAgentStatBoMapper = joinAgentStatBoMapper; + this.applicationCache = applicationCache; + this.tBaseFlatMapperInterceptor = tBaseFlatMapperInterceptor; + } + + public void open(Configuration parameters) throws Exception { + this.joinAgentStatBoMapper = new JoinAgentStatBoMapper(); + Bootstrap bootstrap = Bootstrap.getInstance(); + applicationCache = bootstrap.getApplicationCache(); + tBaseFlatMapperInterceptor = bootstrap.getTbaseFlatMapperInterceptor(); + } + + @Override + public void flatMap(RawData rawData, Collector> out) throws Exception { + final Object data = rawData.getData(); + if (!(data instanceof TBase)) { + logger.error("data is not TBase type {}", data); + return; + } + + TBase tBase = (TBase) data; + + tBaseFlatMapperInterceptor.before(rawData); + + try { + List> outData = serverRequestFlatMap(tBase); + if (outData.size() == 0) { + return; + } + + outData = tBaseFlatMapperInterceptor.middle(outData); + + for (Tuple3 tuple : outData) { + out.collect(tuple); + } + } finally { + tBaseFlatMapperInterceptor.after(); + } + } + + private List> serverRequestFlatMap(TBase tBase) { + List> outData = new ArrayList<>(5); + + if (tBase instanceof TFAgentStatBatch) { + if (logger.isDebugEnabled()) { + logger.debug("raw data : {}", tBase); + } + final TFAgentStatBatch tFAgentStatBatch = (TFAgentStatBatch) tBase; + final JoinAgentStatBo joinAgentStatBo; + try { + joinAgentStatBo = joinAgentStatBoMapper.map(tFAgentStatBatch); + + if (joinAgentStatBo == JoinAgentStatBo.EMPTY_JOIN_AGENT_STAT_BO) { + return EMPTY_LIST; + } + } catch (Exception e) { + logger.error("can't create joinAgentStatBo object {}", tFAgentStatBatch, e); + return EMPTY_LIST; + } + + outData.add(new Tuple3(joinAgentStatBo.getId(), joinAgentStatBo, joinAgentStatBo.getTimestamp())); + + final ApplicationCache.ApplicationKey applicationKey = new ApplicationCache.ApplicationKey(joinAgentStatBo.getId(), joinAgentStatBo.getAgentStartTimestamp()); + final String applicationId = applicationCache.findApplicationId(applicationKey); + + if (applicationId.equals(ApplicationCache.NOT_FOUND_APP_ID)) { + logger.warn("can't found application id. agent id : {}, start time : {}.",joinAgentStatBo.getId(), joinAgentStatBo.getTimestamp()); + return EMPTY_LIST; + } + + List joinApplicationStatBoList = JoinApplicationStatBo.createJoinApplicationStatBo(applicationId, joinAgentStatBo, ApplicationStatBoWindow.WINDOW_SIZE); + + for (JoinApplicationStatBo joinApplicationStatBo : joinApplicationStatBoList) { + outData.add(new Tuple3(applicationId, joinApplicationStatBo, joinApplicationStatBo.getTimestamp())); + } + } + + return outData; + } + +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/process/TBaseFlatMapperInterceptor.java b/flink/src/main/java/com/navercorp/pinpoint/flink/process/TBaseFlatMapperInterceptor.java new file mode 100644 index 000000000000..dd17b09fd850 --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/process/TBaseFlatMapperInterceptor.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.process; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinStatBo; +import com.navercorp.pinpoint.flink.vo.RawData; +import org.apache.flink.api.java.tuple.Tuple3; + +import java.util.List; + +/** + * @author minwoo.jung + */ +public interface TBaseFlatMapperInterceptor { + + void before(RawData rawData); + + void after(); + + List> middle(List> outData); +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/process/TbaseFlatMapper.java b/flink/src/main/java/com/navercorp/pinpoint/flink/process/TbaseFlatMapper.java deleted file mode 100644 index 6b936dc2a6ed..000000000000 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/process/TbaseFlatMapper.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.flink.process; - -import com.navercorp.pinpoint.common.server.bo.stat.join.*; -import com.navercorp.pinpoint.flink.Bootstrap; -import com.navercorp.pinpoint.flink.function.ApplicationStatBoWindow; -import com.navercorp.pinpoint.flink.mapper.thrift.stat.JoinAgentStatBoMapper; -import com.navercorp.pinpoint.thrift.dto.flink.TFAgentStatBatch; -import org.apache.flink.api.common.functions.RichFlatMapFunction; -import org.apache.flink.api.java.tuple.Tuple3; - -import org.apache.flink.configuration.Configuration; -import org.apache.flink.util.Collector; -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; - -/** - * @author minwoo.jung - */ -public class TbaseFlatMapper extends RichFlatMapFunction> { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private transient JoinAgentStatBoMapper joinAgentStatBoMapper; - private transient ApplicationCache applicationCache; - - public TbaseFlatMapper() { - } - - public TbaseFlatMapper(JoinAgentStatBoMapper joinAgentStatBoMapper, ApplicationCache applicationCache) { - this.joinAgentStatBoMapper = joinAgentStatBoMapper; - this.applicationCache = applicationCache; - } - - public void open(Configuration parameters) throws Exception { - this.joinAgentStatBoMapper = new JoinAgentStatBoMapper(); - applicationCache = Bootstrap.getInstance().getApplicationCache(); - } - - @Override - public void flatMap(TBase tBase, Collector> out) throws Exception { - if (tBase instanceof TFAgentStatBatch) { - if (logger.isDebugEnabled()) { - logger.debug("raw data : {}", tBase); - } - final TFAgentStatBatch tFAgentStatBatch = (TFAgentStatBatch) tBase; - final JoinAgentStatBo joinAgentStatBo; - try { - joinAgentStatBo = joinAgentStatBoMapper.map(tFAgentStatBatch); - - if (joinAgentStatBo == JoinAgentStatBo.EMPTY_JOIN_AGENT_STAT_BO) { - return; - } - } catch (Exception e) { - logger.error("can't create joinAgentStatBo object {}", tFAgentStatBatch, e); - return; - } - - out.collect(new Tuple3(joinAgentStatBo.getId(), joinAgentStatBo, joinAgentStatBo.getTimestamp())); - - final ApplicationCache.ApplicationKey applicationKey = new ApplicationCache.ApplicationKey(joinAgentStatBo.getId(), joinAgentStatBo.getAgentStartTimestamp()); - final String applicationId = applicationCache.findApplicationId(applicationKey); - - if (applicationId.equals(ApplicationCache.NOT_FOUND_APP_ID)) { - logger.warn("can't found application id"); - return; - } - - List joinApplicationStatBoList = JoinApplicationStatBo.createJoinApplicationStatBo(applicationId, joinAgentStatBo, ApplicationStatBoWindow.WINDOW_SIZE); - - for (JoinApplicationStatBo joinApplicationStatBo : joinApplicationStatBoList) { - out.collect(new Tuple3(applicationId, joinApplicationStatBo, joinApplicationStatBo.getTimestamp())); - } - } - } -} diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/AddressFilterAdaptor.java b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/AddressFilterAdaptor.java deleted file mode 100644 index 7b6b0182cc55..000000000000 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/AddressFilterAdaptor.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.flink.receiver; - -import com.navercorp.pinpoint.common.server.util.AddressFilter; -import com.navercorp.pinpoint.rpc.server.ChannelFilter; -import org.jboss.netty.channel.Channel; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Objects; - -/** - * @author Woonduk Kang(emeroad) - */ -public class AddressFilterAdaptor implements ChannelFilter { - private final AddressFilter filter; - - public AddressFilterAdaptor(AddressFilter filter) { - this.filter = Objects.requireNonNull(filter, "filter must not be null"); - } - - @Override - public boolean accept(Channel channel) { - final InetSocketAddress remoteAddress = (InetSocketAddress) channel.getRemoteAddress(); - if (remoteAddress == null) { - return true; - } - InetAddress address = remoteAddress.getAddress(); - return filter.accept(address); - } -} diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/AgentStatHandler.java b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/AgentStatHandler.java index 09332acc49aa..7fc6f8a58cb9 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/AgentStatHandler.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/AgentStatHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,9 +17,13 @@ import com.navercorp.pinpoint.collector.handler.SimpleHandler; +import com.navercorp.pinpoint.flink.vo.RawData; +import com.navercorp.pinpoint.io.request.ServerRequest; import org.apache.flink.streaming.api.functions.source.SourceFunction.SourceContext; import org.apache.thrift.TBase; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; /** @@ -34,8 +38,14 @@ public AgentStatHandler(SourceContext sourceContext) { } @Override - public void handleSimple(TBase tBase) { - sourceContext.collect(tBase); + public void handleSimple(ServerRequest serverRequest) { + if (!(serverRequest.getData() instanceof TBase)) { + throw new UnsupportedOperationException("data is not support type : " + serverRequest.getData()); + } + final TBase tBase = (TBase) serverRequest.getData(); + final Map metaInfo = new HashMap<>(serverRequest.getHeaderEntity().getEntityAll()); + + RawData rawData = new RawData(tBase, metaInfo); + sourceContext.collect(rawData); } - } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/FlinkPacketHandlerFactory.java b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/FlinkPacketHandlerFactory.java new file mode 100644 index 000000000000..d261301dfad1 --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/FlinkPacketHandlerFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.flink.receiver; + +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.collector.receiver.thrift.tcp.DefaultTCPPacketHandler; +import com.navercorp.pinpoint.collector.receiver.thrift.tcp.TCPPacketHandler; +import com.navercorp.pinpoint.collector.receiver.thrift.tcp.TCPPacketHandlerFactory; +import com.navercorp.pinpoint.thrift.io.*; + +import java.util.Objects; + +/** + * @author Woonduk Kang(emeroad) + */ +public class FlinkPacketHandlerFactory implements TCPPacketHandlerFactory { + + private final SerializerFactory cachedSerializer; + private final DeserializerFactory cachedDeserializer; + + public FlinkPacketHandlerFactory(HeaderTBaseSerializerFactory flinkHeaderTBaseSerializerFactory, FlinkHeaderTBaseDeserializerFactory flinkHeaderTBaseDeserializerFactory) { + Objects.requireNonNull(flinkHeaderTBaseSerializerFactory, "flinkHeaderTBaseSerializerFactory must be not null."); + Objects.requireNonNull(flinkHeaderTBaseDeserializerFactory, "flinkHeaderTBaseDeserializerFactory must be not null."); + + SerializerFactory cachedSerializer = new ThreadLocalHeaderTBaseSerializerFactory<>(flinkHeaderTBaseSerializerFactory); + this.cachedSerializer = cachedSerializer; + + DeserializerFactory cachedDeserializer = new ThreadLocalHeaderTBaseDeserializerFactory<>(flinkHeaderTBaseDeserializerFactory); + this.cachedDeserializer = cachedDeserializer; + } + + @Override + public TCPPacketHandler build(DispatchHandler dispatchHandler) { + Objects.requireNonNull(dispatchHandler, "dispatchHandler must not be null"); + return new DefaultTCPPacketHandler(dispatchHandler, cachedSerializer, cachedDeserializer); + } +} \ No newline at end of file diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TCPReceiver.java b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TCPReceiver.java deleted file mode 100644 index c8e0b8a0eaf2..000000000000 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TCPReceiver.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.flink.receiver; - -import com.navercorp.pinpoint.collector.receiver.DispatchHandler; -import com.navercorp.pinpoint.collector.receiver.DispatchWorker; -import com.navercorp.pinpoint.collector.receiver.tcp.SendPacketHandler; -import com.navercorp.pinpoint.common.server.util.IgnoreAddressFilter; -import com.navercorp.pinpoint.common.server.util.AddressFilter; -import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; -import com.navercorp.pinpoint.rpc.packet.SendPacket; -import com.navercorp.pinpoint.rpc.server.ChannelFilter; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.ServerMessageListener; -import com.navercorp.pinpoint.thrift.io.FlinkHeaderTBaseDeserializerFactory; -import com.navercorp.pinpoint.thrift.io.ThreadLocalHeaderTBaseDeserializerFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * @author emeroad - * @author koo.taejin - */ -public class TCPReceiver { - - private final Logger logger = LoggerFactory.getLogger(TCPReceiver.class); - - private final String bindIp; - private final int bindPort; - - private PinpointServerAcceptor serverAcceptor; - - private final DispatchWorker worker; - private final SendPacketHandler sendPacketHandler; - - private final AddressFilter ignoreAddressFilter; - - public TCPReceiver(DispatchHandler dispatchHandler, DispatchWorker worker, String bindIp, int bindPort, List ignoreAddressList) { - this.bindIp = Objects.requireNonNull(bindIp, "bindIp must not be null"); - Assert.isTrue(bindPort > 0, "bindPort must be greater than 0"); - this.bindPort = bindPort; - - this.worker = Objects.requireNonNull(worker, "worker must not be null"); - - Objects.requireNonNull(dispatchHandler, " must not be null"); - this.sendPacketHandler = new SendPacketHandler(dispatchHandler, new ThreadLocalHeaderTBaseDeserializerFactory<>(new FlinkHeaderTBaseDeserializerFactory())); - - this.ignoreAddressFilter = new IgnoreAddressFilter(ignoreAddressList); - } - - @PostConstruct - public void start() { - ChannelFilter connectedFilter = new AddressFilterAdaptor(ignoreAddressFilter); - PinpointServerAcceptor acceptor = new PinpointServerAcceptor(connectedFilter); - // take care when attaching message handlers as events are generated from the IO thread. - // pass them to a separate queue and handle them in a different thread. - acceptor.setMessageListener(new ServerMessageListener() { - - @Override - public HandshakeResponseCode handleHandshake(Map properties) { - return HandshakeResponseType.Success.SIMPLEX_COMMUNICATION; - } - - @Override - public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { - receive(sendPacket, pinpointSocket); - } - - @Override - public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - requestResponse(requestPacket, pinpointSocket); - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - } - }); - acceptor.bind(bindIp, bindPort); - this.serverAcceptor = acceptor; - } - - private void receive(SendPacket sendPacket, PinpointSocket pinpointSocket) { - worker.execute(new Runnable() { - @Override - public void run() { - sendPacketHandler.handle(sendPacket, pinpointSocket); - } - }); - } - - private void requestResponse(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - logger.warn("Not support requestResponse"); - } - - @PreDestroy - public void stop() { - logger.info("Pinpoint-TCP-Server stop"); - if (serverAcceptor != null) { - serverAcceptor.close(); - } - } - -} diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TcpDispatchHandler.java b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TcpDispatchHandler.java index 18a3520021e7..86411f6ca8e4 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TcpDispatchHandler.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TcpDispatchHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,34 +16,44 @@ package com.navercorp.pinpoint.flink.receiver; import com.navercorp.pinpoint.collector.handler.SimpleHandler; -import com.navercorp.pinpoint.collector.receiver.AbstractDispatchHandler; -import com.navercorp.pinpoint.thrift.dto.flink.TFAgentStatBatch; -import org.apache.thrift.TBase; +import com.navercorp.pinpoint.collector.receiver.thrift.DispatchHandler; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.request.ServerResponse; +import com.navercorp.pinpoint.thrift.io.FlinkTBaseLocator; -import java.util.ArrayList; -import java.util.List; import java.util.Objects; /** * @author minwoo.jung */ -public class TcpDispatchHandler extends AbstractDispatchHandler { +public class TcpDispatchHandler implements DispatchHandler { private AgentStatHandler agentStatHandler; - @Override - protected List getSimpleHandler(TBase tBase) { - List handlerList = new ArrayList<>(); - - if (tBase instanceof TFAgentStatBatch) { - handlerList.add(agentStatHandler); + private SimpleHandler getSimpleHandler(Header header) { + if (header.getType() == FlinkTBaseLocator.AGENT_STAT_BATCH) { + return agentStatHandler; } + throw new UnsupportedOperationException("unsupported header:" + header); + } - return handlerList; + private SimpleHandler getSimpleHandler(ServerRequest serverRequest) { + final Header header = serverRequest.getHeader(); + return getSimpleHandler(header); } public void setAgentStatHandler(AgentStatHandler agentStatHandler) { this.agentStatHandler = Objects.requireNonNull(agentStatHandler, "agentStatHandler must not be null"); } + @Override + public void dispatchSendMessage(ServerRequest serverRequest) { + SimpleHandler simpleHandler = getSimpleHandler(serverRequest); + simpleHandler.handleSimple(serverRequest); + } + + @Override + public void dispatchRequestMessage(ServerRequest serverRequest, ServerResponse serverResponse) { + } } diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TcpSourceFunction.java b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TcpSourceFunction.java index 2882a2206132..9b4e0947b5d5 100644 --- a/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TcpSourceFunction.java +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/receiver/TcpSourceFunction.java @@ -16,9 +16,9 @@ package com.navercorp.pinpoint.flink.receiver; import com.navercorp.pinpoint.flink.Bootstrap; -import com.navercorp.pinpoint.flink.cluster.FlinkServerRegister; +import com.navercorp.pinpoint.flink.vo.RawData; +import com.navercorp.pinpoint.io.request.ServerRequest; import org.apache.flink.streaming.api.functions.source.ParallelSourceFunction; -import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; @@ -27,18 +27,16 @@ /** * @author minwoo.jung */ -public class TcpSourceFunction implements ParallelSourceFunction { +public class TcpSourceFunction implements ParallelSourceFunction { private final Logger logger = LoggerFactory.getLogger(TcpSourceFunction.class); - private FlinkServerRegister flinkServerRegister; - private TCPReceiver tcpReceiver; @Override - public void run(SourceContext ctx) throws Exception { + public void run(SourceContext ctx) throws Exception { final Bootstrap bootstrap = Bootstrap.getInstance(); bootstrap.setStatHandlerTcpDispatchHandler(ctx); bootstrap.initFlinkServerRegister(); - tcpReceiver = bootstrap.initTcpReceiver(); + bootstrap.initTcpReceiver(); Thread.sleep(Long.MAX_VALUE); } @@ -47,13 +45,6 @@ public void run(SourceContext ctx) throws Exception { public void cancel() { logger.info("cancel TcpSourceFunction."); - if (flinkServerRegister != null) { - flinkServerRegister.stop(); - } - if (tcpReceiver != null) { - tcpReceiver.stop(); - } - ApplicationContext applicationContext = Bootstrap.getInstance().getApplicationContext(); if (applicationContext != null) { ((ConfigurableApplicationContext) applicationContext).close(); diff --git a/flink/src/main/java/com/navercorp/pinpoint/flink/vo/RawData.java b/flink/src/main/java/com/navercorp/pinpoint/flink/vo/RawData.java new file mode 100644 index 000000000000..fe4ad857a2b5 --- /dev/null +++ b/flink/src/main/java/com/navercorp/pinpoint/flink/vo/RawData.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.flink.vo; + +import org.apache.thrift.TBase; + +import java.util.Map; +import java.util.Objects; + +/** + * @author minwoo.jung + */ +public class RawData { + + private final TBase data; + private final Map metaInfo; + + public RawData(TBase data, Map metaInfo) { + this.data = Objects.requireNonNull(data, "data must not be null"); + this.metaInfo = Objects.requireNonNull(metaInfo, "metaInfo must not be null"); + } + + public TBase getData() { + return data; + } + + public String getMetaInfo(String key) { + return metaInfo.get(key); + } + +} diff --git a/flink/src/main/resources/applicationContext-flink-extend.xml b/flink/src/main/resources/applicationContext-flink-extend.xml new file mode 100644 index 000000000000..9f482d1dcd6c --- /dev/null +++ b/flink/src/main/resources/applicationContext-flink-extend.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/flink/src/main/resources/applicationContext-flink.xml b/flink/src/main/resources/applicationContext-flink.xml index 626a856584c5..bbdb2697f6b5 100644 --- a/flink/src/main/resources/applicationContext-flink.xml +++ b/flink/src/main/resources/applicationContext-flink.xml @@ -1,4 +1,20 @@ + + + +
- + - + + @@ -76,7 +95,12 @@ - + + + + + + @@ -86,36 +110,56 @@ + + + + + + + + + + + + + + + + + + + + @@ -123,40 +167,74 @@ - + + + + + + + + + + + + + + + + + + - + - - - - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - -
\ No newline at end of file diff --git a/flink/src/main/resources/applicationContext-hbase.xml b/flink/src/main/resources/applicationContext-hbase.xml index 0e0f62cf2a91..4eafd3511942 100644 --- a/flink/src/main/resources/applicationContext-hbase.xml +++ b/flink/src/main/resources/applicationContext-hbase.xml @@ -1,32 +1,7 @@ - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> @@ -50,7 +25,7 @@ ${hbase.client.async.enable:false} ${hbase.client.async.in.queuesize:10000} ${hbase.client.async.flush.period.ms:100} - ${hbase.client.async.max.retries.in.queue:10} + ${hbase.client.async.max.retries.in.queue:10000} @@ -66,14 +41,18 @@ - - - + + + + + + + - - + + @@ -82,12 +61,16 @@ - + - - + + + + + + diff --git a/flink/src/main/resources/hbase.properties b/flink/src/main/resources/hbase.properties index 8dbd9ff5090d..78081d74439c 100644 --- a/flink/src/main/resources/hbase.properties +++ b/flink/src/main/resources/hbase.properties @@ -21,6 +21,9 @@ hbase.client.port=2181 # hbase default:/hbase hbase.zookeeper.znode.parent=/hbase +# hbase namespace to use default:default +hbase.namespace=default + # hbase timeout option================================================================================== # hbase default:true hbase.ipc.client.tcpnodelay=true diff --git a/flink/src/test/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDirectBufferBoMapperTest.java b/flink/src/test/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDirectBufferBoMapperTest.java new file mode 100644 index 000000000000..6ecb83a7e0c4 --- /dev/null +++ b/flink/src/test/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinDirectBufferBoMapperTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.flink.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinDirectBufferBo; +import com.navercorp.pinpoint.thrift.dto.flink.TFAgentStat; +import com.navercorp.pinpoint.thrift.dto.flink.TFDirectBuffer; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * @author Roy Kim + */ +public class JoinDirectBufferBoMapperTest { + @Test + public void mapTest() throws Exception { + final TFAgentStat tFAgentStat = new TFAgentStat(); + tFAgentStat.setAgentId("testAgent"); + tFAgentStat.setTimestamp(1491274138454L); + + final TFDirectBuffer tfDirectBuffer = new TFDirectBuffer(); + tfDirectBuffer.setDirectCount(10); + tfDirectBuffer.setDirectMemoryUsed(11); + tfDirectBuffer.setMappedCount(12); + tfDirectBuffer.setMappedMemoryUsed(13); + tFAgentStat.setDirectBuffer(tfDirectBuffer); + + final JoinDirectBufferBoMapper mapper = new JoinDirectBufferBoMapper(); + final JoinDirectBufferBo joinDirectBufferBo = mapper.map(tFAgentStat); + + assertNotNull(joinDirectBufferBo); + assertEquals(joinDirectBufferBo.getId(), "testAgent"); + assertEquals(joinDirectBufferBo.getTimestamp(), 1491274138454L); + assertEquals(joinDirectBufferBo.getAvgDirectCount(), 10, 0); + assertEquals(joinDirectBufferBo.getMinDirectCount(), 10, 0); + assertEquals(joinDirectBufferBo.getMaxDirectCount(), 10, 0); + assertEquals(joinDirectBufferBo.getAvgDirectMemoryUsed(), 11, 0); + assertEquals(joinDirectBufferBo.getMinDirectMemoryUsed(), 11, 0); + assertEquals(joinDirectBufferBo.getMaxDirectMemoryUsed(), 11, 0); + assertEquals(joinDirectBufferBo.getAvgMappedCount(), 12, 0); + assertEquals(joinDirectBufferBo.getMinMappedCount(), 12, 0); + assertEquals(joinDirectBufferBo.getMaxMappedCount(), 12, 0); + assertEquals(joinDirectBufferBo.getAvgMappedMemoryUsed(), 13, 0); + assertEquals(joinDirectBufferBo.getMinMappedMemoryUsed(), 13, 0); + assertEquals(joinDirectBufferBo.getMaxMappedMemoryUsed(), 13, 0); + } + + @Test + public void map2Test() { + final TFAgentStat tFAgentStat = new TFAgentStat(); + tFAgentStat.setAgentId("testAgent"); + tFAgentStat.setTimestamp(1491274138454L); + + final JoinDirectBufferBoMapper mapper = new JoinDirectBufferBoMapper(); + final JoinDirectBufferBo joinDirectBufferBo = mapper.map(tFAgentStat); + assertEquals(joinDirectBufferBo, joinDirectBufferBo.EMPTY_JOIN_DIRECT_BUFFER_BO); + } +} \ No newline at end of file diff --git a/flink/src/test/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinFileDescriptorBoMapperTest.java b/flink/src/test/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinFileDescriptorBoMapperTest.java new file mode 100644 index 000000000000..51be74a47cb3 --- /dev/null +++ b/flink/src/test/java/com/navercorp/pinpoint/flink/mapper/thrift/stat/JoinFileDescriptorBoMapperTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.flink.mapper.thrift.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinFileDescriptorBo; +import com.navercorp.pinpoint.thrift.dto.flink.TFAgentStat; +import com.navercorp.pinpoint.thrift.dto.flink.TFFileDescriptor; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * @author Roy Kim + */ +public class JoinFileDescriptorBoMapperTest { + @Test + public void mapTest() throws Exception { + final TFAgentStat tFAgentStat = new TFAgentStat(); + tFAgentStat.setAgentId("testAgent"); + tFAgentStat.setTimestamp(1491274138454L); + + final TFFileDescriptor tfFileDescriptor = new TFFileDescriptor(); + tfFileDescriptor.setOpenFileDescriptorCount(10); + tFAgentStat.setFileDescriptor(tfFileDescriptor); + + final JoinFileDescriptorBoMapper mapper = new JoinFileDescriptorBoMapper(); + final JoinFileDescriptorBo joinFileDescriptorBo = mapper.map(tFAgentStat); + + assertNotNull(joinFileDescriptorBo); + assertEquals(joinFileDescriptorBo.getId(), "testAgent"); + assertEquals(joinFileDescriptorBo.getTimestamp(), 1491274138454L); + assertEquals(joinFileDescriptorBo.getAvgOpenFDCount(), 10, 0); + assertEquals(joinFileDescriptorBo.getMinOpenFDCount(), 10, 0); + assertEquals(joinFileDescriptorBo.getMaxOpenFDCount(), 10, 0); + } + + @Test + public void map2Test() { + final TFAgentStat tFAgentStat = new TFAgentStat(); + tFAgentStat.setAgentId("testAgent"); + tFAgentStat.setTimestamp(1491274138454L); + + final JoinFileDescriptorBoMapper mapper = new JoinFileDescriptorBoMapper(); + final JoinFileDescriptorBo joinFileDescriptorBo = mapper.map(tFAgentStat); + assertEquals(joinFileDescriptorBo, joinFileDescriptorBo.EMPTY_JOIN_FILE_DESCRIPTOR_BO); + } +} \ No newline at end of file diff --git a/flink/src/test/java/com/navercorp/pinpoint/flink/process/TBaseFlatMapperTest.java b/flink/src/test/java/com/navercorp/pinpoint/flink/process/TBaseFlatMapperTest.java new file mode 100644 index 000000000000..dbb91ebb48d6 --- /dev/null +++ b/flink/src/test/java/com/navercorp/pinpoint/flink/process/TBaseFlatMapperTest.java @@ -0,0 +1,498 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.flink.process; + +import com.navercorp.pinpoint.common.server.bo.stat.join.*; +import com.navercorp.pinpoint.flink.mapper.thrift.stat.JoinAgentStatBoMapper; +import com.navercorp.pinpoint.flink.vo.RawData; +import com.navercorp.pinpoint.thrift.dto.flink.*; +import org.apache.flink.api.common.functions.util.ListCollector; +import org.apache.flink.api.java.tuple.Tuple3; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +/** + * @author minwoo.jung + */ +public class TBaseFlatMapperTest { + final static String AGENT_ID = "testAgent"; + final static String APPLICATION_ID = "testApplication"; + + @Test + public void flatMapTest() throws Exception { + + ApplicationCache applicationCache = newMockApplicationCache(); + TBaseFlatMapper mapper = new TBaseFlatMapper(new JoinAgentStatBoMapper(), applicationCache, new DefaultTBaseFlatMapperInterceptor()); + + + TFAgentStatBatch tfAgentStatBatch = createTFAgentStatBatch(); + ArrayList> dataList = new ArrayList<>(); + ListCollector> collector = new ListCollector<>(dataList); + RawData rawData = newRawData(tfAgentStatBatch); + mapper.flatMap(rawData, collector); + + assertEquals(dataList.size(), 2); + + Tuple3 data1 = dataList.get(0); + assertEquals(data1.f0, AGENT_ID); + assertEquals(data1.f2.longValue(), 1491274143454L); + JoinAgentStatBo joinAgentStatBo = (JoinAgentStatBo) data1.f1; + assertEquals(joinAgentStatBo.getId(), AGENT_ID); + assertEquals(joinAgentStatBo.getAgentStartTimestamp(), 1491274142454L); + assertEquals(joinAgentStatBo.getTimestamp(), 1491274143454L); + assertJoinCpuLoadBo(joinAgentStatBo.getJoinCpuLoadBoList()); + + Tuple3 data2 = dataList.get(1); + assertEquals(data2.f0, APPLICATION_ID); + assertEquals(data2.f2.longValue(), 1491274140000L); + JoinApplicationStatBo joinApplicationStatBo = (JoinApplicationStatBo) data2.f1; + assertEquals(joinApplicationStatBo.getId(), APPLICATION_ID); + assertEquals(joinApplicationStatBo.getTimestamp(), 1491274140000L); + assertEquals(joinApplicationStatBo.getStatType(), StatType.APP_STST); + assertJoinCpuLoadBo(joinApplicationStatBo.getJoinCpuLoadBoList()); + } + + private ApplicationCache newMockApplicationCache() { + ApplicationCache applicationCache = mock(ApplicationCache.class); + when(applicationCache.findApplicationId(any(ApplicationCache.ApplicationKey.class))) + .thenReturn(APPLICATION_ID); + return applicationCache; + } + + private void assertJoinCpuLoadBo(List joincpulaodBoList) { + assertEquals(2, joincpulaodBoList.size()); + JoinCpuLoadBo joinCpuLoadBo = joincpulaodBoList.get(0); + assertEquals(joinCpuLoadBo.getId(), AGENT_ID); + assertEquals(joinCpuLoadBo.getTimestamp(), 1491274143454L); + assertEquals(joinCpuLoadBo.getJvmCpuLoad(), 10, 0); + assertEquals(joinCpuLoadBo.getMinJvmCpuLoad(), 10, 0); + assertEquals(joinCpuLoadBo.getMaxJvmCpuLoad(), 10, 0); + assertEquals(joinCpuLoadBo.getSystemCpuLoad(), 30, 0); + assertEquals(joinCpuLoadBo.getMinSystemCpuLoad(), 30, 0); + assertEquals(joinCpuLoadBo.getMaxSystemCpuLoad(), 30, 0); + joinCpuLoadBo = joincpulaodBoList.get(1); + assertEquals(joinCpuLoadBo.getId(), AGENT_ID); + assertEquals(joinCpuLoadBo.getTimestamp(), 1491274148454L); + assertEquals(joinCpuLoadBo.getJvmCpuLoad(), 20, 0); + assertEquals(joinCpuLoadBo.getMinJvmCpuLoad(), 20, 0); + assertEquals(joinCpuLoadBo.getMaxJvmCpuLoad(), 20, 0); + assertEquals(joinCpuLoadBo.getSystemCpuLoad(), 50, 0); + assertEquals(joinCpuLoadBo.getMinSystemCpuLoad(), 50, 0); + assertEquals(joinCpuLoadBo.getMaxSystemCpuLoad(), 50, 0); + } + + private TFAgentStatBatch createTFAgentStatBatch() { + final TFAgentStatBatch tFAgentStatBatch = new TFAgentStatBatch(); + tFAgentStatBatch.setStartTimestamp(1491274142454L); + tFAgentStatBatch.setAgentId(AGENT_ID); + + final TFAgentStat tFAgentStat = new TFAgentStat(); + tFAgentStat.setAgentId(AGENT_ID); + tFAgentStat.setTimestamp(1491274143454L); + + final TFCpuLoad tFCpuLoad = new TFCpuLoad(); + tFCpuLoad.setJvmCpuLoad(10); + tFCpuLoad.setSystemCpuLoad(30); + tFAgentStat.setCpuLoad(tFCpuLoad); + + final TFAgentStat tFAgentStat2 = new TFAgentStat(); + tFAgentStat2.setAgentId(AGENT_ID); + tFAgentStat2.setTimestamp(1491274148454L); + + final TFCpuLoad tFCpuLoad2 = new TFCpuLoad(); + tFCpuLoad2.setJvmCpuLoad(20); + tFCpuLoad2.setSystemCpuLoad(50); + tFAgentStat2.setCpuLoad(tFCpuLoad2); + + final List tFAgentStatList = new ArrayList<>(2); + tFAgentStatList.add(tFAgentStat); + tFAgentStatList.add(tFAgentStat2); + tFAgentStatBatch.setAgentStats(tFAgentStatList); + + return tFAgentStatBatch; + } + + + + @Test + public void flatMap2Test() throws Exception { + ApplicationCache applicationCache = newMockApplicationCache(); + TBaseFlatMapper mapper = new TBaseFlatMapper(new JoinAgentStatBoMapper(), applicationCache, new DefaultTBaseFlatMapperInterceptor()); + + TFAgentStatBatch tfAgentStatBatch = createTFAgentStatBatch2(); + ArrayList> dataList = new ArrayList<>(); + ListCollector> collector = new ListCollector<>(dataList); + RawData rawdata = newRawData(tfAgentStatBatch); + mapper.flatMap(rawdata, collector); + + assertEquals(dataList.size(), 2); + + Tuple3 data1 = dataList.get(0); + assertEquals(data1.f0, AGENT_ID); + assertEquals(data1.f2.longValue(), 1491274143454L); + JoinAgentStatBo joinAgentStatBo = (JoinAgentStatBo) data1.f1; + assertEquals(joinAgentStatBo.getId(), AGENT_ID); + assertEquals(joinAgentStatBo.getAgentStartTimestamp(), 1491274142454L); + assertEquals(joinAgentStatBo.getTimestamp(), 1491274143454L); + assertJoinMemoryBo(joinAgentStatBo.getJoinMemoryBoList()); + + Tuple3 data2 = dataList.get(1); + assertEquals(data2.f0, APPLICATION_ID); + assertEquals(data2.f2.longValue(), 1491274140000L); + JoinApplicationStatBo joinApplicationStatBo = (JoinApplicationStatBo) data2.f1; + assertEquals(joinApplicationStatBo.getId(), APPLICATION_ID); + assertEquals(joinApplicationStatBo.getTimestamp(), 1491274140000L); + assertEquals(joinApplicationStatBo.getStatType(), StatType.APP_STST); + assertJoinMemoryBo(joinApplicationStatBo.getJoinMemoryBoList()); + } + + private void assertJoinMemoryBo(List joinMemoryBoList) { + assertEquals(2, joinMemoryBoList.size()); + + JoinMemoryBo joinMemoryBo = joinMemoryBoList.get(0); + assertEquals(joinMemoryBo.getId(), AGENT_ID); + assertEquals(joinMemoryBo.getHeapUsed(), 3000); + assertEquals(joinMemoryBo.getNonHeapUsed(), 450); + assertEquals(joinMemoryBo.getTimestamp(), 1491274143454L); + + JoinMemoryBo joinMemoryBo2 = joinMemoryBoList.get(1); + assertEquals(joinMemoryBo2.getId(), AGENT_ID); + assertEquals(joinMemoryBo2.getHeapUsed(), 2000); + assertEquals(joinMemoryBo2.getNonHeapUsed(), 850); + assertEquals(joinMemoryBo2.getTimestamp(), 1491274148454L); + } + + private TFAgentStatBatch createTFAgentStatBatch2() { + final TFAgentStatBatch tFAgentStatBatch = new TFAgentStatBatch(); + tFAgentStatBatch.setStartTimestamp(1491274142454L); + tFAgentStatBatch.setAgentId(AGENT_ID); + + final TFAgentStat tFAgentStat = new TFAgentStat(); + tFAgentStat.setAgentId(AGENT_ID); + tFAgentStat.setTimestamp(1491274143454L); + + final TFJvmGc tFJvmGc = new TFJvmGc(); + tFJvmGc.setJvmMemoryHeapUsed(3000); + tFJvmGc.setJvmMemoryNonHeapUsed(450); + tFAgentStat.setGc(tFJvmGc); + + final TFAgentStat tFAgentStat2 = new TFAgentStat(); + tFAgentStat2.setAgentId(AGENT_ID); + tFAgentStat2.setTimestamp(1491274148454L); + + final TFJvmGc tFJvmGc2 = new TFJvmGc(); + tFJvmGc2.setJvmMemoryHeapUsed(2000); + tFJvmGc2.setJvmMemoryNonHeapUsed(850); + tFAgentStat2.setGc(tFJvmGc2); + + final List tFAgentStatList = new ArrayList<>(2); + tFAgentStatList.add(tFAgentStat); + tFAgentStatList.add(tFAgentStat2); + tFAgentStatBatch.setAgentStats(tFAgentStatList); + + return tFAgentStatBatch; + } + + @Test + public void flatMap3Test() throws Exception { + ApplicationCache applicationCache = newMockApplicationCache(); + TBaseFlatMapper mapper = new TBaseFlatMapper(new JoinAgentStatBoMapper(), applicationCache, new DefaultTBaseFlatMapperInterceptor()); + + TFAgentStatBatch tfAgentStatBatch = createTFAgentStatBatch3(); + ArrayList> dataList = new ArrayList<>(); + ListCollector> collector = new ListCollector<>(dataList); + RawData rawData = newRawData(tfAgentStatBatch); + mapper.flatMap(rawData, collector); + + assertEquals(dataList.size(), 2); + + Tuple3 data1 = dataList.get(0); + assertEquals(data1.f0, AGENT_ID); + assertEquals(data1.f2.longValue(), 1491274143454L); + JoinAgentStatBo joinAgentStatBo = (JoinAgentStatBo) data1.f1; + assertEquals(joinAgentStatBo.getId(), AGENT_ID); + assertEquals(joinAgentStatBo.getAgentStartTimestamp(), 1491274142454L); + assertEquals(joinAgentStatBo.getTimestamp(), 1491274143454L); + assertJoinTransactionBo(joinAgentStatBo.getJoinTransactionBoList()); + + Tuple3 data2 = dataList.get(1); + assertEquals(data2.f0, APPLICATION_ID); + assertEquals(data2.f2.longValue(), 1491274140000L); + JoinApplicationStatBo joinApplicationStatBo = (JoinApplicationStatBo) data2.f1; + assertEquals(joinApplicationStatBo.getId(), APPLICATION_ID); + assertEquals(joinApplicationStatBo.getTimestamp(), 1491274140000L); + assertEquals(joinApplicationStatBo.getStatType(), StatType.APP_STST); + assertJoinTransactionBo(joinApplicationStatBo.getJoinTransactionBoList()); + } + + private RawData newRawData(TFAgentStatBatch tfAgentStatBatch) { + return new RawData(tfAgentStatBatch, Collections.EMPTY_MAP); + } + + private void assertJoinTransactionBo(List joinTransactionBoList) { + assertEquals(2, joinTransactionBoList.size()); + + JoinTransactionBo joinTransactionBo = joinTransactionBoList.get(0); + assertEquals(joinTransactionBo.getId(), AGENT_ID); + assertEquals(joinTransactionBo.getTimestamp(), 1491274143454L); + assertEquals(joinTransactionBo.getCollectInterval(), 5000); + assertEquals(joinTransactionBo.getTotalCount(), 120); + assertEquals(joinTransactionBo.getMaxTotalCount(), 120); + assertEquals(joinTransactionBo.getMaxTotalCountAgentId(), AGENT_ID); + assertEquals(joinTransactionBo.getMinTotalCount(), 120); + assertEquals(joinTransactionBo.getMinTotalCountAgentId(), AGENT_ID); + + JoinTransactionBo joinTransactionBo2 = joinTransactionBoList.get(1); + assertEquals(joinTransactionBo2.getId(), AGENT_ID); + assertEquals(joinTransactionBo2.getTimestamp(), 1491274148454L); + assertEquals(joinTransactionBo2.getCollectInterval(), 5000); + assertEquals(joinTransactionBo2.getTotalCount(), 124); + assertEquals(joinTransactionBo2.getMaxTotalCount(), 124); + assertEquals(joinTransactionBo2.getMaxTotalCountAgentId(), AGENT_ID); + assertEquals(joinTransactionBo2.getMinTotalCount(), 124); + assertEquals(joinTransactionBo2.getMinTotalCountAgentId(), AGENT_ID); + } + + private TFAgentStatBatch createTFAgentStatBatch3() { + final TFAgentStatBatch tFAgentStatBatch = new TFAgentStatBatch(); + tFAgentStatBatch.setStartTimestamp(1491274142454L); + tFAgentStatBatch.setAgentId(AGENT_ID); + + final TFAgentStat tFAgentStat = new TFAgentStat(); + tFAgentStat.setAgentId(AGENT_ID); + tFAgentStat.setTimestamp(1491274143454L); + tFAgentStat.setCollectInterval(5000); + + final TFTransaction tFTransaction = new TFTransaction(); + tFTransaction.setSampledNewCount(10); + tFTransaction.setSampledContinuationCount(20); + tFTransaction.setUnsampledNewCount(40); + tFTransaction.setUnsampledContinuationCount(50); + tFAgentStat.setTransaction(tFTransaction); + + final TFAgentStat tFAgentStat2 = new TFAgentStat(); + tFAgentStat2.setAgentId(AGENT_ID); + tFAgentStat2.setTimestamp(1491274148454L); + tFAgentStat2.setCollectInterval(5000); + + final TFTransaction tFTransaction2 = new TFTransaction(); + tFTransaction2.setSampledNewCount(11); + tFTransaction2.setSampledContinuationCount(21); + tFTransaction2.setUnsampledNewCount(41); + tFTransaction2.setUnsampledContinuationCount(51); + tFAgentStat2.setTransaction(tFTransaction2); + + final List tFAgentStatList = new ArrayList<>(2); + tFAgentStatList.add(tFAgentStat); + tFAgentStatList.add(tFAgentStat2); + tFAgentStatBatch.setAgentStats(tFAgentStatList); + + return tFAgentStatBatch; + } + + @Test + public void flatMap4Test() throws Exception { + + ApplicationCache applicationCache = newMockApplicationCache(); + TBaseFlatMapper mapper = new TBaseFlatMapper(new JoinAgentStatBoMapper(), applicationCache, new DefaultTBaseFlatMapperInterceptor()); + + + TFAgentStatBatch tfAgentStatBatch = createTFAgentStatBatch4(); + ArrayList> dataList = new ArrayList<>(); + ListCollector> collector = new ListCollector<>(dataList); + RawData rawData = newRawData(tfAgentStatBatch); + mapper.flatMap(rawData, collector); + + assertEquals(dataList.size(), 2); + + Tuple3 data1 = dataList.get(0); + assertEquals(data1.f0, AGENT_ID); + assertEquals(data1.f2.longValue(), 1491274143454L); + JoinAgentStatBo joinAgentStatBo = (JoinAgentStatBo) data1.f1; + assertEquals(joinAgentStatBo.getId(), AGENT_ID); + assertEquals(joinAgentStatBo.getAgentStartTimestamp(), 1491274142454L); + assertEquals(joinAgentStatBo.getTimestamp(), 1491274143454L); + assertJoinFileDescriptorBo(joinAgentStatBo.getJoinFileDescriptorBoList()); + + Tuple3 data2 = dataList.get(1); + assertEquals(data2.f0, APPLICATION_ID); + assertEquals(data2.f2.longValue(), 1491274140000L); + JoinApplicationStatBo joinApplicationStatBo = (JoinApplicationStatBo) data2.f1; + assertEquals(joinApplicationStatBo.getId(), APPLICATION_ID); + assertEquals(joinApplicationStatBo.getTimestamp(), 1491274140000L); + assertEquals(joinApplicationStatBo.getStatType(), StatType.APP_STST); + assertJoinFileDescriptorBo(joinApplicationStatBo.getJoinFileDescriptorBoList()); + } + + private void assertJoinFileDescriptorBo(List joinFileDescriptorBoList) { + assertEquals(2, joinFileDescriptorBoList.size()); + JoinFileDescriptorBo joinFileDescriptorBo = joinFileDescriptorBoList.get(0); + assertEquals(joinFileDescriptorBo.getId(), AGENT_ID); + assertEquals(joinFileDescriptorBo.getTimestamp(), 1491274143454L); + assertEquals(joinFileDescriptorBo.getAvgOpenFDCount(), 10, 0); + assertEquals(joinFileDescriptorBo.getMinOpenFDCount(), 10, 0); + assertEquals(joinFileDescriptorBo.getMaxOpenFDCount(), 10, 0); + joinFileDescriptorBo = joinFileDescriptorBoList.get(1); + assertEquals(joinFileDescriptorBo.getId(), AGENT_ID); + assertEquals(joinFileDescriptorBo.getTimestamp(), 1491274148454L); + assertEquals(joinFileDescriptorBo.getAvgOpenFDCount(), 20, 0); + assertEquals(joinFileDescriptorBo.getMinOpenFDCount(), 20, 0); + assertEquals(joinFileDescriptorBo.getMaxOpenFDCount(), 20, 0); + } + + private TFAgentStatBatch createTFAgentStatBatch4() { + final TFAgentStatBatch tFAgentStatBatch = new TFAgentStatBatch(); + tFAgentStatBatch.setStartTimestamp(1491274142454L); + tFAgentStatBatch.setAgentId(AGENT_ID); + + final TFAgentStat tFAgentStat = new TFAgentStat(); + tFAgentStat.setAgentId(AGENT_ID); + tFAgentStat.setTimestamp(1491274143454L); + + final TFFileDescriptor tFFileDescriptor = new TFFileDescriptor(); + tFFileDescriptor.setOpenFileDescriptorCount(10); + tFAgentStat.setFileDescriptor(tFFileDescriptor); + + final TFAgentStat tFAgentStat2 = new TFAgentStat(); + tFAgentStat2.setAgentId(AGENT_ID); + tFAgentStat2.setTimestamp(1491274148454L); + + final TFFileDescriptor tFFileDescriptor2 = new TFFileDescriptor(); + tFFileDescriptor2.setOpenFileDescriptorCount(20); + tFAgentStat2.setFileDescriptor(tFFileDescriptor2); + + final List tFAgentStatList = new ArrayList<>(2); + tFAgentStatList.add(tFAgentStat); + tFAgentStatList.add(tFAgentStat2); + tFAgentStatBatch.setAgentStats(tFAgentStatList); + + return tFAgentStatBatch; + } + + + @Test + public void flatMap5Test() throws Exception { + + ApplicationCache applicationCache = newMockApplicationCache(); + TBaseFlatMapper mapper = new TBaseFlatMapper(new JoinAgentStatBoMapper(), applicationCache, new DefaultTBaseFlatMapperInterceptor()); + + + TFAgentStatBatch tfAgentStatBatch = createTFAgentStatBatch5(); + ArrayList> dataList = new ArrayList<>(); + ListCollector> collector = new ListCollector<>(dataList); + RawData rawData = newRawData(tfAgentStatBatch); + mapper.flatMap(rawData, collector); + + assertEquals(dataList.size(), 2); + + Tuple3 data1 = dataList.get(0); + assertEquals(data1.f0, AGENT_ID); + assertEquals(data1.f2.longValue(), 1491274143454L); + JoinAgentStatBo joinAgentStatBo = (JoinAgentStatBo) data1.f1; + assertEquals(joinAgentStatBo.getId(), AGENT_ID); + assertEquals(joinAgentStatBo.getAgentStartTimestamp(), 1491274142454L); + assertEquals(joinAgentStatBo.getTimestamp(), 1491274143454L); + assertJoinDirectBufferBo(joinAgentStatBo.getJoinDirectBufferBoList()); + + Tuple3 data2 = dataList.get(1); + assertEquals(data2.f0, APPLICATION_ID); + assertEquals(data2.f2.longValue(), 1491274140000L); + JoinApplicationStatBo joinApplicationStatBo = (JoinApplicationStatBo) data2.f1; + assertEquals(joinApplicationStatBo.getId(), APPLICATION_ID); + assertEquals(joinApplicationStatBo.getTimestamp(), 1491274140000L); + assertEquals(joinApplicationStatBo.getStatType(), StatType.APP_STST); + assertJoinDirectBufferBo(joinApplicationStatBo.getJoinDirectBufferBoList()); + } + + private void assertJoinDirectBufferBo(List joinDirectBufferBoList) { + assertEquals(2, joinDirectBufferBoList.size()); + JoinDirectBufferBo joinDirectBufferBo = joinDirectBufferBoList.get(0); + assertEquals(joinDirectBufferBo.getId(), AGENT_ID); + assertEquals(joinDirectBufferBo.getTimestamp(), 1491274143454L); + assertEquals(joinDirectBufferBo.getAvgDirectCount(), 10, 0); + assertEquals(joinDirectBufferBo.getMinDirectCount(), 10, 0); + assertEquals(joinDirectBufferBo.getMaxDirectCount(), 10, 0); + assertEquals(joinDirectBufferBo.getAvgDirectMemoryUsed(), 20, 0); + assertEquals(joinDirectBufferBo.getMinDirectMemoryUsed(), 20, 0); + assertEquals(joinDirectBufferBo.getMaxDirectMemoryUsed(), 20, 0); + assertEquals(joinDirectBufferBo.getAvgMappedCount(), 30, 0); + assertEquals(joinDirectBufferBo.getMinMappedCount(), 30, 0); + assertEquals(joinDirectBufferBo.getMaxMappedCount(), 30, 0); + assertEquals(joinDirectBufferBo.getAvgMappedMemoryUsed(), 40, 0); + assertEquals(joinDirectBufferBo.getMinMappedMemoryUsed(), 40, 0); + assertEquals(joinDirectBufferBo.getMaxMappedMemoryUsed(), 40, 0); + joinDirectBufferBo = joinDirectBufferBoList.get(1); + assertEquals(joinDirectBufferBo.getId(), AGENT_ID); + assertEquals(joinDirectBufferBo.getTimestamp(), 1491274148454L); + assertEquals(joinDirectBufferBo.getAvgDirectCount(), 50, 0); + assertEquals(joinDirectBufferBo.getMinDirectCount(), 50, 0); + assertEquals(joinDirectBufferBo.getMaxDirectCount(), 50, 0); + assertEquals(joinDirectBufferBo.getAvgDirectMemoryUsed(), 60, 0); + assertEquals(joinDirectBufferBo.getMinDirectMemoryUsed(), 60, 0); + assertEquals(joinDirectBufferBo.getMaxDirectMemoryUsed(), 60, 0); + assertEquals(joinDirectBufferBo.getAvgMappedCount(), 70, 0); + assertEquals(joinDirectBufferBo.getMinMappedCount(), 70, 0); + assertEquals(joinDirectBufferBo.getMaxMappedCount(), 70, 0); + assertEquals(joinDirectBufferBo.getAvgMappedMemoryUsed(), 80, 0); + assertEquals(joinDirectBufferBo.getMinMappedMemoryUsed(), 80, 0); + assertEquals(joinDirectBufferBo.getMaxMappedMemoryUsed(), 80, 0); + } + + private TFAgentStatBatch createTFAgentStatBatch5() { + final TFAgentStatBatch tFAgentStatBatch = new TFAgentStatBatch(); + tFAgentStatBatch.setStartTimestamp(1491274142454L); + tFAgentStatBatch.setAgentId(AGENT_ID); + + final TFAgentStat tFAgentStat = new TFAgentStat(); + tFAgentStat.setAgentId(AGENT_ID); + tFAgentStat.setTimestamp(1491274143454L); + + final TFDirectBuffer tFDirectBuffer = new TFDirectBuffer(); + tFDirectBuffer.setDirectCount(10); + tFDirectBuffer.setDirectMemoryUsed(20); + tFDirectBuffer.setMappedCount(30); + tFDirectBuffer.setMappedMemoryUsed(40); + tFAgentStat.setDirectBuffer(tFDirectBuffer); + + final TFAgentStat tFAgentStat2 = new TFAgentStat(); + tFAgentStat2.setAgentId(AGENT_ID); + tFAgentStat2.setTimestamp(1491274148454L); + + final TFDirectBuffer tFDirectBuffer2 = new TFDirectBuffer(); + tFDirectBuffer2.setDirectCount(50); + tFDirectBuffer2.setDirectMemoryUsed(60); + tFDirectBuffer2.setMappedCount(70); + tFDirectBuffer2.setMappedMemoryUsed(80); + tFAgentStat2.setDirectBuffer(tFDirectBuffer2); + + final List tFAgentStatList = new ArrayList<>(2); + tFAgentStatList.add(tFAgentStat); + tFAgentStatList.add(tFAgentStat2); + tFAgentStatBatch.setAgentStats(tFAgentStatList); + + return tFAgentStatBatch; + } +} \ No newline at end of file diff --git a/flink/src/test/java/flink/process/TbaseFlatMapperTest.java b/flink/src/test/java/flink/process/TbaseFlatMapperTest.java deleted file mode 100644 index 73e2c1f690f4..000000000000 --- a/flink/src/test/java/flink/process/TbaseFlatMapperTest.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package flink.process; - -import com.navercorp.pinpoint.common.server.bo.stat.join.*; -import com.navercorp.pinpoint.flink.mapper.thrift.stat.JoinAgentStatBoMapper; -import com.navercorp.pinpoint.flink.process.ApplicationCache; -import com.navercorp.pinpoint.flink.process.TbaseFlatMapper; -import com.navercorp.pinpoint.thrift.dto.flink.*; -import org.apache.flink.api.common.functions.util.ListCollector; -import org.apache.flink.api.java.tuple.Tuple3; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - - -/** - * @author minwoo.jung - */ -public class TbaseFlatMapperTest { - final static String AGENT_ID = "testAgent"; - final static String APPLICATION_ID = "testApplication"; - - @Test - public void flatMapTest() throws Exception { - - ApplicationCache applicationCache = newMockApplicationCache(); - TbaseFlatMapper mapper = new TbaseFlatMapper(new JoinAgentStatBoMapper(), applicationCache); - - - TFAgentStatBatch tfAgentStatBatch = createTFAgentStatBatch(); - ArrayList> dataList = new ArrayList<>(); - ListCollector> collector = new ListCollector<>(dataList); - mapper.flatMap(tfAgentStatBatch, collector); - - assertEquals(dataList.size(), 2); - - Tuple3 data1 = dataList.get(0); - assertEquals(data1.f0, AGENT_ID); - assertEquals(data1.f2.longValue(), 1491274143454L); - JoinAgentStatBo joinAgentStatBo = (JoinAgentStatBo) data1.f1; - assertEquals(joinAgentStatBo.getId(), AGENT_ID); - assertEquals(joinAgentStatBo.getAgentStartTimestamp(), 1491274142454L); - assertEquals(joinAgentStatBo.getTimestamp(), 1491274143454L); - assertJoinCpuLoadBo(joinAgentStatBo.getJoinCpuLoadBoList()); - - Tuple3 data2 = dataList.get(1); - assertEquals(data2.f0, APPLICATION_ID); - assertEquals(data2.f2.longValue(), 1491274140000L); - JoinApplicationStatBo joinApplicationStatBo = (JoinApplicationStatBo) data2.f1; - assertEquals(joinApplicationStatBo.getId(), APPLICATION_ID); - assertEquals(joinApplicationStatBo.getTimestamp(), 1491274140000L); - assertEquals(joinApplicationStatBo.getStatType(), StatType.APP_STST); - assertJoinCpuLoadBo(joinApplicationStatBo.getJoinCpuLoadBoList()); - } - - private ApplicationCache newMockApplicationCache() { - ApplicationCache applicationCache = mock(ApplicationCache.class); - when(applicationCache.findApplicationId(any(ApplicationCache.ApplicationKey.class))) - .thenReturn(APPLICATION_ID); - return applicationCache; - } - - private void assertJoinCpuLoadBo(List joincpulaodBoList) { - assertEquals(2, joincpulaodBoList.size()); - JoinCpuLoadBo joinCpuLoadBo = joincpulaodBoList.get(0); - assertEquals(joinCpuLoadBo.getId(), AGENT_ID); - assertEquals(joinCpuLoadBo.getTimestamp(), 1491274143454L); - assertEquals(joinCpuLoadBo.getJvmCpuLoad(), 10, 0); - assertEquals(joinCpuLoadBo.getMinJvmCpuLoad(), 10, 0); - assertEquals(joinCpuLoadBo.getMaxJvmCpuLoad(), 10, 0); - assertEquals(joinCpuLoadBo.getSystemCpuLoad(), 30, 0); - assertEquals(joinCpuLoadBo.getMinSystemCpuLoad(), 30, 0); - assertEquals(joinCpuLoadBo.getMaxSystemCpuLoad(), 30, 0); - joinCpuLoadBo = joincpulaodBoList.get(1); - assertEquals(joinCpuLoadBo.getId(), AGENT_ID); - assertEquals(joinCpuLoadBo.getTimestamp(), 1491274148454L); - assertEquals(joinCpuLoadBo.getJvmCpuLoad(), 20, 0); - assertEquals(joinCpuLoadBo.getMinJvmCpuLoad(), 20, 0); - assertEquals(joinCpuLoadBo.getMaxJvmCpuLoad(), 20, 0); - assertEquals(joinCpuLoadBo.getSystemCpuLoad(), 50, 0); - assertEquals(joinCpuLoadBo.getMinSystemCpuLoad(), 50, 0); - assertEquals(joinCpuLoadBo.getMaxSystemCpuLoad(), 50, 0); - } - - private TFAgentStatBatch createTFAgentStatBatch() { - final TFAgentStatBatch tFAgentStatBatch = new TFAgentStatBatch(); - tFAgentStatBatch.setStartTimestamp(1491274142454L); - tFAgentStatBatch.setAgentId(AGENT_ID); - - final TFAgentStat tFAgentStat = new TFAgentStat(); - tFAgentStat.setAgentId(AGENT_ID); - tFAgentStat.setTimestamp(1491274143454L); - - final TFCpuLoad tFCpuLoad = new TFCpuLoad(); - tFCpuLoad.setJvmCpuLoad(10); - tFCpuLoad.setSystemCpuLoad(30); - tFAgentStat.setCpuLoad(tFCpuLoad); - - final TFAgentStat tFAgentStat2 = new TFAgentStat(); - tFAgentStat2.setAgentId(AGENT_ID); - tFAgentStat2.setTimestamp(1491274148454L); - - final TFCpuLoad tFCpuLoad2 = new TFCpuLoad(); - tFCpuLoad2.setJvmCpuLoad(20); - tFCpuLoad2.setSystemCpuLoad(50); - tFAgentStat2.setCpuLoad(tFCpuLoad2); - - final List tFAgentStatList = new ArrayList<>(2); - tFAgentStatList.add(tFAgentStat); - tFAgentStatList.add(tFAgentStat2); - tFAgentStatBatch.setAgentStats(tFAgentStatList); - - return tFAgentStatBatch; - } - - - - @Test - public void flatMap2Test() throws Exception { - ApplicationCache applicationCache = newMockApplicationCache(); - TbaseFlatMapper mapper = new TbaseFlatMapper(new JoinAgentStatBoMapper(), applicationCache); - - TFAgentStatBatch tfAgentStatBatch = createTFAgentStatBatch2(); - ArrayList> dataList = new ArrayList<>(); - ListCollector> collector = new ListCollector<>(dataList); - mapper.flatMap(tfAgentStatBatch, collector); - - assertEquals(dataList.size(), 2); - - Tuple3 data1 = dataList.get(0); - assertEquals(data1.f0, AGENT_ID); - assertEquals(data1.f2.longValue(), 1491274143454L); - JoinAgentStatBo joinAgentStatBo = (JoinAgentStatBo) data1.f1; - assertEquals(joinAgentStatBo.getId(), AGENT_ID); - assertEquals(joinAgentStatBo.getAgentStartTimestamp(), 1491274142454L); - assertEquals(joinAgentStatBo.getTimestamp(), 1491274143454L); - assertJoinMemoryBo(joinAgentStatBo.getJoinMemoryBoList()); - - Tuple3 data2 = dataList.get(1); - assertEquals(data2.f0, APPLICATION_ID); - assertEquals(data2.f2.longValue(), 1491274140000L); - JoinApplicationStatBo joinApplicationStatBo = (JoinApplicationStatBo) data2.f1; - assertEquals(joinApplicationStatBo.getId(), APPLICATION_ID); - assertEquals(joinApplicationStatBo.getTimestamp(), 1491274140000L); - assertEquals(joinApplicationStatBo.getStatType(), StatType.APP_STST); - assertJoinMemoryBo(joinApplicationStatBo.getJoinMemoryBoList()); - } - - private void assertJoinMemoryBo(List joinMemoryBoList) { - assertEquals(2, joinMemoryBoList.size()); - - JoinMemoryBo joinMemoryBo = joinMemoryBoList.get(0); - assertEquals(joinMemoryBo.getId(), AGENT_ID); - assertEquals(joinMemoryBo.getHeapUsed(), 3000); - assertEquals(joinMemoryBo.getNonHeapUsed(), 450); - assertEquals(joinMemoryBo.getTimestamp(), 1491274143454L); - - JoinMemoryBo joinMemoryBo2 = joinMemoryBoList.get(1); - assertEquals(joinMemoryBo2.getId(), AGENT_ID); - assertEquals(joinMemoryBo2.getHeapUsed(), 2000); - assertEquals(joinMemoryBo2.getNonHeapUsed(), 850); - assertEquals(joinMemoryBo2.getTimestamp(), 1491274148454L); - } - - private TFAgentStatBatch createTFAgentStatBatch2() { - final TFAgentStatBatch tFAgentStatBatch = new TFAgentStatBatch(); - tFAgentStatBatch.setStartTimestamp(1491274142454L); - tFAgentStatBatch.setAgentId(AGENT_ID); - - final TFAgentStat tFAgentStat = new TFAgentStat(); - tFAgentStat.setAgentId(AGENT_ID); - tFAgentStat.setTimestamp(1491274143454L); - - final TFJvmGc tFJvmGc = new TFJvmGc(); - tFJvmGc.setJvmMemoryHeapUsed(3000); - tFJvmGc.setJvmMemoryNonHeapUsed(450); - tFAgentStat.setGc(tFJvmGc); - - final TFAgentStat tFAgentStat2 = new TFAgentStat(); - tFAgentStat2.setAgentId(AGENT_ID); - tFAgentStat2.setTimestamp(1491274148454L); - - final TFJvmGc tFJvmGc2 = new TFJvmGc(); - tFJvmGc2.setJvmMemoryHeapUsed(2000); - tFJvmGc2.setJvmMemoryNonHeapUsed(850); - tFAgentStat2.setGc(tFJvmGc2); - - final List tFAgentStatList = new ArrayList<>(2); - tFAgentStatList.add(tFAgentStat); - tFAgentStatList.add(tFAgentStat2); - tFAgentStatBatch.setAgentStats(tFAgentStatList); - - return tFAgentStatBatch; - } - - @Test - public void flatMap3Test() throws Exception { - ApplicationCache applicationCache = newMockApplicationCache(); - TbaseFlatMapper mapper = new TbaseFlatMapper(new JoinAgentStatBoMapper(), applicationCache); - - TFAgentStatBatch tfAgentStatBatch = createTFAgentStatBatch3(); - ArrayList> dataList = new ArrayList<>(); - ListCollector> collector = new ListCollector<>(dataList); - mapper.flatMap(tfAgentStatBatch, collector); - - assertEquals(dataList.size(), 2); - - Tuple3 data1 = dataList.get(0); - assertEquals(data1.f0, AGENT_ID); - assertEquals(data1.f2.longValue(), 1491274143454L); - JoinAgentStatBo joinAgentStatBo = (JoinAgentStatBo) data1.f1; - assertEquals(joinAgentStatBo.getId(), AGENT_ID); - assertEquals(joinAgentStatBo.getAgentStartTimestamp(), 1491274142454L); - assertEquals(joinAgentStatBo.getTimestamp(), 1491274143454L); - assertJoinTransactionBo(joinAgentStatBo.getJoinTransactionBoList()); - - Tuple3 data2 = dataList.get(1); - assertEquals(data2.f0, APPLICATION_ID); - assertEquals(data2.f2.longValue(), 1491274140000L); - JoinApplicationStatBo joinApplicationStatBo = (JoinApplicationStatBo) data2.f1; - assertEquals(joinApplicationStatBo.getId(), APPLICATION_ID); - assertEquals(joinApplicationStatBo.getTimestamp(), 1491274140000L); - assertEquals(joinApplicationStatBo.getStatType(), StatType.APP_STST); - assertJoinTransactionBo(joinApplicationStatBo.getJoinTransactionBoList()); - } - - private void assertJoinTransactionBo(List joinTransactionBoList) { - assertEquals(2, joinTransactionBoList.size()); - - JoinTransactionBo joinTransactionBo = joinTransactionBoList.get(0); - assertEquals(joinTransactionBo.getId(), AGENT_ID); - assertEquals(joinTransactionBo.getTimestamp(), 1491274143454L); - assertEquals(joinTransactionBo.getCollectInterval(), 5000); - assertEquals(joinTransactionBo.getTotalCount(), 120); - assertEquals(joinTransactionBo.getMaxTotalCount(), 120); - assertEquals(joinTransactionBo.getMaxTotalCountAgentId(), AGENT_ID); - assertEquals(joinTransactionBo.getMinTotalCount(), 120); - assertEquals(joinTransactionBo.getMinTotalCountAgentId(), AGENT_ID); - - JoinTransactionBo joinTransactionBo2 = joinTransactionBoList.get(1); - assertEquals(joinTransactionBo2.getId(), AGENT_ID); - assertEquals(joinTransactionBo2.getTimestamp(), 1491274148454L); - assertEquals(joinTransactionBo2.getCollectInterval(), 5000); - assertEquals(joinTransactionBo2.getTotalCount(), 124); - assertEquals(joinTransactionBo2.getMaxTotalCount(), 124); - assertEquals(joinTransactionBo2.getMaxTotalCountAgentId(), AGENT_ID); - assertEquals(joinTransactionBo2.getMinTotalCount(), 124); - assertEquals(joinTransactionBo2.getMinTotalCountAgentId(), AGENT_ID); - } - - private TFAgentStatBatch createTFAgentStatBatch3() { - final TFAgentStatBatch tFAgentStatBatch = new TFAgentStatBatch(); - tFAgentStatBatch.setStartTimestamp(1491274142454L); - tFAgentStatBatch.setAgentId(AGENT_ID); - - final TFAgentStat tFAgentStat = new TFAgentStat(); - tFAgentStat.setAgentId(AGENT_ID); - tFAgentStat.setTimestamp(1491274143454L); - tFAgentStat.setCollectInterval(5000); - - final TFTransaction tFTransaction = new TFTransaction(); - tFTransaction.setSampledNewCount(10); - tFTransaction.setSampledContinuationCount(20); - tFTransaction.setUnsampledNewCount(40); - tFTransaction.setUnsampledContinuationCount(50); - tFAgentStat.setTransaction(tFTransaction); - - final TFAgentStat tFAgentStat2 = new TFAgentStat(); - tFAgentStat2.setAgentId(AGENT_ID); - tFAgentStat2.setTimestamp(1491274148454L); - tFAgentStat2.setCollectInterval(5000); - - final TFTransaction tFTransaction2 = new TFTransaction(); - tFTransaction2.setSampledNewCount(11); - tFTransaction2.setSampledContinuationCount(21); - tFTransaction2.setUnsampledNewCount(41); - tFTransaction2.setUnsampledContinuationCount(51); - tFAgentStat2.setTransaction(tFTransaction2); - - final List tFAgentStatList = new ArrayList<>(2); - tFAgentStatList.add(tFAgentStat); - tFAgentStatList.add(tFAgentStat2); - tFAgentStatBatch.setAgentStats(tFAgentStatList); - - return tFAgentStatBatch; - } -} \ No newline at end of file diff --git a/grpc/.gitignore b/grpc/.gitignore new file mode 100644 index 000000000000..297014d4972d --- /dev/null +++ b/grpc/.gitignore @@ -0,0 +1,5 @@ +/.settings/ +*.iml +/.project +/target/ +/.classpath diff --git a/grpc/README.md b/grpc/README.md new file mode 100644 index 000000000000..75590681abc3 --- /dev/null +++ b/grpc/README.md @@ -0,0 +1 @@ +# pinpoint-grpc \ No newline at end of file diff --git a/grpc/pom.xml b/grpc/pom.xml new file mode 100644 index 000000000000..944ab16faca9 --- /dev/null +++ b/grpc/pom.xml @@ -0,0 +1,117 @@ + + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + 1.8.1-SNAPSHOT + + + pinpoint-grpc + pinpoint-grpc + jar + + + 1.14.0 + 3.5.1-1 + + + + + + com.navercorp.pinpoint + pinpoint-commons + + + io.grpc + grpc-netty + ${grpc.version} + + + io.grpc + grpc-protobuf + ${grpc.version} + + + io.grpc + grpc-stub + ${grpc.version} + + + + + + org.slf4j + slf4j-api + true + + + + org.slf4j + jcl-over-slf4j + test + + + org.slf4j + slf4j-log4j12 + test + + + log4j + log4j + test + + + commons-lang3 + org.apache.commons + test + + + + + + + + kr.motd.maven + os-maven-plugin + 1.5.0.Final + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.5.1 + + com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + + + + + compile + compile-custom + + + + + + + diff --git a/grpc/src/main/proto/Trace.proto b/grpc/src/main/proto/Trace.proto new file mode 100644 index 000000000000..02fd9887dfe0 --- /dev/null +++ b/grpc/src/main/proto/Trace.proto @@ -0,0 +1,308 @@ +syntax = "proto3"; + +import "google/protobuf/empty.proto"; + +option java_multiple_files = true; +option java_package = "com.navercorp.pinpoint.gpc.trace"; +option java_outer_classname = "TraceProto"; +//option objc_class_prefix = "PIN"; + +package v1; + +service Trace { + rpc SendSpan (stream PSpan) returns (google.protobuf.Empty) {} +} + + +message PSpan { + + string agentId = 1; + string applicationName = 2; + int64 agentStartTime = 3; + + // identical to agentId if null + //4: optional string traceAgentId + //5: i64 traceAgentStartTime; + //6: i64 traceTransactionSequence; + bytes transactionId = 4; + + fixed64 spanId = 7; + fixed64 parentSpanId = 8; + + // span event's startTimestamp + int64 startTime = 9; + int32 elapsed = 10; + + string rpc = 11; + + int32 serviceType = 12; + string endPoint = 13; + string remoteAddr = 14; + +// list annotations = 15; +// i16 flag = 16; +// +// i32 err = 17; +// + repeated PSpanEvent spanEventList = 18; +// +// optional string parentApplicationName = 19; +// optional i16 parentApplicationType = 20; +// optional string acceptorHost = 21; +// +// i32 apiId = 25; +// TIntStringValue exceptionInfo = 26; +// +// i16 applicationServiceType = 30; +// i8 loggingTransactionInfo = 31; +// +// 32: optional i8 version = TRACE_V2; +} + +message PSpanEvent { + + fixed64 spanId = 7; + + int32 sequence = 8; + + int32 startElapsed = 9; + int32 endElapsed = 10; + + string rpc = 11; + sint32 serviceType = 12; + string endPoint = 13; + // 14: optional list annotations + + int32 depth = 15; + fixed64 nextSpanId = 16; + + string destinationId = 20; + + sint32 apiId = 25; +// 26: optional TIntStringValue exceptionInfo; + + int32 asyncId = 30; + int32 nextAsyncId = 31; + int32 asyncSequence = 32; + + +// 8: i16 sequence +// +// // 1.6.x- : delta of the span startTime +// // 1.7.0+: delta of startTime of previous SpanEvent +// // If SpanEvent is the first SpanEvent, startElapsed is span startTime +// 9: i32 startElapsed = 0; +// +// 10: optional i32 endElapsed = 0 +// +// 11: optional string rpc +// 12: i16 serviceType +// 13: optional string endPoint +// +// 14: optional list annotations +// +// 15: optional i32 depth = -1 +// 16: optional i64 nextSpanId = -1 +// +// 20: optional string destinationId +// +// 25: optional i32 apiId; +// 26: optional TIntStringValue exceptionInfo; +// +// 30: optional i32 asyncId; +// 31: optional i32 nextAsyncId; +// 32: optional i16 asyncSequence; +} + + +// 1.6.x- : version = 0; +// 1.7.x+ : version = 1; +//const i8 TRACE_V1 = 0; +//const i8 TRACE_V2 = 1; +// +//struct TIntStringValue { +// 1: i32 intValue; +// 2: optional string stringValue; +//} +// +//struct TIntStringStringValue { +// 1: i32 intValue; +// 2: optional string stringValue1; +// 3: optional string stringValue2; +//} +// +//struct TLongIntIntByteByteStringValue { +// 1: i64 longValue; +// 2: i32 intValue1; +// 3: optional i32 intValue2; +// 4: optional i8 byteValue1; +// 5: optional i8 byteValue2; +// 6: optional string stringValue; +//} +// +//struct TIntBooleanIntBooleanValue { +// 1: i32 intValue1; +// 2: bool boolValue1; +// 3: i32 intValue2; +// 4: bool boolValue2; +//} +// +//union TAnnotationValue { +// 1: string stringValue +// 2: bool boolValue; +// 3: i32 intValue; +// 4: i64 longValue; +// 5: i16 shortValue +// 6: double doubleValue; +// 7: binary binaryValue; +// 8: i8 byteValue; +// 9: TIntStringValue intStringValue; +// 10: TIntStringStringValue intStringStringValue; +// 11: TLongIntIntByteByteStringValue longIntIntByteByteStringValue; +// 12: TIntBooleanIntBooleanValue intBooleanIntBooleanValue; +//} +// +//struct TAnnotation { +// 1: i32 key, +// 2: optional TAnnotationValue value +//} +// +//struct TSpanEvent { +// +// 7: optional i64 spanId +// 8: i16 sequence +// +// // 1.6.x- : delta of the span startTime +// // 1.7.0+: delta of startTime of previous SpanEvent +// // If SpanEvent is the first SpanEvent, startElapsed is span startTime +// 9: i32 startElapsed = 0; +// +// 10: optional i32 endElapsed = 0 +// +// 11: optional string rpc +// 12: i16 serviceType +// 13: optional string endPoint +// +// 14: optional list annotations +// +// 15: optional i32 depth = -1 +// 16: optional i64 nextSpanId = -1 +// +// 20: optional string destinationId +// +// 25: optional i32 apiId; +// 26: optional TIntStringValue exceptionInfo; +// +// 30: optional i32 asyncId; +// 31: optional i32 nextAsyncId; +// 32: optional i16 asyncSequence; +//} +// +//struct TSpan { +// +// 1: string agentId +// 2: string applicationName +// 3: i64 agentStartTime +// +// // identical to agentId if null +// //4: optional string traceAgentId +// //5: i64 traceAgentStartTime; +// //6: i64 traceTransactionSequence; +// 4: binary transactionId; +// +// 7: i64 spanId +// 8: optional i64 parentSpanId = -1 +// +// // span event's startTimestamp +// 9: i64 startTime +// 10: optional i32 elapsed = 0 +// +// 11: optional string rpc +// +// 12: i16 serviceType +// 13: optional string endPoint +// 14: optional string remoteAddr +// +// 15: optional list annotations +// 16: optional i16 flag = 0 +// +// 17: optional i32 err +// +// 18: optional list spanEventList +// +// 19: optional string parentApplicationName +// 20: optional i16 parentApplicationType +// 21: optional string acceptorHost +// +// 25: optional i32 apiId; +// 26: optional TIntStringValue exceptionInfo; +// +// 30: optional i16 applicationServiceType; +// 31: optional i8 loggingTransactionInfo; +// +// 32: optional i8 version = TRACE_V2; +//} +// +//struct TSpanChunk { +// 1: string agentId +// 2: string applicationName +// 3: i64 agentStartTime +// +// // @deprecate (1.7.0) +// 4: i16 serviceType ( deprecated ) +// +// // identical to agentId if null +// //5: optional string traceAgentId +// //6: i64 traceAgentStartTime; +// //7: i64 traceTransactionSequence; +// 5: binary transactionId; +// +// 8: i64 spanId +// +// 9: optional string endPoint +// +// 10: list spanEventList +// +// 11: optional i16 applicationServiceType +// +// // @since 1.7.0 time for data compression +// 12: optional i64 keyTime; +// +// 13: optional i8 version = TRACE_V2; +//} +// +// +//struct TStringMetaData { +// +// 1: string agentId +// 2: i64 agentStartTime +// +// 4: i32 stringId +// 5: string stringValue; +//} +// +//struct TSqlMetaData { +// +// 1: string agentId +// 2: i64 agentStartTime +// +// 4: i32 sqlId +// 5: string sql; +//} +// +// +//struct TApiMetaData { +// 1: string agentId +// 2: i64 agentStartTime +// +// 4: i32 apiId, +// 5: string apiInfo, +// 6: optional i32 line, +// +// 10: optional i32 type; +//} +// +//struct TResult { +// 1: bool success +// 2: optional string message +//} \ No newline at end of file diff --git a/grpc/src/main/thrift/Command.thrift b/grpc/src/main/thrift/Command.thrift new file mode 100644 index 000000000000..98a810b059e9 --- /dev/null +++ b/grpc/src/main/thrift/Command.thrift @@ -0,0 +1,147 @@ +namespace java com.navercorp.pinpoint.thrift.dto.command + +enum TThreadDumpType { + TARGET, + PENDING +} +struct TCommandThreadDump { + 1: TThreadDumpType type = TThreadDumpType.TARGET + 2: optional string name + 3: optional i64 pendingTimeMillis +} + +enum TThreadState { + NEW, + RUNNABLE, + BLOCKED, + WAITING, + TIMED_WAITING, + TERMINATED, + UNKNOWN +} + +struct TMonitorInfo { + 1: i32 stackDepth + 2: string stackFrame +} + +struct TThreadDump { + 1: string threadName + 2: i64 threadId + 3: i64 blockedTime + 4: i64 blockedCount + 5: i64 waitedTime + 6: i64 waitedCount + 7: string lockName + 8: i64 lockOwnerId + 9: string lockOwnerName + 10: bool inNative + 11: bool suspended + 12: TThreadState threadState + 13: list stackTrace + 14: list lockedMonitors + 15: list lockedSynchronizers +} + +struct TThreadLightDump { + 1: string threadName + 2: i64 threadId + 3: optional TThreadState threadState +} + +struct TCommandThreadDumpResponse { + 1: list threadDumps +} + + +struct TCmdActiveThreadCount { +} + +struct TCmdActiveThreadCountRes { + 1: i32 histogramSchemaType + 2: list activeThreadCount + 3: optional i64 timeStamp +} + + +struct TActiveThreadDump { + 1: i64 startTime + 2: i64 localTraceId + 3: TThreadDump threadDump + 4: bool sampled = false + 5: optional string transactionId + 6: optional string entryPoint +} + +struct TActiveThreadLightDump { + 1: i64 startTime + 2: i64 localTraceId + 3: TThreadLightDump threadDump + 4: bool sampled = false + 5: optional string transactionId + 6: optional string entryPoint +} + +struct TCmdActiveThreadDump { + 1: optional i32 limit + 2: optional list threadNameList + 3: optional list localTraceIdList +} + +struct TCmdActiveThreadLightDump { + 1: optional i32 limit + 2: optional list threadNameList + 3: optional list localTraceIdList +} + +struct TCmdActiveThreadDumpRes { + 1: list threadDumps + 2: optional string type + 3: optional string subType + 4: optional string version +} + +struct TCmdActiveThreadLightDumpRes { + 1: list threadDumps + 2: optional string type + 3: optional string subType + 4: optional string version +} + +struct TCommandEcho { + 1: string message +} + +enum TRouteResult { + OK = 0, + + BAD_REQUEST = 200, + EMPTY_REQUEST = 201, + NOT_SUPPORTED_REQUEST = 202, + + BAD_RESPONSE = 210, + EMPTY_RESPONSE = 211, + NOT_SUPPORTED_RESPONSE = 212, + + TIMEOUT = 220, + + NOT_FOUND = 230, + + NOT_ACCEPTABLE = 240, + NOT_SUPPORTED_SERVICE = 241, + + UNKNOWN = -1 +} + +struct TCommandTransfer { + 1: string applicationName + 2: string agentId + 3: optional i64 startTime + 4: binary payload +} + +struct TCommandTransferResponse { + 1: TRouteResult routeResult + 2: binary payload + 3: optional string message +} \ No newline at end of file diff --git a/grpc/src/main/thrift/Flink.thrift b/grpc/src/main/thrift/Flink.thrift new file mode 100644 index 000000000000..45d6ec973cc1 --- /dev/null +++ b/grpc/src/main/thrift/Flink.thrift @@ -0,0 +1,143 @@ +namespace java com.navercorp.pinpoint.thrift.dto.flink + +enum TFJvmGcType { + UNKNOWN, + SERIAL, + PARALLEL, + CMS, + G1 +} + +struct TFServiceInfo { + 1: optional string serviceName + 2: optional list serviceLibs +} + +struct TFServerMetaData { + 1: optional string serverInfo + 2: optional list vmArgs + 10: optional list serviceInfos +} + +struct TFJvmInfo { + 1: i16 version = 0 + 2: optional string vmVersion + 3: optional TFJvmGcType gcType = TFJvmGcType.UNKNOWN +} + +struct TFAgentInfo { + 1: string hostname + 2: string ip + 3: string ports + 4: string agentId + 5: string applicationName + 6: i16 serviceType + 7: i32 pid + 8: string agentVersion; + 9: string vmVersion; + + 10: i64 startTimestamp + + 11: optional i64 endTimestamp + 12: optional i32 endStatus + + 20: optional TFServerMetaData serverMetaData + + 30: optional TFJvmInfo jvmInfo + + 40: optional bool container = false +} + +struct TFJvmGc { + 1: TFJvmGcType type = TFJvmGcType.UNKNOWN + 2: i64 jvmMemoryHeapUsed + 3: i64 jvmMemoryHeapMax + 4: i64 jvmMemoryNonHeapUsed + 5: i64 jvmMemoryNonHeapMax + 6: i64 jvmGcOldCount + 7: i64 jvmGcOldTime + 8: optional TFJvmGcDetailed jvmGcDetailed +} + +struct TFDirectBuffer { + 1: optional i64 directCount + 2: optional i64 directMemoryUsed + 3: optional i64 mappedCount + 4: optional i64 mappedMemoryUsed +} + +struct TFJvmGcDetailed { + 1: optional i64 jvmGcNewCount + 2: optional i64 jvmGcNewTime + 3: optional double jvmPoolCodeCacheUsed + 4: optional double jvmPoolNewGenUsed + 5: optional double jvmPoolOldGenUsed + 6: optional double jvmPoolSurvivorSpaceUsed + 7: optional double jvmPoolPermGenUsed + 8: optional double jvmPoolMetaspaceUsed +} + +struct TFCpuLoad { + 1: optional double jvmCpuLoad + 2: optional double systemCpuLoad +} + +struct TFTransaction { + 2: optional i64 sampledNewCount + 3: optional i64 sampledContinuationCount + 4: optional i64 unsampledNewCount + 5: optional i64 unsampledContinuationCount +} + +struct TFActiveTraceHistogram { + 1: i16 version = 0 + 2: optional i32 histogramSchemaType + 3: optional list activeTraceCount +} + +struct TFActiveTrace { + 1: optional TFActiveTraceHistogram histogram +} + +struct TFResponseTime { + 1: optional i64 avg = 0 +} + +struct TFAgentStat { + 1: optional string agentId + 2: optional i64 startTimestamp + 3: optional i64 timestamp + 4: optional i64 collectInterval + 10: optional TFJvmGc gc + 20: optional TFCpuLoad cpuLoad + 30: optional TFTransaction transaction + 40: optional TFActiveTrace activeTrace + 50: optional TFDataSourceList dataSourceList + 60: optional TFResponseTime responseTime + 80: optional TFFileDescriptor fileDescriptor + 90: optional TFDirectBuffer directBuffer + 200: optional string metadata +} + +struct TFAgentStatBatch { + 1: string agentId + 2: i64 startTimestamp + 10: list agentStats +} + +struct TFDataSource { + 1: i32 id + 2: optional i16 serviceTypeCode + 3: optional string databaseName + 4: optional string url + 5: optional i32 activeConnectionSize = 0 + 6: optional i32 maxConnectionSize +} + +struct TFDataSourceList { + 1: list dataSourceList +} + +struct TFFileDescriptor { + 1: i64 openFileDescriptorCount +} diff --git a/grpc/src/main/thrift/Pinpoint.thrift b/grpc/src/main/thrift/Pinpoint.thrift new file mode 100644 index 000000000000..8b96f718cfa3 --- /dev/null +++ b/grpc/src/main/thrift/Pinpoint.thrift @@ -0,0 +1,152 @@ +include "Command.thrift" + +namespace java com.navercorp.pinpoint.thrift.dto + +enum TJvmGcType { + UNKNOWN, + SERIAL, + PARALLEL, + CMS, + G1 +} + +struct TServiceInfo { + 1: optional string serviceName + 2: optional list serviceLibs +} + +struct TServerMetaData { + 1: optional string serverInfo + 2: optional list vmArgs + 10: optional list serviceInfos +} + +struct TJvmInfo { + 1: i16 version = 0 + 2: optional string vmVersion + 3: optional TJvmGcType gcType = TJvmGcType.UNKNOWN +} + +struct TAgentInfo { + 1: string hostname + 2: string ip + 3: string ports + 4: string agentId + 5: string applicationName + 6: i16 serviceType + 7: i32 pid + 8: string agentVersion; + 9: string vmVersion; + + 10: i64 startTimestamp + + 11: optional i64 endTimestamp + 12: optional i32 endStatus + + 20: optional TServerMetaData serverMetaData + + 30: optional TJvmInfo jvmInfo + + 40: optional bool container = false +} + +struct TJvmGc { + 1: TJvmGcType type = TJvmGcType.UNKNOWN + 2: i64 jvmMemoryHeapUsed + 3: i64 jvmMemoryHeapMax + 4: i64 jvmMemoryNonHeapUsed + 5: i64 jvmMemoryNonHeapMax + 6: i64 jvmGcOldCount + 7: i64 jvmGcOldTime + 8: optional TJvmGcDetailed jvmGcDetailed +} + +struct TDirectBuffer { + 1: optional i64 directCount + 2: optional i64 directMemoryUsed + 3: optional i64 mappedCount + 4: optional i64 mappedMemoryUsed +} + +struct TJvmGcDetailed { + 1: optional i64 jvmGcNewCount + 2: optional i64 jvmGcNewTime + 3: optional double jvmPoolCodeCacheUsed + 4: optional double jvmPoolNewGenUsed + 5: optional double jvmPoolOldGenUsed + 6: optional double jvmPoolSurvivorSpaceUsed + 7: optional double jvmPoolPermGenUsed + 8: optional double jvmPoolMetaspaceUsed +} + +struct TCpuLoad { + 1: optional double jvmCpuLoad + 2: optional double systemCpuLoad +} + +struct TTransaction { + 2: optional i64 sampledNewCount + 3: optional i64 sampledContinuationCount + 4: optional i64 unsampledNewCount + 5: optional i64 unsampledContinuationCount +} + +struct TActiveTraceHistogram { + 1: i16 version = 0 + 2: optional i32 histogramSchemaType + 3: optional list activeTraceCount +} + +struct TActiveTrace { + 1: optional TActiveTraceHistogram histogram +} + +struct TResponseTime { + 1: optional i64 avg = 0 + 2: optional i64 max = 0 +} + +struct TDeadlock { + 1: optional i32 deadlockedThreadCount; + 2: optional list deadlockedThreadList; +} + +struct TAgentStat { + 1: optional string agentId + 2: optional i64 startTimestamp + 3: optional i64 timestamp + 4: optional i64 collectInterval + 10: optional TJvmGc gc + 20: optional TCpuLoad cpuLoad + 30: optional TTransaction transaction + 40: optional TActiveTrace activeTrace + 50: optional TDataSourceList dataSourceList + 60: optional TResponseTime responseTime + 70: optional TDeadlock deadlock + 80: optional TFileDescriptor fileDescriptor + 90: optional TDirectBuffer directBuffer + 200: optional string metadata +} + +struct TAgentStatBatch { + 1: string agentId + 2: i64 startTimestamp + 10: list agentStats +} + +struct TDataSource { + 1: i32 id + 2: optional i16 serviceTypeCode + 3: optional string databaseName + 4: optional string url + 5: optional i32 activeConnectionSize = 0 + 6: optional i32 maxConnectionSize +} + +struct TDataSourceList { + 1: list dataSourceList +} + +struct TFileDescriptor { + 1: i64 openFileDescriptorCount +} diff --git a/grpc/src/main/thrift/Trace.thrift b/grpc/src/main/thrift/Trace.thrift new file mode 100644 index 000000000000..e35c650deaa7 --- /dev/null +++ b/grpc/src/main/thrift/Trace.thrift @@ -0,0 +1,192 @@ +namespace java com.navercorp.pinpoint.thrift.dto +// 1.6.x- : version = 0; +// 1.7.x+ : version = 1; +const i8 TRACE_V1 = 0; +const i8 TRACE_V2 = 1; + +struct TIntStringValue { + 1: i32 intValue; + 2: optional string stringValue; +} + +struct TIntStringStringValue { + 1: i32 intValue; + 2: optional string stringValue1; + 3: optional string stringValue2; +} + +struct TLongIntIntByteByteStringValue { + 1: i64 longValue; + 2: i32 intValue1; + 3: optional i32 intValue2; + 4: optional i8 byteValue1; + 5: optional i8 byteValue2; + 6: optional string stringValue; +} + +struct TIntBooleanIntBooleanValue { + 1: i32 intValue1; + 2: bool boolValue1; + 3: i32 intValue2; + 4: bool boolValue2; +} + +union TAnnotationValue { + 1: string stringValue + 2: bool boolValue; + 3: i32 intValue; + 4: i64 longValue; + 5: i16 shortValue + 6: double doubleValue; + 7: binary binaryValue; + 8: i8 byteValue; + 9: TIntStringValue intStringValue; + 10: TIntStringStringValue intStringStringValue; + 11: TLongIntIntByteByteStringValue longIntIntByteByteStringValue; + 12: TIntBooleanIntBooleanValue intBooleanIntBooleanValue; +} + +struct TAnnotation { + 1: i32 key, + 2: optional TAnnotationValue value +} + +struct TSpanEvent { + + 7: optional i64 spanId + 8: i16 sequence + + // 1.6.x- : delta of the span startTime + // 1.7.0+: delta of startTime of previous SpanEvent + // If SpanEvent is the first SpanEvent, startElapsed is span startTime + 9: i32 startElapsed = 0; + + 10: optional i32 endElapsed = 0 + + 11: optional string rpc + 12: i16 serviceType + 13: optional string endPoint + + 14: optional list annotations + + 15: optional i32 depth = -1 + 16: optional i64 nextSpanId = -1 + + 20: optional string destinationId + + 25: optional i32 apiId; + 26: optional TIntStringValue exceptionInfo; + + 30: optional i32 asyncId; + 31: optional i32 nextAsyncId; + 32: optional i16 asyncSequence; +} + +struct TSpan { + + 1: string agentId + 2: string applicationName + 3: i64 agentStartTime + + // identical to agentId if null + //4: optional string traceAgentId + //5: i64 traceAgentStartTime; + //6: i64 traceTransactionSequence; + 4: binary transactionId; + + 7: i64 spanId + 8: optional i64 parentSpanId = -1 + + // span event's startTimestamp + 9: i64 startTime + 10: optional i32 elapsed = 0 + + 11: optional string rpc + + 12: i16 serviceType + 13: optional string endPoint + 14: optional string remoteAddr + + 15: optional list annotations + 16: optional i16 flag = 0 + + 17: optional i32 err + + 18: optional list spanEventList + + 19: optional string parentApplicationName + 20: optional i16 parentApplicationType + 21: optional string acceptorHost + + 25: optional i32 apiId; + 26: optional TIntStringValue exceptionInfo; + + 30: optional i16 applicationServiceType; + 31: optional i8 loggingTransactionInfo; + + 32: optional i8 version = TRACE_V2; +} + +struct TSpanChunk { + 1: string agentId + 2: string applicationName + 3: i64 agentStartTime + + // @deprecate (1.7.0) + 4: i16 serviceType ( deprecated ) + + // identical to agentId if null + //5: optional string traceAgentId + //6: i64 traceAgentStartTime; + //7: i64 traceTransactionSequence; + 5: binary transactionId; + + 8: i64 spanId + + 9: optional string endPoint + + 10: list spanEventList + + 11: optional i16 applicationServiceType + + // @since 1.7.0 time for data compression + 12: optional i64 keyTime; + + 13: optional i8 version = TRACE_V2; +} + + +struct TStringMetaData { + + 1: string agentId + 2: i64 agentStartTime + + 4: i32 stringId + 5: string stringValue; +} + +struct TSqlMetaData { + + 1: string agentId + 2: i64 agentStartTime + + 4: i32 sqlId + 5: string sql; +} + + +struct TApiMetaData { + 1: string agentId + 2: i64 agentStartTime + + 4: i32 apiId, + 5: string apiInfo, + 6: optional i32 line, + + 10: optional i32 type; +} + +struct TResult { + 1: bool success + 2: optional string message +} \ No newline at end of file diff --git a/hbase/clover.license b/hbase/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/hbase/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-hbase @@ -12,53 +12,4 @@ pom - - - - com.spotify - docker-maven-plugin - ${docker.maven.plugin.version} - - false - naver/${project.artifactId}:${project.version} - java:8-jdk - /opt/hbase/hbase-$HBASE_VERSION/bin/hbase master start - - /usr/lib/jvm/java-8-openjdk-amd64 - 1.2.3 - /opt/hbase/hbase-1.2.3 - http://apache.mirrors.pair.com/hbase - http://archive.apache.org/dist/hbase - - - 2181 - 60000 - 16010 - 60020 - 16030 - - - - /opt/hbase/ - ${project.basedir}/scripts/ - hbase-create.hbase - - - /opt/hbase/ - ${project.basedir}/ - hbase-site.xml - - - - curl -fSL "$HBASE_REPOSITORY/$HBASE_VERSION/hbase-$HBASE_VERSION-bin.tar.gz" -o hbase.tar.gz || curl -fSL "$HBASE_SUB_REPOSITORY/$HBASE_VERSION/hbase-$HBASE_VERSION-bin.tar.gz" -o hbase.tar.gz - tar xfvz hbase.tar.gz -C /opt/hbase - rm -rf hbase.tar.gz - cp /opt/hbase/hbase-site.xml /opt/hbase/hbase-$HBASE_VERSION/conf/hbase-site.xml - $HBASE_HOME/bin/start-hbase.sh; sleep 10; $HBASE_HOME/bin/hbase shell /opt/hbase/hbase-create.hbase; $HBASE_HOME/bin/stop-hbase.sh - - - - - - diff --git a/hbase/scripts/hbase-drop.hbase b/hbase/scripts/hbase-drop.hbase index 2bd4a49b4063..e22d403d44b5 100644 --- a/hbase/scripts/hbase-drop.hbase +++ b/hbase/scripts/hbase-drop.hbase @@ -1,6 +1,6 @@ disable 'AgentInfo' disable 'AgentStatV2' - +disable 'ApplicationStatAggre' disable 'AgentLifeCycle' disable 'AgentEvent' disable 'ApplicationIndex' diff --git a/mvnw b/mvnw index 6ecc150ae0a5..961a82500138 100755 --- a/mvnw +++ b/mvnw @@ -54,38 +54,16 @@ case "`uname`" in CYGWIN*) cygwin=true ;; MINGW*) mingw=true;; Darwin*) darwin=true - # - # Look for the Apple JDKs first to preserve the existing behaviour, and then look - # for the new JDKs provided by Oracle. - # - if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then - # - # Apple JDKs - # - export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then - # - # Apple JDKs - # - export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then - # - # Oracle JDKs - # - export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home - fi - - if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then - # - # Apple JDKs - # - export JAVA_HOME=`/usr/libexec/java_home` - fi - ;; + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; esac if [ -z "$JAVA_HOME" ] ; then @@ -130,7 +108,7 @@ if $cygwin ; then CLASSPATH=`cygpath --path --unix "$CLASSPATH"` fi -# For Migwn, ensure paths are in UNIX format before anything is touched +# For Mingw, ensure paths are in UNIX format before anything is touched if $mingw ; then [ -n "$M2_HOME" ] && M2_HOME="`(cd "$M2_HOME"; pwd)`" @@ -187,14 +165,25 @@ CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { - local basedir=$(pwd) - local wdir=$(pwd) + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" while [ "$wdir" != '/' ] ; do if [ -d "$wdir"/.mvn ] ; then basedir=$wdir break fi - wdir=$(cd "$wdir/.."; pwd) + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround done echo "${basedir}" } @@ -206,7 +195,74 @@ concat_lines() { fi } -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar" + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java @@ -221,14 +277,8 @@ if $cygwin; then MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` fi -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -# avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in $@ exec "$JAVACMD" \ $MAVEN_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ diff --git a/mvnw.cmd b/mvnw.cmd index 6936c3e90d97..830073a17e4e 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -35,6 +35,8 @@ @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' @echo off +@REM set title of command window +title %0 @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% @@ -80,8 +82,6 @@ goto error :init -set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* - @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". @REM Fallback to current working directory if not found. @@ -117,10 +117,26 @@ for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do s :endReadAdditionalConfig SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" - -set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar" +FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* if ERRORLEVEL 1 goto error goto end diff --git a/plugins/activemq-client/clover.license b/plugins/activemq-client/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/activemq-client/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-activemq-client-plugin pinpoint-activemq-client-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/activemq-client/src/main/java/com/navercorp/pinpoint/plugin/activemq/client/ActiveMQClientConstants.java b/plugins/activemq-client/src/main/java/com/navercorp/pinpoint/plugin/activemq/client/ActiveMQClientConstants.java index 52bc4ee5ca31..15214fd3f1d1 100644 --- a/plugins/activemq-client/src/main/java/com/navercorp/pinpoint/plugin/activemq/client/ActiveMQClientConstants.java +++ b/plugins/activemq-client/src/main/java/com/navercorp/pinpoint/plugin/activemq/client/ActiveMQClientConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Naver Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -28,15 +28,17 @@ /** * @author HyunGil Jeong */ -public interface ActiveMQClientConstants { +public final class ActiveMQClientConstants { + private ActiveMQClientConstants() { + } - ServiceType ACTIVEMQ_CLIENT = ServiceTypeFactory.of(8310, "ACTIVEMQ_CLIENT", QUEUE, RECORD_STATISTICS); - ServiceType ACTIVEMQ_CLIENT_INTERNAL = ServiceTypeFactory.of(8311, "ACTIVEMQ_CLIENT_INTERNAL", "ACTIVEMQ_CLIENT"); + public static final ServiceType ACTIVEMQ_CLIENT = ServiceTypeFactory.of(8310, "ACTIVEMQ_CLIENT", QUEUE, RECORD_STATISTICS); + public static final ServiceType ACTIVEMQ_CLIENT_INTERNAL = ServiceTypeFactory.of(8311, "ACTIVEMQ_CLIENT_INTERNAL", "ACTIVEMQ_CLIENT"); - AnnotationKey ACTIVEMQ_BROKER_URL = AnnotationKeyFactory.of(101, "activemq.broker.address", AnnotationKeyProperty.VIEW_IN_RECORD_SET); - AnnotationKey ACTIVEMQ_MESSAGE = AnnotationKeyFactory.of(102, "activemq.message", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final AnnotationKey ACTIVEMQ_BROKER_URL = AnnotationKeyFactory.of(101, "activemq.broker.address", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final AnnotationKey ACTIVEMQ_MESSAGE = AnnotationKeyFactory.of(102, "activemq.message", AnnotationKeyProperty.VIEW_IN_RECORD_SET); - String UNKNOWN_ADDRESS = "Unknown"; + public static final String UNKNOWN_ADDRESS = "Unknown"; - String ACTIVEMQ_CLIENT_SCOPE = "ActiveMQClientScope"; + public static final String ACTIVEMQ_CLIENT_SCOPE = "ActiveMQClientScope"; } diff --git a/plugins/activemq-client/src/main/java/com/navercorp/pinpoint/plugin/activemq/client/interceptor/ActiveMQMessageConsumerReceiveInterceptor.java b/plugins/activemq-client/src/main/java/com/navercorp/pinpoint/plugin/activemq/client/interceptor/ActiveMQMessageConsumerReceiveInterceptor.java index 8e462e4fa673..95098d1ad102 100644 --- a/plugins/activemq-client/src/main/java/com/navercorp/pinpoint/plugin/activemq/client/interceptor/ActiveMQMessageConsumerReceiveInterceptor.java +++ b/plugins/activemq-client/src/main/java/com/navercorp/pinpoint/plugin/activemq/client/interceptor/ActiveMQMessageConsumerReceiveInterceptor.java @@ -41,7 +41,7 @@ public ActiveMQMessageConsumerReceiveInterceptor(TraceContext traceContext, Meth // Instead, only log when the method is actually traced. @Override protected void logBeforeInterceptor(Object target, Object[] args) { - return; + } @Override @@ -55,7 +55,7 @@ protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object // Instead, only log when the method is actually traced. @Override protected void logAfterInterceptor(Object target, Object[] args, Object result, Throwable throwable) { - return; + } @Override diff --git a/plugins/akka-http/.gitignore b/plugins/akka-http/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/akka-http/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/akka-http/pom.xml b/plugins/akka-http/pom.xml new file mode 100644 index 000000000000..a16eec81c5b5 --- /dev/null +++ b/plugins/akka-http/pom.xml @@ -0,0 +1,52 @@ + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-akka-http-plugin + pinpoint-akka-http-plugin + jar + + + 1.6 + ${env.JAVA_8_HOME} + java18 + + + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + + + + com.typesafe.akka + akka-http-core_2.12 + 10.1.0-RC1 + provided + + + com.typesafe.akka + akka-http_2.12 + 10.1.0-RC1 + provided + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + \ No newline at end of file diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpConfig.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpConfig.java new file mode 100644 index 000000000000..3f04292119fd --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpConfig.java @@ -0,0 +1,99 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http; + +import com.navercorp.pinpoint.bootstrap.config.ExcludeMethodFilter; +import com.navercorp.pinpoint.bootstrap.config.ExcludePathFilter; +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.bootstrap.config.SkipFilter; +import com.navercorp.pinpoint.common.util.Assert; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Taejin Koo + */ +public class AkkaHttpConfig { + + private static final String KEY_ENABLE = "profiler.akka.http.enable"; + private static final String KEY_EXCLUDEURL = "profiler.akka.http.excludeurl"; + private static final String KEY_IP_HEADER = "profiler.akka.http.realipheader"; + private static final String KEY_EXCLUDE_HTTP_METHOD = "profiler.akka.http.excludemethod"; + static final String KEY_TRANSFORM_TARGET_NAME = "profiler.akka.http.transform.targetname"; + static final String KEY_TRANSFORM_PARAMETERS = "profiler.akka.http.transform.targetparameter"; + + private static final boolean DEFAULT_ENABLE = false; + private static final String DEFAULT_TRANSFORM_TARGET_NAME = "akka.http.scaladsl.server.directives.BasicDirectives.$anonfun$mapRequestContext$2"; + + // server + private final boolean enable; + private final String realIpHeader; + private final Filter excludeUrlFilter; + private final Filter excludeHttpMethodFilter; + private final String transformTargetName; + private final List transformParameters; + + public AkkaHttpConfig(ProfilerConfig config) { + Assert.requireNonNull(config, "config must not be null"); + + this.enable = config.readBoolean(KEY_ENABLE, DEFAULT_ENABLE); + + this.realIpHeader = config.readString(KEY_IP_HEADER, null); + + final String excludeUrl = config.readString(KEY_EXCLUDEURL, ""); + if (!excludeUrl.isEmpty()) { + this.excludeUrlFilter = new ExcludePathFilter(excludeUrl); + } else { + this.excludeUrlFilter = new SkipFilter(); + } + + final String excludeHttpMethodType = config.readString(KEY_EXCLUDE_HTTP_METHOD, ""); + if (!excludeHttpMethodType.isEmpty()) { + this.excludeHttpMethodFilter = new ExcludeMethodFilter(excludeHttpMethodType); + } else { + this.excludeHttpMethodFilter = new SkipFilter(); + } + + this.transformTargetName = config.readString(KEY_TRANSFORM_TARGET_NAME, DEFAULT_TRANSFORM_TARGET_NAME); + this.transformParameters = config.readList(KEY_TRANSFORM_PARAMETERS); + } + + public boolean isEnable() { + return enable; + } + + public Filter getExcludeUrlFilter() { + return excludeUrlFilter; + } + + public String getRealIpHeader() { + return realIpHeader; + } + + public Filter getExcludeHttpMethodFilter() { + return excludeHttpMethodFilter; + } + + public String getTransformTargetName() { + return transformTargetName; + } + + public List getTransformTargetParameters() { return transformParameters; } + +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpConstants.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpConstants.java new file mode 100644 index 000000000000..af59a60f825e --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpConstants.java @@ -0,0 +1,38 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; +import com.navercorp.pinpoint.common.trace.ServiceTypeProperty; + +/** + * @author lopiter + */ +public class AkkaHttpConstants { + + public static final ServiceType AKKA_HTTP_SERVER = ServiceTypeFactory.of(1310, "AKKA_HTTP_SERVER", ServiceTypeProperty.RECORD_STATISTICS); + public static final ServiceType AKKA_HTTP_SERVER_INTERNAL = ServiceTypeFactory.of(9998, "1311", "AKKA_HTTP_SERVER_INTERNAL"); + + static final String DIRECTIVE_INTERCEPTOR = "com.navercorp.pinpoint.plugin.akka.http.interceptor.DirectivesInterceptor"; + + static final String REQUEST_CONTEXT_COMPLETE_INTERCEPTOR = "com.navercorp.pinpoint.plugin.akka.http.interceptor.RequestContextImplCompleteInterceptor"; + static final String REQUEST_CONTEXT_REDIRECT_INTERCEPTOR = "com.navercorp.pinpoint.plugin.akka.http.interceptor.RequestContextImplRedirectInterceptor"; + static final String REQUEST_CONTEXT_FAIL_INTERCEPTOR = "com.navercorp.pinpoint.plugin.akka.http.interceptor.RequestContextImplFailInterceptor"; + static final String REQUEST_CONTEXT_COPY_INTERCEPTOR = "com.navercorp.pinpoint.plugin.akka.http.interceptor.RequestContextImplCopyInterceptor"; + +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpMetadataProvider.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpMetadataProvider.java new file mode 100644 index 000000000000..9562bc9ad9a0 --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpMetadataProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyMatchers; +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * @author lopiter + */ +public class AkkaHttpMetadataProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER); + context.addServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER_INTERNAL, AnnotationKeyMatchers.exact(AnnotationKey.HTTP_STATUS_CODE)); + } + +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpPlugin.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpPlugin.java new file mode 100644 index 000000000000..351dea3d7953 --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/AkkaHttpPlugin.java @@ -0,0 +1,172 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExecutionPolicy; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.common.util.StringUtils; + +import java.security.ProtectionDomain; +import java.util.Arrays; +import java.util.List; + + +public class AkkaHttpPlugin implements ProfilerPlugin, TransformTemplateAware { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private TransformTemplate transformTemplate; + + @Override + public void setup(ProfilerPluginSetupContext context) { + final AkkaHttpConfig config = new AkkaHttpConfig(context.getConfig()); + if (!config.isEnable()) { + logger.info("Disable akka http plugin"); + return; + } + + final String transformTargetName = config.getTransformTargetName(); + final List transformTargetParameters = config.getTransformTargetParameters(); + + if (StringUtils.isEmpty(transformTargetName)) { + logger.warn("Not found 'profiler.akka.http.transform.targetname' in config"); + } else { + try { + final String className = toClassName(transformTargetName); + final String methodName = toMethodName(transformTargetName); + logger.info("Add request handler method for Akka HTTP Server. class={}, method={}", className, methodName); + + transformDirectives(className, methodName, transformTargetParameters); + transformRequestContext(); + transformHttpRequest(); + } catch (IllegalArgumentException e) { + logger.warn("can't find target '{}' value={}", AkkaHttpConfig.KEY_TRANSFORM_TARGET_NAME, transformTargetName); + } + } + } + + private String toClassName(String fullQualifiedMethodName) { + final int classEndPosition = fullQualifiedMethodName.lastIndexOf('.'); + if (classEndPosition <= 0) { + throw new IllegalArgumentException("invalid full qualified method name(" + fullQualifiedMethodName + "). not found method"); + } + + return fullQualifiedMethodName.substring(0, classEndPosition).trim(); + } + + private String toMethodName(String fullQualifiedMethodName) { + final int methodBeginPosition = fullQualifiedMethodName.lastIndexOf('.'); + if (methodBeginPosition <= 0 || methodBeginPosition + 1 >= fullQualifiedMethodName.length()) { + throw new IllegalArgumentException("invalid full qualified method name(" + fullQualifiedMethodName + "). not found method"); + } + + return fullQualifiedMethodName.substring(methodBeginPosition + 1).trim(); + } + + private void transformDirectives(String clazzName, final String methodName, final List methodParameters) { + transformTemplate.transform(clazzName, new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(methodName))) { + if (checkSuitableMethod(method, methodParameters)) { + logger.info("addInterceptor={}", Arrays.asList(method.getParameterTypes())); + method.addInterceptor(AkkaHttpConstants.DIRECTIVE_INTERCEPTOR); + } else { + logger.info("params={}", Arrays.asList(method.getParameterTypes())); + } + } + return target.toBytecode(); + } + }); + } + + private boolean checkSuitableMethod(InstrumentMethod method, List parameters) { + if (method == null) { + return false; + } + + String[] parameterTypes = method.getParameterTypes(); + int parameterSize = parameters.size(); + + if (ArrayUtils.getLength(parameterTypes) != parameterSize) { + return false; + } + for (int i = 0; i < parameterSize; i++) { + if (!parameterTypes[i].equals(parameters.get(i))) { + return false; + } + } + return true; + } + + private void transformRequestContext() { + transformTemplate.transform("akka.http.scaladsl.server.RequestContextImpl", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(AsyncContextAccessor.class.getName()); + + final InstrumentMethod completeMethod = target.getDeclaredMethod("complete", "akka.http.scaladsl.marshalling.ToResponseMarshallable"); + completeMethod.addScopedInterceptor(AkkaHttpConstants.REQUEST_CONTEXT_COMPLETE_INTERCEPTOR, "test", ExecutionPolicy.ALWAYS); + + final InstrumentMethod redirectMethod = target.getDeclaredMethod("redirect", "akka.http.scaladsl.model.Uri", "akka.http.scaladsl.model.StatusCodes$Redirection"); + redirectMethod.addInterceptor(AkkaHttpConstants.REQUEST_CONTEXT_REDIRECT_INTERCEPTOR); + + final InstrumentMethod failMethod = target.getDeclaredMethod("fail", "java.lang.Throwable"); + failMethod.addInterceptor(AkkaHttpConstants.REQUEST_CONTEXT_FAIL_INTERCEPTOR); + + final InstrumentMethod copyMethod = target.getDeclaredMethod("copy", "akka.http.scaladsl.model.HttpRequest", + "akka.http.scaladsl.model.Uri$Path", "scala.concurrent.ExecutionContextExecutor", "akka.stream.Materializer", "akka.event.LoggingAdapter", + "akka.http.scaladsl.settings.RoutingSettings", "akka.http.scaladsl.settings.ParserSettings"); + copyMethod.addInterceptor(AkkaHttpConstants.REQUEST_CONTEXT_COPY_INTERCEPTOR); + return target.toBytecode(); + } + }); + } + + private void transformHttpRequest() { + transformTemplate.transform("akka.http.javadsl.model.HttpRequest", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(AsyncContextAccessor.class.getName()); + + return target.toBytecode(); + } + }); + } + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } + +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/HttpRequestAdaptor.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/HttpRequestAdaptor.java new file mode 100644 index 000000000000..b9924d9f8d96 --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/HttpRequestAdaptor.java @@ -0,0 +1,133 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http; + +import akka.http.javadsl.model.Host; +import akka.http.javadsl.model.HttpHeader; +import akka.http.javadsl.model.HttpRequest; +import akka.http.javadsl.model.Uri; +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.common.util.StringUtils; + +import java.util.Optional; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpRequestAdaptor implements RequestAdaptor { + + private static final String UNKNOWN = "Unknown"; + + // https://doc.akka.io/docs/akka-http/current/routing-dsl/directives/misc-directives/extractClientIP.html + // X-Forwarded-For, Remote-Address, or X-Real-IP + + private static final String DEFAULT_REMOTE_ADDRESS_HEADER = "Remote-Address"; + + private final String remoteAddressHeader; + + public HttpRequestAdaptor(AkkaHttpConfig config) { + this.remoteAddressHeader = getRealIpHeader(config); + } + + private String getRealIpHeader(AkkaHttpConfig config) { + String realIpHeader = config.getRealIpHeader(); + if (StringUtils.isEmpty(realIpHeader)) { + return DEFAULT_REMOTE_ADDRESS_HEADER; + } + return realIpHeader; + } + + @Override + public String getHeader(HttpRequest request, String name) { + return getHeader(request, name, null); + } + + private String getHeader(HttpRequest request, String name, String defaultValue) { + if (request == null) { + return defaultValue; + } + + Optional optional = request.getHeader(name); + if (optional == null) { + return defaultValue; + } + + HttpHeader header = optional.orElse(null); + if (header == null) { + return defaultValue; + } + + String value = header.value(); + if (value == null) { + return defaultValue; + } + + return value; + } + + @Override + public String getRpcName(HttpRequest request) { + Uri uri = request.getUri(); + if (validateRpcName(uri)) { + return uri.getPathString(); + } + return UNKNOWN; + } + + private boolean validateRpcName(Uri uri) { + if (uri == null) { + return false; + } + return StringUtils.hasText(uri.getPathString()); + } + + @Override + public String getEndPoint(HttpRequest request) { + Uri uri = request.getUri(); + if (validateEndPoint(uri)) { + Host host = uri.getHost(); + return HostAndPort.toHostAndPortString(host.address(), uri.getPort()); + } + return UNKNOWN; + } + + private boolean validateEndPoint(Uri uri) { + if (uri == null) { + return false; + } + + Host host = uri.getHost(); + if (host == null) { + return false; + } + + String hostAddress = host.address(); + return StringUtils.hasText(hostAddress); + } + + @Override + public String getRemoteAddress(HttpRequest request) { + return getHeader(request, remoteAddressHeader, ""); + } + + @Override + public String getAcceptorHost(HttpRequest request) { + return getHeader(request, Header.HTTP_HOST.toString()); + } +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/AkkaHttpServerMethodDescriptor.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/AkkaHttpServerMethodDescriptor.java new file mode 100644 index 000000000000..295962eb52db --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/AkkaHttpServerMethodDescriptor.java @@ -0,0 +1,83 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; + +public class AkkaHttpServerMethodDescriptor implements MethodDescriptor { + private int apiId = 0; + private int type = MethodType.WEB_REQUEST; + + @Override + public String getMethodName() { + return ""; + } + + @Override + public String getClassName() { + return ""; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return "()"; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return AkkaHttpServerMethodDescriptor.class.getName(); + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return apiId; + } + + @Override + public String getApiDescriptor() { + return "Akka HTTP Server"; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/AsyncContextSpanEventEndPointInterceptor.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/AsyncContextSpanEventEndPointInterceptor.java new file mode 100644 index 000000000000..719f27341ef1 --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/AsyncContextSpanEventEndPointInterceptor.java @@ -0,0 +1,206 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.AsyncState; +import com.navercorp.pinpoint.bootstrap.context.AsyncStateSupport; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.scope.TraceScope; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public abstract class AsyncContextSpanEventEndPointInterceptor implements AroundInterceptor { + + protected final PLogger logger = PLoggerFactory.getLogger(getClass()); + protected final boolean isDebug = logger.isDebugEnabled(); + protected static final String ASYNC_TRACE_SCOPE = AsyncContext.ASYNC_TRACE_SCOPE; + + protected final MethodDescriptor methodDescriptor; + protected final TraceContext traceContext; + + public AsyncContextSpanEventEndPointInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + this.traceContext = Assert.requireNonNull(traceContext, "traceContext must not be null"); + this.methodDescriptor = Assert.requireNonNull(methodDescriptor, "methodDescriptor must not be null"); + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final AsyncContext asyncContext = getAsyncContext(target); + if (asyncContext == null) { + logger.debug("AsyncContext not found"); + return; + } + + final Trace trace = getAsyncTrace(asyncContext); + if (trace == null) { + return; + } + + if (isDebug) { + logger.debug("Asynchronous invocation. asyncTraceId={}, trace={}", asyncContext, trace); + } + // entry scope. + entryAsyncTraceScope(trace); + + try { + // trace event for default & async. + final SpanEventRecorder recorder = trace.traceBlockBegin(); + doInBeforeTrace(recorder, asyncContext, target, args); + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("BEFORE. Caused:{}", th.getMessage(), th); + } + } + } + + protected abstract void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args); + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final AsyncContext asyncContext = getAsyncContext(target); + if (asyncContext == null) { + logger.debug("Not found asynchronous invocation metadata"); + return; + } + if (isDebug) { + logger.debug("Asynchronous invocation. asyncContext={}", asyncContext); + } + + final Trace trace = asyncContext.currentAsyncTraceObject(); + if (trace == null) { + return; + } + if (isDebug) { + logger.debug("Asynchronous invocation. asyncTraceId={}, trace={}", asyncContext, trace); + } + + // leave scope. + if (!leaveAsyncTraceScope(trace)) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to leave scope of async trace {}.", trace); + } + // delete unstable trace. + deleteAsyncTrace(trace); + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + doInAfterTrace(recorder, target, args, result, throwable); + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER error. Caused:{}", th.getMessage(), th); + } + } finally { + trace.traceBlockEnd(); + if (isAsyncTraceDestination(trace)) { + if(isDebug) { + logger.debug("Arrived at async trace destination. asyncTraceId={}", asyncContext); + } + deleteAsyncTrace(trace); + } + finishAsyncState(asyncContext); + } + } + + protected abstract void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable); + + protected AsyncContext getAsyncContext(Object target) { + return AsyncContextAccessorUtils.getAsyncContext(target); + } + + private Trace getAsyncTrace(AsyncContext asyncContext) { + final Trace trace = asyncContext.continueAsyncTraceObject(); + if (trace == null) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to continue async trace. 'result is null'"); + } + return null; + } + if (isDebug) { + logger.debug("getAsyncTrace() trace {}, asyncContext={}", trace, asyncContext); + } + + return trace; + } + + private void deleteAsyncTrace(final Trace trace) { + if (isDebug) { + logger.debug("Delete async trace {}.", trace); + } + traceContext.removeTraceObject(); + trace.close(); + } + + private void entryAsyncTraceScope(final Trace trace) { + final TraceScope scope = trace.getScope(ASYNC_TRACE_SCOPE); + if (scope != null) { + scope.tryEnter(); + } + } + + private boolean leaveAsyncTraceScope(final Trace trace) { + final TraceScope scope = trace.getScope(ASYNC_TRACE_SCOPE); + if (scope != null) { + if (scope.canLeave()) { + scope.leave(); + } else { + return false; + } + } + return true; + } + + private boolean isAsyncTraceDestination(final Trace trace) { + if (!trace.isAsync()) { + return false; + } + + final TraceScope scope = trace.getScope(ASYNC_TRACE_SCOPE); + return scope != null && !scope.isActive(); + } + + private void finishAsyncState(final AsyncContext asyncContext) { + if (asyncContext instanceof AsyncStateSupport) { + final AsyncStateSupport asyncStateSupport = (AsyncStateSupport) asyncContext; + AsyncState asyncState = asyncStateSupport.getAsyncState(); + asyncState.finish(); + if (isDebug) { + logger.debug("finished asyncState. asyncTraceId={}", asyncContext); + } + } + } + +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/DirectivesInterceptor.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/DirectivesInterceptor.java new file mode 100644 index 000000000000..96fb724cb68d --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/DirectivesInterceptor.java @@ -0,0 +1,289 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import akka.http.javadsl.model.HttpMethod; +import akka.http.javadsl.model.HttpRequest; +import akka.http.scaladsl.server.RequestContextImpl; +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanId; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; +import com.navercorp.pinpoint.bootstrap.util.NumberUtils; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.plugin.akka.http.AkkaHttpConfig; +import com.navercorp.pinpoint.plugin.akka.http.AkkaHttpConstants; +import com.navercorp.pinpoint.plugin.akka.http.HttpRequestAdaptor; + +public class DirectivesInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(DirectivesInterceptor.class); + private final boolean isTrace = logger.isTraceEnabled(); + private final boolean isDebug = logger.isDebugEnabled(); + + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private static final AkkaHttpServerMethodDescriptor AKKA_HTTP_SERVER_METHOD_DESCRIPTOR = new AkkaHttpServerMethodDescriptor(); + + private final ProxyHttpHeaderRecorder proxyHttpHeaderRecorder; + + private final RequestAdaptor requestAdaptor; + private final Filter excludeHttpMethodFilter; + private final Filter excludeUrlFilter; + + + public DirectivesInterceptor(final TraceContext traceContext, final MethodDescriptor methodDescriptor) { + this.traceContext = traceContext; + this.descriptor = methodDescriptor; + + final AkkaHttpConfig config = new AkkaHttpConfig(traceContext.getProfilerConfig()); + this.excludeUrlFilter = config.getExcludeUrlFilter(); + this.excludeHttpMethodFilter = config.getExcludeHttpMethodFilter(); + this.requestAdaptor = new HttpRequestAdaptor(config); + this.proxyHttpHeaderRecorder = new ProxyHttpHeaderRecorder(traceContext.getProfilerConfig().isProxyHttpHeaderEnable(), requestAdaptor); + + traceContext.cacheApi(AKKA_HTTP_SERVER_METHOD_DESCRIPTOR); + } + + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + int requestContextIndex = getArgsIndexOfRequestContext(args); + if (requestContextIndex == -1) { + return; + } + + if (traceContext.currentTraceObject() != null) { + return; + } + + RequestContextImpl requestContext = (RequestContextImpl) args[requestContextIndex]; + if (!(requestContext instanceof AsyncContextAccessor)) { + if (isDebug) { + logger.debug("Invalid requestContext. Need metadata accessor({}).", AsyncContextAccessor.class.getName()); + } + return; + } + + akka.http.scaladsl.model.HttpRequest request = requestContext.request(); + final Trace trace = createTrace(request); + if (trace == null || !trace.canSampled()) { + return; + } + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER_INTERNAL); + + final AsyncContext asyncContext = recorder.recordNextAsyncContext(true); + ((AsyncContextAccessor) requestContext)._$PINPOINT$_setAsyncContext(asyncContext); + if (isDebug) { + logger.debug("Set closeable-AsyncContext {}", asyncContext); + } + } + + private int getArgsIndexOfRequestContext(Object[] args) { + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof RequestContextImpl) return i; + } + return -1; + } + + private Trace createTrace(final HttpRequest request) { + if (request == null) { + return null; + } + + final String requestUri = String.valueOf(request.getUri()); + if (requestUri != null && excludeUrlFilter.filter(requestUri)) { + // skip request. + if (isTrace) { + logger.trace("filter requestURI:{}", requestUri); + } + return null; + } + + HttpMethod method = request.method(); + if (method != null && excludeHttpMethodFilter.filter(method.value())) { + // skip request. + if (isTrace) { + logger.trace("filter http method:{}", method.value()); + } + return null; + } + + final boolean sampling = samplingEnable(request); + if (!sampling) { + final Trace trace = traceContext.disableSampling(); + if (isDebug) { + logger.debug("Remote call sampling flag found. skip trace requestUrl:{}", requestUri); + } + return trace; + } + + final TraceId traceId = populateTraceIdFromRequest(request); + if (traceId != null) { + final Trace trace = traceContext.continueAsyncTraceObject(traceId); + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + recordRootSpan(recorder, request); + if (isDebug) { + logger.debug("TraceID exist. continue trace. traceId:{}, requestUrl:{}", traceId, requestUri); + } + } else { + if (isDebug) { + logger.debug("TraceID exist. camSampled is false. skip trace. traceId:{}, requestUrl:{}", traceId, requestUri); + } + } + return trace; + } else { + final Trace trace = traceContext.newAsyncTraceObject(); + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + recordRootSpan(recorder, request); + } else { + if (isDebug) { + logger.debug("Sampling is disabled"); + } + } + return trace; + } + } + + private boolean samplingEnable(HttpRequest request) { + // optional value + final String samplingFlag = requestAdaptor.getHeader(request, Header.HTTP_SAMPLED.toString()); + if (isDebug) { + logger.debug("SamplingFlag={}", samplingFlag); + } + return SamplingFlagUtils.isSamplingFlag(samplingFlag); + } + + private TraceId populateTraceIdFromRequest(final HttpRequest request) { + final String transactionId = requestAdaptor.getHeader(request, Header.HTTP_TRACE_ID.toString()); + if (transactionId != null) { + final long parentSpanID = NumberUtils.parseLong(requestAdaptor.getHeader(request, Header.HTTP_PARENT_SPAN_ID.toString()), SpanId.NULL); + final long spanID = NumberUtils.parseLong(requestAdaptor.getHeader(request, Header.HTTP_SPAN_ID.toString()), SpanId.NULL); + final short flags = NumberUtils.parseShort(requestAdaptor.getHeader(request, Header.HTTP_FLAGS.toString()), (short) 0); + final TraceId id = traceContext.createTraceId(transactionId, parentSpanID, spanID, flags); + if (isDebug) { + logger.debug("TraceID exist. continue trace. {}", id); + } + return id; + } else { + return null; + } + } + + private void recordRootSpan(final SpanRecorder recorder, final HttpRequest request) { + recorder.recordServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER); + final String requestURL = requestAdaptor.getRpcName(request); + if (StringUtils.hasLength(requestURL)) { + recorder.recordRpcName(requestURL); + } + + String remoteAddress = requestAdaptor.getRemoteAddress(request); + if (StringUtils.hasLength(remoteAddress)) { + recorder.recordRemoteAddress(remoteAddress); + } + + this.proxyHttpHeaderRecorder.record(recorder, request); + + if (!recorder.isRoot()) { + recordParentInfo(recorder, request); + } + recorder.recordApi(AKKA_HTTP_SERVER_METHOD_DESCRIPTOR); + } + + private void recordParentInfo(SpanRecorder recorder, final HttpRequest request) { + String parentApplicationName = requestAdaptor.getHeader(request, Header.HTTP_PARENT_APPLICATION_NAME.toString()); + if (parentApplicationName != null) { + final String host = requestAdaptor.getAcceptorHost(request); + if (host != null) { + recorder.recordAcceptorHost(host); + } else { + String requestURL = String.valueOf(request.getUri()); + recorder.recordAcceptorHost(NetworkUtils.getHostFromURL(requestURL)); + } + final String type = requestAdaptor.getHeader(request, Header.HTTP_PARENT_APPLICATION_TYPE.toString()); + final short parentApplicationType = NumberUtils.parseShort(type, ServiceType.UNDEFINED.getCode()); + recorder.recordParentApplication(parentApplicationName, parentApplicationType); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + if (getArgsIndexOfRequestContext(args) == -1) { + return; + } + + final Trace trace = traceContext.currentRawTraceObject(); + if (trace == null) { + return; + } + + if (!trace.canSampled()) { + deleteTrace(trace); + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + } catch (Throwable t) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER. Caused:{}", t.getMessage(), t); + } + } finally { + trace.traceBlockEnd(); + deleteTrace(trace); + } + } + + private void deleteTrace(final Trace trace) { + traceContext.removeTraceObject(); + trace.close(); + } + + + + +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplCompleteInterceptor.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplCompleteInterceptor.java new file mode 100644 index 000000000000..523dffb60c8c --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplCompleteInterceptor.java @@ -0,0 +1,80 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import akka.http.javadsl.server.Complete; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.akka.http.AkkaHttpConstants; +import scala.Option; +import scala.concurrent.Future; +import scala.util.Failure; +import scala.util.Success; + +public class RequestContextImplCompleteInterceptor extends AsyncContextSpanEventEndPointInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(RequestContextImplCompleteInterceptor.class); + + public RequestContextImplCompleteInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + try { + if (result instanceof Future && ((Future) result).isCompleted()) { + Option value = ((Future) result).value(); + if (value == null) { + return; + } + + Object routeResult = value.get(); + if (routeResult instanceof Success) { + Object success = ((Success) routeResult).get(); + if (success instanceof Complete) { + akka.http.javadsl.model.HttpResponse response = ((Complete) success).getResponse(); + if (response == null) { + return; + } + akka.http.javadsl.model.StatusCode status = response.status(); + if (status == null) { + return; + } + recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, status.intValue()); + } + } else if (routeResult instanceof Failure) { + Throwable failure = ((Failure) routeResult).exception(); + recorder.recordException(failure); + } + } + } finally { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER_INTERNAL); + recorder.recordException(throwable); + } + } + +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplCopyInterceptor.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplCopyInterceptor.java new file mode 100644 index 000000000000..6580fc0c1258 --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplCopyInterceptor.java @@ -0,0 +1,35 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; + +public class RequestContextImplCopyInterceptor implements AroundInterceptor { + @Override + public void before(Object target, Object[] args) { + + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (result instanceof AsyncContextAccessor) { + ((AsyncContextAccessor) result)._$PINPOINT$_setAsyncContext(AsyncContextAccessorUtils.getAsyncContext(target)); + } + } +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplFailInterceptor.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplFailInterceptor.java new file mode 100644 index 000000000000..a3e083e3796e --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplFailInterceptor.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.plugin.akka.http.AkkaHttpConstants; + +public class RequestContextImplFailInterceptor extends AsyncContextSpanEventEndPointInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(RequestContextImplFailInterceptor.class); + + public RequestContextImplFailInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + if (ArrayUtils.getLength(args) > 0 && args[0] instanceof Throwable) { + recorder.recordException((Throwable) args[0]); + } + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER_INTERNAL); + } + +} diff --git a/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplRedirectInterceptor.java b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplRedirectInterceptor.java new file mode 100644 index 000000000000..adccb9c0e1f9 --- /dev/null +++ b/plugins/akka-http/src/main/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplRedirectInterceptor.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.akka.http.AkkaHttpConstants; + +public class RequestContextImplRedirectInterceptor extends AsyncContextSpanEventEndPointInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(RequestContextImplRedirectInterceptor.class); + + public RequestContextImplRedirectInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER_INTERNAL); + if (throwable != null) { + recorder.recordException(throwable); + } + } +} diff --git a/plugins/akka-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/akka-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..34bb4831ec4a --- /dev/null +++ b/plugins/akka-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.akka.http.AkkaHttpPlugin \ No newline at end of file diff --git a/plugins/akka-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/akka-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..537234f6d6fb --- /dev/null +++ b/plugins/akka-http/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.akka.http.AkkaHttpMetadataProvider \ No newline at end of file diff --git a/plugins/akka-http/src/test/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplCompleteInterceptorTest.java b/plugins/akka-http/src/test/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplCompleteInterceptorTest.java new file mode 100644 index 000000000000..31f1854774e2 --- /dev/null +++ b/plugins/akka-http/src/test/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplCompleteInterceptorTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import akka.http.scaladsl.marshalling.ToResponseMarshallable; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.akka.http.AkkaHttpConstants; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import static org.mockito.Mockito.verify; + +@RunWith(org.mockito.junit.MockitoJUnitRunner.class) +public class RequestContextImplCompleteInterceptorTest { + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + @Mock + private ToResponseMarshallable marshallable; + + private RequestContextImplCompleteInterceptor interceptor; + + @Before + public void setUp() throws Exception { + interceptor = new RequestContextImplCompleteInterceptor(traceContext, descriptor); + } + + @Test + public void doInBeforeTrace() { + interceptor.doInBeforeTrace(recorder, null, null, new Object[]{marshallable}); + } + + @Test + public void doInAfterTrace() { + interceptor.doInAfterTrace(recorder, null, null, null, null); + verify(recorder).recordApi(descriptor); + verify(recorder).recordServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER_INTERNAL); + verify(recorder).recordException(null); + } +} diff --git a/plugins/akka-http/src/test/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplFailInterceptorTest.java b/plugins/akka-http/src/test/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplFailInterceptorTest.java new file mode 100644 index 000000000000..195972b507c7 --- /dev/null +++ b/plugins/akka-http/src/test/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplFailInterceptorTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.akka.http.AkkaHttpConstants; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import static org.mockito.Mockito.verify; + +@RunWith(org.mockito.junit.MockitoJUnitRunner.class) +public class RequestContextImplFailInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + private Exception e = new Exception("Test"); + + RequestContextImplFailInterceptor interceptor; + + @Before + public void setUp() { + interceptor = new RequestContextImplFailInterceptor(traceContext, descriptor); + } + + @Test + public void doInBeforeTrace() { + interceptor.doInBeforeTrace(recorder, null, null, new Object[]{e}); + verify(recorder).recordException(e); + } + + @Test + public void doInAfterTrace() { + interceptor.doInAfterTrace(recorder, null, null, null, null); + verify(recorder).recordApi(descriptor); + verify(recorder).recordServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER_INTERNAL); + } +} diff --git a/plugins/akka-http/src/test/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplRedirectInterceptorTest.java b/plugins/akka-http/src/test/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplRedirectInterceptorTest.java new file mode 100644 index 000000000000..4ff639fb6748 --- /dev/null +++ b/plugins/akka-http/src/test/java/com/navercorp/pinpoint/plugin/akka/http/interceptor/RequestContextImplRedirectInterceptorTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.akka.http.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.akka.http.AkkaHttpConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import static org.mockito.Mockito.verify; + +@RunWith(org.mockito.junit.MockitoJUnitRunner.class) +public class RequestContextImplRedirectInterceptorTest { + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + private Exception e = new Exception("Test"); + + RequestContextImplRedirectInterceptor interceptor; + + @Test + public void doInAfterTrace() { + interceptor = new RequestContextImplRedirectInterceptor(traceContext, descriptor); + interceptor.doInAfterTrace(recorder, null, null, null, e); + verify(recorder).recordApi(descriptor); + verify(recorder).recordServiceType(AkkaHttpConstants.AKKA_HTTP_SERVER_INTERNAL); + verify(recorder).recordException(e); + } +} diff --git a/plugins/akka-http/src/test/resources/pinpoint.config b/plugins/akka-http/src/test/resources/pinpoint.config new file mode 100644 index 000000000000..8ec7f4fbdf0c --- /dev/null +++ b/plugins/akka-http/src/test/resources/pinpoint.config @@ -0,0 +1,723 @@ +# +# Pinpoint agent configuration +# + +########################################################### +# Collector server # +########################################################### +profiler.collector.ip=127.0.0.1 + +# placeHolder support "${key}" +profiler.collector.span.ip=${profiler.collector.ip} +profiler.collector.span.port=9996 + +# placeHolder support "${key}" +profiler.collector.stat.ip=${profiler.collector.ip} +profiler.collector.stat.port=9995 + +# placeHolder support "${key}" +profiler.collector.tcp.ip=${profiler.collector.ip} +profiler.collector.tcp.port=9994 + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +profiler.interceptorregistry.size=8192 + +# Manually override jvm vendor name (Oracle, IBM, OpenJDK, etc) +# You probably won't ever need to set this value. +profiler.jvm.vendor.name= + +# Interval (in milliseconds) at which agent stat data is collected. (default : 5000, min : 1000, max : 5000) +profiler.jvm.stat.collect.interval=5000 +# Number of agent stat data sent to the collector in a single batch. (default : 6) +profiler.jvm.stat.batch.send.count=6 + +# Allow to add detailed collector's metrics +profiler.jvm.stat.collect.detailed.metrics=true + +# Allow sampling. +profiler.sampling.enable=true + +# 1 out of n transactions will be sampled where n is the rate. (1: 100%) +profiler.sampling.rate=1 + +# Allow buffering when flushing span to IO. +profiler.io.buffering.enable=true + +# How many spans to store if buffering enabled. +profiler.io.buffering.buffersize=20 + +# Capacity of the SpanDataSender write queue. +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 +profiler.spandatasender.chunk.size=16384 +profiler.spandatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.spandatasender.transport.type=UDP + +# Capacity of the StatDataSender write queue. +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 +profiler.statdatasender.chunk.size=16384 +profiler.statdatasender.socket.type=OIO +# Should keep in mind +# 1. Loadbancing : TCP transport load balancing is per connection.(UDP transport loadbalancing is per packet) +# 2. In unexpected situations, UDP has its own protection feature (like packet loss etc.), but tcp does not have such a feature. (We will add protection later) +profiler.statdatasender.transport.type=UDP + +# Interval to retry sending agent info. Unit is milliseconds. +profiler.agentInfo.send.retry.interval=300000 + +# Allow TCP data command. +profiler.tcpdatasender.command.accept.enable=true +profiler.tcpdatasender.command.activethread.enable=true +profiler.tcpdatasender.command.activethread.count.enable=true +profiler.tcpdatasender.command.activethread.threaddump.enable=true +profiler.tcpdatasender.command.activethread.threadlightdump.enable=true + +# Trace Agent active thread info. +profiler.pinpoint.activethread=true + +# Trace DataSource +profiler.pinpoint.datasource=true + +# Deadlock Monitor +profiler.monitor.deadlock.enable=true +profiler.monitor.deadlock.interval=60000 + +## Call Stack +# Set max depth, if -1 is unlimited and min is 2. +profiler.callstack.max.depth=64 + +# weather or not to propagate exceptions occurred at interceptor +profiler.interceptor.exception.propagate=false + +# Allow bytecode framework (JAVASSIST or ASM) +profiler.instrument.engine=ASM + +# bytecode dump option +# java bytecode debug option +bytecode.dump.enable=false +#bytecode.dump.classlist=com.naver.user.UserService,com.pinpoint.debug.TestClass +bytecode.dump.classlist= +bytecode.dump.bytecode=false +bytecode.dump.verify=false +bytecode.dump.asm=false + +# Matcher +profiler.instrument.matcher.enable=true +# Matcher cache. max size is 64. +profiler.instrument.matcher.interface.cache.size=4 +profiler.instrument.matcher.interface.cache.entry.size=16 +profiler.instrument.matcher.annotation.cache.size=4 +profiler.instrument.matcher.annotation.cache.entry.size=4 +profiler.instrument.matcher.super.cache.size=4 +profiler.instrument.matcher.super.cache.entry.size=4 + +# Lambda expressions. +profiler.lambda.expressions.support=true + +# Proxy HTTP headers. +# Please see (https://github.com/naver/pinpoint/blob/master/doc/proxy-http-header.md) for more information. +profiler.proxy.http.header.enable=true + +# HTTP status code with request failure. +# 1xx, 2xx, 3xx, 4xx, 5xx, 100, 101, 200, 201, ... 501, 502, 503, 504, 505 +# e.g. profiler.http.status.code.errors=5xx, 401, 403 +profiler.http.status.code.errors=5xx + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + +########################################################### +# application type detect order # +########################################################### +profiler.type.detect.order= + +profiler.plugin.disable= + +########################################################### +# user defined classes # +########################################################### +# Specify classes and methods you want to profile here. + +# Needs to be a comma separated list of fully qualified class names, or fully qualified package names with wild card class. +profiler.include= +# Ex: foo.bar.MyClass, foo.baz.* + +# Needs to be a comma separated list of fully qualified method names. Wild card not supported. +profiler.entrypoint= +# Ex: foo.bar.MyClass.myMethod, foo.bar.MyClass.anotherMethod + +# Message queue listener invoker methods. +# This is usually for when a separate implementation or a framework provides a separate handler for invoking callbacks +# when consuming messages. +# Comma-separated list of fully qualified method names with a Message argument. +profiler.message.queue.client.handler.methods=org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener + +########################################################### +# TOMCAT # +########################################################### +profiler.tomcat.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap +# Check pre-conditions when registering class file transformers mainly due to JBoss plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.apache.catalina.startup.Bootstrap, +# or SpringBoot's launchers. +# Set this to false to bypass this check entirely (such as when launching standalone applications running embedded Tomcat). +profiler.tomcat.conditional.transform=true +# Hide pinpoint headers. +profiler.tomcat.hidepinpointheader=true +# URLs to exclude from tracing +profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html +# HTTP Request methods to exclude from tracing +#profiler.tomcat.excludemethod= +profiler.tomcat.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.tomcat.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.tomcat.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.tomcat.realipemptyvalue}, Ignore header value. +#profiler.tomcat.realipemptyvalue=unknown + + +########################################################### +# JETTY # +########################################################### +profiler.jetty.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main +# URLs to exclude from tracing +profiler.jetty.excludeurl= +# Hide pinpoint headers. 9.x only +profiler.jetty.hide-pinpoint-header=true + +########################################################### +# DUBBO # +########################################################### +profiler.dubbo.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.dubbo.bootstrap.main=com.alibaba.dubbo.container.Main + + +########################################################### +# JBOSS # +########################################################### +profiler.jboss.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jboss.bootstrap.main=org.jboss.modules.Main +# Check pre-conditions when registering class file transformers mainly due to Tomcat plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.jboss.modules.Main. +# Set this to false to bypass this check entirely. +profiler.jboss.conditional.transform=true +# Hide pinpoint headers. +profiler.jboss.hidepinpointheader=true +# URLs to exclude from tracing +profiler.jboss.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jboss.excludemethod= +profiler.jboss.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jboss.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jboss.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. +#profiler.jboss.realipemptyvalue=unknown + +########################################################### +# Vert.x(Reliability and stability can not be guaranteed) # +########################################################### +profiler.vertx.enable=false +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.vertx.bootstrap.main=io.vertx.core.Starter +# Track Vertx.runOnContext() & Vertx.executeBlocking(). +# Sets the base packages that implements io.vertx.core.Handler. +# Improvement is in progress. +profiler.vertx.handler.base-packages= +# e.g. com.service.handler, com.server.http.handler + +# HTTP server +profiler.vertx.http.server.enable=false +# Set HttpServerRequestHandler method name. The argument is io.vertx.core.http.HttpServerRequest. +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept +profiler.vertx.http.server.tracerequestparam=true +profiler.vertx.http.server.hidepinpointheader=true +# URLs to exclude from tracing +profiler.vertx.http.server.excludeurl= +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.vertx.http.server.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.vertx.http.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.vertx.http.server.realipemptyvalue}, Ignore header value. +#profiler.vertx.http.server.realipemptyvalue=unknown +# HTTP Request methods to exclude from tracing +#profiler.vertx.http.server.excludemethod= + +# HTTP client +profiler.vertx.http.client.enable=false +profiler.vertx.http.client.param=true +profiler.vertx.http.client.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.vertx.http.client.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.vertx.http.client.cookie.sampling.rate=1 +profiler.vertx.http.client.entity.statuscode=true + +########################################################### +# SPRING BOOT # +########################################################### +profiler.springboot.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.springboot.bootstrap.main=org.springframework.boot.loader.JarLauncher, org.springframework.boot.loader.WarLauncher, org.springframework.boot.loader.PropertiesLauncher + +########################################################### +# JSP # +########################################################### +profiler.jsp.enable=true + +########################################################### +# JDBC # +########################################################### +# Profile JDBC drivers. +profiler.jdbc=true +# Size of cache. Fixed maximum. +profiler.jdbc.sqlcachesize=1024 +# trace bindvalues for PreparedStatements +profiler.jdbc.tracesqlbindvalue=true +# Maximum bindvalue size. +profiler.jdbc.maxsqlbindvaluesize=1024 + +# +# MYSQL +# +# Profile MySQL. +profiler.jdbc.mysql=true +# Allow profiling of setautocommit. +profiler.jdbc.mysql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mysql.commit=true +# Allow profiling of rollback. +profiler.jdbc.mysql.rollback=true +# Trace bindvalues for MySQL PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mysql.tracesqlbindvalue=true + +# +# MARIADB +# +# Profile MariaDB +profiler.jdbc.mariadb=true +# Allow profiling of setautocommit. +profiler.jdbc.mariadb.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mariadb.commit=true +# Allow profiling of rollback. +profiler.jdbc.mariadb.rollback=true +# Trace bindvalues for MariaDB PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mariadb.tracesqlbindvalue=true + +# +# MSSQL Jtds +# +# Profile jTDS. +profiler.jdbc.jtds=true +# Allow profiling of setautocommit. +profiler.jdbc.jtds.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.jtds.commit=true +# Allow profiling of rollback. +profiler.jdbc.jtds.rollback=true +# Trace bindvalues for jTDS PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.jtds.tracesqlbindvalue=true + +# +# Oracle +# +# Profile Oracle DB. +profiler.jdbc.oracle=true +# Allow profiling of setautocommit. +profiler.jdbc.oracle.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.oracle.commit=true +# Allow profiling of rollback. +profiler.jdbc.oracle.rollback=true +# Trace bindvalues for Oracle PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.oracle.tracesqlbindvalue=true + +# +# CUBRID +# +# Profile CUBRID. +profiler.jdbc.cubrid=true +# Allow profiling of setautocommit. +profiler.jdbc.cubrid.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.cubrid.commit=true +# Allow profiling of rollback. +profiler.jdbc.cubrid.rollback=true +# Trace bindvalues for CUBRID PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.cubrid.tracesqlbindvalue=true + +# +# DBCP +# +# Profile DBCP. +profiler.jdbc.dbcp=true +profiler.jdbc.dbcp.connectionclose=true + +# +# DBCP2 +# +# Profile DBCP2. +profiler.jdbc.dbcp2=true +profiler.jdbc.dbcp2.connectionclose=true + +# +# HIKARICP +# +profiler.jdbc.hikaricp=true +profiler.jdbc.hikaricp.connectionclose=true + +# +# CASSANDRA +# +# Profile CASSANDRA. +profiler.cassandra=true +# Trace bindvalues for CASSANDRA PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.cassandra.tracecqlbindvalue=true + +# +# PostgreSQL +# +# Profile PostgreSQL. +profiler.jdbc.postgresql=true +# Allow profiling of setautocommit. +profiler.jdbc.postgresql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.postgresql.commit=true +# Allow profiling of rollback. +profiler.jdbc.postgresql.rollback=true + + +########################################################### +# Apache HTTP Client 3.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient3.param=true + +# Record Cookies. +profiler.apache.httpclient3.cookie=true + +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient3.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient3.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.entity.dumptype=ALWAYS +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient3.entity.sampling.rate=1 + +# Record IO time. +profiler.apache.httpclient3.io=true + +########################################################### +# Apache HTTP Client 4.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient4.param=true + +# Record cookies. +profiler.apache.httpclient4.cookie=true + +# When cookies should be dumped. It could be ALWAYS or EXCEPTION. +profiler.apache.httpclient4.cookie.dumptype=ALWAYS + +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient4.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient4.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient4.entity.dumptype=ALWAYS + +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient4.entity.sampling.rate=1 + +# Allow profiling status code value. +profiler.apache.httpclient4.entity.statuscode=true + +# Record IO time. +profiler.apache.httpclient4.io=true + +# Not supported yet. +#profiler.apache.nio.httpclient4=true + +########################################################### +# JDK HTTPURLConnection # +########################################################### +# Profile parameter. +profiler.jdk.http.param=true + +########################################################### +# Ning Async HTTP Client # +########################################################### +# Profile Ning Async HTTP Client. +profiler.ning.asynchttpclient=true +# Record cookies. +profiler.ning.asynchttpclient.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS +# Cookie dump size. +profiler.ning.asynchttpclient.cookie.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.cookie.sampling.rate=1 +# Record Entities. +profiler.ning.asynchttpclient.entity=true +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.entity.dumptype=ALWAYS +# Entity dump size. +profiler.ning.asynchttpclient.entity.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.entity.sampling.rate=1 +# Record parameters. (unsupported in 1.8.x, 1.9.x versions) +profiler.ning.asynchttpclient.param=true +# When to dump parameters. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.param.dumptype=ALWAYS +# Parameter dump size. +profiler.ning.asynchttpclient.param.dumpsize=1024 +# 1 out of n parameters will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.param.sampling.rate=1 + + +########################################################### +# Arcus # +########################################################### +# Profile Arcus. +profiler.arcus=true +profiler.arcus.async=true +# Record keytrace. +profiler.arcus.keytrace=true + +########################################################### +# Memcached # +########################################################### +# Profile Memecached. +profiler.memcached=true +profiler.memcached.async=true +# Record keytrace +profiler.memcached.keytrace=true + +########################################################### +# Thrift # +########################################################### +# Profile Thrift +profiler.thrift.client=true +profiler.thrift.client.async=true +# Profile processor. +profiler.thrift.processor=true +profiler.thrift.processor.async=true +# Allow recording arguments. +profiler.thrift.service.args=true +# Allow recording result. +profiler.thrift.service.result=true + + +########################################################### +# ibatis # +########################################################### +# Profile ibatis. +profiler.orm.ibatis=true + +########################################################### +# mybatis # +########################################################### +# Profile mybatis +profiler.orm.mybatis=true + +########################################################### +# spring-beans +########################################################### +# Profile spring-beans +profiler.spring.beans=true + +# filters +# filter +# filter OR filters +# filter +# value +# value AND filter +# value +# token +# token OR token +# token +# profiler.spring.beans.n.scope= [component-scan | post-processor] default is component-scan. +# profiler.spring.beans.n.base-packages= [package name, ...] +# profiler.spring.beans.n.name.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.class.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.annotation= [annotation name, ...] +# +# Scope: +# component-scan: or @ComponentScan +# post-processor: BeanPostProcessor - Slow!!! +# +# ANT Style pattern rules: +# ? - matches on character +# * - matches zero or more characters +# ** - matches zero or more 'directories' in a path + +# Examples +# profiler.spring.beans.1.scope=component-scan +# profiler.spring.beans.1.base-packages=com.foo, com.bar +# profiler.spring.beans.1.name.pattern=.*Foo, regex:.*Bar, antstyle:*Controller +# profiler.spring.beans.1.class.pattern= +# profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository +# +# profiler.spring.beans.2.scope=post-processor +# profiler.spring.beans.2.base-packages=com.foo +# profiler.spring.beans.2.name.pattern= +# profiler.spring.beans.2.class.pattern=antstyle:com.foo.repository.*Repository, antstyle:com.foo.Service.Main* +# profiler.spring.beans.2.annotation= + +profiler.spring.beans.1.scope=component-scan +profiler.spring.beans.1.base-packages= +profiler.spring.beans.1.name.pattern= +profiler.spring.beans.1.class.pattern= +profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository + +profiler.spring.beans.mark.error=false +########################################################### +# log4j (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.log4j.logging.transactioninfo=false + +########################################################### +# logback (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.logback.logging.transactioninfo=false + +########################################################### +# google httpclient +########################################################### +# Profile async. +profiler.google.httpclient.async=true + +########################################################### +# redis +########################################################### +profiler.redis.pipeline +profiler.redis=true +profiler.redis.io=true + +########################################################### +# OkHttp +########################################################### +profiler.okhttp.enable=true +# Record param. +profiler.okhttp.param=true + +# Record Cookies. +profiler.okhttp.cookie=false +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.okhttp.cookie.dumptype=EXCEPTION +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.okhttp.cookie.sampling.rate=10 +# enqueue operation +profiler.okhttp.async=true + +########################################################### +# gson +########################################################### +profiler.json.gson=true + +########################################################### +# jackson +########################################################### +profiler.json.jackson=true + +########################################################### +# json-lib +########################################################### +profiler.json.jsonlib=true + +########################################################### +# ActiveMQ Client +########################################################### +profiler.activemq.client.enable=true +profiler.activemq.client.producer.enable=true +profiler.activemq.client.consumer.enable=true +profiler.activemq.client.trace.message=false + +# ActiveMQ destination path separator (default is ".") +profiler.activemq.client.destination.separator= + +# ActiveMQ destinations to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.activemq.client.destination.exclude= + +########################################################### +# RxJava +########################################################### +profiler.rxjava=true + +########################################################### +# Hystrix +########################################################### +# profiler.rxjava must also be enabled to properly trace hystrix commands +profiler.hystrix=true + +########################################################### +# Resin +########################################################### +# default enable resin plugin +profiler.resin.enable=true +# if empty , default value is : com.caucho.server.resin.Resin +profiler.resin.bootstrap.main= +# trace param in request ,default value is true +profiler.resin.tracerequestparam=true +# excudeurl eg: filter static resources : /**/*.jpg,/**/*.png,/**/*.css,/**/*.js +profiler.resin.excludeurl= +# trace cookies in request ,default value is true +profiler.resin.tracecookies=true +# cookie.sampling.rate ,default value is 10 +profiler.resin.cookie.sampling.rate=10 +# ALWAYS|EXCEPTION ,default value is EXCEPTION +profiler.resin.cookie.dumptype=ALWAYS + +########################################################### +# RestTemplate +########################################################### +profiler.resttemplate=false + +########################################################### +# Netty +########################################################### +# recommend netty plugin disable, when using VERTX. +profiler.netty=false +profiler.netty.http=false + +########################################################### +# RabbitMQ Client +########################################################### +profiler.rabbitmq.client.enable=true +profiler.rabbitmq.client.producer.enable=true +profiler.rabbitmq.client.consumer.enable=true +# RabbitMQ exchange to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.rabbitmq.client.exchange.exclude= \ No newline at end of file diff --git a/plugins/arcus/clover.license b/plugins/arcus/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/arcus/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-arcus-plugin pinpoint-arcus-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/bom/.gitignore b/plugins/bom/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/bom/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/bom/pom.xml b/plugins/bom/pom.xml new file mode 100644 index 000000000000..4852dfa117d2 --- /dev/null +++ b/plugins/bom/pom.xml @@ -0,0 +1,331 @@ + + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pom + pinpoint-plugin-bom + pinpoint-plugin-bom + + + 2.4.2 + 5.1.2.RELEASE + 2.1.7.1 + 2.5.3 + 3.7.0 + + + + + + com.navercorp.arcus + arcus-java-client + 1.8.1 + + + net.sf.ehcache + ehcache-core + ${ehcache.version} + + + com.datastax.cassandra + cassandra-driver-core + ${cassandra.driver.version} + + + org.apache.cassandra + cassandra-all + 2.1.13 + test + + + org.mongodb + mongodb-driver + ${mongo.driver.version} + + + + org.springframework.data + spring-data-redis + 1.1.1.RELEASE + + + + org.apache.httpcomponents + httpclient + ${httpcomponents.version} + + + org.apache.httpcomponents + httpcore + ${httpcomponents.version} + + + org.apache.httpcomponents + httpcore-nio + ${httpcomponents-core.version} + + + org.apache.httpcomponents + httpasyncclient + 4.1.4 + + + commons-httpclient + commons-httpclient + 3.1 + + + + + + com.google.http-client + google-http-client + 1.20.0 + + + + com.squareup.okhttp + okhttp + 2.5.0 + + + com.squareup.okhttp3 + okhttp + 3.8.1 + + + + redis.clients + jedis + ${jedis.version} + + + + io.lettuce + lettuce-core + ${lettuce.version} + + + + com.ning + async-http-client + 1.8.3 + + + + org.asynchttpclient + async-http-client + 2.0.32 + + + + + + org.apache.activemq + activemq-client + 5.13.2 + + + org.apache.activemq + activemq-all + 5.13.2 + test + + + + org.apache.cxf + cxf-rt-frontend-jaxrs + 3.0.16 + + + org.apache.cxf + cxf-rt-frontend-jaxws + 3.0.16 + + + org.apache.cxf + cxf-rt-transports-http + 3.0.16 + + + org.apache.cxf + cxf-rt-rs-client + 3.0.16 + + + + com.netflix.hystrix + hystrix-core + 1.5.12 + + + + io.reactivex + rxjava + 1.2.0 + + + + org.springframework.amqp + spring-rabbit + 1.7.6.RELEASE + + + + commons-dbcp + commons-dbcp + 1.4 + + + org.apache.commons + commons-dbcp2 + 2.1.1 + + + org.mybatis + mybatis + 3.2.7 + + + + + org.mariadb.jdbc + mariadb-java-client + 1.3.4 + + + mysql + mysql-connector-java + 5.1.45 + + + org.postgresql + postgresql + 9.4.1207 + + + net.sourceforge.jtds + jtds + 1.2.8 + + + + + cubrid + cubrid-jdbc + 8.4.3.1005 + + + + + com.alibaba + dubbo + ${dubbo.version} + + + org.springframework + spring + + + + + + com.alibaba + druid + 1.1.10 + + + + com.alibaba + fastjson + 1.2.47 + + + + com.google.code.gson + gson + 2.3.1 + + + net.sf.json-lib + json-lib + 2.3 + jdk15 + + + + + org.apache.tomcat + catalina + 6.0.43 + + + org.apache.tomcat + coyote + 6.0.43 + + + org.apache.tomcat + servlet-api + 6.0.35 + + + + io.undertow + undertow-core + 2.0.1.Final + + + + org.apache.hbase + hbase-shaded-client + 1.2.6.1 + + + + org.apache.kafka + kafka-clients + 0.11.0.1 + + + + com.fasterxml.jackson.core + jackson-core + ${fastxml.jackson-jdk6.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${fastxml.jackson-jdk6.version} + + + com.fasterxml.jackson.core + jackson-databind + ${fastxml.jackson-jdk6.version} + + + + + \ No newline at end of file diff --git a/plugins/cassandra/clover.license b/plugins/cassandra/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/cassandra/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-cassandra-driver-plugin pinpoint-cassandra-driver-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/CassandraConfig.java b/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/CassandraConfig.java index 555765171690..fa4ecf6b830c 100644 --- a/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/CassandraConfig.java +++ b/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/CassandraConfig.java @@ -30,7 +30,6 @@ public CassandraConfig(ProfilerConfig config) { @Override public String toString() { - return "CassandraConfig [cassandra=" + isPluginEnable() + "]"; + return "CassandraConfig [" + super.toString() + "]"; } - } diff --git a/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/CassandraPlugin.java b/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/CassandraPlugin.java index b197d98e168d..6cfcf1405b1a 100644 --- a/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/CassandraPlugin.java +++ b/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/CassandraPlugin.java @@ -54,11 +54,26 @@ public void setup(ProfilerPluginSetupContext context) { return; } + addStatementWrapperTransformer(); addDefaultPreparedStatementTransformer(); addSessionTransformer(config); addClusterTransformer(); } + private void addStatementWrapperTransformer() { + transformTemplate.transform("com.datastax.driver.core.StatementWrapper", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, + byte[] classfileBuffer) throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + target.addGetter("com.navercorp.pinpoint.plugin.cassandra.field.WrappedStatementGetter", "wrapped"); + return target.toBytecode(); + } + }); + } + private void addDefaultPreparedStatementTransformer() { TransformCallback transformer = new TransformCallback() { @@ -99,7 +114,7 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin } if (className.equals(CLASS_SESSION_MANAGER)) { - if (instrumentor.exist(loader, CLASS_ABSTRACT_SESSION)) { + if (instrumentor.exist(loader, CLASS_ABSTRACT_SESSION, protectionDomain)) { return null; } } diff --git a/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/field/WrappedStatementGetter.java b/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/field/WrappedStatementGetter.java new file mode 100644 index 000000000000..b5424969e0cd --- /dev/null +++ b/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/field/WrappedStatementGetter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.cassandra.field; + +import com.datastax.driver.core.Statement; + +/** + * @author HyunGil Jeong + */ +public interface WrappedStatementGetter { + Statement _$PINPOINT$_getStatement(); +} diff --git a/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/interceptor/CassandraStatementExecuteQueryInterceptor.java b/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/interceptor/CassandraStatementExecuteQueryInterceptor.java index 551f0ca76bb5..a9e34f4c446f 100644 --- a/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/interceptor/CassandraStatementExecuteQueryInterceptor.java +++ b/plugins/cassandra/src/main/java/com/navercorp/pinpoint/plugin/cassandra/interceptor/CassandraStatementExecuteQueryInterceptor.java @@ -22,7 +22,7 @@ import com.datastax.driver.core.BatchStatement; import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.RegularStatement; -import com.datastax.driver.core.StatementWrapper; +import com.datastax.driver.core.Statement; import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.ParsingResult; @@ -37,6 +37,8 @@ import com.navercorp.pinpoint.bootstrap.plugin.jdbc.ParsingResultAccessor; import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; import com.navercorp.pinpoint.bootstrap.plugin.jdbc.bindvalue.BindValueUtils; +import com.navercorp.pinpoint.common.util.MapUtils; +import com.navercorp.pinpoint.plugin.cassandra.field.WrappedStatementGetter; /** * @author dawidmalina @@ -102,7 +104,7 @@ public void before(Object target, Object[] args) { Map bindValue = ((BindValueAccessor) target)._$PINPOINT$_getBindValue(); // TODO Add bind variable interceptors to BoundStatement's setter methods and bind method and pass it down // Extracting bind variables from already-serialized is too risky - if (bindValue != null && !bindValue.isEmpty()) { + if (MapUtils.hasLength(bindValue)) { String bindString = toBindVariable(bindValue); recorder.recordSqlParsingResult(parsingResult, bindString); } else { @@ -121,23 +123,24 @@ public void before(Object target, Object[] args) { } private String retrieveSql(Object args0) { - String sql; if (args0 instanceof BoundStatement) { - sql = ((BoundStatement) args0).preparedStatement().getQueryString(); + return ((BoundStatement) args0).preparedStatement().getQueryString(); } else if (args0 instanceof RegularStatement) { - sql = ((RegularStatement) args0).getQueryString(); - } else if (args0 instanceof StatementWrapper) { - // method to get wrapped statement is package-private, skip. - sql = null; + return ((RegularStatement) args0).getQueryString(); + } else if (args0 instanceof WrappedStatementGetter) { + return retrieveWrappedStatement((WrappedStatementGetter) args0); } else if (args0 instanceof BatchStatement) { // we could unroll all the batched statements and append ; between them if need be but it could be too long. - sql = null; + return null; } else if (args0 instanceof String) { - sql = (String) args0; - } else { - sql = null; + return (String) args0; } - return sql; + return null; + } + + private String retrieveWrappedStatement(WrappedStatementGetter wrappedStatementGetter) { + Statement wrappedStatement = wrappedStatementGetter._$PINPOINT$_getStatement(); + return retrieveSql(wrappedStatement); } private void clean(Object target) { @@ -156,7 +159,7 @@ public void after(Object target, Object[] args, Object result, Throwable throwab logger.afterInterceptor(target, args, result, throwable); } - Trace trace = traceContext.currentTraceObject(); + final Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; } diff --git a/plugins/clover.license b/plugins/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-common-servlet + pinpoint-common-servlet + jar + + + + + + + + com.navercorp.pinpoint + pinpoint-commons + provided + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + javax.servlet + javax.servlet-api + + 3.0.1 + + + provided + + + + + diff --git a/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/MethodFilterExtractor.java b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/MethodFilterExtractor.java new file mode 100644 index 000000000000..ea2b21e2d949 --- /dev/null +++ b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/MethodFilterExtractor.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.common.servlet; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class MethodFilterExtractor implements ParameterExtractor { + + private final Filter excludeProfileMethodFilter; + + private final ParameterExtractor delegate; + + public MethodFilterExtractor(Filter excludeProfileMethodFilter, ParameterExtractor delegate) { + this.excludeProfileMethodFilter = Assert.requireNonNull(excludeProfileMethodFilter, "excludeProfileMethodFilter must not be null"); + this.delegate = Assert.requireNonNull(delegate, "delegate must not be null"); + } + + @Override + public String extractParameter(HttpServletRequest httpServletRequest) { + if (excludeProfileMethodFilter.filter(httpServletRequest.getMethod())) { + return null; + } + return delegate.extractParameter(httpServletRequest); + } +} diff --git a/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/ArgumentValidator.java b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/ArgumentValidator.java new file mode 100644 index 000000000000..446d3e09ce9f --- /dev/null +++ b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/ArgumentValidator.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.common.servlet.util; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface ArgumentValidator { + boolean validate(Object[] args); +} diff --git a/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/HttpServletParameterExtractor.java b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/HttpServletParameterExtractor.java new file mode 100644 index 000000000000..2befd56f4ca0 --- /dev/null +++ b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/HttpServletParameterExtractor.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.common.servlet.util; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.common.util.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpServletParameterExtractor implements ParameterExtractor { + + public static final int PARAMETER_EACH_LIMIT = 64; + public static final int PARAMETER_TOTAL_LIMIT = 512; + + private final int eachLimit; + private final int totalLimit; + + public HttpServletParameterExtractor() { + this(PARAMETER_EACH_LIMIT, PARAMETER_TOTAL_LIMIT); + } + + public HttpServletParameterExtractor(int eachLimit, int totalLimit) { + this.eachLimit = eachLimit; + this.totalLimit = totalLimit; + } + + @Override + public String extractParameter(HttpServletRequest httpServletRequest) { + + final Map parameterMap = httpServletRequest.getParameterMap(); + if (parameterMap.isEmpty()) { + return null; + } + final StringBuilder params = new StringBuilder(64); + for (Map.Entry entry : parameterMap.entrySet()) { + if (params.length() != 0) { + params.append('&'); + } + // skip appending parameters if parameter size is bigger than totalLimit + if (params.length() > totalLimit) { + params.append("..."); + return params.toString(); + } + final String key = entry.getKey(); + if (!StringUtils.hasLength(key)) { + // skip empty or null header name + continue; + } + // append key + params.append(StringUtils.abbreviate(key, eachLimit)); + params.append('='); + // append value + String[] values = entry.getValue(); + if (!ArrayUtils.hasLength(values)) { + // skip empty or null header value + continue; + } + for (String value : values) { + if (value != null) { + params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); + } + } + } + return params.toString(); + } +} diff --git a/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/HttpServletRequestAdaptor.java b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/HttpServletRequestAdaptor.java new file mode 100644 index 000000000000..d26c85075633 --- /dev/null +++ b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/HttpServletRequestAdaptor.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.common.servlet.util; + +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpServletRequestAdaptor implements RequestAdaptor { + + public HttpServletRequestAdaptor() { + } + + @Override + public String getHeader(HttpServletRequest request, String name) { + return request.getHeader(name); + } + + @Override + public String getRpcName(HttpServletRequest request) { + return request.getRequestURI(); + } + + @Override + public String getEndPoint(HttpServletRequest request) { + String serverName = request.getServerName(); + int serverPort = request.getServerPort(); + return HostAndPort.toHostAndPortString(serverName, serverPort); + } + + @Override + public String getRemoteAddress(HttpServletRequest request) { + return request.getRemoteAddr(); + } + + @Override + public String getAcceptorHost(HttpServletRequest request) { + StringBuffer url = request.getRequestURL(); + final String acceptorHost = url != null ? NetworkUtils.getHostFromURL(url.toString()) : null; + return acceptorHost; + } +} diff --git a/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/ParameterRecorderFactory.java b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/ParameterRecorderFactory.java new file mode 100644 index 000000000000..e9ca11256677 --- /dev/null +++ b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/ParameterRecorderFactory.java @@ -0,0 +1,41 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.common.servlet.util; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.HttpParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.DisableParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.plugin.common.servlet.MethodFilterExtractor; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ParameterRecorderFactory { + + public static ParameterRecorder newParameterRecorderFactory(Filter excludeProfileMethodFilter, boolean traceRequestParam) { + if (!traceRequestParam) { + return new DisableParameterRecorder(); + } + ParameterExtractor parameterExtractor = new HttpServletParameterExtractor(); + ParameterExtractor methodFilterExtractor = new MethodFilterExtractor(excludeProfileMethodFilter, parameterExtractor); + return new HttpParameterRecorder(methodFilterExtractor); + } +} diff --git a/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/ServletArgumentValidator.java b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/ServletArgumentValidator.java new file mode 100644 index 000000000000..b331f0d2a985 --- /dev/null +++ b/plugins/common-servlet/src/main/java/com/navercorp/pinpoint/plugin/common/servlet/util/ServletArgumentValidator.java @@ -0,0 +1,84 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.common.servlet.util; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ServletArgumentValidator implements ArgumentValidator { + private final PLogger logger; + + private final int requestIndex; + private final Class requestClass; + + private final int responseIndex; + private final Class responseClass; + + private final int minArgsSize; + + public ServletArgumentValidator(PLogger logger, int requestIndex, Class requestClass, int responseIndex, Class responseClass) { + this(logger, requestIndex, requestClass, responseIndex, responseClass, defaultArgumentMin(requestIndex, responseIndex)); + } + + public ServletArgumentValidator(PLogger logger, int requestIndex, Class requestClass, int responseIndex, Class responseClass, int minArgsSize) { + this.logger = Assert.requireNonNull(logger, "logger must not be null"); + + Assert.isTrue(requestIndex >= 0, "requestIndex must be positive"); + this.requestIndex = requestIndex; + this.requestClass = Assert.requireNonNull(requestClass, "requestClass must not be null"); + + Assert.isTrue(responseIndex >= 0, "responseIndex must be positive"); + this.responseIndex = responseIndex; + this.responseClass = Assert.requireNonNull(responseClass, "responseClass must not be null"); + + Assert.isTrue(requestIndex != responseIndex, "requestIndex==responseIndex"); + this.minArgsSize = minArgsSize; + } + + private static int defaultArgumentMin(int requestIndex, int responseIndex) { + return Math.max(requestIndex, responseIndex) + 1; + } + + @Override + public boolean validate(Object[] args) { + if (args == null) { + return false; + } + if (args.length < minArgsSize) { + return false; + } + + final Object request = args[requestIndex]; + if (!(requestClass.isInstance(request))) { + if (logger.isDebugEnabled()) { + logger.debug("Invalid args[{}] object, Not implemented of {}. args[{}]={}", requestIndex, requestClass, requestIndex, request); + } + return false; + } + final Object response = args[responseIndex]; + if (!(responseClass.isInstance(response))) { + if (logger.isDebugEnabled()) { + logger.debug("Invalid args[{}] object, Not implemented of {}. args[{}]={}.", responseIndex, responseClass, responseIndex, response); + } + return false; + } + return true; + } +} diff --git a/plugins/common-servlet/src/test/java/com/navercorp/pinpoint/plugin/common/servlet/RemoteAddressResolverFactoryTest.java b/plugins/common-servlet/src/test/java/com/navercorp/pinpoint/plugin/common/servlet/RemoteAddressResolverFactoryTest.java new file mode 100644 index 000000000000..bad1fbd7a8bd --- /dev/null +++ b/plugins/common-servlet/src/test/java/com/navercorp/pinpoint/plugin/common/servlet/RemoteAddressResolverFactoryTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.common.servlet; + +import com.navercorp.pinpoint.bootstrap.context.RemoteAddressResolver; + +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.RemoteAddressResolverFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.HttpServletRequestAdaptor; +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RemoteAddressResolverFactoryTest { + public static final String X_FORWARDED_FOR = "x-forwarded-for"; + public static final String UNKNOWN = "unknown"; + + @Test + public void getRemoteAddress0() throws Exception { + RequestAdaptor requestAdaptor = new HttpServletRequestAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, "x-forwarded-for", "unknown"); + final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); + when(httpServletRequest.getHeader(X_FORWARDED_FOR)).thenReturn("127.0.0.1"); + + when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.2"); + assertEquals("127.0.0.1", requestAdaptor.getRemoteAddress(httpServletRequest)); + } + + + @Test + public void getRemoteAddress1() throws Exception { + RequestAdaptor requestAdaptor = new HttpServletRequestAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, "x-forwarded-for", "unknown"); + final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); + when(httpServletRequest.getHeader(X_FORWARDED_FOR)).thenReturn("127.0.0.1, proxy1, proxy2"); + + when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.2"); + + assertEquals("127.0.0.1", requestAdaptor.getRemoteAddress(httpServletRequest)); + } + + @Test + public void getRemoteAddress2() throws Exception { + RequestAdaptor requestAdaptor = new HttpServletRequestAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, "x-forwarded-for", "unknown"); + final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); + + when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.2"); + + assertEquals("127.0.0.2", requestAdaptor.getRemoteAddress(httpServletRequest)); + } +} \ No newline at end of file diff --git a/plugins/common-servlet/src/test/java/com/navercorp/pinpoint/plugin/common/servlet/ServerRequestRecorderTest.java b/plugins/common-servlet/src/test/java/com/navercorp/pinpoint/plugin/common/servlet/ServerRequestRecorderTest.java new file mode 100644 index 000000000000..65c50af7b131 --- /dev/null +++ b/plugins/common-servlet/src/test/java/com/navercorp/pinpoint/plugin/common/servlet/ServerRequestRecorderTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.common.servlet; + +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServerRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServerRequestWrapper; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServerRequestWrapperAdaptor; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * @author jaehong.kim + */ +public class ServerRequestRecorderTest { + private static final String RPC_NAME = "rpcName"; + private static final String END_POINT = "endPoint"; + private static final String REMOTE_ADDRESS = "remoteAddress"; + private static final String ACCEPTOR_HOST = "acceptorHost"; + private static final String GET_HEADER = "getHeader"; + + @Test + public void record() throws Exception { + RequestAdaptor requestAdaptor = new ServerRequestWrapperAdaptor(); + final ServerRequestRecorder recorder = new ServerRequestRecorder(requestAdaptor); + + // SpanRecorder + SpanRecorder spanRecorder = mock(SpanRecorder.class); + + recorder.record(spanRecorder, new MockServerRequestWrapper()); + verify(spanRecorder).recordRpcName(RPC_NAME); + verify(spanRecorder).recordEndPoint(END_POINT); + verify(spanRecorder).recordRemoteAddress(REMOTE_ADDRESS); + verify(spanRecorder).recordAcceptorHost(GET_HEADER); + } + + private class MockServerRequestWrapper implements ServerRequestWrapper { + + @Override + public String getRpcName() { + return RPC_NAME; + } + + @Override + public String getEndPoint() { + return END_POINT; + } + + @Override + public String getRemoteAddress() { + return REMOTE_ADDRESS; + } + + @Override + public String getAcceptorHost() { + return ACCEPTOR_HOST; + } + + @Override + public String getHeader(String name) { + return GET_HEADER; + } + } +} \ No newline at end of file diff --git a/plugins/common-servlet/src/test/java/com/navercorp/pinpoint/plugin/common/servlet/util/ServletArgumentValidatorTest.java b/plugins/common-servlet/src/test/java/com/navercorp/pinpoint/plugin/common/servlet/util/ServletArgumentValidatorTest.java new file mode 100644 index 000000000000..bc4077969a5d --- /dev/null +++ b/plugins/common-servlet/src/test/java/com/navercorp/pinpoint/plugin/common/servlet/util/ServletArgumentValidatorTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.common.servlet.util; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import static org.mockito.Mockito.mock; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ServletArgumentValidatorTest { + + private ArgumentValidator validator; + @Before + public void setUp() throws Exception { + PLogger logger = PLoggerFactory.getLogger(this.getClass()); + this.validator = new ServletArgumentValidator(logger, 0, ServletRequest.class, 1, ServletResponse.class); + } + + + @Test + public void valid() { + Object[] argument = new Object[2]; + argument[0] = mock(ServletRequest.class); + argument[1] = mock(ServletResponse.class); + Assert.assertTrue(validator.validate(argument)); + } + + @Test + public void valid_boundary_check() { + + Assert.assertFalse(validator.validate(null)); + Assert.assertFalse(validator.validate(new Object[0])); + Assert.assertFalse(validator.validate(new Object[1])); + + Object[] argument = new Object[10]; + argument[0] = mock(ServletRequest.class); + argument[1] = mock(ServletResponse.class); + Assert.assertTrue(validator.validate(argument)); + } + + @Test + public void valid_fail1() { + Object[] argument = new Object[2]; + argument[0] = mock(ServletRequest.class); + argument[1] = new Object(); + Assert.assertFalse(validator.validate(argument)); + } + + + @Test + public void valid_fail2() { + + Object[] argument = new Object[2]; + argument[0] = new Object(); + argument[1] = mock(ServletResponse.class); + Assert.assertFalse(validator.validate(argument)); + } +} \ No newline at end of file diff --git a/plugins/common-servlet/src/test/resources/log4j.xml b/plugins/common-servlet/src/test/resources/log4j.xml new file mode 100644 index 000000000000..9191e9ece800 --- /dev/null +++ b/plugins/common-servlet/src/test/resources/log4j.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/cubrid-jdbc/clover.license b/plugins/cubrid-jdbc/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/cubrid-jdbc/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-cubrid-jdbc-driver-plugin diff --git a/plugins/cxf/clover.license b/plugins/cxf/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/cxf/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF 4.0.0 @@ -5,20 +20,42 @@ com.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-cxf-plugin pinpoint-cxf-plugin jar + + 1.6 + ${env.JAVA_8_HOME} + java18 + + + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint pinpoint-bootstrap-core provided - + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + org.apache.cxf cxf-rt-frontend-jaxws @@ -29,6 +66,11 @@ cxf-rt-transports-http provided + + org.apache.cxf + cxf-rt-rs-client + provided + \ No newline at end of file diff --git a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPlugin.java b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPlugin.java index 7cd37ae6d4fb..5a5bea8c6c81 100644 --- a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPlugin.java +++ b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPlugin.java @@ -1,16 +1,16 @@ /* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package com.navercorp.pinpoint.plugin.cxf; @@ -27,9 +27,13 @@ import java.security.ProtectionDomain; +import static com.navercorp.pinpoint.common.util.VarArgs.va; + /** * @author barney - * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/10/03 */ public class CxfPlugin implements ProfilerPlugin, TransformTemplateAware { @@ -39,18 +43,108 @@ public class CxfPlugin implements ProfilerPlugin, TransformTemplateAware { public void setup(ProfilerPluginSetupContext context) { CxfPluginConfig config = new CxfPluginConfig(context.getConfig()); - if(config.isClientProfile()) { + if (config.isServiceProfile()) { + addCxfService(); + } + + if (config.isLoggingProfile()) { + addCxfLogging(); + } + + if (config.isClientProfile()) { addCxfClient(); } + } + + private void addCxfService() { + + // cxf service invoker interceptor + transformTemplate.transform("org.apache.cxf.interceptor.ServiceInvokerInterceptor", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + // handleMessageMethod + InstrumentMethod handleMessageMethod = InstrumentUtils.findMethod(target, "handleMessage", new String[]{"org.apache.cxf.message.Message"}); + handleMessageMethod.addInterceptor("com.navercorp.pinpoint.bootstrap.interceptor.BasicMethodInterceptor", va(CxfPluginConstants.CXF_SERVICE_INVOKER_SERVICE_TYPE)); + + return target.toBytecode(); + } + }); + + // cxf message sender interceptor + transformTemplate.transform("org.apache.cxf.interceptor.MessageSenderInterceptor", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + // handleMessageMethod + InstrumentMethod handleMessageMethod = InstrumentUtils.findMethod(target, "handleMessage", new String[]{"org.apache.cxf.message.Message"}); + handleMessageMethod.addInterceptor("com.navercorp.pinpoint.bootstrap.interceptor.BasicMethodInterceptor", va(CxfPluginConstants.CXF_MESSAGE_SENDER_SERVICE_TYPE)); + + return target.toBytecode(); + } + }); } + private void addCxfLogging() { + + // cxf logging in interceptor + transformTemplate.transform("org.apache.cxf.interceptor.LoggingInInterceptor", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + // formatLoggingMessage + InstrumentMethod formatLoggingMessage = InstrumentUtils.findMethod(target, "formatLoggingMessage", new String[]{"org.apache.cxf.interceptor.LoggingMessage"}); + formatLoggingMessage.addScopedInterceptor("com.navercorp.pinpoint.plugin.cxf.interceptor.CxfLoggingInMessageMethodInterceptor", CxfPluginConstants.CXF_SCOPE); + + return target.toBytecode(); + } + }); + + // cxf logging out interceptor + transformTemplate.transform("org.apache.cxf.interceptor.LoggingOutInterceptor", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + // formatLoggingMessage + InstrumentMethod formatLoggingMessage = InstrumentUtils.findMethod(target, "formatLoggingMessage", new String[]{"org.apache.cxf.interceptor.LoggingMessage"}); + formatLoggingMessage.addScopedInterceptor("com.navercorp.pinpoint.plugin.cxf.interceptor.CxfLoggingOutMessageMethodInterceptor", CxfPluginConstants.CXF_SCOPE); + + return target.toBytecode(); + } + }); + } + + + @Deprecated private void addCxfClient() { + + // cxf ws client transformTemplate.transform("org.apache.cxf.frontend.ClientProxy", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, - Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) + Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); @@ -61,10 +155,27 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, return target.toBytecode(); } }); + + // cxf rs client + transformTemplate.transform("org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + // handleMessageMethod + InstrumentMethod handleMessageMethod = InstrumentUtils.findMethod(target, "handleMessage", new String[]{"org.apache.cxf.message.Message"}); + handleMessageMethod.addScopedInterceptor("com.navercorp.pinpoint.plugin.cxf.interceptor.CxfClientHandleMessageMethodInterceptor", CxfPluginConstants.CXF_CLIENT_SCOPE); + + return target.toBytecode(); + } + }); } @Override public void setTransformTemplate(TransformTemplate transformTemplate) { this.transformTemplate = transformTemplate; } -} +} \ No newline at end of file diff --git a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginConfig.java b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginConfig.java index 3587c456036a..335acdbc86bc 100644 --- a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginConfig.java +++ b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginConfig.java @@ -1,48 +1,75 @@ /* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package com.navercorp.pinpoint.plugin.cxf; -import java.util.Arrays; -import java.util.List; - import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.common.util.StringUtils; +import java.util.Arrays; +import java.util.List; + /** * @author barney - * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/10/03 */ public class CxfPluginConfig { - private final boolean clientProfile; + private final boolean serviceProfile; + private final boolean loggingProfile; + @Deprecated + private final boolean clientProfile; + @Deprecated private final String[] clientHiddenParams; + + /** + * Instantiates a new Cxf plugin config. + *

+ * profiler.cxf.client and profiler.cxf.client.hiddenParams is deprecated. + * + * @param src the src + */ public CxfPluginConfig(ProfilerConfig src) { + this.serviceProfile = src.readBoolean("profiler.cxf.service.enable", false); + this.loggingProfile = src.readBoolean("profiler.cxf.logging.enable", false); this.clientProfile = src.readBoolean("profiler.cxf.client", false); this.clientHiddenParams = getStringArray(src.readString("profiler.cxf.client.hiddenParams", "")); } + public boolean isServiceProfile() { + return serviceProfile; + } + + public boolean isLoggingProfile() { + return loggingProfile; + } + + @Deprecated public boolean isClientProfile() { return clientProfile; } + @Deprecated public String[] getClientHiddenParams() { return clientHiddenParams; } + @Deprecated private String[] getStringArray(String value) { if (StringUtils.isEmpty(value)) { return null; @@ -51,22 +78,27 @@ private String[] getStringArray(String value) { return toStringArray(tokenList); } + @Deprecated private String[] toStringArray(List list) { - if (list == null) { - return null; - } + if (list == null) { + return null; + } - return list.toArray(new String[list.size()]); - } + return list.toArray(new String[0]); + } @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("CxfPluginConfig [clientProfile="); + builder.append("CxfPluginConfig [serviceProfile="); + builder.append(serviceProfile); + builder.append(", loggingProfile="); + builder.append(loggingProfile); + builder.append(", clientProfile(Deprecated)="); builder.append(clientProfile); - builder.append(", clientHiddenParams="); + builder.append(", clientHiddenParams(Deprecated)="); builder.append(Arrays.toString(clientHiddenParams)); builder.append("]"); return builder.toString(); } -} +} \ No newline at end of file diff --git a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginConstants.java b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginConstants.java index bd945c5ea454..710b93fafd83 100644 --- a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginConstants.java +++ b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginConstants.java @@ -1,10 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,23 +15,41 @@ */ package com.navercorp.pinpoint.plugin.cxf; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; -import com.navercorp.pinpoint.common.trace.AnnotationKeyProperty; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; -import com.navercorp.pinpoint.common.trace.ServiceTypeProperty; +import com.navercorp.pinpoint.common.trace.*; /** * @author barney - * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/10/03 */ -public interface CxfPluginConstants { +public final class CxfPluginConstants { + private CxfPluginConstants() { + } + + @Deprecated + public static final ServiceType CXF_CLIENT_SERVICE_TYPE = ServiceTypeFactory.of(9080, "CXF_CLIENT", ServiceTypeProperty.RECORD_STATISTICS); + @Deprecated + public static final AnnotationKey CXF_OPERATION = AnnotationKeyFactory.of(200, "cxf.operation", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + @Deprecated + public static final AnnotationKey CXF_ARGS = AnnotationKeyFactory.of(201, "cxf.args", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + @Deprecated + public static final String CXF_CLIENT_SCOPE = "CxfClientScope"; + + public static final ServiceType CXF_SERVICE_INVOKER_SERVICE_TYPE = ServiceTypeFactory.of(9081, "CXF_SERVICE_INVOKER"); + public static final ServiceType CXF_MESSAGE_SENDER_SERVICE_TYPE = ServiceTypeFactory.of(9082, "CXF_MESSAGE_SENDER"); + public static final ServiceType CXF_LOGGING_IN_SERVICE_TYPE = ServiceTypeFactory.of(9083, "CXF_LOGGING_IN"); + public static final ServiceType CXF_LOGGING_OUT_SERVICE_TYPE = ServiceTypeFactory.of(9084, "CXF_LOGGING_OUT"); - ServiceType CXF_CLIENT_SERVICE_TYPE = ServiceTypeFactory.of(9080, "CXF_CLIENT", ServiceTypeProperty.RECORD_STATISTICS); + public static final AnnotationKey CXF_ADDRESS = AnnotationKeyFactory.of(203, "cxf.address", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final AnnotationKey CXF_RESPONSE_CODE = AnnotationKeyFactory.of(204, "cxf.response.code", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final AnnotationKey CXF_ENCODING = AnnotationKeyFactory.of(205, "cxf.encoding", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final AnnotationKey CXF_HTTP_METHOD = AnnotationKeyFactory.of(206, "cxf.http.method", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final AnnotationKey CXF_CONTENT_TYPE = AnnotationKeyFactory.of(207, "cxf.content.type", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final AnnotationKey CXF_HEADERS = AnnotationKeyFactory.of(208, "cxf.headers", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final AnnotationKey CXF_MESSAGES = AnnotationKeyFactory.of(209, "cxf.messages", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final AnnotationKey CXF_PAYLOAD = AnnotationKeyFactory.of(210, "cxf.payload", AnnotationKeyProperty.VIEW_IN_RECORD_SET); - AnnotationKey CXF_OPERATION = AnnotationKeyFactory.of(200, "cxf.operation", AnnotationKeyProperty.VIEW_IN_RECORD_SET); - AnnotationKey CXF_ARGS = AnnotationKeyFactory.of(201, "cxf.args", AnnotationKeyProperty.VIEW_IN_RECORD_SET); + public static final String CXF_SCOPE = "CXF_SCOPE"; - String CXF_CLIENT_SCOPE = "CxfClientScope"; -} +} \ No newline at end of file diff --git a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginTraceMetadataProvider.java b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginTraceMetadataProvider.java index 095c7f7548e7..a074f24ae39b 100644 --- a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginTraceMetadataProvider.java +++ b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/CxfPluginTraceMetadataProvider.java @@ -1,8 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.plugin.cxf; import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; +/** + * @author barney + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/10/03 + */ public class CxfPluginTraceMetadataProvider implements TraceMetadataProvider { @Override @@ -10,6 +31,20 @@ public void setup(TraceMetadataSetupContext context) { context.addServiceType(CxfPluginConstants.CXF_CLIENT_SERVICE_TYPE); context.addAnnotationKey(CxfPluginConstants.CXF_OPERATION); context.addAnnotationKey(CxfPluginConstants.CXF_ARGS); + + context.addServiceType(CxfPluginConstants.CXF_SERVICE_INVOKER_SERVICE_TYPE); + context.addServiceType(CxfPluginConstants.CXF_MESSAGE_SENDER_SERVICE_TYPE); + context.addServiceType(CxfPluginConstants.CXF_LOGGING_IN_SERVICE_TYPE); + context.addServiceType(CxfPluginConstants.CXF_LOGGING_OUT_SERVICE_TYPE); + + context.addAnnotationKey(CxfPluginConstants.CXF_ADDRESS); + context.addAnnotationKey(CxfPluginConstants.CXF_RESPONSE_CODE); + context.addAnnotationKey(CxfPluginConstants.CXF_CONTENT_TYPE); + context.addAnnotationKey(CxfPluginConstants.CXF_ENCODING); + context.addAnnotationKey(CxfPluginConstants.CXF_HTTP_METHOD); + context.addAnnotationKey(CxfPluginConstants.CXF_HEADERS); + context.addAnnotationKey(CxfPluginConstants.CXF_MESSAGES); + context.addAnnotationKey(CxfPluginConstants.CXF_PAYLOAD); } -} +} \ No newline at end of file diff --git a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientHandleMessageMethodInterceptor.java b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientHandleMessageMethodInterceptor.java new file mode 100644 index 000000000000..a6ce2b2de255 --- /dev/null +++ b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientHandleMessageMethodInterceptor.java @@ -0,0 +1,162 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.cxf.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.cxf.CxfPluginConfig; +import com.navercorp.pinpoint.plugin.cxf.CxfPluginConstants; + +import java.net.MalformedURLException; +import java.util.Map; + +/** + * The type Cxf client handle message method interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/08/16 + */ +@Deprecated +public class CxfClientHandleMessageMethodInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final CxfPluginConfig pluginConfig; + + /** + * Instantiates a new Cxf client handle message method interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public CxfClientHandleMessageMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + this.pluginConfig = new CxfPluginConfig(traceContext.getProfilerConfig()); + } + + @Override + public void before(Object target, Object[] args) { + + if (logger.isDebugEnabled()) { + logger.beforeInterceptor(target, args); + } + + Trace trace = traceContext.currentRawTraceObject(); + + if (trace != null && trace.canSampled()) { + + String destination = getDestination(args); + + if (destination != null) { + String httpUri = getHttpUri(args); + String requestMethod = getRequestMethod(args); + String contentType = getContentType(args); + + SpanEventRecorder recorder = trace.traceBlockBegin(); + TraceId nextId = trace.getTraceId().getNextTraceId(); + recorder.recordNextSpanId(nextId.getSpanId()); + recorder.recordServiceType(CxfPluginConstants.CXF_CLIENT_SERVICE_TYPE); + recorder.recordDestinationId(destination); + recorder.recordAttribute(CxfPluginConstants.CXF_ADDRESS, httpUri); + recorder.recordAttribute(CxfPluginConstants.CXF_HTTP_METHOD, requestMethod); + recorder.recordAttribute(CxfPluginConstants.CXF_CONTENT_TYPE, contentType); + } + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (logger.isDebugEnabled()) { + logger.afterInterceptor(target, args); + } + Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + } finally { + trace.traceBlockEnd(); + } + } + + private String getDestination(Object[] args) { + + if (args[0] instanceof Map) { + + Map message = (Map) args[0]; + + String address = (String) message.get("org.apache.cxf.message.Message.ENDPOINT_ADDRESS"); + + try { + java.net.URL url = new java.net.URL(address); + + return url.getProtocol() + "://" + url.getAuthority(); + + } catch (MalformedURLException e) { + } + } + return null; + } + + private String getHttpUri(Object[] args) { + + if (args[0] instanceof Map) { + + Map message = (Map) args[0]; + + String httpUri = (String) message.get("org.apache.cxf.request.uri"); + + return httpUri != null ? httpUri : "unknown"; + } + + return "unknown"; + } + + private String getRequestMethod(Object[] args) { + + if (args[0] instanceof Map) { + + Map message = (Map) args[0]; + + String requestMethod = (String) message.get("org.apache.cxf.request.method"); + + return requestMethod != null ? requestMethod : "unknown"; + } + return "unknown"; + } + + private String getContentType(Object[] args) { + + if (args[0] instanceof Map) { + + Map message = (Map) args[0]; + + String contentType = (String) message.get("Content-Type"); + + return contentType != null ? contentType : "unknown"; + } + return "unknown"; + } +} \ No newline at end of file diff --git a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientInvokeSyncMethodInterceptor.java b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientInvokeSyncMethodInterceptor.java index 303f33a52d9d..a500e6cd8574 100644 --- a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientInvokeSyncMethodInterceptor.java +++ b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientInvokeSyncMethodInterceptor.java @@ -1,24 +1,20 @@ /* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package com.navercorp.pinpoint.plugin.cxf.interceptor; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.Trace; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.context.*; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; @@ -32,12 +28,14 @@ /** * @author barney - * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/08/16 */ +@Deprecated public class CxfClientInvokeSyncMethodInterceptor implements AroundInterceptor { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); private final TraceContext traceContext; private final MethodDescriptor descriptor; @@ -53,38 +51,34 @@ public CxfClientInvokeSyncMethodInterceptor(TraceContext traceContext, MethodDes @Override public void before(Object target, Object[] args) { - if (isDebug) { + + if (logger.isDebugEnabled()) { logger.beforeInterceptor(target, args); } + Trace trace = traceContext.currentRawTraceObject(); - if (trace == null) { - return; - } - if (!trace.canSampled()) { - if (isDebug) { - logger.debug("Sampling is disabled"); - } - return; - } - String endpoint = getDestination(args); - String operation = getOperation(args); - Object[] parameters = getParameters(operation, args); - - SpanEventRecorder recorder = trace.traceBlockBegin(); - TraceId nextId = trace.getTraceId().getNextTraceId(); - recorder.recordNextSpanId(nextId.getSpanId()); - recorder.recordServiceType(CxfPluginConstants.CXF_CLIENT_SERVICE_TYPE); - recorder.recordDestinationId(endpoint); - recorder.recordAttribute(CxfPluginConstants.CXF_OPERATION, operation); - recorder.recordAttribute(CxfPluginConstants.CXF_ARGS, Arrays.toString(parameters)); + if (trace != null && trace.canSampled()) { + + String endpoint = getDestination(args); + String operation = getOperation(args); + Object[] parameters = getParameters(operation, args); + + SpanEventRecorder recorder = trace.traceBlockBegin(); + TraceId nextId = trace.getTraceId().getNextTraceId(); + recorder.recordNextSpanId(nextId.getSpanId()); + recorder.recordServiceType(CxfPluginConstants.CXF_CLIENT_SERVICE_TYPE); + recorder.recordDestinationId(endpoint); + recorder.recordAttribute(CxfPluginConstants.CXF_OPERATION, operation); + recorder.recordAttribute(CxfPluginConstants.CXF_ARGS, Arrays.toString(parameters)); + } } private String getDestination(Object[] args) { String operationInfo = args[1].toString(); int start = operationInfo.indexOf('{'); int end = operationInfo.indexOf('}'); - if(start < 0 || end < 0) { + if (start < 0 || end < 0) { return operationInfo; } return operationInfo.substring(start + 1, end); @@ -123,7 +117,7 @@ private Object[] getParameters(String operation, Object[] args) { } } else { if (op.equals(operation)) { - return new Object[] { "HIDDEN " + params.length + " PARAM" }; + return new Object[]{"HIDDEN " + params.length + " PARAM"}; } } } @@ -132,7 +126,7 @@ private Object[] getParameters(String operation, Object[] args) { @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { - if (isDebug) { + if (logger.isDebugEnabled()) { logger.afterInterceptor(target, args); } Trace trace = traceContext.currentTraceObject(); @@ -149,4 +143,4 @@ public void after(Object target, Object[] args, Object result, Throwable throwab } } -} +} \ No newline at end of file diff --git a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingInMessageMethodInterceptor.java b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingInMessageMethodInterceptor.java new file mode 100644 index 000000000000..abba8572f05a --- /dev/null +++ b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingInMessageMethodInterceptor.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.cxf.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.cxf.CxfPluginConstants; +import org.apache.cxf.interceptor.LoggingMessage; + +/** + * The type Cxf logging in message method interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/09/30 + */ +public class CxfLoggingInMessageMethodInterceptor extends CxfLoggingMessageMethodInterceptor { + + /** + * Instantiates a new Cxf logging message method interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public CxfLoggingInMessageMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + recorder.recordServiceType(CxfPluginConstants.CXF_LOGGING_IN_SERVICE_TYPE); + if (args[0] instanceof LoggingMessage) { + recordAttributes(recorder, (LoggingMessage) args[0]); + } + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(getMethodDescriptor()); + recorder.recordException(throwable); + } +} \ No newline at end of file diff --git a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingMessageMethodInterceptor.java b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingMessageMethodInterceptor.java new file mode 100644 index 000000000000..4b14c684c8a8 --- /dev/null +++ b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingMessageMethodInterceptor.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.cxf.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.plugin.cxf.CxfPluginConstants; +import org.apache.cxf.interceptor.LoggingMessage; + +/** + * The type Cxf logging message method interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/09/30 + */ +public abstract class CxfLoggingMessageMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + /** + * Instantiates a new Cxf logging message method interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + protected CxfLoggingMessageMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + /** + * Record attributes. + * + * @param recorder the recorder + * @param loggingMessage the logging message + */ + protected void recordAttributes(SpanEventRecorder recorder, LoggingMessage loggingMessage) { + + StringBuilder address = loggingMessage.getAddress(); + if (address.length() > 0) { + recorder.recordAttribute(CxfPluginConstants.CXF_ADDRESS, address.toString()); + } + + StringBuilder responseCode = loggingMessage.getResponseCode(); + if (responseCode.length() > 0) { + recorder.recordAttribute(CxfPluginConstants.CXF_RESPONSE_CODE, responseCode.toString()); + } + + StringBuilder encoding = loggingMessage.getEncoding(); + if (encoding.length() > 0) { + recorder.recordAttribute(CxfPluginConstants.CXF_ENCODING, encoding.toString()); + } + + StringBuilder httpMethod = loggingMessage.getHttpMethod(); + if (httpMethod.length() > 0) { + recorder.recordAttribute(CxfPluginConstants.CXF_HTTP_METHOD, httpMethod.toString()); + } + + StringBuilder contentType = loggingMessage.getContentType(); + if (contentType.length() > 0) { + recorder.recordAttribute(CxfPluginConstants.CXF_CONTENT_TYPE, contentType.toString()); + } + + StringBuilder header = loggingMessage.getHeader(); + if (header.length() > 0) { + recorder.recordAttribute(CxfPluginConstants.CXF_HEADERS, header.toString()); + } + + StringBuilder message = loggingMessage.getMessage(); + if (message.length() > 0) { + recorder.recordAttribute(CxfPluginConstants.CXF_MESSAGES, message.toString()); + } + + StringBuilder payload = loggingMessage.getPayload(); + if (payload.length() > 0) { + recorder.recordAttribute(CxfPluginConstants.CXF_PAYLOAD, payload.toString()); + } + + } + +} \ No newline at end of file diff --git a/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingOutMessageMethodInterceptor.java b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingOutMessageMethodInterceptor.java new file mode 100644 index 000000000000..cfa6b5d096f6 --- /dev/null +++ b/plugins/cxf/src/main/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingOutMessageMethodInterceptor.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.cxf.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.cxf.CxfPluginConstants; +import org.apache.cxf.interceptor.LoggingMessage; + +/** + * The type Cxf logging out message method interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/09/30 + */ +public class CxfLoggingOutMessageMethodInterceptor extends CxfLoggingMessageMethodInterceptor { + /** + * Instantiates a new Cxf logging message method interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public CxfLoggingOutMessageMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + recorder.recordServiceType(CxfPluginConstants.CXF_LOGGING_OUT_SERVICE_TYPE); + if (args[0] instanceof LoggingMessage) { + recordAttributes(recorder, (LoggingMessage) args[0]); + } + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(getMethodDescriptor()); + recorder.recordException(throwable); + } +} \ No newline at end of file diff --git a/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientHandleMessageMethodInterceptorTest.java b/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientHandleMessageMethodInterceptorTest.java new file mode 100644 index 000000000000..35149a5a85e1 --- /dev/null +++ b/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientHandleMessageMethodInterceptorTest.java @@ -0,0 +1,105 @@ +package com.navercorp.pinpoint.plugin.cxf.interceptor; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.plugin.cxf.CxfPluginConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class CxfClientHandleMessageMethodInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private ProfilerConfig profilerConfig; + + @Mock + private Trace trace; + + @Mock + private TraceId traceId; + + @Mock + private TraceId nextId; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void test1() throws Exception { + doReturn(profilerConfig).when(traceContext).getProfilerConfig(); + doReturn(trace).when(traceContext).currentRawTraceObject(); + doReturn(true).when(trace).canSampled(); + doReturn(traceId).when(trace).getTraceId(); + doReturn(nextId).when(traceId).getNextTraceId(); + doReturn(recorder).when(trace).traceBlockBegin(); + + Object target = new Object(); + Map map = new HashMap(); + map.put("org.apache.cxf.message.Message.ENDPOINT_ADDRESS", "http://foo.com/getFoo"); + map.put("org.apache.cxf.request.uri", "http://foo.com/getFoo"); + map.put("org.apache.cxf.request.method", "POST"); + map.put("Content-Type", "application/json"); + Object[] args = new Object[]{map}; + + CxfClientHandleMessageMethodInterceptor interceptor = new CxfClientHandleMessageMethodInterceptor(traceContext, descriptor); + interceptor.before(target, args); + + verify(recorder).recordServiceType(CxfPluginConstants.CXF_CLIENT_SERVICE_TYPE); + verify(recorder).recordDestinationId("http://foo.com"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_ADDRESS, "http://foo.com/getFoo"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_HTTP_METHOD, "POST"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_CONTENT_TYPE, "application/json"); + } + + @Test + public void test2() throws Exception { + doReturn(profilerConfig).when(traceContext).getProfilerConfig(); + doReturn(trace).when(traceContext).currentRawTraceObject(); + doReturn(true).when(trace).canSampled(); + + Object target = new Object(); + Object[] args = new Object[]{""}; + + CxfClientHandleMessageMethodInterceptor interceptor = new CxfClientHandleMessageMethodInterceptor(traceContext, descriptor); + interceptor.before(target, args); + + verify(trace, never()).traceBlockBegin(); + } + + @Test + public void test3() throws Exception { + doReturn(profilerConfig).when(traceContext).getProfilerConfig(); + doReturn(trace).when(traceContext).currentRawTraceObject(); + doReturn(true).when(trace).canSampled(); + doReturn(traceId).when(trace).getTraceId(); + doReturn(nextId).when(traceId).getNextTraceId(); + doReturn(recorder).when(trace).traceBlockBegin(); + + Object target = new Object(); + Map map = new HashMap(); + map.put("org.apache.cxf.message.Message.ENDPOINT_ADDRESS", "http://foo.com/getFoo"); + Object[] args = new Object[]{map}; + + CxfClientHandleMessageMethodInterceptor interceptor = new CxfClientHandleMessageMethodInterceptor(traceContext, descriptor); + interceptor.before(target, args); + + verify(recorder).recordServiceType(CxfPluginConstants.CXF_CLIENT_SERVICE_TYPE); + verify(recorder).recordDestinationId("http://foo.com"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_ADDRESS, "unknown"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_HTTP_METHOD, "unknown"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_CONTENT_TYPE, "unknown"); + } +} \ No newline at end of file diff --git a/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientInvokeSyncMethodInterceptorTest.java b/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientInvokeSyncMethodInterceptorTest.java index 346dacdc4c56..e41080621250 100644 --- a/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientInvokeSyncMethodInterceptorTest.java +++ b/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfClientInvokeSyncMethodInterceptorTest.java @@ -14,26 +14,18 @@ */ package com.navercorp.pinpoint.plugin.cxf.interceptor; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.plugin.cxf.CxfPluginConstants; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.Trace; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.plugin.cxf.CxfPluginConstants; +import static org.mockito.Mockito.*; /** * @author barney - * */ @RunWith(MockitoJUnitRunner.class) public class CxfClientInvokeSyncMethodInterceptorTest { @@ -70,8 +62,8 @@ public void before() throws Exception { Object target = new Object(); Object operInfo = "[BindingOperationInfo: {http://foo.com/}getFoo]"; - Object[] arg = new Object[] { "foo", "bar" }; - Object[] args = new Object[] { "", operInfo, arg }; + Object[] arg = new Object[]{"foo", "bar"}; + Object[] args = new Object[]{"", operInfo, arg}; CxfClientInvokeSyncMethodInterceptor interceptor = new CxfClientInvokeSyncMethodInterceptor(traceContext, descriptor); interceptor.before(target, args); @@ -89,7 +81,7 @@ public void sampled_false() throws Exception { doReturn(false).when(trace).canSampled(); Object target = new Object(); - Object[] args = new Object[] {}; + Object[] args = new Object[]{}; CxfClientInvokeSyncMethodInterceptor interceptor = new CxfClientInvokeSyncMethodInterceptor(traceContext, descriptor); interceptor.before(target, args); @@ -110,8 +102,8 @@ public void hidden_all_params() throws Exception { Object target = new Object(); Object operInfo = "[BindingOperationInfo: {http://foo.com/}getFoo]"; - Object[] arg = new Object[] { "foo", "bar" }; - Object[] args = new Object[] { "", operInfo, arg }; + Object[] arg = new Object[]{"foo", "bar"}; + Object[] args = new Object[]{"", operInfo, arg}; CxfClientInvokeSyncMethodInterceptor interceptor = new CxfClientInvokeSyncMethodInterceptor(traceContext, descriptor); interceptor.before(target, args); @@ -135,8 +127,8 @@ public void hidden_param_index() throws Exception { Object target = new Object(); Object operInfo = "[BindingOperationInfo: {http://foo.com/}getFoo]"; - Object[] arg = new Object[] { "foo", "bar" }; - Object[] args = new Object[] { "", operInfo, arg }; + Object[] arg = new Object[]{"foo", "bar"}; + Object[] args = new Object[]{"", operInfo, arg}; CxfClientInvokeSyncMethodInterceptor interceptor = new CxfClientInvokeSyncMethodInterceptor(traceContext, descriptor); interceptor.before(target, args); @@ -160,8 +152,8 @@ public void hidden_param_incorrect_index() throws Exception { Object target = new Object(); Object operInfo = "[BindingOperationInfo: {http://foo.com/}getFoo]"; - Object[] arg = new Object[] { "foo", "bar" }; - Object[] args = new Object[] { "", operInfo, arg }; + Object[] arg = new Object[]{"foo", "bar"}; + Object[] args = new Object[]{"", operInfo, arg}; CxfClientInvokeSyncMethodInterceptor interceptor = new CxfClientInvokeSyncMethodInterceptor(traceContext, descriptor); interceptor.before(target, args); @@ -171,4 +163,4 @@ public void hidden_param_incorrect_index() throws Exception { verify(recorder).recordAttribute(CxfPluginConstants.CXF_OPERATION, "{http://foo.com/}getFoo"); verify(recorder).recordAttribute(CxfPluginConstants.CXF_ARGS, "[foo, bar]"); } -} +} \ No newline at end of file diff --git a/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingInMessageMethodInterceptorTest.java b/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingInMessageMethodInterceptorTest.java new file mode 100644 index 000000000000..24f00dcc6355 --- /dev/null +++ b/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingInMessageMethodInterceptorTest.java @@ -0,0 +1,74 @@ +package com.navercorp.pinpoint.plugin.cxf.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.cxf.CxfPluginConstants; +import org.apache.cxf.interceptor.LoggingMessage; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class CxfLoggingInMessageMethodInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void doInBeforeTrace() { + + LoggingMessage message = new LoggingMessage("", "1"); + message.getAddress().append("http://foo.com/getFoo"); + message.getContentType().append("application/json"); + message.getHttpMethod().append("POST"); + message.getHeader().append("test"); + + Object target = new Object(); + Object[] args = new Object[]{message}; + + CxfLoggingInMessageMethodInterceptor inMessageMethodInterceptor = + new CxfLoggingInMessageMethodInterceptor(traceContext, descriptor); + + inMessageMethodInterceptor.doInBeforeTrace(recorder, target, args); + + verify(recorder).recordServiceType(CxfPluginConstants.CXF_LOGGING_IN_SERVICE_TYPE); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_ADDRESS, "http://foo.com/getFoo"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_HTTP_METHOD, "POST"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_CONTENT_TYPE, "application/json"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_HEADERS, "test"); + + } + + @Test + public void doInAfterTrace() { + + LoggingMessage message = new LoggingMessage("", "1"); + message.getAddress().append("http://foo.com/getFoo"); + message.getContentType().append("application/json"); + message.getHttpMethod().append("POST"); + message.getHeader().append("test"); + + Object target = new Object(); + Object[] args = new Object[]{message}; + + CxfLoggingInMessageMethodInterceptor inMessageMethodInterceptor = + new CxfLoggingInMessageMethodInterceptor(traceContext, descriptor); + + inMessageMethodInterceptor.doInAfterTrace(recorder, target, args, null, null); + + verify(recorder, never()).recordServiceType(CxfPluginConstants.CXF_LOGGING_IN_SERVICE_TYPE); + + verify(recorder).recordApi(descriptor); + } +} \ No newline at end of file diff --git a/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingOutMessageMethodInterceptorTest.java b/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingOutMessageMethodInterceptorTest.java new file mode 100644 index 000000000000..0162b845ab5b --- /dev/null +++ b/plugins/cxf/src/test/java/com/navercorp/pinpoint/plugin/cxf/interceptor/CxfLoggingOutMessageMethodInterceptorTest.java @@ -0,0 +1,74 @@ +package com.navercorp.pinpoint.plugin.cxf.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.cxf.CxfPluginConstants; +import org.apache.cxf.interceptor.LoggingMessage; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class CxfLoggingOutMessageMethodInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void doInBeforeTrace() { + + LoggingMessage message = new LoggingMessage("", "1"); + message.getEncoding().append("UTF-8"); + message.getContentType().append("application/json"); + message.getResponseCode().append("200"); + message.getHeader().append("test"); + + Object target = new Object(); + Object[] args = new Object[]{message}; + + CxfLoggingOutMessageMethodInterceptor outMessageMethodInterceptor = + new CxfLoggingOutMessageMethodInterceptor(traceContext, descriptor); + + outMessageMethodInterceptor.doInBeforeTrace(recorder, target, args); + + verify(recorder).recordServiceType(CxfPluginConstants.CXF_LOGGING_OUT_SERVICE_TYPE); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_ENCODING, "UTF-8"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_RESPONSE_CODE, "200"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_CONTENT_TYPE, "application/json"); + verify(recorder).recordAttribute(CxfPluginConstants.CXF_HEADERS, "test"); + + } + + @Test + public void doInAfterTrace() { + + LoggingMessage message = new LoggingMessage("", "1"); + message.getEncoding().append("UTF-8"); + message.getContentType().append("application/json"); + message.getResponseCode().append("200"); + message.getHeader().append("test"); + + Object target = new Object(); + Object[] args = new Object[]{message}; + + CxfLoggingOutMessageMethodInterceptor outMessageMethodInterceptor = + new CxfLoggingOutMessageMethodInterceptor(traceContext, descriptor); + + outMessageMethodInterceptor.doInAfterTrace(recorder, target, args, null, null); + + verify(recorder, never()).recordServiceType(CxfPluginConstants.CXF_LOGGING_IN_SERVICE_TYPE); + + verify(recorder).recordApi(descriptor); + } +} \ No newline at end of file diff --git a/plugins/dbcp/clover.license b/plugins/dbcp/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/dbcp/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-commons-dbcp-plugin pinpoint-commons-dbcp-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/dbcp/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp/CommonsDbcpConstants.java b/plugins/dbcp/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp/CommonsDbcpConstants.java index d49691ecf982..4c786a80431f 100644 --- a/plugins/dbcp/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp/CommonsDbcpConstants.java +++ b/plugins/dbcp/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp/CommonsDbcpConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -23,6 +23,8 @@ * @author Taejin Koo */ public final class CommonsDbcpConstants { + private CommonsDbcpConstants() { + } public static final String SCOPE = "DBCP_SCOPE"; diff --git a/plugins/dbcp2/clover.license b/plugins/dbcp2/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/dbcp2/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT @@ -34,6 +34,19 @@ pinpoint-commons-dbcp2-plugin jar + + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Constants.java b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Constants.java index 73a778c0d187..9e8c76802542 100644 --- a/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Constants.java +++ b/plugins/dbcp2/src/main/java/com/navercorp/pinpoint/plugin/commons/dbcp2/CommonsDbcp2Constants.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -22,7 +22,9 @@ /** * @author Taejin Koo */ -public class CommonsDbcp2Constants { +public final class CommonsDbcp2Constants { + private CommonsDbcp2Constants() { + } public static final String SCOPE = "DBCP2_SCOPE"; diff --git a/plugins/druid/.gitignore b/plugins/druid/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/druid/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/druid/pom.xml b/plugins/druid/pom.xml new file mode 100644 index 000000000000..7012a583056e --- /dev/null +++ b/plugins/druid/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-druid-plugin + pinpoint-druid-plugin + jar + + + 1.6 + ${env.JAVA_7_HOME} + java17 + + + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + com.alibaba + druid + provided + + + \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DataSourceMonitorAccessor.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DataSourceMonitorAccessor.java new file mode 100644 index 000000000000..89b8d06ed0e8 --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DataSourceMonitorAccessor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid; + +/** + * The interface Data source monitor accessor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public interface DataSourceMonitorAccessor { + + /** + * Pinpoint set data source monitor. + * + * @param dataSourceMonitor the data source monitor + */ + void _$PINPOINT$_setDataSourceMonitor(DruidDataSourceMonitor dataSourceMonitor); + + /** + * Pinpoint get data source monitor druid data source monitor. + * + * @return the druid data source monitor + */ + DruidDataSourceMonitor _$PINPOINT$_getDataSourceMonitor(); +} \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidConfig.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidConfig.java new file mode 100644 index 000000000000..3a38793049dd --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidConfig.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +/** + * The type Druid config. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public class DruidConfig { + + private final boolean pluginEnable; + private final boolean profileClose; + + /** + * Instantiates a new Druid config. + * + * @param config the config + */ + public DruidConfig(ProfilerConfig config) { + + pluginEnable = config.readBoolean(DruidConstants.PLUGIN_ENABLE, false); + profileClose = config.readBoolean(DruidConstants.PROFILE_CONNECTIONCLOSE_ENABLE, false); + } + + /** + * Is plugin enable boolean. + * + * @return the boolean + */ + public boolean isPluginEnable() { + return pluginEnable; + } + + /** + * Is profile close boolean. + * + * @return the boolean + */ + public boolean isProfileClose() { + return profileClose; + } +} \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidConstants.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidConstants.java new file mode 100644 index 000000000000..0947aa1b43fc --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidConstants.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +/** + * The type Druid constants. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public final class DruidConstants { + + private DruidConstants() { + } + + /** + * The constant SCOPE. + */ + public static final String SCOPE = "DRUID_SCOPE"; + + /** + * The constant SERVICE_TYPE. + */ + public static final ServiceType SERVICE_TYPE = ServiceTypeFactory.of(6062, "DRUID"); + + /** + * The constant ACCESSOR_DATASOURCE_MONITOR. + */ + public static final String ACCESSOR_DATASOURCE_MONITOR = "com.navercorp.pinpoint.plugin.druid.DataSourceMonitorAccessor"; + + /** + * The constant INTERCEPTOR_CONSTRUCTOR. + */ + public static final String INTERCEPTOR_CONSTRUCTOR = "com.navercorp.pinpoint.plugin.druid.interceptor.DataSourceConstructorInterceptor"; + /** + * The constant INTERCEPTOR_CLOSE. + */ + public static final String INTERCEPTOR_CLOSE = "com.navercorp.pinpoint.plugin.druid.interceptor.DataSourceCloseInterceptor"; + + /** + * The constant INTERCEPTOR_GET_CONNECTION. + */ + public static final String INTERCEPTOR_GET_CONNECTION = "com.navercorp.pinpoint.plugin.druid.interceptor.DataSourceGetConnectionInterceptor"; + /** + * The constant INTERCEPTOR_CLOSE_CONNECTION. + */ + public static final String INTERCEPTOR_CLOSE_CONNECTION = "com.navercorp.pinpoint.plugin.druid.interceptor.DataSourceCloseConnectionInterceptor"; + + /** + * The constant PLUGIN_ENABLE. + */ + public static final String PLUGIN_ENABLE = "profiler.jdbc.druid"; + /** + * The constant PROFILE_CONNECTIONCLOSE_ENABLE. + */ + public static final String PROFILE_CONNECTIONCLOSE_ENABLE = "profiler.jdbc.druid.connectionclose"; + +} \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidDataSourceMonitor.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidDataSourceMonitor.java new file mode 100644 index 000000000000..b1297863e056 --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidDataSourceMonitor.java @@ -0,0 +1,93 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid; + +import com.alibaba.druid.pool.DruidDataSource; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitor; +import com.navercorp.pinpoint.common.trace.ServiceType; + +/** + * The type Druid data source monitor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public class DruidDataSourceMonitor implements DataSourceMonitor { + + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + private volatile boolean closed = false; + + private final DruidDataSource dataSource; + + /** + * Instantiates a new Druid data source monitor. + * + * @param dataSource the data source + */ + public DruidDataSourceMonitor(Object dataSource) { + + if (dataSource instanceof DruidDataSource) { + this.dataSource = (DruidDataSource) dataSource; + } else { + this.dataSource = null; + logger.error("DataSource must be instance of DruidDataSource!"); + } + } + + @Override + public ServiceType getServiceType() { + return DruidConstants.SERVICE_TYPE; + } + + @Override + public String getUrl() { + if (dataSource != null) { + return dataSource.getUrl(); + } + return null; + } + + @Override + public int getActiveConnectionSize() { + if (dataSource != null) { + return dataSource.getActiveCount(); + } + return -1; + } + + @Override + public int getMaxConnectionSize() { + if (dataSource != null) { + return dataSource.getMaxActive(); + } + return -1; + } + + @Override + public boolean isDisabled() { + return closed; + } + + /** + * Close. + */ + public void close() { + closed = true; + } +} \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidMetadataProvider.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidMetadataProvider.java new file mode 100644 index 000000000000..2861f644b1f4 --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidMetadataProvider.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * The type Druid metadata provider. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public class DruidMetadataProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(DruidConstants.SERVICE_TYPE); + } +} \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidPlugin.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidPlugin.java new file mode 100644 index 000000000000..5636de9632c1 --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/DruidPlugin.java @@ -0,0 +1,126 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import com.navercorp.pinpoint.bootstrap.plugin.util.InstrumentUtils; + +import java.security.ProtectionDomain; + +/** + * The type Druid plugin. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public class DruidPlugin implements ProfilerPlugin, TransformTemplateAware { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private DruidConfig config; + + private TransformTemplate transformTemplate; + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } + + @Override + public void setup(ProfilerPluginSetupContext context) { + + config = new DruidConfig(context.getConfig()); + + if (!config.isPluginEnable()) { + + logger.info("Disable druid option. 'profiler.jdbc.druid=false'"); + return; + } + + addDruidDataSourceTransformer(); + + if (config.isProfileClose()) { + + addDruidPooledConnectionTransformer(); + } + } + + private boolean isAvailableDataSourceMonitor(InstrumentClass target) { + + return target.hasMethod("getUrl") && target.hasMethod("getMaxActive") && target.hasMethod("getActiveCount"); + } + + private void addDruidPooledConnectionTransformer() { + + transformTemplate.transform("com.alibaba.druid.pool.DruidPooledConnection", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + // closeMethod + InstrumentMethod closeMethod = InstrumentUtils.findMethod(target, "close"); + + closeMethod.addScopedInterceptor(DruidConstants.INTERCEPTOR_CLOSE_CONNECTION, DruidConstants.SCOPE); + + return target.toBytecode(); + } + }); + } + + private void addDruidDataSourceTransformer() { + + transformTemplate.transform("com.alibaba.druid.pool.DruidDataSource", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (isAvailableDataSourceMonitor(target)) { + target.addField(DruidConstants.ACCESSOR_DATASOURCE_MONITOR); + + // closeMethod + InstrumentMethod closeMethod = InstrumentUtils.findMethod(target, "close"); + closeMethod.addScopedInterceptor(DruidConstants.INTERCEPTOR_CLOSE, DruidConstants.SCOPE); + + // constructor + InstrumentMethod defaultConstructor = InstrumentUtils.findConstructor(target); + defaultConstructor.addScopedInterceptor(DruidConstants.INTERCEPTOR_CONSTRUCTOR, DruidConstants.SCOPE); + } + + // getConnectionMethod + InstrumentMethod getConnectionMethod = InstrumentUtils.findMethod(target, "getConnection"); + getConnectionMethod.addScopedInterceptor(DruidConstants.INTERCEPTOR_GET_CONNECTION, DruidConstants.SCOPE); + getConnectionMethod = InstrumentUtils.findMethod(target, "getConnection", new String[]{"java.lang.String", "java.lang.String"}); + getConnectionMethod.addScopedInterceptor(DruidConstants.INTERCEPTOR_GET_CONNECTION, DruidConstants.SCOPE); + + return target.toBytecode(); + } + }); + } +} \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseConnectionInterceptor.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseConnectionInterceptor.java new file mode 100644 index 000000000000..b83120fb35db --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseConnectionInterceptor.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.plugin.druid.DruidConstants; + +/** + * The type Data source close connection interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public class DataSourceCloseConnectionInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + /** + * Instantiates a new Data source close connection interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public DataSourceCloseConnectionInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + public void doInBeforeTrace(SpanEventRecorder recorder, final Object target, Object[] args) { + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordServiceType(DruidConstants.SERVICE_TYPE); + recorder.recordApi(getMethodDescriptor()); + recorder.recordException(throwable); + } + +} \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseInterceptor.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseInterceptor.java new file mode 100644 index 000000000000..18929944ddf3 --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseInterceptor.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid.interceptor; + +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitorRegistry; +import com.navercorp.pinpoint.plugin.druid.DataSourceMonitorAccessor; +import com.navercorp.pinpoint.plugin.druid.DruidDataSourceMonitor; + +/** + * The type Data source close interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public class DataSourceCloseInterceptor implements AroundInterceptor { + + private final DataSourceMonitorRegistry dataSourceMonitorRegistry; + + /** + * Instantiates a new Data source close interceptor. + * + * @param dataSourceMonitorRegistry the data source monitor registry + */ + public DataSourceCloseInterceptor(DataSourceMonitorRegistry dataSourceMonitorRegistry) { + this.dataSourceMonitorRegistry = dataSourceMonitorRegistry; + } + + @Override + public void before(Object target, Object[] args) { + + if (target instanceof DataSourceMonitorAccessor) { + + final DataSourceMonitorAccessor dataSourceMonitorAccessor = (DataSourceMonitorAccessor) target; + + final DruidDataSourceMonitor dataSourceMonitor = dataSourceMonitorAccessor._$PINPOINT$_getDataSourceMonitor(); + + if (dataSourceMonitor != null) { + dataSourceMonitorAccessor._$PINPOINT$_setDataSourceMonitor(null); + dataSourceMonitor.close(); + dataSourceMonitorRegistry.unregister(dataSourceMonitor); + } + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + } + +} \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceConstructorInterceptor.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceConstructorInterceptor.java new file mode 100644 index 000000000000..a501190edc86 --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceConstructorInterceptor.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid.interceptor; + +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitorRegistry; +import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; +import com.navercorp.pinpoint.plugin.druid.DataSourceMonitorAccessor; +import com.navercorp.pinpoint.plugin.druid.DruidDataSourceMonitor; + +/** + * The type Data source constructor interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public class DataSourceConstructorInterceptor implements AroundInterceptor { + + private final DataSourceMonitorRegistry dataSourceMonitorRegistry; + + /** + * Instantiates a new Data source constructor interceptor. + * + * @param dataSourceMonitorRegistry the data source monitor registry + */ + public DataSourceConstructorInterceptor(DataSourceMonitorRegistry dataSourceMonitorRegistry) { + this.dataSourceMonitorRegistry = dataSourceMonitorRegistry; + } + + @Override + public void before(Object target, Object[] args) { + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + if (!InterceptorUtils.isSuccess(throwable)) { + return; + } + + if (target instanceof DataSourceMonitorAccessor) { + final DruidDataSourceMonitor dbcpDataSourceMonitor = new DruidDataSourceMonitor(target); + this.dataSourceMonitorRegistry.register(dbcpDataSourceMonitor); + ((DataSourceMonitorAccessor) target)._$PINPOINT$_setDataSourceMonitor(dbcpDataSourceMonitor); + } + } +} \ No newline at end of file diff --git a/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceGetConnectionInterceptor.java b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceGetConnectionInterceptor.java new file mode 100644 index 000000000000..21a28c728edc --- /dev/null +++ b/plugins/druid/src/main/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceGetConnectionInterceptor.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.druid.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.plugin.druid.DruidConstants; + +/** + * The type Data source get connection interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/21 + */ +public class DataSourceGetConnectionInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + /** + * Instantiates a new Data source get connection interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public DataSourceGetConnectionInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + public void doInBeforeTrace(SpanEventRecorder recorder, final Object target, Object[] args) { + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordServiceType(DruidConstants.SERVICE_TYPE); + if (args == null) { +// getConnection() without any arguments + recorder.recordApi(getMethodDescriptor()); + } else if (args.length == 2) { +// skip args[1] because it's a password. + recorder.recordApi(getMethodDescriptor(), args[0], 0); + } + recorder.recordException(throwable); + } + +} \ No newline at end of file diff --git a/plugins/druid/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/druid/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..e3bfa04fec7b --- /dev/null +++ b/plugins/druid/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.druid.DruidPlugin \ No newline at end of file diff --git a/plugins/druid/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/druid/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..6c2bf6661ba2 --- /dev/null +++ b/plugins/druid/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.druid.DruidMetadataProvider \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DataSourceMonitorAccessorTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DataSourceMonitorAccessorTest.java new file mode 100644 index 000000000000..1d64489e70bc --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DataSourceMonitorAccessorTest.java @@ -0,0 +1,22 @@ +package com.navercorp.pinpoint.plugin.druid; + +import org.junit.Test; + +public class DataSourceMonitorAccessorTest implements DataSourceMonitorAccessor { + + @Override + public void _$PINPOINT$_setDataSourceMonitor(DruidDataSourceMonitor dataSourceMonitor) { + + } + + @Override + public DruidDataSourceMonitor _$PINPOINT$_getDataSourceMonitor() { + return new DruidDataSourceMonitor(new DruidDataSourceTest()); + } + + @Test + public void test() { + DataSourceMonitorAccessorTest test = new DataSourceMonitorAccessorTest(); + test._$PINPOINT$_setDataSourceMonitor(test._$PINPOINT$_getDataSourceMonitor()); + } +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidConfigTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidConfigTest.java new file mode 100644 index 000000000000..19590d97937a --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidConfigTest.java @@ -0,0 +1,20 @@ +package com.navercorp.pinpoint.plugin.druid; + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import org.junit.Assert; +import org.junit.Test; + +public class DruidConfigTest { + + @Test + public void test() { + + DruidConfig config = new DruidConfig(new DefaultProfilerConfig()); + + Assert.assertNotNull(config); + Assert.assertFalse(config.isPluginEnable()); + Assert.assertFalse(config.isProfileClose()); + + } + +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidConstantsTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidConstantsTest.java new file mode 100644 index 000000000000..816de544f6aa --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidConstantsTest.java @@ -0,0 +1,22 @@ +package com.navercorp.pinpoint.plugin.druid; + +import org.junit.Assert; +import org.junit.Test; + +public class DruidConstantsTest { + + @Test + public void test() { + Assert.assertEquals(DruidConstants.SCOPE, "DRUID_SCOPE"); + Assert.assertEquals(DruidConstants.SERVICE_TYPE.getName(), "DRUID"); + + Assert.assertEquals(DruidConstants.ACCESSOR_DATASOURCE_MONITOR, "com.navercorp.pinpoint.plugin.druid.DataSourceMonitorAccessor"); + Assert.assertEquals(DruidConstants.INTERCEPTOR_CONSTRUCTOR, "com.navercorp.pinpoint.plugin.druid.interceptor.DataSourceConstructorInterceptor"); + Assert.assertEquals(DruidConstants.INTERCEPTOR_CLOSE, "com.navercorp.pinpoint.plugin.druid.interceptor.DataSourceCloseInterceptor"); + Assert.assertEquals(DruidConstants.INTERCEPTOR_GET_CONNECTION, "com.navercorp.pinpoint.plugin.druid.interceptor.DataSourceGetConnectionInterceptor"); + Assert.assertEquals(DruidConstants.INTERCEPTOR_CLOSE_CONNECTION, "com.navercorp.pinpoint.plugin.druid.interceptor.DataSourceCloseConnectionInterceptor"); + + Assert.assertEquals(DruidConstants.PLUGIN_ENABLE, "profiler.jdbc.druid"); + Assert.assertEquals(DruidConstants.PROFILE_CONNECTIONCLOSE_ENABLE, "profiler.jdbc.druid.connectionclose"); + } +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidDataSourceMonitorTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidDataSourceMonitorTest.java new file mode 100644 index 000000000000..145c532b23ef --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidDataSourceMonitorTest.java @@ -0,0 +1,26 @@ +package com.navercorp.pinpoint.plugin.druid; + +import org.junit.Assert; +import org.junit.Test; + +public class DruidDataSourceMonitorTest extends DataSourceMonitorAccessorTest { + + @Test + public void test() { + + DruidDataSourceMonitor monitor = new DruidDataSourceMonitor(new DruidDataSourceTest()); + + Assert.assertFalse(monitor.isDisabled()); + + monitor.close(); + + Assert.assertTrue(monitor.isDisabled()); + + Assert.assertEquals(monitor.getServiceType(), DruidConstants.SERVICE_TYPE); + + Assert.assertEquals(monitor.getUrl(), null); + Assert.assertEquals(monitor.getActiveConnectionSize(), -1); + Assert.assertEquals(monitor.getMaxConnectionSize(), -1); + } + +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidDataSourceTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidDataSourceTest.java new file mode 100644 index 000000000000..b454433f6bad --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidDataSourceTest.java @@ -0,0 +1,32 @@ +package com.navercorp.pinpoint.plugin.druid; + +public class DruidDataSourceTest extends DruidDataSourceMonitorTest { + + private String url; + private int maxActive; + private int activeCount; + + public String getUrl() { + return ""; + } + + public void setUrl(String url) { + this.url = url; + } + + public int getMaxActive() { + return 0; + } + + public void setMaxActive(int maxActive) { + this.maxActive = maxActive; + } + + public int getActiveCount() { + return 0; + } + + public void setActiveCount(int activeCount) { + this.activeCount = activeCount; + } +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidMetadataProviderTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidMetadataProviderTest.java new file mode 100644 index 000000000000..ba6591421935 --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidMetadataProviderTest.java @@ -0,0 +1,36 @@ +package com.navercorp.pinpoint.plugin.druid; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyMatcher; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; +import org.junit.Assert; +import org.junit.Test; + +public class DruidMetadataProviderTest { + + @Test + public void test() { + + DruidMetadataProvider provider = new DruidMetadataProvider(); + + provider.setup(new TraceMetadataSetupContext() { + + @Override + public void addServiceType(ServiceType serviceType) { + + Assert.assertEquals(serviceType, DruidConstants.SERVICE_TYPE); + } + + @Override + public void addServiceType(ServiceType serviceType, AnnotationKeyMatcher primaryAnnotationKeyMatcher) { + + } + + @Override + public void addAnnotationKey(AnnotationKey annotationKey) { + + } + }); + } +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidPluginTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidPluginTest.java new file mode 100644 index 000000000000..fe1edd40067f --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/DruidPluginTest.java @@ -0,0 +1,30 @@ +package com.navercorp.pinpoint.plugin.druid; + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class DruidPluginTest { + + private DruidPlugin plugin = new DruidPlugin(); + + @Test + public void setTransformTemplate() { + InstrumentContext instrumentContext = mock(InstrumentContext.class); + plugin.setTransformTemplate(new TransformTemplate(instrumentContext)); + } + + @Test + public void setup() { + ProfilerPluginSetupContext profilerPluginSetupContext = mock(ProfilerPluginSetupContext.class); + when(profilerPluginSetupContext.getConfig()).thenReturn(new DefaultProfilerConfig()); + + plugin.setup(profilerPluginSetupContext); + } + +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseConnectionInterceptorTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseConnectionInterceptorTest.java new file mode 100644 index 000000000000..e91ac6baadec --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseConnectionInterceptorTest.java @@ -0,0 +1,38 @@ +package com.navercorp.pinpoint.plugin.druid.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class DataSourceCloseConnectionInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void doInBeforeTrace() { + + DataSourceCloseConnectionInterceptor interceptor = new DataSourceCloseConnectionInterceptor(traceContext, descriptor); + + interceptor.doInBeforeTrace(null, null, null); + } + + @Test + public void doInAfterTrace() { + + DataSourceCloseConnectionInterceptor interceptor = new DataSourceCloseConnectionInterceptor(traceContext, descriptor); + + interceptor.doInAfterTrace(recorder, null, null, null, null); + } +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseInterceptorTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseInterceptorTest.java new file mode 100644 index 000000000000..e3b462d14522 --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceCloseInterceptorTest.java @@ -0,0 +1,31 @@ +package com.navercorp.pinpoint.plugin.druid.interceptor; + +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitor; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitorRegistry; +import com.navercorp.pinpoint.plugin.druid.DruidDataSourceTest; +import org.junit.Test; + +public class DataSourceCloseInterceptorTest { + + private DataSourceCloseInterceptor interceptor = new DataSourceCloseInterceptor(new DataSourceMonitorRegistry() { + @Override + public boolean register(DataSourceMonitor dataSourceMonitor) { + return false; + } + + @Override + public boolean unregister(DataSourceMonitor dataSourceMonitor) { + return false; + } + }); + + @Test + public void before() { + interceptor.before(new DruidDataSourceTest(), null); + } + + @Test + public void after() { + interceptor.after(null, null, null, null); + } +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceConstructorInterceptorTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceConstructorInterceptorTest.java new file mode 100644 index 000000000000..6fc13740fda9 --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceConstructorInterceptorTest.java @@ -0,0 +1,35 @@ +package com.navercorp.pinpoint.plugin.druid.interceptor; + +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitor; +import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitorRegistry; +import com.navercorp.pinpoint.plugin.druid.DruidDataSourceTest; +import org.junit.Test; + +public class DataSourceConstructorInterceptorTest { + + private DataSourceConstructorInterceptor interceptor = new DataSourceConstructorInterceptor(new DataSourceMonitorRegistry() { + @Override + public boolean register(DataSourceMonitor dataSourceMonitor) { + return false; + } + + @Override + public boolean unregister(DataSourceMonitor dataSourceMonitor) { + return false; + } + }); + + @Test + public void before() { + + interceptor.before(null, null); + } + + @Test + public void after() { + + interceptor.after(new DruidDataSourceTest(), null, null, new Throwable()); + + interceptor.after(new DruidDataSourceTest(), null, null, null); + } +} \ No newline at end of file diff --git a/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceGetConnectionInterceptorTest.java b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceGetConnectionInterceptorTest.java new file mode 100644 index 000000000000..15a85e0d7a7f --- /dev/null +++ b/plugins/druid/src/test/java/com/navercorp/pinpoint/plugin/druid/interceptor/DataSourceGetConnectionInterceptorTest.java @@ -0,0 +1,46 @@ +package com.navercorp.pinpoint.plugin.druid.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class DataSourceGetConnectionInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void doInBeforeTrace() { + + DataSourceGetConnectionInterceptor interceptor = new DataSourceGetConnectionInterceptor(traceContext, descriptor); + + interceptor.doInBeforeTrace(null, null, null); + } + + @Test + public void doInAfterTrace1() { + + DataSourceGetConnectionInterceptor interceptor = new DataSourceGetConnectionInterceptor(traceContext, descriptor); + + interceptor.doInAfterTrace(recorder, null, null, null, null); + } + + @Test + public void doInAfterTrace2() { + + DataSourceGetConnectionInterceptor interceptor = new DataSourceGetConnectionInterceptor(traceContext, descriptor); + + interceptor.doInAfterTrace(recorder, null, new Object[]{"", ""}, null, null); + } +} \ No newline at end of file diff --git a/plugins/dubbo/clover.license b/plugins/dubbo/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/dubbo/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-dubbo-plugin pinpoint-dubbo-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint @@ -22,7 +34,6 @@ com.alibaba dubbo - ${dubbo.version} provided diff --git a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboConstants.java b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboConstants.java index 5d921285f494..259c1432029c 100644 --- a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboConstants.java +++ b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboConstants.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.plugin.dubbo; import com.navercorp.pinpoint.common.trace.AnnotationKey; @@ -5,25 +21,30 @@ import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; +import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET; import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; /** * @author Jinkai.Ma */ -public interface DubboConstants { +public final class DubboConstants { + private DubboConstants() { + } - ServiceType DUBBO_PROVIDER_SERVICE_TYPE = ServiceTypeFactory.of(1110, "DUBBO_PROVIDER", RECORD_STATISTICS); - ServiceType DUBBO_CONSUMER_SERVICE_TYPE = ServiceTypeFactory.of(9110, "DUBBO_CONSUMER", RECORD_STATISTICS); - AnnotationKey DUBBO_ARGS_ANNOTATION_KEY = AnnotationKeyFactory.of(90, "dubbo.args"); - AnnotationKey DUBBO_RESULT_ANNOTATION_KEY = AnnotationKeyFactory.of(91, "dubbo.result"); + public static final ServiceType DUBBO_PROVIDER_SERVICE_TYPE = ServiceTypeFactory.of(1110, "DUBBO_PROVIDER", RECORD_STATISTICS); + public static final ServiceType DUBBO_CONSUMER_SERVICE_TYPE = ServiceTypeFactory.of(9110, "DUBBO_CONSUMER", RECORD_STATISTICS); + public static final ServiceType DUBBO_PROVIDER_SERVICE_NO_STATISTICS_TYPE = ServiceTypeFactory.of(9111, "DUBBO"); + public static final AnnotationKey DUBBO_ARGS_ANNOTATION_KEY = AnnotationKeyFactory.of(90, "dubbo.args"); + public static final AnnotationKey DUBBO_RESULT_ANNOTATION_KEY = AnnotationKeyFactory.of(91, "dubbo.result"); + public static final AnnotationKey DUBBO_RPC_ANNOTATION_KEY = AnnotationKeyFactory.of(92, "dubbo.rpc", VIEW_IN_RECORD_SET); - String META_DO_NOT_TRACE = "_DUBBO_DO_NOT_TRACE"; - String META_TRANSACTION_ID = "_DUBBO_TRASACTION_ID"; - String META_SPAN_ID = "_DUBBO_SPAN_ID"; - String META_PARENT_SPAN_ID = "_DUBBO_PARENT_SPAN_ID"; - String META_PARENT_APPLICATION_NAME = "_DUBBO_PARENT_APPLICATION_NAME"; - String META_PARENT_APPLICATION_TYPE = "_DUBBO_PARENT_APPLICATION_TYPE"; - String META_FLAGS = "_DUBBO_FLAGS"; + public static final String META_DO_NOT_TRACE = "_DUBBO_DO_NOT_TRACE"; + public static final String META_TRANSACTION_ID = "_DUBBO_TRASACTION_ID"; + public static final String META_SPAN_ID = "_DUBBO_SPAN_ID"; + public static final String META_PARENT_SPAN_ID = "_DUBBO_PARENT_SPAN_ID"; + public static final String META_PARENT_APPLICATION_NAME = "_DUBBO_PARENT_APPLICATION_NAME"; + public static final String META_PARENT_APPLICATION_TYPE = "_DUBBO_PARENT_APPLICATION_TYPE"; + public static final String META_FLAGS = "_DUBBO_FLAGS"; - String MONITOR_SERVICE_FQCN = "com.alibaba.dubbo.monitor.MonitorService"; + public static final String MONITOR_SERVICE_FQCN = "com.alibaba.dubbo.monitor.MonitorService"; } diff --git a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboPlugin.java b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboPlugin.java index be633d43ecb3..88cabba07e8f 100644 --- a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboPlugin.java +++ b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboPlugin.java @@ -2,6 +2,7 @@ import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; @@ -35,23 +36,25 @@ public void setup(ProfilerPluginSetupContext context) { } private void addTransformers() { - transformTemplate.transform("com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker", new TransformCallback() { + transformTemplate.transform("com.alibaba.dubbo.rpc.protocol.AbstractInvoker", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - - target.getDeclaredMethod("invoke", "com.alibaba.dubbo.rpc.Invocation").addInterceptor("com.navercorp.pinpoint.plugin.dubbo.interceptor.DubboConsumerInterceptor"); - + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + InstrumentMethod invokeMethod = target.getDeclaredMethod("invoke", "com.alibaba.dubbo.rpc.Invocation"); + if (invokeMethod != null) { + invokeMethod.addInterceptor("com.navercorp.pinpoint.plugin.dubbo.interceptor.DubboConsumerInterceptor"); + } return target.toBytecode(); } }); transformTemplate.transform("com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - - target.getDeclaredMethod("invoke", "com.alibaba.dubbo.rpc.Invocation").addInterceptor("com.navercorp.pinpoint.plugin.dubbo.interceptor.DubboProviderInterceptor"); - + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + InstrumentMethod invokeMethod = target.getDeclaredMethod("invoke", "com.alibaba.dubbo.rpc.Invocation"); + if (invokeMethod != null) { + invokeMethod.addInterceptor("com.navercorp.pinpoint.plugin.dubbo.interceptor.DubboProviderInterceptor"); + } return target.toBytecode(); } }); diff --git a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboProviderMethodDescriptor.java b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboProviderMethodDescriptor.java new file mode 100644 index 000000000000..d59b06cd5f5c --- /dev/null +++ b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboProviderMethodDescriptor.java @@ -0,0 +1,83 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.dubbo; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; + +/** + * @author jaehong.kim + */ +public class DubboProviderMethodDescriptor implements MethodDescriptor { + private int apiId = 0; + private int type = MethodType.WEB_REQUEST; + + @Override + public String getMethodName() { + return null; + } + + @Override + public String getClassName() { + return null; + } + + @Override + public String[] getParameterTypes() { + return new String[0]; + } + + @Override + public String[] getParameterVariableName() { + return new String[0]; + } + + @Override + public String getParameterDescriptor() { + return null; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return "com.navercorp.pinpoint.plugin.dubbo.DubboProviderMethodDescriptor.invoke()"; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return this.apiId; + } + + @Override + public String getApiDescriptor() { + return "Dubbo Provider Process"; + } + + @Override + public int getType() { + return this.type; + } +} diff --git a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboTraceMetadataProvider.java b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboTraceMetadataProvider.java index 6ab296e2e7c9..900a9912ff36 100644 --- a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboTraceMetadataProvider.java +++ b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/DubboTraceMetadataProvider.java @@ -11,7 +11,9 @@ public class DubboTraceMetadataProvider implements TraceMetadataProvider { public void setup(TraceMetadataSetupContext context) { context.addServiceType(DubboConstants.DUBBO_PROVIDER_SERVICE_TYPE); context.addServiceType(DubboConstants.DUBBO_CONSUMER_SERVICE_TYPE); + context.addServiceType(DubboConstants.DUBBO_PROVIDER_SERVICE_NO_STATISTICS_TYPE); context.addAnnotationKey(DubboConstants.DUBBO_ARGS_ANNOTATION_KEY); context.addAnnotationKey(DubboConstants.DUBBO_RESULT_ANNOTATION_KEY); + context.addAnnotationKey(DubboConstants.DUBBO_RPC_ANNOTATION_KEY); } } diff --git a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/interceptor/DubboConsumerInterceptor.java b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/interceptor/DubboConsumerInterceptor.java index 37508a894ddc..40577dd6556e 100644 --- a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/interceptor/DubboConsumerInterceptor.java +++ b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/interceptor/DubboConsumerInterceptor.java @@ -4,13 +4,17 @@ import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcInvocation; import com.navercorp.pinpoint.bootstrap.context.*; -import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor1; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.plugin.dubbo.DubboConstants; /** * @author Jinkai.Ma */ -public class DubboConsumerInterceptor implements AroundInterceptor1 { +public class DubboConsumerInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); private final MethodDescriptor descriptor; private final TraceContext traceContext; @@ -21,27 +25,31 @@ public DubboConsumerInterceptor(TraceContext traceContext, MethodDescriptor desc } @Override - public void before(Object target, Object arg0) { + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + // Ignore monitor service if (isMonitorService(target)) { return; } - Trace trace = traceContext.currentRawTraceObject(); + final Trace trace = traceContext.currentRawTraceObject(); if (trace == null) { return; } - RpcInvocation invocation = (RpcInvocation) arg0; + final RpcInvocation invocation = (RpcInvocation) args[0]; if (trace.canSampled()) { - SpanEventRecorder recorder = trace.traceBlockBegin(); + final SpanEventRecorder recorder = trace.traceBlockBegin(); // RPC call trace have to be recorded with a service code in RPC client code range. recorder.recordServiceType(DubboConstants.DUBBO_CONSUMER_SERVICE_TYPE); // You have to issue a TraceId the receiver of this request will use. - TraceId nextId = trace.getTraceId().getNextTraceId(); + final TraceId nextId = trace.getTraceId().getNextTraceId(); // Then record it as next span id. recorder.recordNextSpanId(nextId.getSpanId()); @@ -49,37 +57,45 @@ public void before(Object target, Object arg0) { // Finally, pass some tracing data to the server. // How to put them in a message is protocol specific. // This example assumes that the target protocol message can include any metadata (like HTTP headers). - invocation.setAttachment(DubboConstants.META_TRANSACTION_ID, nextId.getTransactionId()); - invocation.setAttachment(DubboConstants.META_SPAN_ID, Long.toString(nextId.getSpanId())); - invocation.setAttachment(DubboConstants.META_PARENT_SPAN_ID, Long.toString(nextId.getParentSpanId())); - invocation.setAttachment(DubboConstants.META_PARENT_APPLICATION_TYPE, Short.toString(traceContext.getServerTypeCode())); - invocation.setAttachment(DubboConstants.META_PARENT_APPLICATION_NAME, traceContext.getApplicationName()); - invocation.setAttachment(DubboConstants.META_FLAGS, Short.toString(nextId.getFlags())); + setAttachment(invocation, DubboConstants.META_TRANSACTION_ID, nextId.getTransactionId()); + setAttachment(invocation, DubboConstants.META_SPAN_ID, Long.toString(nextId.getSpanId())); + setAttachment(invocation, DubboConstants.META_PARENT_SPAN_ID, Long.toString(nextId.getParentSpanId())); + setAttachment(invocation, DubboConstants.META_PARENT_APPLICATION_TYPE, Short.toString(traceContext.getServerTypeCode())); + setAttachment(invocation, DubboConstants.META_PARENT_APPLICATION_NAME, traceContext.getApplicationName()); + setAttachment(invocation, DubboConstants.META_FLAGS, Short.toString(nextId.getFlags())); } else { // If sampling this transaction is disabled, pass only that infomation to the server. - invocation.setAttachment(DubboConstants.META_DO_NOT_TRACE, "1"); + setAttachment(invocation, DubboConstants.META_DO_NOT_TRACE, "1"); + } + } + + private void setAttachment(RpcInvocation invocation, String name, String value) { + invocation.setAttachment(name, value); + if (isDebug) { + logger.debug("Set attachment {}={}", name, value); } } @Override - public void after(Object target, Object arg0, Object result, Throwable throwable) { + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args); + } + // Ignore monitor service if (isMonitorService(target)) { return; } - Trace trace = traceContext.currentTraceObject(); + final Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; } - RpcInvocation invocation = (RpcInvocation) arg0; - try { - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - + final RpcInvocation invocation = (RpcInvocation) args[0]; + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordApi(descriptor); - if (throwable == null) { String endPoint = RpcContext.getContext().getRemoteAddressString(); // RPC client have to record end point (server address) diff --git a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/interceptor/DubboProviderInterceptor.java b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/interceptor/DubboProviderInterceptor.java index b1d2d57bfa2d..2e7e2c955b06 100644 --- a/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/interceptor/DubboProviderInterceptor.java +++ b/plugins/dubbo/src/main/java/com/navercorp/pinpoint/plugin/dubbo/interceptor/DubboProviderInterceptor.java @@ -4,38 +4,53 @@ import com.alibaba.dubbo.rpc.RpcContext; import com.alibaba.dubbo.rpc.RpcInvocation; import com.navercorp.pinpoint.bootstrap.context.*; -import com.navercorp.pinpoint.bootstrap.interceptor.SpanSimpleAroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanRecursiveAroundInterceptor; import com.navercorp.pinpoint.bootstrap.util.NumberUtils; import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.plugin.dubbo.DubboConstants; +import com.navercorp.pinpoint.plugin.dubbo.DubboProviderMethodDescriptor; /** * @author Jinkai.Ma + * @author Jiaqi Feng + * @author lanzuyou + * @author jaehong.kim */ -public class DubboProviderInterceptor extends SpanSimpleAroundInterceptor { +public class DubboProviderInterceptor extends SpanRecursiveAroundInterceptor { + private static final String SCOPE_NAME = "##DUBBO_PROVIDER_TRACE"; + private static final MethodDescriptor DUBBO_PROVIDER_METHOD_DESCRIPTOR = new DubboProviderMethodDescriptor(); public DubboProviderInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { - super(traceContext, descriptor, DubboProviderInterceptor.class); + super(traceContext, descriptor, SCOPE_NAME); + traceContext.cacheApi(DUBBO_PROVIDER_METHOD_DESCRIPTOR); } - @Override protected Trace createTrace(Object target, Object[] args) { - Invoker invoker = (Invoker) target; + final Trace trace = readRequestTrace(target, args); + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + // You have to record a service type within Server range. + recorder.recordServiceType(DubboConstants.DUBBO_PROVIDER_SERVICE_TYPE); + recorder.recordApi(DUBBO_PROVIDER_METHOD_DESCRIPTOR); + recordRequest(recorder, target, args); + } + return trace; + } + + private Trace readRequestTrace(Object target, Object[] args) { + final Invoker invoker = (Invoker) target; // Ignore monitor service. if (DubboConstants.MONITOR_SERVICE_FQCN.equals(invoker.getInterface().getName())) { return traceContext.disableSampling(); } - RpcInvocation invocation = (RpcInvocation) args[0]; - + final RpcInvocation invocation = (RpcInvocation) args[0]; // If this transaction is not traceable, mark as disabled. if (invocation.getAttachment(DubboConstants.META_DO_NOT_TRACE) != null) { return traceContext.disableSampling(); } - - String transactionId = invocation.getAttachment(DubboConstants.META_TRANSACTION_ID); - + final String transactionId = invocation.getAttachment(DubboConstants.META_TRANSACTION_ID); // If there's no trasanction id, a new trasaction begins here. // FIXME There seems to be cases where the invoke method is called after a span is already created. // We'll have to check if a trace object already exists and create a span event instead of a span in that case. @@ -44,36 +59,33 @@ protected Trace createTrace(Object target, Object[] args) { } // otherwise, continue tracing with given data. - long parentSpanID = NumberUtils.parseLong(invocation.getAttachment(DubboConstants.META_PARENT_SPAN_ID), SpanId.NULL); - long spanID = NumberUtils.parseLong(invocation.getAttachment(DubboConstants.META_SPAN_ID), SpanId.NULL); - short flags = NumberUtils.parseShort(invocation.getAttachment(DubboConstants.META_FLAGS), (short) 0); - TraceId traceId = traceContext.createTraceId(transactionId, parentSpanID, spanID, flags); + final long parentSpanID = NumberUtils.parseLong(invocation.getAttachment(DubboConstants.META_PARENT_SPAN_ID), SpanId.NULL); + final long spanID = NumberUtils.parseLong(invocation.getAttachment(DubboConstants.META_SPAN_ID), SpanId.NULL); + final short flags = NumberUtils.parseShort(invocation.getAttachment(DubboConstants.META_FLAGS), (short) 0); + final TraceId traceId = traceContext.createTraceId(transactionId, parentSpanID, spanID, flags); return traceContext.continueTraceObject(traceId); } - - @Override - protected void doInBeforeTrace(SpanRecorder recorder, Object target, Object[] args) { - RpcInvocation invocation = (RpcInvocation) args[0]; - RpcContext rpcContext = RpcContext.getContext(); - - // You have to record a service type within Server range. - recorder.recordServiceType(DubboConstants.DUBBO_PROVIDER_SERVICE_TYPE); + private void recordRequest(SpanRecorder recorder, Object target, Object[] args) { + final RpcInvocation invocation = (RpcInvocation) args[0]; + final RpcContext rpcContext = RpcContext.getContext(); // Record rpc name, client address, server address. recorder.recordRpcName(invocation.getInvoker().getInterface().getSimpleName() + ":" + invocation.getMethodName()); recorder.recordEndPoint(rpcContext.getLocalAddressString()); - recorder.recordRemoteAddress(rpcContext.getRemoteAddressString()); + if (rpcContext.getRemoteHost() != null) { + recorder.recordRemoteAddress(rpcContext.getRemoteAddressString()); + } else { + recorder.recordRemoteAddress("Unknown"); + } // If this transaction did not begin here, record parent(client who sent this request) information if (!recorder.isRoot()) { - String parentApplicationName = invocation.getAttachment(DubboConstants.META_PARENT_APPLICATION_NAME); - + final String parentApplicationName = invocation.getAttachment(DubboConstants.META_PARENT_APPLICATION_NAME); if (parentApplicationName != null) { - short parentApplicationType = NumberUtils.parseShort(invocation.getAttachment(DubboConstants.META_PARENT_APPLICATION_TYPE), ServiceType.UNDEFINED.getCode()); + final short parentApplicationType = NumberUtils.parseShort(invocation.getAttachment(DubboConstants.META_PARENT_APPLICATION_TYPE), ServiceType.UNDEFINED.getCode()); recorder.recordParentApplication(parentApplicationName, parentApplicationType); - // Pinpoint finds caller - callee relation by matching caller's end point and callee's acceptor host. // https://github.com/naver/pinpoint/issues/1395 recorder.recordAcceptorHost(rpcContext.getLocalAddressString()); @@ -82,9 +94,17 @@ protected void doInBeforeTrace(SpanRecorder recorder, Object target, Object[] ar } @Override - protected void doInAfterTrace(SpanRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { - RpcInvocation invocation = (RpcInvocation) args[0]; + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + final RpcInvocation invocation = (RpcInvocation) args[0]; + recorder.recordServiceType(DubboConstants.DUBBO_PROVIDER_SERVICE_NO_STATISTICS_TYPE); + recorder.recordApi(methodDescriptor); + recorder.recordAttribute(DubboConstants.DUBBO_RPC_ANNOTATION_KEY, + invocation.getInvoker().getInterface().getSimpleName() + ":" + invocation.getMethodName()); + } + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + final RpcInvocation invocation = (RpcInvocation) args[0]; recorder.recordApi(methodDescriptor); recorder.recordAttribute(DubboConstants.DUBBO_ARGS_ANNOTATION_KEY, invocation.getArguments()); @@ -94,4 +114,4 @@ protected void doInAfterTrace(SpanRecorder recorder, Object target, Object[] arg recorder.recordException(throwable); } } -} +} \ No newline at end of file diff --git a/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboConfigurationTest.java b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboConfigurationTest.java new file mode 100644 index 000000000000..6e396e6f41e9 --- /dev/null +++ b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboConfigurationTest.java @@ -0,0 +1,32 @@ +package com.navercorp.pinpoint.plugin.dubbo; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class DubboConfigurationTest { + + @Mock + ProfilerConfig config; + + @Test + public void isDubboEnabled() { + + DubboConfiguration configuration = new DubboConfiguration(config); + + Assert.assertFalse(configuration.isDubboEnabled()); + } + + @Test + public void getDubboBootstrapMains() { + + DubboConfiguration configuration = new DubboConfiguration(config); + + Assert.assertEquals(configuration.getDubboBootstrapMains().size(),0); + } + +} \ No newline at end of file diff --git a/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboConstantsTest.java b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboConstantsTest.java new file mode 100644 index 000000000000..a32c2a346e11 --- /dev/null +++ b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboConstantsTest.java @@ -0,0 +1,28 @@ +package com.navercorp.pinpoint.plugin.dubbo; + +import org.junit.Assert; +import org.junit.Test; + +public class DubboConstantsTest { + + @Test + public void test() { + + Assert.assertEquals(DubboConstants.DUBBO_PROVIDER_SERVICE_TYPE.getCode(), 1110); + Assert.assertEquals(DubboConstants.DUBBO_CONSUMER_SERVICE_TYPE.getCode(), 9110); + Assert.assertEquals(DubboConstants.DUBBO_PROVIDER_SERVICE_NO_STATISTICS_TYPE.getCode(), 9111); + Assert.assertEquals(DubboConstants.DUBBO_ARGS_ANNOTATION_KEY.getCode(), 90); + Assert.assertEquals(DubboConstants.DUBBO_RESULT_ANNOTATION_KEY.getCode(), 91); + Assert.assertEquals(DubboConstants.DUBBO_RPC_ANNOTATION_KEY.getCode(), 92); + + Assert.assertEquals(DubboConstants.META_DO_NOT_TRACE, "_DUBBO_DO_NOT_TRACE"); + Assert.assertEquals(DubboConstants.META_TRANSACTION_ID, "_DUBBO_TRASACTION_ID"); + Assert.assertEquals(DubboConstants.META_SPAN_ID, "_DUBBO_SPAN_ID"); + Assert.assertEquals(DubboConstants.META_PARENT_SPAN_ID, "_DUBBO_PARENT_SPAN_ID"); + Assert.assertEquals(DubboConstants.META_PARENT_APPLICATION_NAME, "_DUBBO_PARENT_APPLICATION_NAME"); + Assert.assertEquals(DubboConstants.META_PARENT_APPLICATION_TYPE, "_DUBBO_PARENT_APPLICATION_TYPE"); + Assert.assertEquals(DubboConstants.META_FLAGS, "_DUBBO_FLAGS"); + Assert.assertEquals(DubboConstants.MONITOR_SERVICE_FQCN, "com.alibaba.dubbo.monitor.MonitorService"); + + } +} \ No newline at end of file diff --git a/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboProviderDetectorTest.java b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboProviderDetectorTest.java new file mode 100644 index 000000000000..37b63f501184 --- /dev/null +++ b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboProviderDetectorTest.java @@ -0,0 +1,31 @@ +package com.navercorp.pinpoint.plugin.dubbo; + +import com.navercorp.pinpoint.bootstrap.resolver.ConditionProvider; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class DubboProviderDetectorTest { + + @Mock + ConditionProvider conditionProvider; + + @Test + public void getApplicationType() { + + DubboProviderDetector dubboProviderDetector = new DubboProviderDetector(null); + + Assert.assertEquals(dubboProviderDetector.getApplicationType().getCode(), 1110); + } + + @Test + public void detect() { + + DubboProviderDetector dubboProviderDetector = new DubboProviderDetector(null); + + Assert.assertFalse(dubboProviderDetector.detect(conditionProvider)); + } +} \ No newline at end of file diff --git a/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboProviderMethodDescriptorTest.java b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboProviderMethodDescriptorTest.java new file mode 100644 index 000000000000..94f5f9bbfe63 --- /dev/null +++ b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboProviderMethodDescriptorTest.java @@ -0,0 +1,29 @@ +package com.navercorp.pinpoint.plugin.dubbo; + +import com.navercorp.pinpoint.common.trace.MethodType; +import org.junit.Assert; +import org.junit.Test; + +public class DubboProviderMethodDescriptorTest { + + @Test + public void test() { + + DubboProviderMethodDescriptor descriptor = new DubboProviderMethodDescriptor(); + + Assert.assertEquals(descriptor.getApiDescriptor(), "Dubbo Provider Process"); + Assert.assertEquals(descriptor.getApiId(), 0); + Assert.assertNull(descriptor.getClassName()); + Assert.assertEquals(descriptor.getFullName(), "com.navercorp.pinpoint.plugin.dubbo.DubboProviderMethodDescriptor.invoke()"); + + Assert.assertEquals(descriptor.getLineNumber(), -1); + Assert.assertNull(descriptor.getMethodName()); + + Assert.assertNull(descriptor.getParameterDescriptor()); + + Assert.assertArrayEquals(descriptor.getParameterTypes(), new String[0]); + + Assert.assertArrayEquals(descriptor.getParameterVariableName(), new String[0]); + Assert.assertEquals(descriptor.getType(), MethodType.WEB_REQUEST); + } +} \ No newline at end of file diff --git a/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboTraceMetadataProviderTest.java b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboTraceMetadataProviderTest.java new file mode 100644 index 000000000000..ec448d409fdb --- /dev/null +++ b/plugins/dubbo/src/test/java/com/navercorp/pinpoint/plugin/dubbo/DubboTraceMetadataProviderTest.java @@ -0,0 +1,31 @@ +package com.navercorp.pinpoint.plugin.dubbo; + +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class DubboTraceMetadataProviderTest { + + @Mock + TraceMetadataSetupContext context; + + @Test + public void setup() { + + DubboTraceMetadataProvider provider = new DubboTraceMetadataProvider(); + + provider.setup(context); + + verify(context).addServiceType(DubboConstants.DUBBO_PROVIDER_SERVICE_TYPE); + verify(context).addServiceType(DubboConstants.DUBBO_CONSUMER_SERVICE_TYPE); + verify(context).addServiceType(DubboConstants.DUBBO_PROVIDER_SERVICE_NO_STATISTICS_TYPE); + verify(context).addAnnotationKey(DubboConstants.DUBBO_ARGS_ANNOTATION_KEY); + verify(context).addAnnotationKey(DubboConstants.DUBBO_RESULT_ANNOTATION_KEY); + verify(context).addAnnotationKey(DubboConstants.DUBBO_RPC_ANNOTATION_KEY); + } +} \ No newline at end of file diff --git a/plugins/fastjson/.gitignore b/plugins/fastjson/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/fastjson/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/fastjson/pom.xml b/plugins/fastjson/pom.xml new file mode 100644 index 000000000000..de4ca6c616e6 --- /dev/null +++ b/plugins/fastjson/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-fastjson-plugin + pinpoint-fastjson-plugin + jar + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + + diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConfig.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConfig.java new file mode 100644 index 000000000000..29714a468fbc --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConfig.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +/** + * The type Fastjson config. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class FastjsonConfig { + + private final boolean profile; + + /** + * Instantiates a new Fastjson config. + * + * @param config the config + */ + public FastjsonConfig(ProfilerConfig config) { + this.profile = config.readBoolean(FastjsonConstants.CONFIG, false); + } + + /** + * Is profile boolean. + * + * @return the boolean + */ + public boolean isProfile() { + return profile; + } + + @Override + public String toString() { + return "FastjsonConfig{" + "profile=" + profile + '}'; + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConstants.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConstants.java new file mode 100644 index 000000000000..7db3b8fa793e --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConstants.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +/** + * The type Fastjson constants. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public final class FastjsonConstants { + + private FastjsonConstants() { + } + + /** + * The constant SERVICE_TYPE. + */ + public static final ServiceType SERVICE_TYPE = ServiceTypeFactory.of(5013, "FASTJSON"); + /** + * The constant ANNOTATION_KEY_JSON_LENGTH. + */ + public static final AnnotationKey ANNOTATION_KEY_JSON_LENGTH = AnnotationKeyFactory.of(9003, "fastjson.json.length"); + + /** + * The constant SCOPE. + */ + public static final String SCOPE = "FASTJSON_SCOPE"; + + /** + * The constant CONFIG. + */ + public static final String CONFIG = "profiler.json.fastjson"; +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonMetadataProvider.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonMetadataProvider.java new file mode 100644 index 000000000000..ba00671b52dd --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonMetadataProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * The type Fastjson metadata provider. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class FastjsonMetadataProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(FastjsonConstants.SERVICE_TYPE); + context.addAnnotationKey(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH); + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonPlugin.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonPlugin.java new file mode 100644 index 000000000000..bb25a9a03559 --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonPlugin.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson; + +import com.navercorp.pinpoint.bootstrap.instrument.*; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; + +import java.security.ProtectionDomain; + +/** + * The type Fastjson plugin. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class FastjsonPlugin implements ProfilerPlugin, TransformTemplateAware { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private TransformTemplate transformTemplate; + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } + + @Override + public void setup(ProfilerPluginSetupContext context) { + + FastjsonConfig config = new FastjsonConfig(context.getConfig()); + + logger.debug("[Fastjson] Initialized config={}", config); + + if (config.isProfile()) { + + transformTemplate.transform("com.alibaba.fastjson.JSON", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("parse"))) { + m.addScopedInterceptor("com.navercorp.pinpoint.plugin.fastjson.interceptor.ParseInterceptor", FastjsonConstants.SCOPE); + } + + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("parseObject"))) { + m.addScopedInterceptor("com.navercorp.pinpoint.plugin.fastjson.interceptor.ParseObjectInterceptor", FastjsonConstants.SCOPE); + } + + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("parseArray"))) { + m.addScopedInterceptor("com.navercorp.pinpoint.plugin.fastjson.interceptor.ParseArrayInterceptor", FastjsonConstants.SCOPE); + } + + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("toJSON"))) { + m.addScopedInterceptor("com.navercorp.pinpoint.plugin.fastjson.interceptor.ToJsonInterceptor", FastjsonConstants.SCOPE); + } + + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("toJavaObject"))) { + m.addScopedInterceptor("com.navercorp.pinpoint.plugin.fastjson.interceptor.ToJavaObjectInterceptor", FastjsonConstants.SCOPE); + } + + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("toJSONString"))) { + m.addScopedInterceptor("com.navercorp.pinpoint.plugin.fastjson.interceptor.ToJsonStringInterceptor", FastjsonConstants.SCOPE); + } + + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("toJSONBytes"))) { + m.addScopedInterceptor("com.navercorp.pinpoint.plugin.fastjson.interceptor.ToJsonBytesInterceptor", FastjsonConstants.SCOPE); + } + + for (InstrumentMethod m : target.getDeclaredMethods(MethodFilters.name("writeJSONString"))) { + m.addScopedInterceptor("com.navercorp.pinpoint.plugin.fastjson.interceptor.WriteJsonStringInterceptor", FastjsonConstants.SCOPE); + } + + return target.toBytecode(); + } + }); + } + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseArrayInterceptor.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseArrayInterceptor.java new file mode 100644 index 000000000000..9a12d6096b80 --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseArrayInterceptor.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; + +/** + * The type Parse array interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class ParseArrayInterceptor implements AroundInterceptor { + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + /** + * Instantiates a new Parse array interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public ParseArrayInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + + if (logger.isDebugEnabled()) { + + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + if (logger.isDebugEnabled()) { + + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordServiceType(FastjsonConstants.SERVICE_TYPE); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + + if (args[0] != null && args[0] instanceof String) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((String) args[0]).length()); + } + + } finally { + trace.traceBlockEnd(); + } + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseInterceptor.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseInterceptor.java new file mode 100644 index 000000000000..3161c66b5797 --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseInterceptor.java @@ -0,0 +1,99 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; + +/** + * The type Parse interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class ParseInterceptor implements AroundInterceptor { + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + /** + * Instantiates a new Parse interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public ParseInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + + if (logger.isDebugEnabled()) { + + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + if (logger.isDebugEnabled()) { + + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordServiceType(FastjsonConstants.SERVICE_TYPE); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + + if (args[0] != null) { + if (args[0] instanceof String) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((String) args[0]).length()); + } else if (args[0] instanceof byte[]) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((byte[]) args[0]).length); + } + } + } finally { + trace.traceBlockEnd(); + } + + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseObjectInterceptor.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseObjectInterceptor.java new file mode 100644 index 000000000000..12d97c82110b --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseObjectInterceptor.java @@ -0,0 +1,107 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; + +import java.io.IOException; +import java.io.InputStream; + +/** + * The type Parse object interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class ParseObjectInterceptor implements AroundInterceptor { + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + /** + * Instantiates a new Parse object interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public ParseObjectInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + + if (logger.isDebugEnabled()) { + + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + if (logger.isDebugEnabled()) { + + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordServiceType(FastjsonConstants.SERVICE_TYPE); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + + if (args[0] != null) { + if (args[0] instanceof String) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((String) args[0]).length()); + } else if (args[0] instanceof byte[]) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((byte[]) args[0]).length); + } else if (args[0] instanceof char[]) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((char[]) args[0]).length); + } else if (args[0] instanceof InputStream) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((InputStream) args[0]).available()); + } + } + } catch (IOException e) { + } finally { + trace.traceBlockEnd(); + } + + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJavaObjectInterceptor.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJavaObjectInterceptor.java new file mode 100644 index 000000000000..abcaf9d77ef0 --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJavaObjectInterceptor.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; + +/** + * The type To java object interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class ToJavaObjectInterceptor implements AroundInterceptor { + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + /** + * Instantiates a new To java object interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public ToJavaObjectInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + + if (logger.isDebugEnabled()) { + + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + if (logger.isDebugEnabled()) { + + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordServiceType(FastjsonConstants.SERVICE_TYPE); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + + if (result != null) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, result.hashCode()); + } + } finally { + trace.traceBlockEnd(); + } + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonBytesInterceptor.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonBytesInterceptor.java new file mode 100644 index 000000000000..b5d5bce48a4d --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonBytesInterceptor.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; + +/** + * The type To json bytes interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class ToJsonBytesInterceptor implements AroundInterceptor { + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + /** + * Instantiates a new To json bytes interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public ToJsonBytesInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + + if (logger.isDebugEnabled()) { + + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + if (logger.isDebugEnabled()) { + + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordServiceType(FastjsonConstants.SERVICE_TYPE); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + + if (result != null && result instanceof byte[]) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((byte[]) result).length); + } + } finally { + trace.traceBlockEnd(); + } + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonInterceptor.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonInterceptor.java new file mode 100644 index 000000000000..8983ca4035e7 --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonInterceptor.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; + +/** + * The type To json interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class ToJsonInterceptor implements AroundInterceptor { + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + /** + * Instantiates a new To json interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public ToJsonInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + + if (logger.isDebugEnabled()) { + + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + if (logger.isDebugEnabled()) { + + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordServiceType(FastjsonConstants.SERVICE_TYPE); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + + if (result != null && result instanceof Object) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, result.hashCode()); + } + } finally { + trace.traceBlockEnd(); + } + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonStringInterceptor.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonStringInterceptor.java new file mode 100644 index 000000000000..64f9f71c812b --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonStringInterceptor.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; + +/** + * The type To json string interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class ToJsonStringInterceptor implements AroundInterceptor { + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + /** + * Instantiates a new To json string interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public ToJsonStringInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + + if (logger.isDebugEnabled()) { + + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + if (logger.isDebugEnabled()) { + + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordServiceType(FastjsonConstants.SERVICE_TYPE); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + + if (result != null && result instanceof String) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((String) result).length()); + } + } finally { + trace.traceBlockEnd(); + } + } +} diff --git a/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/WriteJsonStringInterceptor.java b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/WriteJsonStringInterceptor.java new file mode 100644 index 000000000000..eeb5949b18c1 --- /dev/null +++ b/plugins/fastjson/src/main/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/WriteJsonStringInterceptor.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; + +/** + * The type Write json string interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2017/07/17 + */ +public class WriteJsonStringInterceptor implements AroundInterceptor { + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + /** + * Instantiates a new Write json string interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public WriteJsonStringInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + + if (logger.isDebugEnabled()) { + + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + if (logger.isDebugEnabled()) { + + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordServiceType(FastjsonConstants.SERVICE_TYPE); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + + if (result != null && result instanceof Integer) { + recorder.recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, ((Integer) result).intValue()); + } + } finally { + trace.traceBlockEnd(); + } + } +} diff --git a/plugins/fastjson/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/fastjson/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..557be82270ee --- /dev/null +++ b/plugins/fastjson/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.fastjson.FastjsonPlugin \ No newline at end of file diff --git a/plugins/fastjson/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/fastjson/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..f69c62ff7a3b --- /dev/null +++ b/plugins/fastjson/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.fastjson.FastjsonMetadataProvider \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConfigTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConfigTest.java new file mode 100644 index 000000000000..299915953a60 --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConfigTest.java @@ -0,0 +1,22 @@ +package com.navercorp.pinpoint.plugin.fastjson; + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import org.junit.Assert; +import org.junit.Test; + +public class FastjsonConfigTest { + + @Test + public void isProfile() { + + ProfilerConfig profilerConfig = new DefaultProfilerConfig(); + + FastjsonConfig config = new FastjsonConfig(profilerConfig); + + Assert.assertFalse(config.isProfile()); + + System.out.println(config.toString()); + } + +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConstantsTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConstantsTest.java new file mode 100644 index 000000000000..edc28366c096 --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonConstantsTest.java @@ -0,0 +1,18 @@ +package com.navercorp.pinpoint.plugin.fastjson; + +import org.junit.Assert; +import org.junit.Test; + +public class FastjsonConstantsTest { + + @Test + public void test() { + + Assert.assertEquals(FastjsonConstants.SCOPE, "FASTJSON_SCOPE"); + Assert.assertEquals(FastjsonConstants.CONFIG, "profiler.json.fastjson"); + Assert.assertEquals(FastjsonConstants.SERVICE_TYPE.getCode(), 5013); + Assert.assertEquals(FastjsonConstants.SERVICE_TYPE.getName(), "FASTJSON"); + Assert.assertEquals(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH.getCode(), 9003); + Assert.assertEquals(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH.getName(), "fastjson.json.length"); + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonMetadataProviderTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonMetadataProviderTest.java new file mode 100644 index 000000000000..b9f66ee08d8e --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonMetadataProviderTest.java @@ -0,0 +1,35 @@ +package com.navercorp.pinpoint.plugin.fastjson; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyMatcher; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; +import org.junit.Assert; +import org.junit.Test; + +public class FastjsonMetadataProviderTest { + + @Test + public void setup() { + + FastjsonMetadataProvider provider = new FastjsonMetadataProvider(); + + provider.setup(new TraceMetadataSetupContext() { + + @Override + public void addServiceType(ServiceType serviceType) { + Assert.assertEquals(serviceType, FastjsonConstants.SERVICE_TYPE); + } + + @Override + public void addServiceType(ServiceType serviceType, AnnotationKeyMatcher annotationKeyMatcher) { + Assert.assertEquals(serviceType, FastjsonConstants.SERVICE_TYPE); + } + + @Override + public void addAnnotationKey(AnnotationKey annotationKey) { + Assert.assertEquals(annotationKey, FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH); + } + }); + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonPluginTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonPluginTest.java new file mode 100644 index 000000000000..910353c1458e --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/FastjsonPluginTest.java @@ -0,0 +1,29 @@ +package com.navercorp.pinpoint.plugin.fastjson; + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class FastjsonPluginTest { + + private FastjsonPlugin plugin = new FastjsonPlugin(); + + @Test + public void setTransformTemplate() { + InstrumentContext instrumentContext = mock(InstrumentContext.class); + plugin.setTransformTemplate(new TransformTemplate(instrumentContext)); + } + + @Test + public void setup() { + ProfilerPluginSetupContext profilerPluginSetupContext = mock(ProfilerPluginSetupContext.class); + when(profilerPluginSetupContext.getConfig()).thenReturn(new DefaultProfilerConfig()); + + plugin.setup(profilerPluginSetupContext); + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseArrayInterceptorTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseArrayInterceptorTest.java new file mode 100644 index 000000000000..9149028e379c --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseArrayInterceptorTest.java @@ -0,0 +1,55 @@ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ParseArrayInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).traceBlockBegin(); + + ParseArrayInterceptor interceptor = new ParseArrayInterceptor(traceContext, descriptor); + + interceptor.before(null, null); + } + + @Test + public void after() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ParseArrayInterceptor interceptor = new ParseArrayInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{"{\"firstName\": \"Json\"}"}, null, null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, "{\"firstName\": \"Json\"}".length()); + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseInterceptorTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseInterceptorTest.java new file mode 100644 index 000000000000..6b87f6d348bd --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseInterceptorTest.java @@ -0,0 +1,71 @@ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ParseInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).traceBlockBegin(); + + ParseInterceptor interceptor = new ParseInterceptor(traceContext, descriptor); + + interceptor.before(null, null); + } + + @Test + public void after1() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ParseInterceptor interceptor = new ParseInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{"{\"firstName\": \"Json\"}"}, null, null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, "{\"firstName\": \"Json\"}".length()); + } + + + @Test + public void after2() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ParseInterceptor interceptor = new ParseInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{new byte[]{01}}, null, null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, new byte[]{01}.length); + + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseObjectInterceptorTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseObjectInterceptorTest.java new file mode 100644 index 000000000000..2fc4fab03404 --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ParseObjectInterceptorTest.java @@ -0,0 +1,112 @@ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.IOException; +import java.io.InputStream; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ParseObjectInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanEventRecorder recorder; + + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).traceBlockBegin(); + + ParseObjectInterceptor interceptor = new ParseObjectInterceptor(traceContext, descriptor); + + interceptor.before(null, null); + } + + @Test + public void after1() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ParseObjectInterceptor interceptor = new ParseObjectInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{"{\"firstName\": \"Json\"}"}, null, null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, "{\"firstName\": \"Json\"}".length()); + } + + @Test + public void after2() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ParseObjectInterceptor interceptor = new ParseObjectInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{new byte[]{01}}, null, null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, new byte[]{01}.length); + } + + @Test + public void after3() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ParseObjectInterceptor interceptor = new ParseObjectInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{new char[]{'1'}}, null, null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, new char[]{'1'}.length); + } + + + @Test + public void after4() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ParseObjectInterceptor interceptor = new ParseObjectInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{new InputStream() { + @Override + public int read() throws IOException { + return 0; + } + + @Override + public int available() throws IOException { + return 1; + } + }}, null, null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, 1); + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJavaObjectInterceptorTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJavaObjectInterceptorTest.java new file mode 100644 index 000000000000..abd45ee23ab1 --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJavaObjectInterceptorTest.java @@ -0,0 +1,55 @@ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ToJavaObjectInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).traceBlockBegin(); + + ToJavaObjectInterceptor interceptor = new ToJavaObjectInterceptor(traceContext, descriptor); + + interceptor.before(null, null); + } + + @Test + public void after() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ToJavaObjectInterceptor interceptor = new ToJavaObjectInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{}, "{\"firstName\": \"Json\"}", null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, "{\"firstName\": \"Json\"}".hashCode()); + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonBytesInterceptorTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonBytesInterceptorTest.java new file mode 100644 index 000000000000..1d31d4f612ab --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonBytesInterceptorTest.java @@ -0,0 +1,56 @@ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ToJsonBytesInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanEventRecorder recorder; + + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).traceBlockBegin(); + + ToJsonBytesInterceptor interceptor = new ToJsonBytesInterceptor(traceContext, descriptor); + + interceptor.before(null, null); + } + + @Test + public void after() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ToJsonBytesInterceptor interceptor = new ToJsonBytesInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{}, new byte[]{01}, null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, new byte[]{01}.length); + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonInterceptorTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonInterceptorTest.java new file mode 100644 index 000000000000..149afd8a4611 --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonInterceptorTest.java @@ -0,0 +1,55 @@ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ToJsonInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanEventRecorder recorder; + + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).traceBlockBegin(); + + ToJsonInterceptor interceptor = new ToJsonInterceptor(traceContext, descriptor); + interceptor.before(null, null); + } + + @Test + public void after() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ToJsonInterceptor interceptor = new ToJsonInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{}, "{\"firstName\": \"Json\"}", null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, "{\"firstName\": \"Json\"}".hashCode()); + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonStringInterceptorTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonStringInterceptorTest.java new file mode 100644 index 000000000000..12eeb34e5545 --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/ToJsonStringInterceptorTest.java @@ -0,0 +1,55 @@ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ToJsonStringInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).traceBlockBegin(); + + ToJsonStringInterceptor interceptor = new ToJsonStringInterceptor(traceContext, descriptor); + + interceptor.before(null, null); + } + + @Test + public void after() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + ToJsonStringInterceptor interceptor = new ToJsonStringInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{}, "{\"firstName\": \"Json\"}", null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, "{\"firstName\": \"Json\"}".length()); + } +} \ No newline at end of file diff --git a/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/WriteJsonStringInterceptorTest.java b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/WriteJsonStringInterceptorTest.java new file mode 100644 index 000000000000..9c4a0ff115c0 --- /dev/null +++ b/plugins/fastjson/src/test/java/com/navercorp/pinpoint/plugin/fastjson/interceptor/WriteJsonStringInterceptorTest.java @@ -0,0 +1,54 @@ +package com.navercorp.pinpoint.plugin.fastjson.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.fastjson.FastjsonConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class WriteJsonStringInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).traceBlockBegin(); + + WriteJsonStringInterceptor interceptor = new WriteJsonStringInterceptor(traceContext, descriptor); + interceptor.before(null, null); + } + + @Test + public void after() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + + WriteJsonStringInterceptor interceptor = new WriteJsonStringInterceptor(traceContext, descriptor); + + interceptor.after(null, new Object[]{}, 1, null); + + verify(recorder).recordServiceType(FastjsonConstants.SERVICE_TYPE); + verify(recorder).recordAttribute(FastjsonConstants.ANNOTATION_KEY_JSON_LENGTH, 1); + } +} \ No newline at end of file diff --git a/plugins/google-httpclient/clover.license b/plugins/google-httpclient/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/google-httpclient/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-google-httpclient-plugin pinpoint-google-httpclient-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/grpc/.gitignore b/plugins/grpc/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/grpc/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/grpc/pom.xml b/plugins/grpc/pom.xml new file mode 100644 index 000000000000..805ad8211dc8 --- /dev/null +++ b/plugins/grpc/pom.xml @@ -0,0 +1,45 @@ + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-grpc-plugin + pinpoint-grpc-plugin + jar + + + 1.14.0 + 3.5.1-1 + + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + + com.navercorp.pinpoint + pinpoint-commons + + + + io.grpc + grpc-core + ${grpc.version} + + + * + * + + + + + + diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcClientPlugin.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcClientPlugin.java new file mode 100644 index 000000000000..7fc0328f4cd3 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcClientPlugin.java @@ -0,0 +1,137 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.Assert; + +import java.security.ProtectionDomain; +import java.util.List; + +/** + * @author Taejin Koo + */ +class GrpcClientPlugin { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private final TransformTemplate transformTemplate; + + GrpcClientPlugin(TransformTemplate transformTemplate) { + this.transformTemplate = Assert.requireNonNull(transformTemplate, "transformTemplate must not be null"); + } + + void addInterceptor() { + final String managedChannel = "io.grpc.internal.ManagedChannelImpl$RealChannel"; + transformTemplate.transform(managedChannel, new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + addNewCallMethodInterceptor(target); + + return target.toBytecode(); + } + + }); + + final String oobChannel = "io.grpc.internal.OobChannel"; + transformTemplate.transform(oobChannel, new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + addNewCallMethodInterceptor(target); + + return target.toBytecode(); + } + + }); + + + final String clientStreamListener = "io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl"; + transformTemplate.transform(clientStreamListener, new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + InstrumentMethod constructor = target.getConstructor("io.grpc.internal.ClientCallImpl", "io.grpc.ClientCall$Listener"); + if (constructor == null) { + logger.info("can't find \"io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl\" constructor"); + return target.toBytecode(); + } + + constructor.addInterceptor("com.navercorp.pinpoint.plugin.grpc.interceptor.client.ListenerConstructorInterceptor"); + + MethodFilter closedMethodsFilter = MethodFilters.chain(MethodFilters.name("closed"), MethodFilters.argAt(0, "io.grpc.Status")); + List closedMethods = target.getDeclaredMethods(closedMethodsFilter); + for (InstrumentMethod closedMethod : closedMethods) { + closedMethod.addInterceptor("com.navercorp.pinpoint.plugin.grpc.interceptor.client.ListenerClosedInterceptor"); + } + + target.addField(AsyncContextAccessor.class.getName()); + + return target.toBytecode(); + } + + }); + + transformTemplate.transform("io.grpc.internal.ClientCallImpl", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + InstrumentMethod startMethod = target.getDeclaredMethod("start", "io.grpc.ClientCall$Listener", "io.grpc.Metadata"); + if (startMethod == null) { + logger.debug("can't find start method"); + return target.toBytecode(); + } + + startMethod.addInterceptor("com.navercorp.pinpoint.plugin.grpc.interceptor.client.ClientCallStartInterceptor"); + + target.addField("com.navercorp.pinpoint.plugin.grpc.field.accessor.RemoteAddressAccessor"); + target.addField("com.navercorp.pinpoint.plugin.grpc.field.accessor.MethodNameAccessor"); + + return target.toBytecode(); + } + }); + } + + private void addNewCallMethodInterceptor(InstrumentClass target) throws InstrumentException { + InstrumentMethod newCallMethod = target.getDeclaredMethod("newCall", "io.grpc.MethodDescriptor", "io.grpc.CallOptions"); + if (newCallMethod != null) { + newCallMethod.addInterceptor("com.navercorp.pinpoint.plugin.grpc.interceptor.client.ChannelNewCallInterceptor"); + } else { + logger.debug("can't find newCall method"); + } + } + + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcConfig.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcConfig.java new file mode 100644 index 000000000000..195a6d82f762 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcConfig.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +public class GrpcConfig { + + static final String CLIENT_ENABLE = "profiler.grpc.client.enable"; + static final String SERVER_ENABLE = "profiler.grpc.server.enable"; + static final String SERVER_STREAMING_ON_MESSAGE_ENABLE = "profiler.grpc.server.streaming.onmessage.enable"; + + private final boolean clientEnable; + private final boolean serverEnable; + private final boolean serverStreamingOnMessageEnable; + + public GrpcConfig(ProfilerConfig config) { + this.clientEnable = config.readBoolean(CLIENT_ENABLE, false); + this.serverEnable = config.readBoolean(SERVER_ENABLE, false); + this.serverStreamingOnMessageEnable = config.readBoolean(SERVER_STREAMING_ON_MESSAGE_ENABLE, false); + } + + public boolean isClientEnable() { + return clientEnable; + } + + public boolean isServerEnable() { + return serverEnable; + } + + public boolean isServerStreamingOnMessageEnable() { + return serverStreamingOnMessageEnable; + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcConstants.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcConstants.java new file mode 100644 index 000000000000..163c15892246 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcConstants.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; + +public final class GrpcConstants { + + private GrpcConstants() { + } + + public static final ServiceType SERVICE_TYPE = ServiceTypeFactory.of(9160, "GRPC", RECORD_STATISTICS); + public static final ServiceType SERVICE_TYPE_INTERNAL = ServiceTypeFactory.of(9161, "GRPC_INTERNAL"); + + public static final ServiceType SERVER_SERVICE_TYPE = ServiceTypeFactory.of(1130, "GRPC_SERVER", RECORD_STATISTICS); + public static final ServiceType SERVER_SERVICE_TYPE_INTERNAL = ServiceTypeFactory.of(9162, "GRPC_SERVER_INTERNAL"); + + public static final AnnotationKey CLIENT_STATUS_ANNOTATION = AnnotationKeyFactory.of(160, "grpc.status", VIEW_IN_RECORD_SET); + + public static final String UNKNOWN_ADDRESS = "Unknown"; + public static final String UNKNOWN_METHOD = "UnknownMethod"; + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcMetadataProvider.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcMetadataProvider.java new file mode 100644 index 000000000000..20f7711db2bd --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcMetadataProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.grpc; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyMatchers; +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +public class GrpcMetadataProvider implements TraceMetadataProvider { + + /** + * @see TraceMetadataProvider#setup(TraceMetadataSetupContext) + */ + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(GrpcConstants.SERVICE_TYPE, AnnotationKeyMatchers.exact(AnnotationKey.HTTP_URL)); + context.addServiceType(GrpcConstants.SERVICE_TYPE_INTERNAL, AnnotationKeyMatchers.exact(GrpcConstants.CLIENT_STATUS_ANNOTATION)); + + context.addServiceType(GrpcConstants.SERVER_SERVICE_TYPE); + context.addServiceType(GrpcConstants.SERVER_SERVICE_TYPE_INTERNAL); + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcPlugin.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcPlugin.java new file mode 100644 index 000000000000..4757d558917a --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcPlugin.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.grpc; + +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; + +public class GrpcPlugin implements ProfilerPlugin, TransformTemplateAware { + + private TransformTemplate transformTemplate; + + @Override + public void setup(ProfilerPluginSetupContext context) { + final GrpcConfig config = new GrpcConfig(context.getConfig()); + + if (config.isClientEnable()) { + addClientInterceptor(); + } + + if (config.isServerEnable()) { + addServerInterceptor(config); + } + } + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } + + private void addClientInterceptor() { + GrpcClientPlugin grpcClientPlugin = new GrpcClientPlugin(transformTemplate); + grpcClientPlugin.addInterceptor(); + } + + private void addServerInterceptor(GrpcConfig config) { + GrpcServerPlugin grpcServerPlugin = new GrpcServerPlugin(transformTemplate, config); + grpcServerPlugin.addInterceptor(); + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcServerPlugin.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcServerPlugin.java new file mode 100644 index 000000000000..f9dd0afcd168 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/GrpcServerPlugin.java @@ -0,0 +1,175 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.Assert; + +import java.security.ProtectionDomain; +import java.util.List; + +/** + * @author Taejin Koo + */ +class GrpcServerPlugin { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TransformTemplate transformTemplate; + private final GrpcConfig grpcConfig; + + GrpcServerPlugin(TransformTemplate transformTemplate, GrpcConfig grpcConfig) { + this.transformTemplate = Assert.requireNonNull(transformTemplate, "transformTemplate must not be null"); + this.grpcConfig = Assert.requireNonNull(grpcConfig, "grpcConfig must not be null"); + } + + void addInterceptor() { + transformTemplate.transform("io.grpc.internal.ServerImpl$ServerTransportListenerImpl", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + InstrumentMethod streamCreatedMethod = target.getDeclaredMethod("streamCreated", + "io.grpc.internal.ServerStream", "java.lang.String", "io.grpc.Metadata"); + if (streamCreatedMethod != null) { + streamCreatedMethod.addInterceptor("com.navercorp.pinpoint.plugin.grpc.interceptor.server.ServerStreamCreatedInterceptor"); + } else { + if (isDebug) { + logger.debug("can't find streamCreated method"); + } + } + + return target.toBytecode(); + } + }); + + transformTemplate.transform("io.grpc.internal.AbstractServerStream", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + target.addField("com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor"); + + return target.toBytecode(); + } + }); + + transformTemplate.transform("io.grpc.ServerCall$Listener", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + target.addField("com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor"); + + return target.toBytecode(); + } + }); + + transformTemplate.transform("io.grpc.internal.ServerCallImpl", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + target.addGetter("com.navercorp.pinpoint.plugin.grpc.field.accessor.ServerStreamGetter", "stream"); + + return target.toBytecode(); + } + }); + + transformTemplate.transform("io.grpc.stub.ServerCalls$UnaryServerCallHandler", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + addStartCallMethodInterceptor(target); + + return target.toBytecode(); + } + }); + + + transformTemplate.transform("io.grpc.stub.ServerCalls$UnaryServerCallHandler$UnaryServerCallListener", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + addListenerMethod(target, true); + + return target.toBytecode(); + } + }); + + transformTemplate.transform("io.grpc.stub.ServerCalls$StreamingServerCallHandler", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + addStartCallMethodInterceptor(target); + + return target.toBytecode(); + } + }); + + + transformTemplate.transform("io.grpc.stub.ServerCalls$StreamingServerCallHandler$StreamingServerCallListener", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + addListenerMethod(target, grpcConfig.isServerStreamingOnMessageEnable()); + + return target.toBytecode(); + } + }); + + } + + private void addStartCallMethodInterceptor(InstrumentClass target) throws InstrumentException { + InstrumentMethod startCall = target.getDeclaredMethod("startCall", "io.grpc.ServerCall", "io.grpc.Metadata"); + if (startCall != null) { + startCall.addInterceptor("com.navercorp.pinpoint.plugin.grpc.interceptor.server.CopyAsyncContextInterceptor"); + } else { + if (isDebug) { + logger.debug("can't find startCall method"); + } + } + } + + private void addListenerMethod(InstrumentClass target, boolean traceOnMessage) throws InstrumentException { + List declaredMethods = target.getDeclaredMethods(); + for (InstrumentMethod declaredMethod : declaredMethods) { + if (declaredMethod.getName().equals("onMessage") && !traceOnMessage) { + if (isDebug) { + logger.debug("skip add onMessage interceptor"); + } + continue; + } + + declaredMethod.addInterceptor("com.navercorp.pinpoint.plugin.grpc.interceptor.server.ServerListenerInterceptor"); + } + + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/descriptor/GrpcServerCallMethodDescritpro.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/descriptor/GrpcServerCallMethodDescritpro.java new file mode 100644 index 000000000000..40edec41c4de --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/descriptor/GrpcServerCallMethodDescritpro.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.descriptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; + +/** + * @author Taejin Koo + */ +public class GrpcServerCallMethodDescritpro implements MethodDescriptor { + + private int apiId = 0; + private int type = MethodType.WEB_REQUEST; + + @Override + public String getMethodName() { + return ""; + } + + @Override + public String getClassName() { + return ""; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return "()"; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return GrpcServerCallMethodDescritpro.class.getName(); + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return apiId; + } + + @Override + public String getApiDescriptor() { + return "Grpc HTTP Server"; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} + diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/descriptor/GrpcStreamListenerResultMethodDescriptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/descriptor/GrpcStreamListenerResultMethodDescriptor.java new file mode 100644 index 000000000000..cdb565351357 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/descriptor/GrpcStreamListenerResultMethodDescriptor.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.descriptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; + +/** + * @author Taejin Koo + */ +public class GrpcStreamListenerResultMethodDescriptor implements MethodDescriptor { + + private int apiId = 0; + private int type = MethodType.DEFAULT; + + @Override + public String getMethodName() { + return ""; + } + + @Override + public String getClassName() { + return ""; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return "()"; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return GrpcStreamListenerResultMethodDescriptor.class.getName(); + } + + @Override + public int getApiId() { + return apiId; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public String getApiDescriptor() { + return "Grpc client listener Result Invocation"; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/field/accessor/MethodNameAccessor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/field/accessor/MethodNameAccessor.java new file mode 100644 index 000000000000..9ee7e8d5e7cc --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/field/accessor/MethodNameAccessor.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.field.accessor; + +/** + * @author Taejin Koo + */ +public interface MethodNameAccessor { + + void _$PINPOINT$_setMethodName(String methodName); + + String _$PINPOINT$_getMethodName(); + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/field/accessor/RemoteAddressAccessor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/field/accessor/RemoteAddressAccessor.java new file mode 100644 index 000000000000..04905ad746ad --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/field/accessor/RemoteAddressAccessor.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.field.accessor; + +/** + * @author Taejin Koo + */ +public interface RemoteAddressAccessor { + + void _$PINPOINT$_setRemoteAddress(String remoteAddress); + + String _$PINPOINT$_getRemoteAddress(); + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/field/accessor/ServerStreamGetter.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/field/accessor/ServerStreamGetter.java new file mode 100644 index 000000000000..63cbc5fd44d4 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/field/accessor/ServerStreamGetter.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.field.accessor; + +import io.grpc.internal.ServerStream; + +/** + * @author Taejin Koo + */ +public interface ServerStreamGetter { + + ServerStream _$PINPOINT$_getServerStream(); + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ChannelNewCallInterceptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ChannelNewCallInterceptor.java new file mode 100644 index 000000000000..e508ec795122 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ChannelNewCallInterceptor.java @@ -0,0 +1,104 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.client; + +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.plugin.grpc.field.accessor.MethodNameAccessor; +import com.navercorp.pinpoint.plugin.grpc.field.accessor.RemoteAddressAccessor; +import io.grpc.MethodDescriptor; + +/** + * @author Taejin Koo + */ +public class ChannelNewCallInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + if (ArrayUtils.isEmpty(args)) { + return; + } + + setMethodName(result, args[0]); + setRemoteAddress(result, target); + } + + private void setMethodName(Object result, Object methodDescriptor) { + if (!(result instanceof MethodNameAccessor)) { + if (isDebug) { + logger.debug("invalid result object. result:{}", result); + } + return; + } + + try { + if (methodDescriptor instanceof io.grpc.MethodDescriptor) { + String fullMethodName = ((MethodDescriptor) methodDescriptor).getFullMethodName(); + ((MethodNameAccessor) result)._$PINPOINT$_setMethodName((String) fullMethodName); + } else { + if (isDebug) { + logger.debug("invalid methodDescriptor. methodDescriptor:{}", methodDescriptor); + } + } + } catch (Exception e) { + if (isDebug) { + logger.debug("failed to invoke getFullMethodName method. caused:{}", e.getMessage(), e); + } + } + } + + private void setRemoteAddress(Object result, Object channel) { + if (!(result instanceof RemoteAddressAccessor)) { + if (isDebug) { + logger.debug("invalid result object. result:{}", result); + } + return; + } + + try { + if (channel instanceof io.grpc.Channel) { + String remoteAddress = ((io.grpc.Channel) channel).authority(); + ((RemoteAddressAccessor) result)._$PINPOINT$_setRemoteAddress((String) remoteAddress); + } else { + if (isDebug) { + logger.debug("invalid channel. channel:{}", channel); + } + } + } catch (Exception e) { + if (isDebug) { + logger.debug("failed to invoke authority method. caused:{}", e.getMessage(), e); + } + } + } + +} \ No newline at end of file diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ClientCallStartInterceptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ClientCallStartInterceptor.java new file mode 100644 index 000000000000..2afcd0299a67 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ClientCallStartInterceptor.java @@ -0,0 +1,153 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.client; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.plugin.grpc.GrpcConstants; +import com.navercorp.pinpoint.plugin.grpc.field.accessor.MethodNameAccessor; +import com.navercorp.pinpoint.plugin.grpc.field.accessor.RemoteAddressAccessor; +import io.grpc.Metadata; + +/** + * @author Taejin Koo + */ +public class ClientCallStartInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + private final RequestTraceWriter requestTraceWriter; + + public ClientCallStartInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + + GrpcClientHeaderAdaptor grpcClientHeaderAdaptor = new GrpcClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(grpcClientHeaderAdaptor, traceContext); + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if (ArrayUtils.getLength(args) != 2) { + return; + } + + if (!(args[1] instanceof Metadata)) { + return; + } + + Metadata metadata = (Metadata) args[1]; + if (!trace.canSampled()) { + requestTraceWriter.write(metadata); + return; + } + + SpanEventRecorder recorder = trace.traceBlockBegin(); + + recorder.recordApi(descriptor); + recorder.recordServiceType(GrpcConstants.SERVICE_TYPE); + + final TraceId nextId = trace.getTraceId().getNextTraceId(); + recorder.recordNextSpanId(nextId.getSpanId()); + + String remoteAddress = getEndPoint(target); + recorder.recordEndPoint(remoteAddress); + recorder.recordDestinationId(remoteAddress); + + String methodName = getMethodName(target); + recorder.recordAttribute(AnnotationKey.HTTP_URL, combineAddressAndMethodName(remoteAddress, methodName)); + + requestTraceWriter.write(metadata, nextId, remoteAddress); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args); + } + + Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + if (throwable != null) { + recorder.recordException(throwable); + } + } finally { + trace.traceBlockEnd(); + } + } + + + private String combineAddressAndMethodName(String remoteAddress, String methodName) { + Assert.requireNonNull(remoteAddress, "remoteAddress must not be null"); + Assert.requireNonNull(methodName, "methodName must not be null"); + + if (remoteAddress.startsWith("http")) { + return remoteAddress + "/" + methodName; + } else { + return "http://" + remoteAddress + "/" + methodName; + } + } + + private String getMethodName(Object target) { + if (target instanceof MethodNameAccessor) { + String methodName = ((MethodNameAccessor) target)._$PINPOINT$_getMethodName(); + if (methodName != null) { + return methodName; + } + } + return GrpcConstants.UNKNOWN_METHOD; + } + + public static String getEndPoint(Object target) { + if (target instanceof RemoteAddressAccessor) { + String remoteAddress = ((RemoteAddressAccessor) target)._$PINPOINT$_getRemoteAddress(); + if (remoteAddress != null) { + return remoteAddress; + } + } + return GrpcConstants.UNKNOWN_ADDRESS; + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/GrpcClientHeaderAdaptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/GrpcClientHeaderAdaptor.java new file mode 100644 index 000000000000..f2e14d033662 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/GrpcClientHeaderAdaptor.java @@ -0,0 +1,41 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.client; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import io.grpc.Metadata; + +/** + * @author Taejin Koo + */ +class GrpcClientHeaderAdaptor implements ClientHeaderAdaptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(Metadata header, String name, String value) { + final Metadata.Key key = Metadata.Key.of(name, Metadata.ASCII_STRING_MARSHALLER); + header.put(key, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ListenerClosedInterceptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ListenerClosedInterceptor.java new file mode 100644 index 000000000000..b3c08e1c7b05 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ListenerClosedInterceptor.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.grpc.interceptor.client; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AsyncContextSpanEventSimpleAroundInterceptor; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.plugin.grpc.GrpcConstants; + +/** + * @author jaehong.kim + */ +public class ListenerClosedInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor { + + public ListenerClosedInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + public void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(GrpcConstants.SERVICE_TYPE_INTERNAL); + + if (throwable != null) { + recorder.recordException(throwable); + } + + if (ArrayUtils.isEmpty(args)) { + return; + } + + if (args[0] instanceof io.grpc.Status) { + io.grpc.Status status = (io.grpc.Status) args[0]; + recorder.recordAttribute(GrpcConstants.CLIENT_STATUS_ANNOTATION, status.getCode().name()); + } + + } +} \ No newline at end of file diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ListenerConstructorInterceptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ListenerConstructorInterceptor.java new file mode 100644 index 000000000000..c5198380edc3 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/client/ListenerConstructorInterceptor.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.client; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.plugin.grpc.GrpcConstants; +import com.navercorp.pinpoint.plugin.grpc.descriptor.GrpcStreamListenerResultMethodDescriptor; + +/** + * @author Taejin Koo + */ +public class ListenerConstructorInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + private static final GrpcStreamListenerResultMethodDescriptor LISTENER_RESULT_DESCRIPTOR = new GrpcStreamListenerResultMethodDescriptor(); + + public ListenerConstructorInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + traceContext.cacheApi(LISTENER_RESULT_DESCRIPTOR); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + recorder.recordServiceType(GrpcConstants.SERVICE_TYPE_INTERNAL); + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + if (target instanceof AsyncContextAccessor) { + // set asynchronous trace + final AsyncContext asyncContext = recorder.recordNextAsyncContext(); + + ((AsyncContextAccessor) target)._$PINPOINT$_setAsyncContext(asyncContext); + if (isDebug) { + logger.debug("Set AsyncContext {}", asyncContext); + } + } + + recorder.recordApi(LISTENER_RESULT_DESCRIPTOR); + recorder.recordException(throwable); + } + +} + diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/CopyAsyncContextInterceptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/CopyAsyncContextInterceptor.java new file mode 100644 index 000000000000..29e6325491e8 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/CopyAsyncContextInterceptor.java @@ -0,0 +1,72 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.server; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.plugin.grpc.field.accessor.ServerStreamGetter; +import io.grpc.internal.ServerStream; + +/** + * @author Taejin Koo + */ +public class CopyAsyncContextInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(CopyAsyncContextInterceptor.class); + private final boolean isDebug = logger.isDebugEnabled(); + + public CopyAsyncContextInterceptor() { + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args); + } + + if (ArrayUtils.getLength(args) == 2) { + AsyncContext asyncContext = getAsyncContext(args[0]); + + if (result instanceof AsyncContextAccessor) { + logger.info("set AsyncContext:{}", asyncContext); + ((AsyncContextAccessor) result)._$PINPOINT$_setAsyncContext(asyncContext); + } + } + } + + AsyncContext getAsyncContext(Object object) { + if (object instanceof ServerStreamGetter) { + ServerStream serverStream = ((ServerStreamGetter) object)._$PINPOINT$_getServerStream(); + if (serverStream instanceof AsyncContextAccessor) { + return ((AsyncContextAccessor) serverStream)._$PINPOINT$_getAsyncContext(); + } + } + return null; + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/GrpcAsyncContextSpanEventEndPointInterceptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/GrpcAsyncContextSpanEventEndPointInterceptor.java new file mode 100644 index 000000000000..85fe353f5fd7 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/GrpcAsyncContextSpanEventEndPointInterceptor.java @@ -0,0 +1,134 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.server; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.AsyncState; +import com.navercorp.pinpoint.bootstrap.context.AsyncStateSupport; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.scope.TraceScope; +import com.navercorp.pinpoint.bootstrap.interceptor.AsyncContextSpanEventSimpleAroundInterceptor; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public abstract class GrpcAsyncContextSpanEventEndPointInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor { + + protected final TraceContext traceContext; + + public GrpcAsyncContextSpanEventEndPointInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + this.traceContext = Assert.requireNonNull(traceContext, "traceContext must not be null"); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final AsyncContext asyncContext = getAsyncContext(target); + if (asyncContext == null) { + logger.debug("Not found asynchronous invocation metadata"); + return; + } + if (isDebug) { + logger.debug("Asynchronous invocation. asyncContext={}", asyncContext); + } + + final Trace trace = asyncContext.currentAsyncTraceObject(); + if (trace == null) { + return; + } + if (isDebug) { + logger.debug("Asynchronous invocation. asyncTraceId={}, trace={}", asyncContext, trace); + } + + // leave scope. + if (!leaveAsyncTraceScope(trace)) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to leave scope of async trace {}.", trace); + } + // delete unstable trace. + deleteAsyncTrace(trace); + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + doInAfterTrace(recorder, target, args, result, throwable); + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER error. Caused:{}", th.getMessage(), th); + } + } finally { + trace.traceBlockEnd(); + if (isAsyncTraceDestination(trace)) { + if (isDebug) { + logger.debug("Arrived at async trace destination. asyncTraceId={}", asyncContext); + } + deleteAsyncTrace(trace); + } + finishAsyncState(asyncContext); + } + } + + private void deleteAsyncTrace(final Trace trace) { + if (isDebug) { + logger.debug("Delete async trace {}.", trace); + } + traceContext.removeTraceObject(); + trace.close(); + } + + private boolean leaveAsyncTraceScope(final Trace trace) { + final TraceScope scope = trace.getScope(ASYNC_TRACE_SCOPE); + if (scope != null) { + if (scope.canLeave()) { + scope.leave(); + } else { + return false; + } + } + return true; + } + + private boolean isAsyncTraceDestination(final Trace trace) { + if (!trace.isAsync()) { + return false; + } + + final TraceScope scope = trace.getScope(ASYNC_TRACE_SCOPE); + return scope != null && !scope.isActive(); + } + + private void finishAsyncState(final AsyncContext asyncContext) { + if (asyncContext instanceof AsyncStateSupport) { + final AsyncStateSupport asyncStateSupport = (AsyncStateSupport) asyncContext; + AsyncState asyncState = asyncStateSupport.getAsyncState(); + asyncState.finish(); + if (isDebug) { + logger.debug("finished asyncState. asyncTraceId={}", asyncContext); + } + } + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/GrpcServerStreamRequest.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/GrpcServerStreamRequest.java new file mode 100644 index 000000000000..100b7d225853 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/GrpcServerStreamRequest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.server; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.plugin.grpc.GrpcConstants; +import io.grpc.Attributes; +import io.grpc.Metadata; +import io.grpc.internal.ServerStream; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Iterator; +import java.util.Set; + +/** + * @author Taejin Koo + */ +public class GrpcServerStreamRequest { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final ServerStream serverStream; + private final String methodName; + private final Metadata metadata; + + static GrpcServerStreamRequest create(Object[] args) { + if (validate(args)) { + return new GrpcServerStreamRequest((ServerStream) args[0], (String) args[1], (Metadata) args[2]); + } + return null; + } + + static boolean validate(Object[] args) { + if (ArrayUtils.getLength(args) == 3) { + if (!(args[0] instanceof io.grpc.internal.ServerStream)) { + return false; + } + if (!(args[1] instanceof String)) { + return false; + } + if (!(args[2] instanceof io.grpc.Metadata)) { + return false; + } + return true; + } + return false; + } + + GrpcServerStreamRequest(ServerStream serverStream, String methodName, Metadata metadata) { + this.serverStream = Assert.requireNonNull(serverStream, "serverStream must not be null"); + this.methodName = Assert.requireNonNull(methodName, "methodName must not be null"); + this.metadata = Assert.requireNonNull(metadata, "metadata must not be null"); + } + + public ServerStream getServerStream() { + return serverStream; + } + + public String getMethodName() { + return methodName; + } + + public String getHeader(String name) { + final Metadata.Key key = Metadata.Key.of(name, Metadata.ASCII_STRING_MARSHALLER); + Iterable headerValues = metadata.removeAll(key); + + String headerValue = null; + if (headerValues != null) { + Iterator iterator = headerValues.iterator(); + if (iterator.hasNext()) { + headerValue = iterator.next(); + if (iterator.hasNext()) { + headerValue = null; + } + } + } + + return headerValue; + } + + String getRemoteAddress() { + Attributes attributes = serverStream.getAttributes(); + if (attributes == null) { + return null; + } + + try { + // keys method is being considered for removal, + Set> keys = attributes.keys(); + if (keys == null) { + if (isDebug) { + logger.debug("can't attributes keys"); + } + return null; + } + + for (Attributes.Key key : keys) { + if (key != null && key.toString().equals("remote-addr")) { + Object remoteAddress = attributes.get(key); + if (remoteAddress instanceof SocketAddress) { + return getSocketAddressAsString((SocketAddress) remoteAddress); + } else if (remoteAddress instanceof String) { + return (String) remoteAddress; + } + } + } + } catch (Exception e) { + if (isDebug) { + logger.debug("can't find keys method"); + } + } + + return GrpcConstants.UNKNOWN_ADDRESS; + } + + + public static String getSocketAddressAsString(SocketAddress socketAddress) { + if (socketAddress instanceof InetSocketAddress) { + final InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; + final InetAddress remoteAddress = inetSocketAddress.getAddress(); + if (remoteAddress != null) { + return HostAndPort.toHostAndPortString(remoteAddress.getHostAddress(), inetSocketAddress.getPort()); + } + } + + return GrpcConstants.UNKNOWN_ADDRESS; + } + + + String getServerAddress() { + return serverStream.getAuthority(); + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/GrpcServerStreamRequestAdaptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/GrpcServerStreamRequestAdaptor.java new file mode 100644 index 000000000000..7bd24d920b9e --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/GrpcServerStreamRequestAdaptor.java @@ -0,0 +1,57 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.server; + +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.common.util.StringUtils; + +/** + * @author Taejin Koo + */ +public class GrpcServerStreamRequestAdaptor implements RequestAdaptor { + + @Override + public String getHeader(GrpcServerStreamRequest request, String name) { + return request.getHeader(name); + } + + @Override + public String getRpcName(GrpcServerStreamRequest request) { + String methodName = request.getMethodName(); + if (StringUtils.hasText(methodName) && !methodName.startsWith("/")) { + return "/" + methodName; + } + + return methodName; + } + + @Override + public String getEndPoint(GrpcServerStreamRequest request) { + return request.getServerAddress(); + } + + @Override + public String getRemoteAddress(GrpcServerStreamRequest request) { + return request.getRemoteAddress(); + } + + @Override + public String getAcceptorHost(GrpcServerStreamRequest request) { + return request.getServerAddress(); + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/ServerListenerInterceptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/ServerListenerInterceptor.java new file mode 100644 index 000000000000..b7753cb244fc --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/ServerListenerInterceptor.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.server; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.grpc.GrpcConstants; + +/** + * @author Taejin Koo + */ +public class ServerListenerInterceptor extends GrpcAsyncContextSpanEventEndPointInterceptor { + + public ServerListenerInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected AsyncContext getAsyncContext(Object target) { + if (target instanceof AsyncContextAccessor) { + return ((AsyncContextAccessor) target)._$PINPOINT$_getAsyncContext(); + } + + logger.info("failed to get AsyncContext"); + return null; + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(GrpcConstants.SERVER_SERVICE_TYPE_INTERNAL); + } + +} diff --git a/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/ServerStreamCreatedInterceptor.java b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/ServerStreamCreatedInterceptor.java new file mode 100644 index 000000000000..fc89bf697229 --- /dev/null +++ b/plugins/grpc/src/main/java/com/navercorp/pinpoint/plugin/grpc/interceptor/server/ServerStreamCreatedInterceptor.java @@ -0,0 +1,146 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc.interceptor.server; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceReader; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServerRequestRecorder; +import com.navercorp.pinpoint.plugin.grpc.GrpcConstants; +import com.navercorp.pinpoint.plugin.grpc.descriptor.GrpcServerCallMethodDescritpro; + +/** + * @author Taejin Koo + */ +public class ServerStreamCreatedInterceptor implements AroundInterceptor { + + private static final GrpcServerCallMethodDescritpro GRPC_SERVER_CALL_METHOD_DESCRIPTOR = new GrpcServerCallMethodDescritpro(); + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + private final ServerRequestRecorder serverRequestRecorder; + private final RequestTraceReader requestTraceReader; + + public ServerStreamCreatedInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + + final RequestAdaptor requestAdaptor = new GrpcServerStreamRequestAdaptor(); + this.serverRequestRecorder = new ServerRequestRecorder(requestAdaptor); + this.requestTraceReader = new RequestTraceReader(traceContext, requestAdaptor, true); + + traceContext.cacheApi(GRPC_SERVER_CALL_METHOD_DESCRIPTOR); + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (traceContext.currentTraceObject() != null) { + return; + } + + GrpcServerStreamRequest request = GrpcServerStreamRequest.create(args); + if (request == null) { + return; + } + + final Trace trace = createTrace(request); + if (trace == null || !trace.canSampled()) { + return; + } + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(GrpcConstants.SERVER_SERVICE_TYPE_INTERNAL); + + final AsyncContext asyncContext = recorder.recordNextAsyncContext(true); + if (args[0] instanceof AsyncContextAccessor) { + ((AsyncContextAccessor) args[0])._$PINPOINT$_setAsyncContext(asyncContext); + logger.debug("Set closeable-AsyncContext {}", asyncContext); + } + } + + private Trace createTrace(final GrpcServerStreamRequest request) { + Trace trace = requestTraceReader.read(request); + if (trace.canSampled()) { + SpanRecorder spanRecorder = trace.getSpanRecorder(); + spanRecorder.recordServiceType(GrpcConstants.SERVER_SERVICE_TYPE); + spanRecorder.recordApi(GRPC_SERVER_CALL_METHOD_DESCRIPTOR); + + this.serverRequestRecorder.record(spanRecorder, request); + } + + return trace; + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentRawTraceObject(); + if (trace == null) { + return; + } + + if (!trace.canSampled()) { + deleteTrace(trace); + return; + } + + if (!GrpcServerStreamRequest.validate(args)) { + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(descriptor); + if (throwable != null) { + recorder.recordException(throwable); + } + } catch (Throwable t) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER. Caused:{}", t.getMessage(), t); + } + } finally { + trace.traceBlockEnd(); + deleteTrace(trace); + } + } + + private void deleteTrace(final Trace trace) { + traceContext.removeTraceObject(); + trace.close(); + } + +} diff --git a/plugins/grpc/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/grpc/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..8242f7d87ece --- /dev/null +++ b/plugins/grpc/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.grpc.GrpcPlugin \ No newline at end of file diff --git a/plugins/grpc/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/grpc/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..c380c2fa60e1 --- /dev/null +++ b/plugins/grpc/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.grpc.GrpcMetadataProvider \ No newline at end of file diff --git a/plugins/grpc/src/test/java/com/navercorp/pinpoint/plugin/grpc/GrpcConfigTest.java b/plugins/grpc/src/test/java/com/navercorp/pinpoint/plugin/grpc/GrpcConfigTest.java new file mode 100644 index 000000000000..f105e7e4e087 --- /dev/null +++ b/plugins/grpc/src/test/java/com/navercorp/pinpoint/plugin/grpc/GrpcConfigTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.grpc; + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Properties; + +/** + * @author Taejin Koo + */ +public class GrpcConfigTest { + + @Test + public void configTest1() throws Exception { + GrpcConfig config = createConfig("false", "false"); + + Assert.assertFalse(config.isClientEnable()); + Assert.assertFalse(config.isServerEnable()); + } + + @Test + public void configTest2() throws Exception { + GrpcConfig config = createConfig("false", "true"); + + Assert.assertFalse(config.isClientEnable()); + Assert.assertTrue(config.isServerEnable()); + } + + @Test + public void configTest3() throws Exception { + GrpcConfig config = createConfig("true", "false"); + + Assert.assertTrue(config.isClientEnable()); + Assert.assertFalse(config.isServerEnable()); + } + + @Test + public void configTest4() throws Exception { + GrpcConfig config = createConfig("true", "true"); + + Assert.assertTrue(config.isClientEnable()); + Assert.assertTrue(config.isServerEnable()); + } + + private GrpcConfig createConfig(String clientEnable, String serverEnable) { + Properties properties = new Properties(); + properties.put(GrpcConfig.CLIENT_ENABLE, clientEnable); + properties.put(GrpcConfig.SERVER_ENABLE, serverEnable); + + ProfilerConfig profilerConfig = new DefaultProfilerConfig(properties); + + return new GrpcConfig(profilerConfig); + } + +} diff --git a/plugins/gson/clover.license b/plugins/gson/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/gson/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-gson-plugin diff --git a/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/GsonConstants.java b/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/GsonConstants.java new file mode 100644 index 000000000000..3102f4135206 --- /dev/null +++ b/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/GsonConstants.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.gson; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class GsonConstants { + private GsonConstants() { + } + + public static final ServiceType GSON_SERVICE_TYPE = ServiceTypeFactory.of(5010, "GSON"); + public static final AnnotationKey GSON_ANNOTATION_KEY_JSON_LENGTH = AnnotationKeyFactory.of(9000, "gson.json.length"); +} diff --git a/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/GsonMetadataProvider.java b/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/GsonMetadataProvider.java index f38c443f438a..94fa2eccd656 100644 --- a/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/GsonMetadataProvider.java +++ b/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/GsonMetadataProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,7 +27,7 @@ public class GsonMetadataProvider implements TraceMetadataProvider { */ @Override public void setup(TraceMetadataSetupContext context) { - context.addServiceType(GsonPlugin.GSON_SERVICE_TYPE); - context.addAnnotationKey(GsonPlugin.GSON_ANNOTATION_KEY_JSON_LENGTH); + context.addServiceType(GsonConstants.GSON_SERVICE_TYPE); + context.addAnnotationKey(GsonConstants.GSON_ANNOTATION_KEY_JSON_LENGTH); } } diff --git a/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/interceptor/FromJsonInterceptor.java b/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/interceptor/FromJsonInterceptor.java index c8415c09e67b..baa926a6734c 100644 --- a/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/interceptor/FromJsonInterceptor.java +++ b/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/interceptor/FromJsonInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -22,7 +22,8 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor2; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.gson.GsonPlugin; +import com.navercorp.pinpoint.plugin.gson.GsonConstants; + /** * Gson method interceptor @@ -66,12 +67,12 @@ public void after(Object target, Object arg0, Object arg1, Object result, Throwa try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordServiceType(GsonPlugin.GSON_SERVICE_TYPE); + recorder.recordServiceType(GsonConstants.GSON_SERVICE_TYPE); recorder.recordApi(descriptor); recorder.recordException(throwable); if (arg0 != null && arg0 instanceof String) { - recorder.recordAttribute(GsonPlugin.GSON_ANNOTATION_KEY_JSON_LENGTH, ((String) arg0).length()); + recorder.recordAttribute(GsonConstants.GSON_ANNOTATION_KEY_JSON_LENGTH, ((String) arg0).length()); } } finally { trace.traceBlockEnd(); diff --git a/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/interceptor/ToJsonInterceptor.java b/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/interceptor/ToJsonInterceptor.java index 23302ab33282..41d081d366c1 100644 --- a/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/interceptor/ToJsonInterceptor.java +++ b/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/interceptor/ToJsonInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -22,7 +22,8 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor0; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.gson.GsonPlugin; +import com.navercorp.pinpoint.plugin.gson.GsonConstants; + /** * Gson method interceptor @@ -66,12 +67,12 @@ public void after(Object target, Object result, Throwable throwable) { try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordServiceType(GsonPlugin.GSON_SERVICE_TYPE); + recorder.recordServiceType(GsonConstants.GSON_SERVICE_TYPE); recorder.recordApi(descriptor); recorder.recordException(throwable); if (result != null && result instanceof String) { - recorder.recordAttribute(GsonPlugin.GSON_ANNOTATION_KEY_JSON_LENGTH, ((String) result).length()); + recorder.recordAttribute(GsonConstants.GSON_ANNOTATION_KEY_JSON_LENGTH, ((String) result).length()); } } finally { trace.traceBlockEnd(); diff --git a/plugins/hbase/.gitignore b/plugins/hbase/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/hbase/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/hbase/pom.xml b/plugins/hbase/pom.xml new file mode 100644 index 000000000000..db1e83651b21 --- /dev/null +++ b/plugins/hbase/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-hbase-plugin + pinpoint-hbase-plugin + jar + + + 1.6 + ${env.JAVA_7_HOME} + java17 + + + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + org.apache.hbase + hbase-shaded-client + provided + + + + diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePlugin.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePlugin.java new file mode 100644 index 000000000000..0804c484cb96 --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePlugin.java @@ -0,0 +1,155 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.instrument.*; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExecutionPolicy; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; + +import java.security.ProtectionDomain; + +import static com.navercorp.pinpoint.common.util.VarArgs.va; + +/** + * The type Hbase plugin. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018/10/12 + */ +public class HbasePlugin implements ProfilerPlugin, TransformTemplateAware { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private TransformTemplate transformTemplate; + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } + + @Override + public void setup(ProfilerPluginSetupContext context) { + + HbasePluginConfig config = new HbasePluginConfig(context.getConfig()); + + if (!config.isClientProfile()) { + logger.info("Disable HbasePlugin. config={}", config); + return; + } + if (config.isAdminProfile()) { + addHbaseAdminTransformer(config.isParamsProfile()); + } + if (config.isTableProfile()) { + addHbaseTableTransformer(config.isParamsProfile()); + } + addHbaseClientTransformer(); + } + + private void addHbaseClientTransformer() { + + transformTemplate.transform("org.apache.hadoop.hbase.client.AsyncProcess", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("submit", "submitAll"))) { + + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.hbase.interceptor.HbaseClientMainInterceptor", HbasePluginConstants.HBASE_CLIENT_SCOPE); + } + return target.toBytecode(); + } + }); + + transformTemplate.transform("org.apache.hadoop.hbase.client.AsyncProcess$AsyncRequestFutureImpl$SingleServerRequestRunnable", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + target.addField(AsyncContextAccessor.class.getName()); + + InstrumentMethod constructor = target.getConstructor("org.apache.hadoop.hbase.client.AsyncProcess$AsyncRequestFutureImpl", "org.apache.hadoop.hbase.client.MultiAction", "int", "org.apache.hadoop.hbase.ServerName", "java.util.Set"); + + constructor.addScopedInterceptor("com.navercorp.pinpoint.plugin.hbase.interceptor.HbaseClientConstructorInterceptor", HbasePluginConstants.HBASE_CLIENT_SCOPE, ExecutionPolicy.INTERNAL); + + InstrumentMethod method = target.getDeclaredMethod("run"); + + method.addInterceptor("com.navercorp.pinpoint.plugin.hbase.interceptor.HbaseClientRunInterceptor"); + + return target.toBytecode(); + } + }); + + TransformCallback transformCallback = new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("call"))) { + + method.addInterceptor("com.navercorp.pinpoint.plugin.hbase.interceptor.HbaseClientMethodInterceptor"); + } + return target.toBytecode(); + } + }; + + transformTemplate.transform("org.apache.hadoop.hbase.ipc.RpcClientImpl", transformCallback); + transformTemplate.transform("org.apache.hadoop.hbase.ipc.AsyncRpcClient", transformCallback); + } + + private void addHbaseAdminTransformer(final boolean paramsProfile) { + + transformTemplate.transform("org.apache.hadoop.hbase.client.HBaseAdmin", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(HbasePluginConstants.adminMethodNames))) { + + method.addInterceptor("com.navercorp.pinpoint.plugin.hbase.interceptor.HbaseAdminMethodInterceptor", va(paramsProfile)); + } + return target.toBytecode(); + } + }); + } + + private void addHbaseTableTransformer(final boolean paramsProfile) { + + transformTemplate.transform("org.apache.hadoop.hbase.client.HTable", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + + InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(HbasePluginConstants.tableMethodNames))) { + + method.addInterceptor("com.navercorp.pinpoint.plugin.hbase.interceptor.HbaseTableMethodInterceptor", va(paramsProfile)); + } + return target.toBytecode(); + } + }); + } +} diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConfig.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConfig.java new file mode 100644 index 000000000000..03a56e96c056 --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConfig.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +/** + * The type Hbase plugin config. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018 /10/12 + */ +public class HbasePluginConfig { + + private final boolean clientProfile; + private final boolean adminProfile; + private final boolean tableProfile; + private final boolean paramsProfile; + + /** + * Instantiates a new Hbase plugin config. + * + * @param config the config + */ + public HbasePluginConfig(ProfilerConfig config) { + this.clientProfile = config.readBoolean(HbasePluginConstants.HBASE_CLIENT_CONFIG, true); + this.adminProfile = config.readBoolean(HbasePluginConstants.HBASE_CLIENT_ADMIN_CONFIG, true); + this.tableProfile = config.readBoolean(HbasePluginConstants.HBASE_CLIENT_TABLE_CONFIG, true); + this.paramsProfile = config.readBoolean(HbasePluginConstants.HBASE_CLIENT_PARAMS_CONFIG, false); + } + + /** + * Is client profile boolean. + * + * @return the boolean + */ + public boolean isClientProfile() { + return clientProfile; + } + + /** + * Is admin profile boolean. + * + * @return the boolean + */ + public boolean isAdminProfile() { + return adminProfile; + } + + /** + * Is table profile boolean. + * + * @return the boolean + */ + public boolean isTableProfile() { + return tableProfile; + } + + /** + * Is params profile boolean. + * + * @return the boolean + */ + public boolean isParamsProfile() { + return paramsProfile; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("HbasePluginConfig [clientProfile="); + builder.append(clientProfile); + builder.append(", adminProfile="); + builder.append(adminProfile); + builder.append(", tableProfile="); + builder.append(tableProfile); + builder.append(", paramsProfile="); + builder.append(paramsProfile); + builder.append("]"); + return builder.toString(); + } +} diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConstants.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConstants.java new file mode 100644 index 000000000000..6c94e1f68114 --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConstants.java @@ -0,0 +1,103 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.TERMINAL; + +/** + * The type Hbase plugin constants. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018/10/12 + */ +public final class HbasePluginConstants { + + private HbasePluginConstants() { + } + + /** + * The constant HBASE_CLIENT. + */ + public static final ServiceType HBASE_CLIENT = ServiceTypeFactory.of(8800, "HBASE_CLIENT", TERMINAL, RECORD_STATISTICS); + + /** + * The constant HBASE_CLIENT_ADMIN. + */ + public static final ServiceType HBASE_CLIENT_ADMIN = ServiceTypeFactory.of(8801, "HBASE_CLIENT_ADMIN"); + + /** + * The constant HBASE_CLIENT_TABLE. + */ + public static final ServiceType HBASE_CLIENT_TABLE = ServiceTypeFactory.of(8802, "HBASE_CLIENT_TABLE"); + + /** + * The constant HBASE_ASYNC_CLIENT. + */ + public static final ServiceType HBASE_ASYNC_CLIENT = ServiceTypeFactory.of(8803, "HBASE_ASYNC_CLIENT"); + + /** + * The constant HBASE_CLIENT_PARAMS. + */ + public static final AnnotationKey HBASE_CLIENT_PARAMS = AnnotationKeyFactory.of(320, "hbase.client.params", VIEW_IN_RECORD_SET); + + /** + * The constant HBASE_DESTINATION_ID. + */ + public static final String HBASE_DESTINATION_ID = "HBASE"; + + /** + * The constant HBASE_CLIENT_SCOPE. + */ + public static final String HBASE_CLIENT_SCOPE = "HBASE_CLIENT_SCOPE"; + + /** + * The constant HBASE_CLIENT_CONFIG. + */ + public static final String HBASE_CLIENT_CONFIG = "profiler.hbase.client.enable"; + + /** + * The constant HBASE_CLIENT_ADMIN_CONFIG. + */ + public static final String HBASE_CLIENT_ADMIN_CONFIG = "profiler.hbase.client.admin.enable"; + + /** + * The constant HBASE_CLIENT_TABLE_CONFIG. + */ + public static final String HBASE_CLIENT_TABLE_CONFIG = "profiler.hbase.client.table.enable"; + + /** + * The constant HBASE_CLIENT_PARAMS_CONFIG. + */ + public static final String HBASE_CLIENT_PARAMS_CONFIG = "profiler.hbase.client.params.enable"; + + /** + * The constant tableMethodNames. + */ + public static final String[] tableMethodNames = new String[]{"append", "increment", "exists", "existsAll", "get", "getScanner", "put", "checkAndPut", "delete", "checkAndDelete", "mutateRow", "checkAndMutate"}; + + /** + * The constant adminMethodNames. + */ + public static final String[] adminMethodNames = new String[]{"tableExists", "listTables", "listTableNames", "getTableDescriptor", "createTable", "deleteTable", "modifyTable", "truncateTable", "enableTable", "enableTableAsync", "enableTables", "disableTableAsync", "disableTable", "disableTables", "getAlterStatus", "addColumn", "deleteColumn", "modifyColumn", "compact", "majorCompact", "split", "getTableRegions", "snapshot", "restoreSnapshot", "cloneSnapshot", "listSnapshots", "deleteSnapshot"}; + +} diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginMetadataProvider.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginMetadataProvider.java new file mode 100644 index 000000000000..633c4e566c20 --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginMetadataProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * The type Hbase plugin metadata provider. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018/10/12 + */ +public class HbasePluginMetadataProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(HbasePluginConstants.HBASE_CLIENT); + context.addServiceType(HbasePluginConstants.HBASE_CLIENT_ADMIN); + context.addServiceType(HbasePluginConstants.HBASE_CLIENT_TABLE); + context.addServiceType(HbasePluginConstants.HBASE_ASYNC_CLIENT); + context.addAnnotationKey(HbasePluginConstants.HBASE_CLIENT_PARAMS); + } +} diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseAdminMethodInterceptor.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseAdminMethodInterceptor.java new file mode 100644 index 000000000000..d98fd45b2df3 --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseAdminMethodInterceptor.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; + +import java.util.Arrays; + +/** + * The type Hbase admin method interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018/10/12 + */ +public class HbaseAdminMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + private final boolean paramsProfile; + + /** + * Instantiates a new Hbase admin method interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + * @param paramsProfile + */ + public HbaseAdminMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor, boolean paramsProfile) { + super(traceContext, descriptor); + this.paramsProfile = paramsProfile; + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + recorder.recordServiceType(HbasePluginConstants.HBASE_CLIENT_ADMIN); + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + if (paramsProfile) { + String attributes = parseAttributes(args); + if (attributes != null) + recorder.recordAttribute(HbasePluginConstants.HBASE_CLIENT_PARAMS, attributes); + } + recorder.recordApi(getMethodDescriptor()); + recorder.recordException(throwable); + } + + /** + * Parse attributes string. + * + * @param args the args + * @return the string + */ + protected String parseAttributes(Object[] args) { + + if (args != null && args.length > 0) { // if has params, print all params. + + return Arrays.asList(args).toString(); + } + return null; + } + +} diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientConstructorInterceptor.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientConstructorInterceptor.java new file mode 100644 index 000000000000..7ddf253208ad --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientConstructorInterceptor.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.annotation.IgnoreMethod; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; + +/** + * The type Hbase client constructor interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018/10/18 + */ +public class HbaseClientConstructorInterceptor implements AroundInterceptor { + private final InterceptorScope scope; + + /** + * Instantiates a new Hbase client constructor interceptor. + * + * @param scope the scope + */ + public HbaseClientConstructorInterceptor(InterceptorScope scope) { + this.scope = scope; + } + + @IgnoreMethod + @Override + public void before(Object target, Object[] args) { + + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + AsyncContext asyncContext = (AsyncContext) scope.getCurrentInvocation().getAttachment(); + ((AsyncContextAccessor) target)._$PINPOINT$_setAsyncContext(asyncContext); + } +} diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMainInterceptor.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMainInterceptor.java new file mode 100644 index 000000000000..10534a430bf9 --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMainInterceptor.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; + +/** + * The type Hbase client main interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018/10/18 + */ +public class HbaseClientMainInterceptor implements AroundInterceptor { + private final MethodDescriptor descriptor; + private final TraceContext traceContext; + private final InterceptorScope scope; + + /** + * Instantiates a new Hbase client main interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + * @param scope the scope + */ + public HbaseClientMainInterceptor(TraceContext traceContext, MethodDescriptor descriptor, InterceptorScope scope) { + this.traceContext = traceContext; + this.descriptor = descriptor; + this.scope = scope; + } + + @Override + public void before(Object target, Object[] args) { + Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(HbasePluginConstants.HBASE_ASYNC_CLIENT); + recorder.recordApi(descriptor, args); + + // To trace async invocations, you have to create AsyncContext like below, automatically attaching it to the current span event. + AsyncContext asyncContext = recorder.recordNextAsyncContext(); + + // Finally, you have to pass the AsyncContext to the thread which handles the async task. + // How to do this depends on the target library implementation. + scope.getCurrentInvocation().setAttachment(asyncContext); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + if (throwable != null) { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordException(throwable); + } + } finally { + trace.traceBlockEnd(); + } + } +} diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMethodInterceptor.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMethodInterceptor.java new file mode 100644 index 000000000000..fd40bc171925 --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMethodInterceptor.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.util.SocketAddressUtils; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; + +import java.net.InetSocketAddress; + +/** + * The type Hbase client method interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018/10/12 + */ +public class HbaseClientMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + /** + * Instantiates a new Hbase client method interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + */ + public HbaseClientMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + recorder.recordServiceType(HbasePluginConstants.HBASE_CLIENT); + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + String endPoint = getEndPoint(args); + recorder.recordEndPoint(endPoint != null ? endPoint : "Unknown"); + recorder.recordDestinationId(HbasePluginConstants.HBASE_DESTINATION_ID); + recorder.recordApi(getMethodDescriptor()); + recorder.recordException(throwable); + } + + /** + * Gets end point. + * + * @param args the args + * @return the end point + */ + protected String getEndPoint(Object[] args) { + // call(PayloadCarryingRpcController pcrc, MethodDescriptor md, + // Message param, Message returnType, User ticket, InetSocketAddress addr, + // MetricsConnection.CallStats callStats) + if (args != null && args.length == 7) { + + if (args[5] instanceof InetSocketAddress) { + + return SocketAddressUtils.getHostNameFirst((InetSocketAddress) args[5]); + } + } + return null; + } + +} diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientRunInterceptor.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientRunInterceptor.java new file mode 100644 index 000000000000..8a0cba148286 --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientRunInterceptor.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AsyncContextSpanEventSimpleAroundInterceptor; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; + +/** + * The type Hbase client run interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018/10/18 + */ +public class HbaseClientRunInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor { + + /** + * Instantiates a new Hbase client run interceptor. + * + * @param traceContext the trace context + * @param methodDescriptor the method descriptor + */ + public HbaseClientRunInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + // do nothing + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordServiceType(HbasePluginConstants.HBASE_ASYNC_CLIENT); + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + } +} diff --git a/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseTableMethodInterceptor.java b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseTableMethodInterceptor.java new file mode 100644 index 000000000000..94832444e438 --- /dev/null +++ b/plugins/hbase/src/main/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseTableMethodInterceptor.java @@ -0,0 +1,108 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.Mutation; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.util.Bytes; + +import java.util.List; + +/** + * The type Hbase table method interceptor. + * + * @author Victor.Zxy + * @version 1.8.1 + * @since 2018/10/12 + */ +public class HbaseTableMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + private boolean paramsProfile; + + /** + * Instantiates a new Hbase table method interceptor. + * + * @param traceContext the trace context + * @param descriptor the descriptor + * @param paramsProfile + */ + public HbaseTableMethodInterceptor(TraceContext traceContext, MethodDescriptor descriptor, boolean paramsProfile) { + super(traceContext, descriptor); + this.paramsProfile = paramsProfile; + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + recorder.recordServiceType(HbasePluginConstants.HBASE_CLIENT_TABLE); + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + if (paramsProfile) { + String attributes = parseAttributes(args); + if (attributes != null) + recorder.recordAttribute(HbasePluginConstants.HBASE_CLIENT_PARAMS, attributes); + } + recorder.recordApi(getMethodDescriptor()); + recorder.recordException(throwable); + } + + /** + * Parse attributes string. + * + * @param args the args + * @return the string + */ + protected String parseAttributes(Object[] args) { + + Object param = null; + + if (args != null && args.length == 1) { // only one + param = args[0]; + } else if (args != null && args.length > 1) { // last param + param = args[args.length - 1]; + } else { + return null; + } + + // Put/Delete/Append/Increment + if (param instanceof Mutation) { + Mutation mutation = (Mutation) param; + return "rowKey: " + Bytes.toStringBinary(mutation.getRow()); + } + if (param instanceof Get) { + Get get = (Get) param; + return "rowKey: " + Bytes.toStringBinary(get.getRow()); + } + if (param instanceof Scan) { + Scan scan = (Scan) param; + String startRowKey = Bytes.toStringBinary(scan.getStartRow()); + String stopRowKey = Bytes.toStringBinary(scan.getStopRow()); + return "startRowKey: " + startRowKey + " stopRowKey: " + stopRowKey; + } + // if param instanceof List. + if (param instanceof List) { + List list = (List) param; + return "size: " + list.size(); + } + return null; + } +} diff --git a/plugins/hbase/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/hbase/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..5bb7f349cdae --- /dev/null +++ b/plugins/hbase/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.hbase.HbasePlugin \ No newline at end of file diff --git a/plugins/hbase/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/hbase/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..4f1b8c060966 --- /dev/null +++ b/plugins/hbase/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.hbase.HbasePluginMetadataProvider \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConfigTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConfigTest.java new file mode 100644 index 000000000000..ae06c7452d79 --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConfigTest.java @@ -0,0 +1,43 @@ +package com.navercorp.pinpoint.plugin.hbase; + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class HbasePluginConfigTest { + + @Test + public void isClientProfile() { + ProfilerConfig profilerConfig = new DefaultProfilerConfig(); + HbasePluginConfig config = new HbasePluginConfig(profilerConfig); + assertTrue(config.isClientProfile()); + System.out.println(config); + } + + @Test + public void isAdminProfile() { + ProfilerConfig profilerConfig = new DefaultProfilerConfig(); + HbasePluginConfig config = new HbasePluginConfig(profilerConfig); + assertTrue(config.isAdminProfile()); + System.out.println(config); + } + + @Test + public void isTableProfile() { + ProfilerConfig profilerConfig = new DefaultProfilerConfig(); + HbasePluginConfig config = new HbasePluginConfig(profilerConfig); + assertTrue(config.isTableProfile()); + System.out.println(config); + } + + @Test + public void isParamsProfile() { + ProfilerConfig profilerConfig = new DefaultProfilerConfig(); + HbasePluginConfig config = new HbasePluginConfig(profilerConfig); + assertFalse(config.isParamsProfile()); + System.out.println(config); + } +} \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConstantsTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConstantsTest.java new file mode 100644 index 000000000000..76ece1abd6f7 --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginConstantsTest.java @@ -0,0 +1,23 @@ +package com.navercorp.pinpoint.plugin.hbase; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class HbasePluginConstantsTest { + + @Test + public void test() { + assertEquals(HbasePluginConstants.HBASE_CLIENT.getCode(), 8800); + assertEquals(HbasePluginConstants.HBASE_CLIENT_ADMIN.getCode(), 8801); + assertEquals(HbasePluginConstants.HBASE_CLIENT_TABLE.getCode(), 8802); + assertEquals(HbasePluginConstants.HBASE_ASYNC_CLIENT.getCode(), 8803); + assertEquals(HbasePluginConstants.HBASE_CLIENT_PARAMS.getCode(), 320); + assertEquals(HbasePluginConstants.HBASE_CLIENT_SCOPE, "HBASE_CLIENT_SCOPE"); + assertEquals(HbasePluginConstants.HBASE_DESTINATION_ID, "HBASE"); + assertEquals(HbasePluginConstants.HBASE_CLIENT_CONFIG, "profiler.hbase.client.enable"); + assertEquals(HbasePluginConstants.HBASE_CLIENT_ADMIN_CONFIG, "profiler.hbase.client.admin.enable"); + assertEquals(HbasePluginConstants.HBASE_CLIENT_TABLE_CONFIG, "profiler.hbase.client.table.enable"); + assertEquals(HbasePluginConstants.HBASE_CLIENT_PARAMS_CONFIG, "profiler.hbase.client.params.enable"); + } +} \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginMetadataProviderTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginMetadataProviderTest.java new file mode 100644 index 000000000000..9e0a3bf88bbf --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginMetadataProviderTest.java @@ -0,0 +1,29 @@ +package com.navercorp.pinpoint.plugin.hbase; + +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class HbasePluginMetadataProviderTest { + + @Mock + private TraceMetadataSetupContext context; + + @Test + public void setup() { + + HbasePluginMetadataProvider provider = new HbasePluginMetadataProvider(); + provider.setup(context); + + verify(context).addServiceType(HbasePluginConstants.HBASE_CLIENT); + verify(context).addServiceType(HbasePluginConstants.HBASE_CLIENT_ADMIN); + verify(context).addServiceType(HbasePluginConstants.HBASE_CLIENT_TABLE); + verify(context).addServiceType(HbasePluginConstants.HBASE_ASYNC_CLIENT); + verify(context).addAnnotationKey(HbasePluginConstants.HBASE_CLIENT_PARAMS); + } +} \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginTest.java new file mode 100644 index 000000000000..6952d7757deb --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/HbasePluginTest.java @@ -0,0 +1,29 @@ +package com.navercorp.pinpoint.plugin.hbase; + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; + +@RunWith(MockitoJUnitRunner.class) +public class HbasePluginTest { + + @Mock + private ProfilerPluginSetupContext context; + + @Mock + private TransformTemplate transformTemplate; + + @Test + public void setup() { + doReturn(new DefaultProfilerConfig()).when(context).getConfig(); + HbasePlugin plugin = new HbasePlugin(); + plugin.setTransformTemplate(transformTemplate); + plugin.setup(context); + } +} \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseAdminMethodInterceptorTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseAdminMethodInterceptorTest.java new file mode 100644 index 000000000000..2f29e9a84b09 --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseAdminMethodInterceptorTest.java @@ -0,0 +1,49 @@ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class HbaseAdminMethodInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void doInBeforeTrace() { + + Object target = new Object(); + Object[] args = new Object[]{}; + + HbaseAdminMethodInterceptor interceptor = new HbaseAdminMethodInterceptor(traceContext, descriptor, true); + interceptor.doInBeforeTrace(recorder, target, args); + verify(recorder).recordServiceType(HbasePluginConstants.HBASE_CLIENT_ADMIN); + } + + @Test + public void doInAfterTrace() { + + Object target = new Object(); + Object[] args = new Object[]{"test"}; + + HbaseAdminMethodInterceptor interceptor = new HbaseAdminMethodInterceptor(traceContext, descriptor, true); + interceptor.doInAfterTrace(recorder, target, args, null, null); + verify(recorder).recordAttribute(HbasePluginConstants.HBASE_CLIENT_PARAMS, "[test]"); + verify(recorder).recordApi(descriptor); + verify(recorder).recordException(null); + } +} \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientConstructorInterceptorTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientConstructorInterceptorTest.java new file mode 100644 index 000000000000..28008dc51b4c --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientConstructorInterceptorTest.java @@ -0,0 +1,40 @@ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.AttachmentFactory; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExecutionPolicy; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; + +@RunWith(MockitoJUnitRunner.class) +public class HbaseClientConstructorInterceptorTest { + + @Mock + private AsyncContext context; + + @Mock + private InterceptorScope scope; + + @Mock + private AsyncContextAccessor target; + + @Mock + private InterceptorScopeInvocation invocation; + + @Test + public void after() { + doReturn(invocation).when(scope).getCurrentInvocation(); + doReturn(context).when(invocation).getAttachment(); + + HbaseClientConstructorInterceptor interceptor = new HbaseClientConstructorInterceptor(scope); + interceptor.after(target, null, null, null); + } +} \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMainInterceptorTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMainInterceptorTest.java new file mode 100644 index 000000000000..7fb6e704cd86 --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMainInterceptorTest.java @@ -0,0 +1,69 @@ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class HbaseClientMainInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanEventRecorder recorder; + + @Mock + private InterceptorScope scope; + + @Mock + private AsyncContext asyncContext; + + @Mock + private InterceptorScopeInvocation invocation; + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(recorder).when(trace).traceBlockBegin(); + doReturn(asyncContext).when(recorder).recordNextAsyncContext(); + doReturn(invocation).when(scope).getCurrentInvocation(); + + Object target = new Object(); + Object[] args = new Object[]{"foo", "bar"}; + + HbaseClientMainInterceptor interceptor = new HbaseClientMainInterceptor(traceContext, descriptor, scope); + interceptor.before(target, args); + + verify(recorder).recordServiceType(HbasePluginConstants.HBASE_ASYNC_CLIENT); + verify(recorder).recordApi(descriptor, args); + + } + + @Test + public void after() { + + doReturn(trace).when(traceContext).currentTraceObject(); + + Object target = new Object(); + Object[] args = new Object[]{"foo", "bar"}; + + HbaseClientMainInterceptor interceptor = new HbaseClientMainInterceptor(traceContext, descriptor, scope); + interceptor.after(target, args,null,null); + } +} \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMethodInterceptorTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMethodInterceptorTest.java new file mode 100644 index 000000000000..20999a7ab1aa --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientMethodInterceptorTest.java @@ -0,0 +1,53 @@ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.net.InetSocketAddress; + +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class HbaseClientMethodInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void doInBeforeTrace() { + + Object target = new Object(); + Object[] args = new Object[]{}; + + HbaseClientMethodInterceptor interceptor = new HbaseClientMethodInterceptor(traceContext, descriptor); + interceptor.doInBeforeTrace(recorder, target, args); + verify(recorder).recordServiceType(HbasePluginConstants.HBASE_CLIENT); + } + + @Test + public void doInAfterTrace() { + + Object target = new Object(); + Object[] args = new Object[]{null, null, null, null, null, InetSocketAddress.createUnresolved("localhost", 1234), null}; + + HbaseClientMethodInterceptor interceptor = new HbaseClientMethodInterceptor(traceContext, descriptor); + interceptor.doInAfterTrace(recorder, target, args, null, null); + verify(recorder).recordEndPoint("localhost"); + verify(recorder).recordDestinationId("HBASE"); + verify(recorder).recordApi(descriptor); + verify(recorder).recordException(null); + } + +} \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientRunInterceptorTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientRunInterceptorTest.java new file mode 100644 index 000000000000..acf2bd5c8d2c --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseClientRunInterceptorTest.java @@ -0,0 +1,39 @@ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class HbaseClientRunInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void doInAfterTrace() { + + Object target = new Object(); + Object[] args = new Object[]{"foo", "bar"}; + + HbaseClientRunInterceptor interceptor = new HbaseClientRunInterceptor(traceContext, descriptor); + interceptor.doInAfterTrace(recorder, target, args, null, null); + + verify(recorder).recordServiceType(HbasePluginConstants.HBASE_ASYNC_CLIENT); + verify(recorder).recordApi(descriptor); + verify(recorder).recordException(null); + } +} \ No newline at end of file diff --git a/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseTableMethodInterceptorTest.java b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseTableMethodInterceptorTest.java new file mode 100644 index 000000000000..9a425161a0e8 --- /dev/null +++ b/plugins/hbase/src/test/java/com/navercorp/pinpoint/plugin/hbase/interceptor/HbaseTableMethodInterceptorTest.java @@ -0,0 +1,51 @@ +package com.navercorp.pinpoint.plugin.hbase.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.hbase.HbasePluginConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Collections; + +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class HbaseTableMethodInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private SpanEventRecorder recorder; + + @Test + public void doInBeforeTrace() { + + Object target = new Object(); + Object[] args = new Object[]{}; + + HbaseTableMethodInterceptor interceptor = new HbaseTableMethodInterceptor(traceContext, descriptor,true); + interceptor.doInBeforeTrace(recorder, target, args); + verify(recorder).recordServiceType(HbasePluginConstants.HBASE_CLIENT_TABLE); + } + + @Test + public void doInAfterTrace() { + + Object target = new Object(); + Object[] args = new Object[]{Collections.singletonList("test")}; + + HbaseTableMethodInterceptor interceptor = new HbaseTableMethodInterceptor(traceContext, descriptor, true); + interceptor.doInAfterTrace(recorder, target, args, null, null); + verify(recorder).recordAttribute(HbasePluginConstants.HBASE_CLIENT_PARAMS, "size: 1"); + verify(recorder).recordApi(descriptor); + verify(recorder).recordException(null); + } +} \ No newline at end of file diff --git a/plugins/hikaricp/clover.license b/plugins/hikaricp/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/hikaricp/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-hikaricp-plugin diff --git a/plugins/hikaricp/src/main/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpConstants.java b/plugins/hikaricp/src/main/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpConstants.java index 5464edf7a41d..415ff8a7316b 100644 --- a/plugins/hikaricp/src/main/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpConstants.java +++ b/plugins/hikaricp/src/main/java/com/navercorp/pinpoint/plugin/hikaricp/HikariCpConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -23,6 +23,8 @@ * @author Taejin Koo */ public final class HikariCpConstants { + private HikariCpConstants() { + } public static final String SCOPE = "HIKARICP_SCOPE"; public static final String SCOPE_DEPRECATED = "DEPRECATED_HIKARICP_SCOPE"; diff --git a/plugins/httpclient3/clover.license b/plugins/httpclient3/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/httpclient3/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-httpclient3-plugin pinpoint-httpclient3-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3CookieExtractor.java b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3CookieExtractor.java new file mode 100644 index 000000000000..3bbcf9f9b973 --- /dev/null +++ b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3CookieExtractor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.httpclient3; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.common.util.StringUtils; +import org.apache.commons.httpclient.HttpMethod; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpClient3CookieExtractor implements CookieExtractor { + + public static final CookieExtractor INSTANCE = new HttpClient3CookieExtractor(); + + @Override + public String getCookie(HttpMethod httpMethod) { + final org.apache.commons.httpclient.Header cookie = httpMethod.getRequestHeader("Cookie"); + if (cookie != null) { + final String value = cookie.getValue(); + if (StringUtils.hasLength(value)) { + return value; + } + } + return null; + } + +} diff --git a/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3EntityExtractor.java b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3EntityExtractor.java new file mode 100644 index 000000000000..1d83bb080063 --- /dev/null +++ b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3EntityExtractor.java @@ -0,0 +1,86 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.httpclient3; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityExtractor; +import com.navercorp.pinpoint.bootstrap.util.FixedByteArrayOutputStream; +import com.navercorp.pinpoint.common.util.StringUtils; +import org.apache.commons.httpclient.HttpConstants; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; +import org.apache.commons.httpclient.methods.EntityEnclosingMethod; +import org.apache.commons.httpclient.methods.RequestEntity; +import org.apache.commons.httpclient.methods.StringRequestEntity; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpClient3EntityExtractor implements EntityExtractor { + + private static final int MAX_READ_SIZE = 1024; + + public static final EntityExtractor INSTANCE = new HttpClient3EntityExtractor(); + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public String getEntity(HttpMethod httpMethod) { + if (httpMethod instanceof EntityEnclosingMethod) { + final EntityEnclosingMethod entityEnclosingMethod = (EntityEnclosingMethod) httpMethod; + final RequestEntity entity = entityEnclosingMethod.getRequestEntity(); + if (entity != null && entity.isRepeatable() && entity.getContentLength() > 0) { + try { + String entityValue; + String charSet = entityEnclosingMethod.getRequestCharSet(); + if (StringUtils.isEmpty(charSet)) { + charSet = HttpConstants.DEFAULT_CONTENT_CHARSET; + } + if (entity instanceof ByteArrayRequestEntity || entity instanceof StringRequestEntity) { + entityValue = entityUtilsToString(entity, charSet); + } else { + entityValue = entity.getClass() + " (ContentType:" + entity.getContentType() + ")"; + } + return entityValue; + } catch (Exception e) { + if (isDebug) { + logger.debug("Failed to get entity. httpMethod={}", httpMethod, e); + } + } + } + } + return null; + } + + private static String entityUtilsToString(final RequestEntity entity, final String charSet) throws Exception { + final FixedByteArrayOutputStream outStream = new FixedByteArrayOutputStream(MAX_READ_SIZE); + entity.writeRequest(outStream); + final String entityValue = outStream.toString(charSet); + if (entity.getContentLength() > MAX_READ_SIZE) { + StringBuilder sb = new StringBuilder(); + sb.append(entityValue); + sb.append(" (HTTP entity is large. length: "); + sb.append(entity.getContentLength()); + sb.append(" )"); + return sb.toString(); + } + + return entityValue; + } +} diff --git a/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3PluginConfig.java b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3PluginConfig.java index 16e7e64db4df..0eb9fa2cb194 100644 --- a/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3PluginConfig.java +++ b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3PluginConfig.java @@ -16,33 +16,31 @@ package com.navercorp.pinpoint.plugin.httpclient3; import com.navercorp.pinpoint.bootstrap.config.DumpType; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; /** - * * @author jaehong.kim - * */ public class HttpClient3PluginConfig { private boolean param = true; - private boolean cookie = false; - private DumpType cookieDumpType = DumpType.EXCEPTION; - private int cookieSamplingRate = 1; - private boolean entity = false; - private DumpType entityDumpType = DumpType.EXCEPTION; - private int entitySamplingRate = 1; private boolean io; + private HttpDumpConfig httpDumpConfig; public HttpClient3PluginConfig(ProfilerConfig src) { this.param = src.readBoolean("profiler.apache.httpclient3.param", true); - this.cookie = src.readBoolean("profiler.apache.httpclient3.cookie", false); - this.cookieDumpType = src.readDumpType("profiler.apache.httpclient3.cookie.dumptype", DumpType.EXCEPTION); - this.cookieSamplingRate = src.readInt("profiler.apache.httpclient3.cookie.sampling.rate", 1); - this.entity = src.readBoolean("profiler.apache.httpclient3.entity", false); - this.entityDumpType = src.readDumpType("profiler.apache.httpclient3.entity.dumptype", DumpType.EXCEPTION); - this.entitySamplingRate = src.readInt("profiler.apache.httpclient3.entity.sampling.rate", 1); + boolean cookie = src.readBoolean("profiler.apache.httpclient3.cookie", false); + DumpType cookieDumpType = src.readDumpType("profiler.apache.httpclient3.cookie.dumptype", DumpType.EXCEPTION); + int cookieSamplingRate = src.readInt("profiler.apache.httpclient3.cookie.sampling.rate", 1); + int cookieDumpSize = src.readInt("profiler.apache.httpclient3.cookie.dumpsize", 1024); + + boolean entity = src.readBoolean("profiler.apache.httpclient3.entity", false); + DumpType entityDumpType = src.readDumpType("profiler.apache.httpclient3.entity.dumptype", DumpType.EXCEPTION); + int entitySamplingRate = src.readInt("profiler.apache.httpclient3.entity.sampling.rate", 1); + int entityDumpSize = src.readInt("profiler.apache.httpclient3.entity.dumpsize", 1024); + this.httpDumpConfig = HttpDumpConfig.get(cookie, cookieDumpType, cookieSamplingRate, cookieDumpSize, entity, entityDumpType, entitySamplingRate, entityDumpSize); this.io = src.readBoolean("profiler.apache.httpclient3.io", true); } @@ -51,28 +49,8 @@ public boolean isParam() { return param; } - public boolean isCookie() { - return cookie; - } - - public DumpType getCookieDumpType() { - return cookieDumpType; - } - - public int getCookieSamplingRate() { - return cookieSamplingRate; - } - - public boolean isEntity() { - return entity; - } - - public DumpType getEntityDumpType() { - return entityDumpType; - } - - public int getEntitySamplingRate() { - return entitySamplingRate; + public HttpDumpConfig getHttpDumpConfig() { + return httpDumpConfig; } public boolean isIo() { @@ -83,13 +61,8 @@ public boolean isIo() { public String toString() { final StringBuilder sb = new StringBuilder("HttpClient3PluginConfig{"); sb.append("param=").append(param); - sb.append(", cookie=").append(cookie); - sb.append(", cookieDumpType=").append(cookieDumpType); - sb.append(", cookieSamplingRate=").append(cookieSamplingRate); - sb.append(", entity=").append(entity); - sb.append(", entityDumpType=").append(entityDumpType); - sb.append(", entitySamplingRate=").append(entitySamplingRate); sb.append(", io=").append(io); + sb.append(", httpDumpConfig=").append(httpDumpConfig); sb.append('}'); return sb.toString(); } diff --git a/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3RequestWrapper.java b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3RequestWrapper.java new file mode 100644 index 000000000000..8c50bbb1a03d --- /dev/null +++ b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpClient3RequestWrapper.java @@ -0,0 +1,132 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.httpclient3; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.bootstrap.util.FixedByteArrayOutputStream; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; +import org.apache.commons.httpclient.HttpConnection; +import org.apache.commons.httpclient.HttpConstants; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.URI; +import org.apache.commons.httpclient.URIException; +import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; +import org.apache.commons.httpclient.methods.EntityEnclosingMethod; +import org.apache.commons.httpclient.methods.RequestEntity; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.apache.commons.httpclient.protocol.Protocol; + +/** + * @author jaehong.kim + */ +public class HttpClient3RequestWrapper implements ClientRequestWrapper { + private static final int SKIP_DEFAULT_PORT = -1; + + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final HttpMethod httpMethod; + private final HttpConnection httpConnection; + + public HttpClient3RequestWrapper(final HttpMethod httpMethod, final HttpConnection httpConnection) { + this.httpMethod = Assert.requireNonNull(httpMethod, "httpMethod must not be null"); + this.httpConnection = httpConnection; + } + + + @Override + public String getDestinationId() { + try { + final URI uri = this.httpMethod.getURI(); + // if uri have schema or not found HttpConnection argument. + if (uri.isAbsoluteURI() || this.httpConnection == null) { + return getEndpoint(uri.getHost(), uri.getPort()); + } + final String host = this.httpConnection.getHost(); + final int port = getPort(this.httpConnection); + return getEndpoint(host, port); + } catch (Exception e) { + if (isDebug) { + logger.debug("Failed to get destinationId. httpMethod={}", this.httpMethod, e); + } + } + return "unknown"; + } + + @Override + public String getUrl() { + try { + final URI uri = this.httpMethod.getURI(); + // if uri have schema or not found HttpConnection argument. + if (uri.isAbsoluteURI() || this.httpConnection == null) { + return uri.getURI(); + } + final String host = this.httpConnection.getHost(); + final int port = getPort(this.httpConnection); + return getHttpUrl(host, port, uri, this.httpConnection); + } catch (Exception e) { + if (isDebug) { + logger.debug("Failed to get url. httpMethod={}", this.httpMethod, e); + } + } + return null; + } + + public static String getEndpoint(final String host, final int port) { + if (host == null) { + return "Unknown"; + } + return HostAndPort.toHostAndPortString(host, HostAndPort.getPortOrNoPort(port)); + } + + public static int getPort(final HttpConnection httpConnection) { + if (httpConnection == null) { + return SKIP_DEFAULT_PORT; + } + final int port = httpConnection.getPort(); + final Protocol protocol = httpConnection.getProtocol(); + // if port is default port number. + if (protocol != null && port == protocol.getDefaultPort()) { + // skip + return SKIP_DEFAULT_PORT; + } + return port; + } + + private static String getHttpUrl(final String host, final int port, final URI uri, final HttpConnection httpConnection) throws URIException { + final Protocol protocol = httpConnection.getProtocol(); + if (protocol == null) { + return uri.getURI(); + } + final StringBuilder sb = new StringBuilder(); + final String scheme = protocol.getScheme(); + sb.append(scheme).append("://"); + sb.append(host); + // if port is default port number. + if (port != SKIP_DEFAULT_PORT) { + sb.append(':').append(port); + } + sb.append(uri.getURI()); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpMethodClientHeaderAdaptor.java b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpMethodClientHeaderAdaptor.java new file mode 100644 index 000000000000..427cdd0042ad --- /dev/null +++ b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/HttpMethodClientHeaderAdaptor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.httpclient3; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import org.apache.commons.httpclient.HttpMethod; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpMethodClientHeaderAdaptor implements ClientHeaderAdaptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(HttpMethod httpMethod, String name, String value) { + httpMethod.setRequestHeader(name, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } +} diff --git a/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/interceptor/HttpMethodBaseExecuteMethodInterceptor.java b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/interceptor/HttpMethodBaseExecuteMethodInterceptor.java index 907de8a123f5..06a44137f338 100644 --- a/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/interceptor/HttpMethodBaseExecuteMethodInterceptor.java +++ b/plugins/httpclient3/src/main/java/com/navercorp/pinpoint/plugin/httpclient3/interceptor/HttpMethodBaseExecuteMethodInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,22 +16,28 @@ package com.navercorp.pinpoint.plugin.httpclient3.interceptor; -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapperAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorderFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityRecorderFactory; import com.navercorp.pinpoint.common.util.IntBooleanIntBooleanValue; -import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.plugin.httpclient3.HttpClient3EntityExtractor; +import com.navercorp.pinpoint.plugin.httpclient3.HttpClient3RequestWrapper; +import com.navercorp.pinpoint.plugin.httpclient3.HttpMethodClientHeaderAdaptor; +import com.navercorp.pinpoint.plugin.httpclient3.HttpClient3CookieExtractor; import org.apache.commons.httpclient.HttpConnection; -import org.apache.commons.httpclient.HttpConstants; import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.URI; -import org.apache.commons.httpclient.URIException; -import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; -import org.apache.commons.httpclient.methods.EntityEnclosingMethod; -import org.apache.commons.httpclient.methods.RequestEntity; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.commons.httpclient.protocol.Protocol; -import com.navercorp.pinpoint.bootstrap.config.DumpType; -import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -42,43 +48,30 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.FixedByteArrayOutputStream; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.bootstrap.util.SimpleSampler; -import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; import com.navercorp.pinpoint.common.trace.AnnotationKey; import com.navercorp.pinpoint.plugin.httpclient3.HttpClient3CallContext; import com.navercorp.pinpoint.plugin.httpclient3.HttpClient3CallContextFactory; import com.navercorp.pinpoint.plugin.httpclient3.HttpClient3Constants; import com.navercorp.pinpoint.plugin.httpclient3.HttpClient3PluginConfig; +import org.apache.commons.httpclient.URI; /** * @author Minwoo Jung * @author jaehong.kim */ public class HttpMethodBaseExecuteMethodInterceptor implements AroundInterceptor { - - private static final int SKIP_DEFAULT_PORT = -1; - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private static final int MAX_READ_SIZE = 1024; private final TraceContext traceContext; private final MethodDescriptor descriptor; private final InterceptorScope interceptorScope; - - private final boolean param; - private final boolean cookie; - private final DumpType cookieDumpType; - private SimpleSampler cookieSampler; - - private final boolean entity; - private final DumpType entityDumpType; - private SimpleSampler entitySampler; + private final ClientRequestRecorder clientRequestRecorder; + private final RequestTraceWriter requestTraceWriter; private final boolean io; + private final CookieRecorder cookieRecorder; + private final EntityRecorder entityRecorder; public HttpMethodBaseExecuteMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorScope interceptorScope) { if (traceContext == null) { @@ -95,20 +88,20 @@ public HttpMethodBaseExecuteMethodInterceptor(TraceContext traceContext, MethodD this.interceptorScope = interceptorScope; final HttpClient3PluginConfig config = new HttpClient3PluginConfig(traceContext.getProfilerConfig()); - this.param = config.isParam(); - this.cookie = config.isCookie(); - this.cookieDumpType = config.getCookieDumpType(); + final boolean param = config.isParam(); + final HttpDumpConfig httpDumpConfig = config.getHttpDumpConfig(); - if (cookie) { - this.cookieSampler = SimpleSamplerFactory.createSampler(cookie, config.getCookieSamplingRate()); - } + ClientRequestAdaptor clientRequestAdaptor = ClientRequestWrapperAdaptor.INSTANCE; + this.clientRequestRecorder = new ClientRequestRecorder(param, clientRequestAdaptor); - this.entity = config.isEntity(); - this.entityDumpType = config.getEntityDumpType(); + CookieExtractor cookieExtractor = HttpClient3CookieExtractor.INSTANCE; + this.cookieRecorder = CookieRecorderFactory.newCookieRecorder(httpDumpConfig, cookieExtractor); - if (entity) { - this.entitySampler = SimpleSamplerFactory.createSampler(entity, config.getEntitySamplingRate()); - } + EntityExtractor entityExtractor = HttpClient3EntityExtractor.INSTANCE; + this.entityRecorder = EntityRecorderFactory.newEntityRecorder(httpDumpConfig, entityExtractor); + + ClientHeaderAdaptor clientHeaderAdaptor = new HttpMethodClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); this.io = config.isIo(); } @@ -125,8 +118,10 @@ public void before(Object target, Object[] args) { } if (!trace.canSampled()) { - // set http header. - setHttpSampledHeader(target); + if (target instanceof HttpMethod) { + final HttpMethod httpMethod = (HttpMethod) target; + this.requestTraceWriter.write(httpMethod); + } return; } @@ -136,13 +131,45 @@ public void before(Object target, Object[] args) { recorder.recordNextSpanId(nextId.getSpanId()); recorder.recordServiceType(HttpClient3Constants.HTTP_CLIENT_3); // set http header for trace. - setHttpTraceHeader(target, args, nextId); + if (target instanceof HttpMethod) { + final HttpMethod httpMethod = (HttpMethod) target; + final HttpConnection httpConnection = getHttpConnection(args); + final String host = getHost(httpMethod, httpConnection); + this.requestTraceWriter.write(httpMethod, nextId, host); + } // init attachment for io(read/write). initAttachment(); } + private String getHost(HttpMethod httpMethod, HttpConnection httpConnection) { + try { + final URI uri = httpMethod.getURI(); + // if uri have schema + if (uri.isAbsoluteURI()) { + return HttpClient3RequestWrapper.getEndpoint(uri.getHost(), uri.getPort()); + } + if (httpConnection != null) { + final String host = httpConnection.getHost(); + final int port = HttpClient3RequestWrapper.getPort(httpConnection); + return HttpClient3RequestWrapper.getEndpoint(host, port); + } + } catch (Exception e) { + if (isDebug) { + logger.debug("Failed to get host. httpMethod={}", httpMethod, e); + } + } + return null; + } + + private HttpConnection getHttpConnection(final Object[] args) { + if (args != null && args.length > 1 && args[1] instanceof HttpConnection) { + return (HttpConnection) args[1]; + } + return null; + } + @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { @@ -156,19 +183,21 @@ public void after(Object target, Object[] args, Object result, Throwable throwab try { final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(descriptor); + recorder.recordException(throwable); if (target instanceof HttpMethod) { - HttpMethod httpMethod = (HttpMethod) target; - recordDestination(trace, httpMethod, args); - recordRequest(trace, httpMethod, throwable); + final HttpMethod httpMethod = (HttpMethod) target; + final HttpConnection httpConnection = getHttpConnection(args); + final ClientRequestWrapper requestWrapper = new HttpClient3RequestWrapper(httpMethod, httpConnection); + this.clientRequestRecorder.record(recorder, requestWrapper, throwable); + this.cookieRecorder.record(recorder, httpMethod, throwable); + this.entityRecorder.record(recorder, httpMethod, throwable); } if (result != null) { recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, result); } - recorder.recordApi(descriptor); - recorder.recordException(throwable); - final HttpClient3CallContext callContext = getAndCleanAttachment(); if (callContext != null) { recordIo(recorder, callContext); @@ -178,59 +207,6 @@ public void after(Object target, Object[] args, Object result, Throwable throwab } } - - private void setHttpSampledHeader(final Object target) { - if (isDebug) { - logger.debug("set Sampling flag=false"); - } - if (target instanceof HttpMethod) { - final HttpMethod httpMethod = (HttpMethod) target; - httpMethod.setRequestHeader(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); - } - } - - private void setHttpTraceHeader(final Object target, final Object[] args, TraceId nextId) { - if (target instanceof HttpMethod) { - final HttpMethod httpMethod = (HttpMethod) target; - httpMethod.setRequestHeader(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - httpMethod.setRequestHeader(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - httpMethod.setRequestHeader(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - httpMethod.setRequestHeader(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - httpMethod.setRequestHeader(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - httpMethod.setRequestHeader(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - final String host = getHost(httpMethod, args); - if (host != null) { - httpMethod.setRequestHeader(Header.HTTP_HOST.toString(), host); - } - } - } - - private String getHost(HttpMethod httpMethod, Object[] args) { - try { - final URI url = httpMethod.getURI(); - if (url.isAbsoluteURI()) { - return getEndpoint(url.getHost(), url.getPort()); - } - - if (isDebug) { - logger.debug("URI is not absolute. {}", url.getURI()); - } - - // if not found schema, use httpConnection. - final HttpConnection httpConnection = getHttpConnection(args); - if (httpConnection != null) { - final String host = httpConnection.getHost(); - final int port = getPort(httpConnection); - return getEndpoint(host, port); - } - } catch (URIException e) { - // unexpected error, perhaps of user fault. - logger.error("[HttpClient3] Fail get URI", e); - } - - return null; - } - private void initAttachment() { InterceptorScopeInvocation invocation = interceptorScope.getCurrentInvocation(); if (invocation != null) { @@ -255,166 +231,10 @@ private Object getAttachment(InterceptorScopeInvocation invocation) { return invocation.getAttachment(); } - private void recordDestination(final Trace trace, final HttpMethod httpMethod, final Object[] args) { - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - try { - final URI uri = httpMethod.getURI(); - final HttpConnection httpConnection = getHttpConnection(args); - // if uri have schema or not found HttpConnection argument. - if (uri.isAbsoluteURI() || httpConnection == null) { - recorder.recordAttribute(AnnotationKey.HTTP_URL, InterceptorUtils.getHttpUrl(uri.getURI(), param)); - recorder.recordDestinationId(getEndpoint(uri.getHost(), uri.getPort())); - return; - } - - if (isDebug) { - logger.debug("URI is not absolute. {}", uri.getURI()); - } - - // use HttpConnection argument. - final String host = httpConnection.getHost(); - final int port = getPort(httpConnection); - final String httpUrl = getHttpUrl(host, port, uri, httpConnection); - recorder.recordAttribute(AnnotationKey.HTTP_URL, InterceptorUtils.getHttpUrl(httpUrl, param)); - recorder.recordDestinationId(getEndpoint(host, port)); - } catch (URIException e) { - logger.error("Fail get URI", e); - recorder.recordDestinationId("unknown"); - } - } - - private String getHttpUrl(String host, int port, URI uri, HttpConnection httpConnection) throws URIException { - final Protocol protocol = httpConnection.getProtocol(); - if (protocol == null) { - return uri.getURI(); - } - final StringBuilder sb = new StringBuilder(); - final String scheme = protocol.getScheme(); - sb.append(scheme).append("://"); - sb.append(host); - // if port is default port number. - if (port != SKIP_DEFAULT_PORT) { - sb.append(':').append(port); - } - sb.append(uri.getURI()); - return sb.toString(); - } - - private int getPort(HttpConnection httpConnection) { - final int port = httpConnection.getPort(); - final Protocol protocol = httpConnection.getProtocol(); - // if port is default port number. - if (protocol != null && port == protocol.getDefaultPort()) { - // skip - return SKIP_DEFAULT_PORT; - } - return port; - } - - private void recordIo(SpanEventRecorder recorder, HttpClient3CallContext callContext) { if (io) { IntBooleanIntBooleanValue value = new IntBooleanIntBooleanValue((int) callContext.getWriteElapsedTime(), callContext.isWriteFail(), (int) callContext.getReadElapsedTime(), callContext.isReadFail()); recorder.recordAttribute(AnnotationKey.HTTP_IO, value); } } - - private void recordRequest(Trace trace, HttpMethod httpMethod, Throwable throwable) { - final boolean isException = InterceptorUtils.isThrowable(throwable); - - if (cookie) { - if (DumpType.ALWAYS == cookieDumpType) { - recordCookie(httpMethod, trace); - } else if (DumpType.EXCEPTION == cookieDumpType && isException) { - recordCookie(httpMethod, trace); - } - } - if (entity) { - if (DumpType.ALWAYS == entityDumpType) { - recordEntity(httpMethod, trace); - } else if (DumpType.EXCEPTION == entityDumpType && isException) { - recordEntity(httpMethod, trace); - } - } - } - - private void recordEntity(HttpMethod httpMethod, Trace trace) { - if (httpMethod instanceof EntityEnclosingMethod) { - final EntityEnclosingMethod entityEnclosingMethod = (EntityEnclosingMethod) httpMethod; - final RequestEntity entity = entityEnclosingMethod.getRequestEntity(); - - if (entity != null && entity.isRepeatable() && entity.getContentLength() > 0) { - if (entitySampler.isSampling()) { - try { - String entityValue; - String charSet = entityEnclosingMethod.getRequestCharSet(); - - if (StringUtils.isEmpty(charSet)) { - charSet = HttpConstants.DEFAULT_CONTENT_CHARSET; - } - - if (entity instanceof ByteArrayRequestEntity || entity instanceof StringRequestEntity) { - entityValue = entityUtilsToString(entity, charSet); - } else { - entityValue = entity.getClass() + " (ContentType:" + entity.getContentType() + ")"; - } - - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, entityValue); - } catch (Exception e) { - logger.debug("HttpEntityEnclosingRequest entity record fail. Caused:{}", e.getMessage(), e); - } - } - } - } - } - - private String entityUtilsToString(RequestEntity entity, String charSet) throws Exception { - FixedByteArrayOutputStream outStream = new FixedByteArrayOutputStream(MAX_READ_SIZE); - entity.writeRequest(outStream); - - String entityValue = outStream.toString(charSet); - - if (entity.getContentLength() > MAX_READ_SIZE) { - StringBuilder sb = new StringBuilder(); - sb.append(entityValue); - sb.append(" (HTTP entity is large. length: "); - sb.append(entity.getContentLength()); - sb.append(" )"); - return sb.toString(); - } - - return entityValue; - } - - private void recordCookie(HttpMethod httpMethod, Trace trace) { - org.apache.commons.httpclient.Header cookie = httpMethod.getRequestHeader("Cookie"); - if (cookie == null) { - return; - } - - final String value = cookie.getValue(); - if (StringUtils.hasLength(value)) { - if (cookieSampler.isSampling()) { - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, StringUtils.abbreviate(value, MAX_READ_SIZE)); - } - } - } - - private String getEndpoint(String host, int port) { - if (host == null) { - return "unknown"; - } - port = HostAndPort.getPortOrNoPort(port); - return HostAndPort.toHostAndPortString(host, port); - } - - private HttpConnection getHttpConnection(final Object[] args) { - if (args != null && args.length > 1 && args[1] instanceof HttpConnection) { - return (HttpConnection) args[1]; - } - - return null; - } } \ No newline at end of file diff --git a/plugins/httpclient4/clover.license b/plugins/httpclient4/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/httpclient4/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-httpclient4-plugin pinpoint-httpclient4-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4CookieExtractor.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4CookieExtractor.java new file mode 100644 index 000000000000..4ce3cf507978 --- /dev/null +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4CookieExtractor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.httpclient4; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.common.util.StringUtils; +import org.apache.http.HttpRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpClient4CookieExtractor implements CookieExtractor { + + public static final CookieExtractor INSTANCE = new HttpClient4CookieExtractor(); + + @Override + public String getCookie(HttpRequest cookie) { + final org.apache.http.Header[] cookies = cookie.getHeaders("Cookie"); + for (org.apache.http.Header header : cookies) { + final String value = header.getValue(); + if (StringUtils.hasLength(value)) { + return value; + } + } + return null; + } + +} diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4EntityExtractor.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4EntityExtractor.java new file mode 100644 index 000000000000..b6bbe6e52e33 --- /dev/null +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4EntityExtractor.java @@ -0,0 +1,129 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.httpclient4; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityExtractor; +import com.navercorp.pinpoint.bootstrap.util.FixedByteArrayOutputStream; +import com.navercorp.pinpoint.common.Charsets; +import org.apache.http.HeaderElement; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpRequest; +import org.apache.http.NameValuePair; +import org.apache.http.ParseException; +import org.apache.http.protocol.HTTP; + +import java.io.IOException; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpClient4EntityExtractor implements EntityExtractor { + + public static final EntityExtractor INSTANCE = new HttpClient4EntityExtractor(); + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + + @Override + public String getEntity(HttpRequest httpRequest) { + if (httpRequest instanceof HttpEntityEnclosingRequest) { + final HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) httpRequest; + try { + final HttpEntity entity = entityRequest.getEntity(); + if (entity != null && entity.isRepeatable() && entity.getContentLength() > 0) { + return entityUtilsToString(entity, Charsets.UTF_8_NAME, 1024); + } + } catch (Exception e) { + logger.debug("Failed to get entity. httpRequest={}", httpRequest, e); + } + } + return null; + } + + /** + * copy: EntityUtils Get the entity content as a String, using the provided default character set if none is found in the entity. If defaultCharset is null, the default "ISO-8859-1" is used. + * + * @param entity must not be null + * @param defaultCharset character set to be applied if none found in the entity + * @return the entity content as a String. May be null if {@link HttpEntity#getContent()} is null. + * @throws ParseException if header elements cannot be parsed + * @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE + * @throws IOException if an error occurs reading the input stream + */ + @SuppressWarnings("deprecation") + private static String entityUtilsToString(final HttpEntity entity, final String defaultCharset, final int maxLength) throws Exception { + if (entity == null) { + throw new IllegalArgumentException("HTTP entity must not be null"); + } + if (entity.getContentLength() > Integer.MAX_VALUE) { + return "HTTP entity is too large to be buffered in memory length:" + entity.getContentLength(); + } + if (entity.getContentType().getValue().startsWith("multipart/form-data")) { + return "content type is multipart/form-data. content length:" + entity.getContentLength(); + } + + String charset = getContentCharSet(entity); + if (charset == null) { + charset = defaultCharset; + } + if (charset == null) { + charset = HTTP.DEFAULT_CONTENT_CHARSET; + } + + final FixedByteArrayOutputStream outStream = new FixedByteArrayOutputStream(maxLength); + entity.writeTo(outStream); + final String entityValue = outStream.toString(charset); + if (entity.getContentLength() > maxLength) { + final StringBuilder sb = new StringBuilder(); + sb.append(entityValue); + sb.append("HTTP entity large length: "); + sb.append(entity.getContentLength()); + sb.append(" )"); + return sb.toString(); + } + + return entityValue; + } + + /** + * copy: EntityUtils Obtains character set of the entity, if known. + * + * @param entity must not be null + * @return the character set, or null if not found + * @throws ParseException if header elements cannot be parsed + * @throws IllegalArgumentException if entity is null + */ + private static String getContentCharSet(final HttpEntity entity) throws ParseException { + if (entity == null) { + throw new IllegalArgumentException("HTTP entity must not be null"); + } + String charset = null; + if (entity.getContentType() != null) { + HeaderElement values[] = entity.getContentType().getElements(); + if (values.length > 0) { + NameValuePair param = values[0].getParameterByName("charset"); + if (param != null) { + charset = param.getValue(); + } + } + } + return charset; + } +} diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4PluginConfig.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4PluginConfig.java index 1b281439d2aa..aeaf7c6b9cc3 100644 --- a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4PluginConfig.java +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4PluginConfig.java @@ -16,40 +16,30 @@ package com.navercorp.pinpoint.plugin.httpclient4; import com.navercorp.pinpoint.bootstrap.config.DumpType; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; /** - * * @author jaehong.kim - * */ public class HttpClient4PluginConfig { - - /** - * apache http client 4 - */ private boolean param = true; - private boolean cookie = false; - private DumpType cookieDumpType = DumpType.EXCEPTION; - private int cookieSamplingRate = 1; - private boolean entity = false; - private DumpType entityDumpType = DumpType.EXCEPTION; - private int entitySamplingRate = 1; private boolean statusCode = true; private boolean io; + private HttpDumpConfig httpDumpConfig; public HttpClient4PluginConfig(ProfilerConfig src) { - /* - * apache http client 4 - */ this.param = src.readBoolean("profiler.apache.httpclient4.param", true); - this.cookie = src.readBoolean("profiler.apache.httpclient4.cookie", false); - this.cookieDumpType = src.readDumpType("profiler.apache.httpclient4.cookie.dumptype", DumpType.EXCEPTION); - this.cookieSamplingRate = src.readInt("profiler.apache.httpclient4.cookie.sampling.rate", 1); - this.entity = src.readBoolean("profiler.apache.httpclient4.entity", false); - this.entityDumpType = src.readDumpType("profiler.apache.httpclient4.entity.dumptype", DumpType.EXCEPTION); - this.entitySamplingRate = src.readInt("profiler.apache.httpclient4.entity.sampling.rate", 1); + boolean cookie = src.readBoolean("profiler.apache.httpclient4.cookie", false); + DumpType cookieDumpType = src.readDumpType("profiler.apache.httpclient4.cookie.dumptype", DumpType.EXCEPTION); + int cookieSamplingRate = src.readInt("profiler.apache.httpclient4.cookie.sampling.rate", 1); + int cookieDumpSize = src.readInt("profiler.apache.httpclient4.cookie.dumpsize", 1024); + boolean entity = src.readBoolean("profiler.apache.httpclient4.entity", false); + DumpType entityDumpType = src.readDumpType("profiler.apache.httpclient4.entity.dumptype", DumpType.EXCEPTION); + int entitySamplingRate = src.readInt("profiler.apache.httpclient4.entity.sampling.rate", 1); + int entityDumpSize = src.readInt("profiler.apache.httpclient4.entity.dumpsize", 1024); + this.httpDumpConfig = HttpDumpConfig.get(cookie, cookieDumpType, cookieSamplingRate, cookieDumpSize, entity, entityDumpType, entitySamplingRate, entityDumpSize); this.statusCode = src.readBoolean("profiler.apache.httpclient4.entity.statuscode", true); this.io = src.readBoolean("profiler.apache.httpclient4.io", true); @@ -59,30 +49,6 @@ public boolean isParam() { return param; } - public boolean isCookie() { - return cookie; - } - - public DumpType getCookieDumpType() { - return cookieDumpType; - } - - public int getCookieSamplingRate() { - return cookieSamplingRate; - } - - public boolean isEntity() { - return entity; - } - - public DumpType getEntityDumpType() { - return entityDumpType; - } - - public int getEntitySamplingRate() { - return entitySamplingRate; - } - public boolean isStatusCode() { return statusCode; } @@ -91,19 +57,18 @@ public boolean isIo() { return io; } + public HttpDumpConfig getHttpDumpConfig() { + return httpDumpConfig; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("HttpClient4PluginConfig{"); sb.append("param=").append(param); - sb.append(", cookie=").append(cookie); - sb.append(", cookieDumpType=").append(cookieDumpType); - sb.append(", cookieSamplingRate=").append(cookieSamplingRate); - sb.append(", entity=").append(entity); - sb.append(", entityDumpType=").append(entityDumpType); - sb.append(", entitySamplingRate=").append(entitySamplingRate); sb.append(", statusCode=").append(statusCode); sb.append(", io=").append(io); + sb.append(", httpDumpConfig=").append(httpDumpConfig); sb.append('}'); return sb.toString(); } -} +} \ No newline at end of file diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4RequestWrapper.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4RequestWrapper.java new file mode 100644 index 000000000000..75a0edfc66eb --- /dev/null +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpClient4RequestWrapper.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.httpclient4; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.bootstrap.util.FixedByteArrayOutputStream; +import com.navercorp.pinpoint.common.Charsets; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; +import org.apache.http.HeaderElement; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpRequest; +import org.apache.http.NameValuePair; +import org.apache.http.ParseException; +import org.apache.http.RequestLine; +import org.apache.http.protocol.HTTP; + +import java.io.IOException; + +/** + * @author jaehong.kim + */ +public class HttpClient4RequestWrapper implements ClientRequestWrapper { + + private final HttpRequest httpRequest; + private final String hostName; + private final int port; + + public HttpClient4RequestWrapper(final HttpRequest httpRequest, final String hostName, final int port) { + this.httpRequest = Assert.requireNonNull(httpRequest, "httpRequest must not be null"); + this.hostName = hostName; + this.port = port; + } + + + @Override + public String getDestinationId() { + return getEndpoint(this.hostName, this.port); + } + + private static String getEndpoint(final String host, final int port) { + if (host == null) { + return "Unknown"; + } + if (port < 0) { + return host; + } + final StringBuilder sb = new StringBuilder(host.length() + 8); + sb.append(host); + sb.append(':'); + sb.append(port); + return sb.toString(); + } + + + @Override + public String getUrl() { + final RequestLine requestLine = this.httpRequest.getRequestLine(); + if (requestLine != null) { + return requestLine.getUri(); + } + return null; + } + +} \ No newline at end of file diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpRequest4ClientHeaderAdaptor.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpRequest4ClientHeaderAdaptor.java new file mode 100644 index 000000000000..3e732d5fdf61 --- /dev/null +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/HttpRequest4ClientHeaderAdaptor.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.httpclient4; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import org.apache.http.HttpRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpRequest4ClientHeaderAdaptor implements ClientHeaderAdaptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(HttpRequest request, String name, String value) { + request.setHeader(name, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } +} diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/DefaultClientExchangeHandlerImplStartMethodInterceptor.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/DefaultClientExchangeHandlerImplStartMethodInterceptor.java index 8cc2214a58ed..a77361a9dde2 100644 --- a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/DefaultClientExchangeHandlerImplStartMethodInterceptor.java +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/DefaultClientExchangeHandlerImplStartMethodInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,26 +16,32 @@ package com.navercorp.pinpoint.plugin.httpclient4.interceptor; -import java.io.IOException; - import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; import com.navercorp.pinpoint.bootstrap.context.AsyncContext; -import com.navercorp.pinpoint.common.Charsets; -import com.navercorp.pinpoint.common.util.StringUtils; -import org.apache.http.HeaderElement; -import org.apache.http.HttpEntity; -import org.apache.http.HttpEntityEnclosingRequest; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapperAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorderFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityRecorderFactory; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4CookieExtractor; +import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4EntityExtractor; +import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4RequestWrapper; +import com.navercorp.pinpoint.plugin.httpclient4.HttpRequest4ClientHeaderAdaptor; import org.apache.http.HttpHost; -import org.apache.http.HttpMessage; import org.apache.http.HttpRequest; -import org.apache.http.NameValuePair; -import org.apache.http.ParseException; import org.apache.http.concurrent.BasicFuture; import org.apache.http.nio.protocol.HttpAsyncRequestProducer; -import org.apache.http.protocol.HTTP; -import com.navercorp.pinpoint.bootstrap.config.DumpType; -import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -45,22 +51,14 @@ import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.pair.NameIntValuePair; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.FixedByteArrayOutputStream; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.bootstrap.util.SimpleSampler; -import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; -import com.navercorp.pinpoint.common.trace.AnnotationKey; import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4Constants; import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4PluginConfig; import com.navercorp.pinpoint.plugin.httpclient4.RequestProducerGetter; import com.navercorp.pinpoint.plugin.httpclient4.ResultFutureGetter; /** - * * @author minwoo.jung * @author jaehong.kim - * */ public class DefaultClientExchangeHandlerImplStartMethodInterceptor implements AroundInterceptor { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); @@ -68,39 +66,37 @@ public class DefaultClientExchangeHandlerImplStartMethodInterceptor implements A private final TraceContext traceContext; private final MethodDescriptor methodDescriptor; + private final ClientRequestRecorder clientRequestRecorder; + private final CookieRecorder cookieRecorder; + private final EntityRecorder entityRecorder; - private final boolean param; - protected final boolean cookie; - protected final DumpType cookieDumpType; - protected SimpleSampler cookieSampler; - - protected final boolean entity; - protected final DumpType entityDumpType; - protected SimpleSampler entitySampler; + private final RequestTraceWriter requestTraceWriter; public DefaultClientExchangeHandlerImplStartMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { this.traceContext = traceContext; this.methodDescriptor = methodDescriptor; final HttpClient4PluginConfig config = new HttpClient4PluginConfig(traceContext.getProfilerConfig()); - this.param = config.isParam(); - this.cookie = config.isCookie(); - this.cookieDumpType = config.getCookieDumpType(); - if (cookie) { - this.cookieSampler = SimpleSamplerFactory.createSampler(cookie, config.getCookieSamplingRate()); - } + final boolean param = config.isParam(); + final HttpDumpConfig httpDumpConfig = config.getHttpDumpConfig(); - this.entity = config.isEntity(); - this.entityDumpType = config.getEntityDumpType(); - if (entity) { - this.entitySampler = SimpleSamplerFactory.createSampler(entity, config.getEntitySamplingRate()); - } + ClientRequestAdaptor clientRequestAdaptor = ClientRequestWrapperAdaptor.INSTANCE; + this.clientRequestRecorder = new ClientRequestRecorder(param, clientRequestAdaptor); + + CookieExtractor cookieExtractor = HttpClient4CookieExtractor.INSTANCE; + this.cookieRecorder = CookieRecorderFactory.newCookieRecorder(httpDumpConfig, cookieExtractor); + + EntityExtractor entityExtractor = HttpClient4EntityExtractor.INSTANCE; + this.entityRecorder = EntityRecorderFactory.newEntityRecorder(httpDumpConfig, entityExtractor); + + ClientHeaderAdaptor clientHeaderAdaptor = new HttpRequest4ClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } @Override public void before(Object target, Object[] args) { if (isDebug) { - logger.beforeInterceptor(target, "", methodDescriptor.getMethodName(), "", args); + logger.beforeInterceptor(target, args); } final Trace trace = traceContext.currentRawTraceObject(); @@ -109,48 +105,32 @@ public void before(Object target, Object[] args) { } final HttpRequest httpRequest = getHttpRequest(target); + final NameIntValuePair host = getHost(target); final boolean sampling = trace.canSampled(); if (!sampling) { - if (isDebug) { - logger.debug("set Sampling flag=false"); - } if (httpRequest != null) { - httpRequest.setHeader(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); + this.requestTraceWriter.write(httpRequest); } return; } - SpanEventRecorder recorder = trace.traceBlockBegin(); - + final SpanEventRecorder recorder = trace.traceBlockBegin(); // set remote trace final TraceId nextId = trace.getTraceId().getNextTraceId(); recorder.recordNextSpanId(nextId.getSpanId()); recorder.recordServiceType(HttpClient4Constants.HTTP_CLIENT_4); if (httpRequest != null) { - httpRequest.setHeader(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - httpRequest.setHeader(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - - httpRequest.setHeader(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - - httpRequest.setHeader(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - httpRequest.setHeader(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - httpRequest.setHeader(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - final NameIntValuePair host = getHost(target); - if (host != null) { - final String endpoint = getEndpoint(host.getName(), host.getValue()); - logger.debug("Get host {}", endpoint); - httpRequest.setHeader(Header.HTTP_HOST.toString(), endpoint); - } + final String hostString = getHostString(host.getName(), host.getValue()); + this.requestTraceWriter.write(httpRequest, nextId, hostString); } try { if (isAsynchronousInvocation(target, args)) { // set asynchronous trace final AsyncContext asyncContext = recorder.recordNextAsyncContext(); - // check type isAsynchronousInvocation() - ((AsyncContextAccessor)((ResultFutureGetter)target)._$PINPOINT$_getResultFuture())._$PINPOINT$_setAsyncContext(asyncContext); + ((AsyncContextAccessor) ((ResultFutureGetter) target)._$PINPOINT$_getResultFuture())._$PINPOINT$_setAsyncContext(asyncContext); if (isDebug) { logger.debug("Set AsyncContext {}", asyncContext); } @@ -160,27 +140,44 @@ public void before(Object target, Object[] args) { } } + + private String getHostString(String hostName, int port) { + if (hostName != null) { + return HostAndPort.toHostAndPortString(hostName, port); + } + return null; + } + private HttpRequest getHttpRequest(final Object target) { try { if (!(target instanceof RequestProducerGetter)) { return null; } - - final HttpAsyncRequestProducer requestProducer = ((RequestProducerGetter)target)._$PINPOINT$_getRequestProducer(); + final HttpAsyncRequestProducer requestProducer = ((RequestProducerGetter) target)._$PINPOINT$_getRequestProducer(); return requestProducer.generateRequest(); } catch (Exception e) { return null; } } + private NameIntValuePair getHost(final Object target) { + if (target instanceof RequestProducerGetter) { + final HttpAsyncRequestProducer producer = ((RequestProducerGetter) target)._$PINPOINT$_getRequestProducer(); + final HttpHost httpHost = producer.getTarget(); + if (httpHost != null) { + return new NameIntValuePair(httpHost.getHostName(), httpHost.getPort()); + } + } + return new NameIntValuePair(null, -1); + } + private boolean isAsynchronousInvocation(final Object target, final Object[] args) { if (!(target instanceof ResultFutureGetter)) { logger.debug("Invalid target object. Need field accessor({}).", HttpClient4Constants.FIELD_RESULT_FUTURE); return false; } - - BasicFuture future = ((ResultFutureGetter)target)._$PINPOINT$_getResultFuture(); + BasicFuture future = ((ResultFutureGetter) target)._$PINPOINT$_getResultFuture(); if (future == null) { logger.debug("Invalid target object. field is null({}).", HttpClient4Constants.FIELD_RESULT_FUTURE); return false; @@ -208,18 +205,13 @@ public void after(Object target, Object[] args, Object result, Throwable throwab try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); final HttpRequest httpRequest = getHttpRequest(target); + final NameIntValuePair host = getHost(target); if (httpRequest != null) { // Accessing httpRequest here not BEFORE() because it can cause side effect. - if(httpRequest.getRequestLine() != null) { - final String httpUrl = InterceptorUtils.getHttpUrl(httpRequest.getRequestLine().getUri(), param); - recorder.recordAttribute(AnnotationKey.HTTP_URL, httpUrl); - } - final NameIntValuePair host = getHost(target); - if (host != null) { - final String endpoint = getEndpoint(host.getName(), host.getValue()); - recorder.recordDestinationId(endpoint); - } - recordHttpRequest(recorder, httpRequest, throwable); + ClientRequestWrapper clientRequest = new HttpClient4RequestWrapper(httpRequest, host.getName(), host.getValue()); + this.clientRequestRecorder.record(recorder, clientRequest, throwable); + this.cookieRecorder.record(recorder, httpRequest, throwable); + this.entityRecorder.record(recorder, httpRequest, throwable); } recorder.recordApi(methodDescriptor); recorder.recordException(throwable); @@ -227,164 +219,4 @@ public void after(Object target, Object[] args, Object result, Throwable throwab trace.traceBlockEnd(); } } - - private NameIntValuePair getHost(final Object target) { - if (!(target instanceof RequestProducerGetter)) { - return null; - } - - final HttpAsyncRequestProducer producer = ((RequestProducerGetter)target)._$PINPOINT$_getRequestProducer(); - final HttpHost httpHost = producer.getTarget(); - if(httpHost != null) { - return new NameIntValuePair(httpHost.getHostName(), httpHost.getPort()); - } else { - return null; - } - } - - private String getEndpoint(String host, int port) { - if (host == null) { - return "UnknownHttpClient"; - } - if (port < 0) { - return host; - } - StringBuilder sb = new StringBuilder(host.length() + 8); - sb.append(host); - sb.append(':'); - sb.append(port); - return sb.toString(); - } - - private void recordHttpRequest(SpanEventRecorder recorder, HttpRequest httpRequest, Throwable throwable) { - final boolean isException = InterceptorUtils.isThrowable(throwable); - if (cookie) { - if (DumpType.ALWAYS == cookieDumpType) { - recordCookie(httpRequest, recorder); - } else if (DumpType.EXCEPTION == cookieDumpType && isException) { - recordCookie(httpRequest, recorder); - } - } - if (entity) { - if (DumpType.ALWAYS == entityDumpType) { - recordEntity(httpRequest, recorder); - } else if (DumpType.EXCEPTION == entityDumpType && isException) { - recordEntity(httpRequest, recorder); - } - } - } - - protected void recordCookie(HttpMessage httpMessage, SpanEventRecorder recorder) { - org.apache.http.Header[] cookies = httpMessage.getHeaders("Cookie"); - for (org.apache.http.Header header : cookies) { - final String value = header.getValue(); - if (value != null && !value.isEmpty()) { - if (cookieSampler.isSampling()) { - recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, StringUtils.abbreviate(value, 1024)); - } - - // Can a cookie have 2 or more values? - // PMD complains if we use break here - return; - } - } - } - - protected void recordEntity(HttpMessage httpMessage, SpanEventRecorder recorder) { - if (httpMessage instanceof HttpEntityEnclosingRequest) { - final HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) httpMessage; - try { - final HttpEntity entity = entityRequest.getEntity(); - if (entity != null && entity.isRepeatable() && entity.getContentLength() > 0) { - if (entitySampler.isSampling()) { - final String entityString = entityUtilsToString(entity, Charsets.UTF_8_NAME, 1024); - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, entityString); - } - } - } catch (Exception e) { - logger.debug("HttpEntityEnclosingRequest entity record fail. Caused:{}", e.getMessage(), e); - } - } - } - - /** - * copy: EntityUtils Get the entity content as a String, using the provided default character set if none is found in the entity. If defaultCharset is null, the default "ISO-8859-1" is used. - * - * @param entity - * must not be null - * @param defaultCharset - * character set to be applied if none found in the entity - * @return the entity content as a String. May be null if {@link HttpEntity#getContent()} is null. - * @throws ParseException - * if header elements cannot be parsed - * @throws IllegalArgumentException - * if entity is null or if content length > Integer.MAX_VALUE - * @throws IOException - * if an error occurs reading the input stream - */ - @SuppressWarnings("deprecation") - public static String entityUtilsToString(final HttpEntity entity, final String defaultCharset, int maxLength) throws Exception { - if (entity == null) { - throw new IllegalArgumentException("HTTP entity must not be null"); - } - if (entity.getContentLength() > Integer.MAX_VALUE) { - return "HTTP entity is too large to be buffered in memory length:" + entity.getContentLength(); - } - if (entity.getContentType().getValue().startsWith("multipart/form-data")) { - return "content type is multipart/form-data. content length:" + entity.getContentLength(); - } - - String charset = getContentCharSet(entity); - - if (charset == null) { - charset = defaultCharset; - } - if (charset == null) { - charset = HTTP.DEFAULT_CONTENT_CHARSET; - } - - FixedByteArrayOutputStream outStream = new FixedByteArrayOutputStream(maxLength); - entity.writeTo(outStream); - - String entityValue = outStream.toString(charset); - - if (entity.getContentLength() > maxLength) { - StringBuilder sb = new StringBuilder(); - sb.append(entityValue); - sb.append("HTTP entity large length: "); - sb.append(entity.getContentLength()); - sb.append(" )"); - return sb.toString(); - } - - return entityValue; - } - - /** - * copy: EntityUtils Obtains character set of the entity, if known. - * - * @param entity - * must not be null - * @return the character set, or null if not found - * @throws ParseException - * if header elements cannot be parsed - * @throws IllegalArgumentException - * if entity is null - */ - public static String getContentCharSet(final HttpEntity entity) throws ParseException { - if (entity == null) { - throw new IllegalArgumentException("HTTP entity must not be null"); - } - String charset = null; - if (entity.getContentType() != null) { - HeaderElement values[] = entity.getContentType().getElements(); - if (values.length > 0) { - NameValuePair param = values[0].getParameterByName("charset"); - if (param != null) { - charset = param.getValue(); - } - } - } - return charset; - } -} +} \ No newline at end of file diff --git a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/HttpRequestExecutorExecuteMethodInterceptor.java b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/HttpRequestExecutorExecuteMethodInterceptor.java index 9aae6aa3c383..756fcbc58c95 100644 --- a/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/HttpRequestExecutorExecuteMethodInterceptor.java +++ b/plugins/httpclient4/src/main/java/com/navercorp/pinpoint/plugin/httpclient4/interceptor/HttpRequestExecutorExecuteMethodInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,30 +16,30 @@ package com.navercorp.pinpoint.plugin.httpclient4.interceptor; -import java.io.IOException; - import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; -import com.navercorp.pinpoint.common.Charsets; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapperAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorderFactory; import com.navercorp.pinpoint.common.plugin.util.HostAndPort; import com.navercorp.pinpoint.common.util.IntBooleanIntBooleanValue; -import com.navercorp.pinpoint.common.util.StringUtils; import com.navercorp.pinpoint.plugin.httpclient4.HttpCallContext; import com.navercorp.pinpoint.plugin.httpclient4.HttpCallContextFactory; +import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4CookieExtractor; import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4PluginConfig; -import org.apache.http.HeaderElement; -import org.apache.http.HttpEntity; -import org.apache.http.HttpEntityEnclosingRequest; -import org.apache.http.HttpMessage; +import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4RequestWrapper; +import com.navercorp.pinpoint.plugin.httpclient4.HttpRequest4ClientHeaderAdaptor; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.ParseException; import org.apache.http.StatusLine; -import org.apache.http.protocol.HTTP; -import com.navercorp.pinpoint.bootstrap.config.DumpType; -import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -49,11 +49,6 @@ import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.pair.NameIntValuePair; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.FixedByteArrayOutputStream; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.bootstrap.util.SimpleSampler; -import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; import com.navercorp.pinpoint.common.trace.AnnotationKey; import com.navercorp.pinpoint.plugin.httpclient4.HttpClient4Constants; @@ -62,27 +57,18 @@ * @author jaehong.kim */ public class HttpRequestExecutorExecuteMethodInterceptor implements AroundInterceptor { - private static final int HTTP_REQUEST_INDEX = 1; - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final TraceContext traceContext; private final MethodDescriptor methodDescriptor; - private final boolean param; - private final boolean cookie; - private final DumpType cookieDumpType; - private final SimpleSampler cookieSampler; - - private final boolean entity; - private final DumpType entityDumpType; - private final SimpleSampler entitySampler; - private final boolean statusCode; private final InterceptorScope interceptorScope; - private final boolean io; + private final ClientRequestRecorder clientRequestRecorder; + private final CookieRecorder cookieRecorder; + private final RequestTraceWriter requestTraceWriter; public HttpRequestExecutorExecuteMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorScope interceptorScope) { this.traceContext = traceContext; @@ -90,24 +76,17 @@ public HttpRequestExecutorExecuteMethodInterceptor(TraceContext traceContext, Me this.interceptorScope = interceptorScope; final HttpClient4PluginConfig profilerConfig = new HttpClient4PluginConfig(traceContext.getProfilerConfig()); - this.param = profilerConfig.isParam(); - this.cookie = profilerConfig.isCookie(); - this.cookieDumpType = profilerConfig.getCookieDumpType(); - if (cookie) { - this.cookieSampler = SimpleSamplerFactory.createSampler(cookie, profilerConfig.getCookieSamplingRate()); - } else { - this.cookieSampler = null; - } - this.entity = profilerConfig.isEntity(); - this.entityDumpType = profilerConfig.getEntityDumpType(); - if (entity) { - this.entitySampler = SimpleSamplerFactory.createSampler(entity, profilerConfig.getEntitySamplingRate()); - } else { - this.entitySampler = null; - } + ClientRequestAdaptor clientRequestAdaptor = ClientRequestWrapperAdaptor.INSTANCE; + this.clientRequestRecorder = new ClientRequestRecorder(profilerConfig.isParam(), clientRequestAdaptor); + + CookieExtractor cookieExtractor = HttpClient4CookieExtractor.INSTANCE; + this.cookieRecorder = CookieRecorderFactory.newCookieRecorder(profilerConfig.getHttpDumpConfig(), cookieExtractor); + this.statusCode = profilerConfig.isStatusCode(); this.io = profilerConfig.isIo(); + ClientHeaderAdaptor clientHeaderAdaptor = new HttpRequest4ClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } @Override @@ -121,14 +100,11 @@ public void before(Object target, Object[] args) { } final HttpRequest httpRequest = getHttpRequest(args); - + final NameIntValuePair host = getHost(); final boolean sampling = trace.canSampled(); if (!sampling) { - if (isDebug) { - logger.debug("set Sampling flag=false"); - } if (httpRequest != null) { - httpRequest.setHeader(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); + this.requestTraceWriter.write(httpRequest); } return; } @@ -137,22 +113,9 @@ public void before(Object target, Object[] args) { TraceId nextId = trace.getTraceId().getNextTraceId(); recorder.recordNextSpanId(nextId.getSpanId()); recorder.recordServiceType(HttpClient4Constants.HTTP_CLIENT_4); - if (httpRequest != null) { - httpRequest.setHeader(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - httpRequest.setHeader(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - - httpRequest.setHeader(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - - httpRequest.setHeader(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - httpRequest.setHeader(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - httpRequest.setHeader(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - final NameIntValuePair host = getHost(); - if (host != null) { - final String endpoint = getEndpoint(host.getName(), host.getValue()); - logger.debug("Get host {}", endpoint); - httpRequest.setHeader(Header.HTTP_HOST.toString(), endpoint); - } + final String hostString = getHostString(host.getName(), host.getValue()); + this.requestTraceWriter.write(httpRequest, nextId, hostString); } InterceptorScopeInvocation invocation = interceptorScope.getCurrentInvocation(); @@ -161,6 +124,13 @@ public void before(Object target, Object[] args) { } } + private String getHostString(String hostName, int port) { + if (hostName != null) { + return HostAndPort.toHostAndPortString(hostName, port); + } + return null; + } + private HttpRequest getHttpRequest(Object[] args) { if (args != null && args.length >= 1 && args[0] != null && args[0] instanceof HttpRequest) { return (HttpRequest) args[0]; @@ -176,8 +146,7 @@ private NameIntValuePair getHost() { HttpCallContext callContext = (HttpCallContext) attachment; return new NameIntValuePair(callContext.getHost(), callContext.getPort()); } - - return null; + return new NameIntValuePair(null, -1); } @Override @@ -194,19 +163,11 @@ public void after(Object target, Object[] args, Object result, Throwable throwab try { final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); final HttpRequest httpRequest = getHttpRequest(args); + final NameIntValuePair host = getHost(); if (httpRequest != null) { - // Accessing httpRequest here not BEFORE() because it can cause side effect. - if (httpRequest.getRequestLine() != null) { - final String httpUrl = InterceptorUtils.getHttpUrl(httpRequest.getRequestLine().getUri(), param); - recorder.recordAttribute(AnnotationKey.HTTP_URL, httpUrl); - } - final NameIntValuePair host = getHost(); - if (host != null) { - final String endpoint = getEndpoint(host.getName(), host.getValue()); - recorder.recordDestinationId(endpoint); - } - - recordHttpRequest(trace, httpRequest, throwable); + ClientRequestWrapper clientRequest = new HttpClient4RequestWrapper(httpRequest, host.getName(), host.getValue()); + this.clientRequestRecorder.record(recorder, clientRequest, throwable); + this.cookieRecorder.record(recorder, httpRequest, throwable); } if (statusCode) { @@ -231,7 +192,6 @@ public void after(Object target, Object[] args, Object result, Throwable throwab // clear invocation.removeAttachment(); } - } finally { trace.traceBlockEnd(); } @@ -261,138 +221,4 @@ Integer getStatusCodeFromResponse(Object result) { } return null; } - - private String getEndpoint(String host, int port) { - if (host == null) { - return "UnknownHttpClient"; - } - port = HostAndPort.getPortOrNoPort(port); - return HostAndPort.toHostAndPortString(host, port); - } - - private void recordHttpRequest(Trace trace, HttpRequest httpRequest, Throwable throwable) { - final boolean isException = InterceptorUtils.isThrowable(throwable); - if (cookie) { - if (DumpType.ALWAYS == cookieDumpType) { - recordCookie(httpRequest, trace); - } else if (DumpType.EXCEPTION == cookieDumpType && isException) { - recordCookie(httpRequest, trace); - } - } - if (entity) { - if (DumpType.ALWAYS == entityDumpType) { - recordEntity(httpRequest, trace); - } else if (DumpType.EXCEPTION == entityDumpType && isException) { - recordEntity(httpRequest, trace); - } - } - } - - protected void recordCookie(HttpMessage httpMessage, Trace trace) { - org.apache.http.Header[] cookies = httpMessage.getHeaders("Cookie"); - for (org.apache.http.Header header : cookies) { - final String value = header.getValue(); - if (StringUtils.hasLength(value)) { - if (cookieSampler.isSampling()) { - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, StringUtils.abbreviate(value, 1024)); - } - - // Can a cookie have 2 or more values? - // PMD complains if we use break here - return; - } - } - } - - protected void recordEntity(HttpMessage httpMessage, Trace trace) { - if (httpMessage instanceof HttpEntityEnclosingRequest) { - final HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) httpMessage; - try { - final HttpEntity entity = entityRequest.getEntity(); - if (entity != null && entity.isRepeatable() && entity.getContentLength() > 0) { - if (entitySampler.isSampling()) { - final String entityString = entityUtilsToString(entity, Charsets.UTF_8_NAME, 1024); - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, entityString); - } - } - } catch (Exception e) { - logger.debug("HttpEntityEnclosingRequest entity record fail. Caused:{}", e.getMessage(), e); - } - } - } - - /** - * copy: EntityUtils Get the entity content as a String, using the provided default character set if none is found in the entity. If defaultCharset is null, the default "ISO-8859-1" is used. - * - * @param entity must not be null - * @param defaultCharset character set to be applied if none found in the entity - * @return the entity content as a String. May be null if {@link HttpEntity#getContent()} is null. - * @throws ParseException if header elements cannot be parsed - * @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE - * @throws IOException if an error occurs reading the input stream - */ - @SuppressWarnings("deprecation") - public static String entityUtilsToString(final HttpEntity entity, final String defaultCharset, int maxLength) throws Exception { - if (entity == null) { - throw new IllegalArgumentException("HTTP entity must not be null"); - } - if (entity.getContentLength() > Integer.MAX_VALUE) { - return "HTTP entity is too large to be buffered in memory length:" + entity.getContentLength(); - } - if (entity.getContentType().getValue().startsWith("multipart/form-data")) { - return "content type is multipart/form-data. content length:" + entity.getContentLength(); - } - - String charset = getContentCharSet(entity); - - if (charset == null) { - charset = defaultCharset; - } - if (charset == null) { - charset = HTTP.DEFAULT_CONTENT_CHARSET; - } - - FixedByteArrayOutputStream outStream = new FixedByteArrayOutputStream(maxLength); - entity.writeTo(outStream); - - String entityValue = outStream.toString(charset); - - if (entity.getContentLength() > maxLength) { - StringBuilder sb = new StringBuilder(); - sb.append(entityValue); - sb.append(" (HTTP entity is large. length: "); - sb.append(entity.getContentLength()); - sb.append(" )"); - return sb.toString(); - } - - return entityValue; - } - - /** - * copy: EntityUtils Obtains character set of the entity, if known. - * - * @param entity must not be null - * @return the character set, or null if not found - * @throws ParseException if header elements cannot be parsed - * @throws IllegalArgumentException if entity is null - */ - public static String getContentCharSet(final HttpEntity entity) throws ParseException { - if (entity == null) { - throw new IllegalArgumentException("HTTP entity must not be null"); - } - String charset = null; - if (entity.getContentType() != null) { - HeaderElement values[] = entity.getContentType().getElements(); - if (values.length > 0) { - NameValuePair param = values[0].getParameterByName("charset"); - if (param != null) { - charset = param.getValue(); - } - } - } - return charset; - } -} +} \ No newline at end of file diff --git a/plugins/hystrix/clover.license b/plugins/hystrix/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/hystrix/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-hystrix-plugin pinpoint-hystrix-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/hystrix/src/main/java/com/navercorp/pinpoint/plugin/hystrix/HystrixPluginConstants.java b/plugins/hystrix/src/main/java/com/navercorp/pinpoint/plugin/hystrix/HystrixPluginConstants.java index 479dbfd8096a..6ba1b24da835 100644 --- a/plugins/hystrix/src/main/java/com/navercorp/pinpoint/plugin/hystrix/HystrixPluginConstants.java +++ b/plugins/hystrix/src/main/java/com/navercorp/pinpoint/plugin/hystrix/HystrixPluginConstants.java @@ -1,10 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -25,19 +26,23 @@ * @author Jiaqi Feng * @author HyunGil Jeong */ -public interface HystrixPluginConstants { - ServiceType HYSTRIX_SERVICE_TYPE = ServiceTypeFactory.of(9120, "HYSTRIX_COMMAND"); - ServiceType HYSTRIX_INTERNAL_SERVICE_TYPE = ServiceTypeFactory.of(9121, "HYSTRIX_COMMAND_INTERNAL", "HYSTRIX_COMMAND"); +public final class HystrixPluginConstants { + private HystrixPluginConstants() { + } + + public static final ServiceType HYSTRIX_SERVICE_TYPE = ServiceTypeFactory.of(9120, "HYSTRIX_COMMAND"); + public static final ServiceType HYSTRIX_INTERNAL_SERVICE_TYPE = ServiceTypeFactory.of(9121, "HYSTRIX_COMMAND_INTERNAL", "HYSTRIX_COMMAND"); - AnnotationKey HYSTRIX_COMMAND_ANNOTATION_KEY = AnnotationKeyFactory.of(110, "hystrix.command", VIEW_IN_RECORD_SET); - @Deprecated AnnotationKey HYSTRIX_COMMAND_EXECUTION_ANNOTATION_KEY = AnnotationKeyFactory.of(111, "hystrix.command.execution", VIEW_IN_RECORD_SET); - AnnotationKey HYSTRIX_FALLBACK_CAUSE_ANNOTATION_KEY = AnnotationKeyFactory.of(112, "hystrix.command.fallback.cause", VIEW_IN_RECORD_SET); - AnnotationKey HYSTRIX_FALLBACK_EXCEPTION_ANNOTATION_KEY = AnnotationKeyFactory.of(113, "hystrix.command.exception", VIEW_IN_RECORD_SET); + public static final AnnotationKey HYSTRIX_COMMAND_ANNOTATION_KEY = AnnotationKeyFactory.of(110, "hystrix.command", VIEW_IN_RECORD_SET); + @Deprecated + public static final AnnotationKey HYSTRIX_COMMAND_EXECUTION_ANNOTATION_KEY = AnnotationKeyFactory.of(111, "hystrix.command.execution", VIEW_IN_RECORD_SET); + public static final AnnotationKey HYSTRIX_FALLBACK_CAUSE_ANNOTATION_KEY = AnnotationKeyFactory.of(112, "hystrix.command.fallback.cause", VIEW_IN_RECORD_SET); + public static final AnnotationKey HYSTRIX_FALLBACK_EXCEPTION_ANNOTATION_KEY = AnnotationKeyFactory.of(113, "hystrix.command.exception", VIEW_IN_RECORD_SET); - AnnotationKey HYSTRIX_COMMAND_KEY_ANNOTATION_KEY = AnnotationKeyFactory.of(115, "hystrix.command.key", VIEW_IN_RECORD_SET); - AnnotationKey HYSTRIX_COMMAND_GROUP_KEY_ANNOTATION_KEY = AnnotationKeyFactory.of(116, "hystrix.command.group.key", VIEW_IN_RECORD_SET); - AnnotationKey HYSTRIX_THREAD_POOL_KEY_ANNOTATION_KEY = AnnotationKeyFactory.of(117, "hystrix.thread.pool.key", VIEW_IN_RECORD_SET); - AnnotationKey HYSTRIX_COLLAPSER_KEY_ANNOTATION_KEY = AnnotationKeyFactory.of(118, "hystrix.collapser.key", VIEW_IN_RECORD_SET); + public static final AnnotationKey HYSTRIX_COMMAND_KEY_ANNOTATION_KEY = AnnotationKeyFactory.of(115, "hystrix.command.key", VIEW_IN_RECORD_SET); + public static final AnnotationKey HYSTRIX_COMMAND_GROUP_KEY_ANNOTATION_KEY = AnnotationKeyFactory.of(116, "hystrix.command.group.key", VIEW_IN_RECORD_SET); + public static final AnnotationKey HYSTRIX_THREAD_POOL_KEY_ANNOTATION_KEY = AnnotationKeyFactory.of(117, "hystrix.thread.pool.key", VIEW_IN_RECORD_SET); + public static final AnnotationKey HYSTRIX_COLLAPSER_KEY_ANNOTATION_KEY = AnnotationKeyFactory.of(118, "hystrix.collapser.key", VIEW_IN_RECORD_SET); - String HYSTRIX_COMMAND_EXECUTION_SCOPE = "HystrixCommandExecutionScope"; + public static final String HYSTRIX_COMMAND_EXECUTION_SCOPE = "HystrixCommandExecutionScope"; } diff --git a/plugins/ibatis/clover.license b/plugins/ibatis/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/ibatis/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-ibatis-plugin diff --git a/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisConstants.java b/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisConstants.java new file mode 100644 index 000000000000..9ce38ba284d8 --- /dev/null +++ b/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisConstants.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ibatis; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class IBatisConstants { + private IBatisConstants() { + } + + public static final ServiceType IBATIS = ServiceTypeFactory.of(5500, "IBATIS"); + public static final ServiceType IBATIS_SPRING = ServiceTypeFactory.of(5501, "IBATIS_SPRING", "IBATIS"); +} diff --git a/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisMetadataProvider.java b/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisMetadataProvider.java index b1e1c9fed625..56975bf77b99 100644 --- a/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisMetadataProvider.java +++ b/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisMetadataProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2015 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,7 +27,7 @@ public class IBatisMetadataProvider implements TraceMetadataProvider { @Override public void setup(TraceMetadataSetupContext context) { - context.addServiceType(IBatisPlugin.IBATIS, AnnotationKeyMatchers.ARGS_MATCHER); - context.addServiceType(IBatisPlugin.IBATIS_SPRING, AnnotationKeyMatchers.ARGS_MATCHER); + context.addServiceType(IBatisConstants.IBATIS, AnnotationKeyMatchers.ARGS_MATCHER); + context.addServiceType(IBatisConstants.IBATIS_SPRING, AnnotationKeyMatchers.ARGS_MATCHER); } } diff --git a/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisPlugin.java b/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisPlugin.java index a9d34c6bdc57..c7a2b79076c5 100644 --- a/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisPlugin.java +++ b/plugins/ibatis/src/main/java/com/navercorp/pinpoint/plugin/ibatis/IBatisPlugin.java @@ -1,11 +1,11 @@ /* - * Copyright 2015 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -36,16 +36,12 @@ import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; /** * @author HyunGil Jeong */ public class IBatisPlugin implements ProfilerPlugin, TransformTemplateAware { - public static final ServiceType IBATIS = ServiceTypeFactory.of(5500, "IBATIS"); - public static final ServiceType IBATIS_SPRING = ServiceTypeFactory.of(5501, "IBATIS_SPRING", "IBATIS"); - private static final String IBATIS_SCOPE = "IBATIS_SCOPE"; private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); @@ -65,7 +61,7 @@ public void setup(ProfilerPluginSetupContext context) { // SqlMapClient / SqlMapSession private void addInterceptorsForSqlMapExecutors() { - final ServiceType serviceType = IBATIS; + final ServiceType serviceType = IBatisConstants.IBATIS; final String[] sqlMapExecutorImplClasses = { "com.ibatis.sqlmap.engine.impl.SqlMapClientImpl", "com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl" }; addInterceptorsForClasses(serviceType, sqlMapExecutorImplClasses); @@ -73,7 +69,7 @@ private void addInterceptorsForSqlMapExecutors() { // SqlMapClientTemplate private void addInterceptorsForSqlMapClientTemplate() { - final ServiceType serviceType = IBATIS_SPRING; + final ServiceType serviceType = IBatisConstants.IBATIS_SPRING; final String[] sqlMapClientTemplateClasses = { "org.springframework.orm.ibatis.SqlMapClientTemplate" }; addInterceptorsForClasses(serviceType, sqlMapClientTemplateClasses); } diff --git a/plugins/jackson/clover.license b/plugins/jackson/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/plugins/jackson/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-jackson-plugin diff --git a/plugins/jboss/clover.license b/plugins/jboss/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/jboss/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 @@ -5,7 +21,7 @@ com.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-jboss-plugin @@ -53,5 +69,41 @@ commons-lang3 test + + + com.navercorp.pinpoint + pinpoint-common-servlet + ${project.version} + compile + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${plugin.shade.version} + + + package + + shade + + + + + com.navercorp.pinpoint.plugin.common.servlet + com.navercorp.pinpoint.plugin.jboss.common.servlet + + + + ${project.build.directory}/dependency-reduced-pom.xml + + + + + + + diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/AsyncAccessor.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/AsyncAccessor.java deleted file mode 100644 index 2ba0488d98bb..000000000000 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/AsyncAccessor.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016 Pinpoint contributors and NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.jboss; - -/** - * The Interface AsyncAccessor. - * - */ -public interface AsyncAccessor { - - /** - * $ PINPOIN t$ set async. - * - * @param async the async - */ - void _$PINPOINT$_setAsync(final boolean async); - - /** - * $ PINPOIN t$ is async. - * - * @return true, if successful - */ - boolean _$PINPOINT$_isAsync(); -} \ No newline at end of file diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossAsyncListener.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossAsyncListener.java new file mode 100644 index 000000000000..e61e0b1405fc --- /dev/null +++ b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossAsyncListener.java @@ -0,0 +1,122 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jboss; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.AsyncListenerInterceptorHelper; + +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author jaehong.kim + */ +public class JbossAsyncListener implements AsyncListener { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private final AsyncListenerInterceptorHelper asyncListenerInterceptorHelper; + + public JbossAsyncListener(final TraceContext traceContext, final AsyncContext asyncContext) { + this.asyncListenerInterceptorHelper = new AsyncListenerInterceptorHelper(traceContext, asyncContext); + } + + @Override + public void onComplete(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Complete asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + final int statusCode = getStatusCode(asyncEvent); + this.asyncListenerInterceptorHelper.complete(asyncEvent.getThrowable(), statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + } + + @Override + public void onTimeout(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Timeout asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.timeout(asyncEvent.getThrowable()); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onError(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Error asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + // Use complete() because it does not conform to the AsyncListener spec. + final int statusCode = getStatusCode(asyncEvent); + this.asyncListenerInterceptorHelper.complete(asyncEvent.getThrowable(), statusCode); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onStartAsync(AsyncEvent asyncEvent) throws IOException { + } + + private int getStatusCode(final AsyncEvent asyncEvent) { + try { + if (asyncEvent.getSuppliedResponse() instanceof HttpServletResponse) { + return ((HttpServletResponse) asyncEvent.getSuppliedResponse()).getStatus(); + } + } catch (Exception ignored) { + } + return 0; + } +} \ No newline at end of file diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossConfig.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossConfig.java index 548ff6fd041f..dd2ca0b4059b 100644 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossConfig.java +++ b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossConfig.java @@ -28,26 +28,33 @@ * The Class JbossConfig. * * @author Suraj Raturi + * @author jaehong.kim */ public class JbossConfig { - /** The jboss hide pinpoint header. */ - private final boolean jbossHidePinpointHeader; + /** + * The jboss hide pinpoint header. + */ + private final boolean hidePinpointHeader; - /** The jboss exclude url filter. */ - private final Filter jbossExcludeUrlFilter; + /** + * The jboss exclude url filter. + */ + private final Filter excludeUrlFilter; - /** The jboss trace ejb. */ - private final boolean jbossTraceEjb; - private final boolean jbossEnable; + /** + * The jboss trace ejb. + */ + private final boolean traceEjb; + private final boolean enable; - private final List jbossBootstrapMains; - private final boolean jbossConditionalTransformEnable; + private final List bootstrapMains; + private final boolean conditionalTransformEnable; - private final String jbossRealIpHeader; - private final String jbossRealIpEmptyValue; - private final boolean jbossTraceRequestParam; - private final Filter jbossExcludeProfileMethodFilter; + private final String realIpHeader; + private final String realIpEmptyValue; + private final boolean traceRequestParam; + private final Filter excludeProfileMethodFilter; /** * Instantiates a new jboss configuration. @@ -55,41 +62,41 @@ public class JbossConfig { * @param config the config */ public JbossConfig(final ProfilerConfig config) { - this.jbossEnable = config.readBoolean("profiler.jboss.enable", true); - this.jbossTraceEjb = config.readBoolean("profiler.jboss.traceEjb", false); + this.enable = config.readBoolean("profiler.jboss.enable", true); + this.traceEjb = config.readBoolean("profiler.jboss.traceEjb", false); - this.jbossBootstrapMains = config.readList("profiler.jboss.bootstrap.main"); - this.jbossConditionalTransformEnable = config.readBoolean("profiler.jboss.conditional.transform", true); - this.jbossHidePinpointHeader = config.readBoolean("profiler.jboss.hidepinpointheader", true); + this.bootstrapMains = config.readList("profiler.jboss.bootstrap.main"); + this.conditionalTransformEnable = config.readBoolean("profiler.jboss.conditional.transform", true); + this.hidePinpointHeader = config.readBoolean("profiler.jboss.hidepinpointheader", true); - this.jbossTraceRequestParam = config.readBoolean("profiler.jboss.tracerequestparam", true); + this.traceRequestParam = config.readBoolean("profiler.jboss.tracerequestparam", true); final String jbossExcludeURL = config.readString("profiler.jboss.excludeurl", ""); if (!jbossExcludeURL.isEmpty()) { - this.jbossExcludeUrlFilter = new ExcludePathFilter(jbossExcludeURL); + this.excludeUrlFilter = new ExcludePathFilter(jbossExcludeURL); } else { - this.jbossExcludeUrlFilter = new SkipFilter(); + this.excludeUrlFilter = new SkipFilter(); } - this.jbossRealIpHeader = config.readString("profiler.jboss.realipheader", null); - this.jbossRealIpEmptyValue = config.readString("profiler.jboss.realipemptyvalue", null); + this.realIpHeader = config.readString("profiler.jboss.realipheader", null); + this.realIpEmptyValue = config.readString("profiler.jboss.realipemptyvalue", null); final String jbossExcludeProfileMethod = config.readString("profiler.jboss.excludemethod", ""); if (!jbossExcludeProfileMethod.isEmpty()) { - this.jbossExcludeProfileMethodFilter = new ExcludeMethodFilter(jbossExcludeProfileMethod); + this.excludeProfileMethodFilter = new ExcludeMethodFilter(jbossExcludeProfileMethod); } else { - this.jbossExcludeProfileMethodFilter = new SkipFilter(); + this.excludeProfileMethodFilter = new SkipFilter(); } } - public boolean isJbossEnable() { - return jbossEnable; + public boolean isEnable() { + return enable; } - public List getJbossBootstrapMains() { - return jbossBootstrapMains; + public List getBootstrapMains() { + return bootstrapMains; } - public boolean isJbossConditionalTransformEnable() { - return jbossConditionalTransformEnable; + public boolean isConditionalTransformEnable() { + return conditionalTransformEnable; } /** @@ -97,8 +104,8 @@ public boolean isJbossConditionalTransformEnable() { * * @return true, if is jboss hide pinpoint header */ - public boolean isJbossHidePinpointHeader() { - return jbossHidePinpointHeader; + public boolean isHidePinpointHeader() { + return hidePinpointHeader; } /** @@ -106,8 +113,8 @@ public boolean isJbossHidePinpointHeader() { * * @return the jboss exclude url filter */ - public Filter getJbossExcludeUrlFilter() { - return jbossExcludeUrlFilter; + public Filter getExcludeUrlFilter() { + return excludeUrlFilter; } /** @@ -115,34 +122,40 @@ public Filter getJbossExcludeUrlFilter() { * * @return true, if is jboss trace ejb */ - public boolean isJbossTraceEjb() { - return jbossTraceEjb; + public boolean isTraceEjb() { + return traceEjb; } - public String getJbossRealIpHeader() { - return jbossRealIpHeader; + public String getRealIpHeader() { + return realIpHeader; } - public String getJbossRealIpEmptyValue() { - return jbossRealIpEmptyValue; + public String getRealIpEmptyValue() { + return realIpEmptyValue; } - public boolean isJbossTraceRequestParam() { - return jbossTraceRequestParam; + public boolean isTraceRequestParam() { + return traceRequestParam; } - public Filter getJbossExcludeProfileMethodFilter() { - return jbossExcludeProfileMethodFilter; + public Filter getExcludeProfileMethodFilter() { + return excludeProfileMethodFilter; } @Override public String toString() { final StringBuilder sb = new StringBuilder("JbossConfig{"); - sb.append("jbossHidePinpointHeader=").append(jbossHidePinpointHeader); - sb.append(", jbossExcludeUrlFilter=").append(jbossExcludeUrlFilter); - sb.append(", jbossTraceEjb=").append(jbossTraceEjb); - sb.append(", jbossEnable=").append(jbossEnable); + sb.append("hidePinpointHeader=").append(hidePinpointHeader); + sb.append(", excludeUrlFilter=").append(excludeUrlFilter); + sb.append(", traceEjb=").append(traceEjb); + sb.append(", enable=").append(enable); + sb.append(", bootstrapMains=").append(bootstrapMains); + sb.append(", conditionalTransformEnable=").append(conditionalTransformEnable); + sb.append(", realIpHeader='").append(realIpHeader).append('\''); + sb.append(", realIpEmptyValue='").append(realIpEmptyValue).append('\''); + sb.append(", traceRequestParam=").append(traceRequestParam); + sb.append(", excludeProfileMethodFilter=").append(excludeProfileMethodFilter); sb.append('}'); return sb.toString(); } diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossConstants.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossConstants.java index a5bb8f1370fc..826deec5ece1 100644 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossConstants.java +++ b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Pinpoint contributors and NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -23,13 +23,15 @@ * The Class JbossConstants. * * @author Suraj Raturi + * @author jaehong.kim */ public final class JbossConstants { + private JbossConstants() { + } /** The Constant JBOSS. */ public static final ServiceType JBOSS = ServiceTypeFactory.of(1040, "JBOSS", RECORD_STATISTICS); /** The Constant JBOSS_METHOD. */ public static final ServiceType JBOSS_METHOD = ServiceTypeFactory.of(1041, "JBOSS_METHOD"); - } diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossPlugin.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossPlugin.java index f7a12fedc992..967d437eb35d 100644 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossPlugin.java +++ b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/JbossPlugin.java @@ -34,71 +34,100 @@ * The Class JbossPlugin. * * @author Suraj Raturi + * @author jaehong.kim */ public class JbossPlugin implements ProfilerPlugin, TransformTemplateAware { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isInfo = logger.isInfoEnabled(); - /** The transform template. */ + /** + * The transform template. + */ private TransformTemplate transformTemplate; @Override public void setup(final ProfilerPluginSetupContext context) { final JbossConfig jbossConfig = new JbossConfig(context.getConfig()); - if (logger.isInfoEnabled()) { - logger.info("JBossPlugin config:{}", jbossConfig); - } - if (!jbossConfig.isJbossEnable()) { - logger.info("JBossPlugin disabled"); + if (!jbossConfig.isEnable()) { + if (isInfo) { + logger.info("JBossPlugin disabled"); + } return; } - JbossDetector jbossDetector = new JbossDetector(jbossConfig.getJbossBootstrapMains()); + if (isInfo) { + logger.info("JBossPlugin config:{}", jbossConfig); + } + + final JbossDetector jbossDetector = new JbossDetector(jbossConfig.getBootstrapMains()); context.addApplicationTypeDetector(jbossDetector); if (shouldAddTransformers(jbossConfig)) { - logger.info("Adding JBoss transformers"); + if (isInfo) { + logger.info("Adding JBoss transformers"); + } addTransformers(jbossConfig); } else { - logger.info("Not adding JBoss transformers"); + if (isInfo) { + logger.info("Not adding JBoss transformers"); + } } } private boolean shouldAddTransformers(JbossConfig jbossConfig) { // Transform if conditional check is disabled - if (!jbossConfig.isJbossConditionalTransformEnable()) { + if (!jbossConfig.isConditionalTransformEnable()) { return true; } // Only transform if it's a JBoss application ConditionProvider conditionProvider = ConditionProvider.DEFAULT_CONDITION_PROVIDER; - boolean isJbossApplication = conditionProvider.checkMainClass(jbossConfig.getJbossBootstrapMains()); + boolean isJbossApplication = conditionProvider.checkMainClass(jbossConfig.getBootstrapMains()); return isJbossApplication; } private void addTransformers(JbossConfig jbossConfig) { // Instrumenting class on the base of ejb based application or rest based application. - if (jbossConfig.isJbossTraceEjb()) { + if (jbossConfig.isTraceEjb()) { addMethodInvocationMessageHandlerEditor(); } else { - if(jbossConfig.isJbossHidePinpointHeader()) { - requestFacade(); - } - addStandardHostValveEditor(); + // Add async listener. Servlet 3.0 + addRequestEditor(); addContextInvocationEditor(); + // Hide pinpoint headers + requestFacade(jbossConfig); + // Clear bind trace. defense code + addStandardHostValveEditor(); } } - private void requestFacade() { + private void requestFacade(final JbossConfig jbossConfig) { transformTemplate.transform("org.apache.catalina.connector.RequestFacade", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - if (target != null) { + if (jbossConfig.isHidePinpointHeader()) { + // Hide pinpoint headers target.weave("com.navercorp.pinpoint.plugin.jboss.aspect.RequestFacadeAspect"); - return target.toBytecode(); + } + return target.toBytecode(); + } + }); + } + + private void addRequestEditor() { + transformTemplate.transform("org.apache.catalina.connector.Request", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Add async listener. Servlet 3.0 + InstrumentMethod startAsyncMethodEditor = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); + if (startAsyncMethodEditor != null) { + startAsyncMethodEditor.addInterceptor("com.navercorp.pinpoint.plugin.jboss.interceptor.RequestStartAsyncInterceptor"); } - return null; + return target.toBytecode(); } }); } @@ -111,13 +140,13 @@ private void addMethodInvocationMessageHandlerEditor() { @Override public byte[] doInTransform(final Instrumentor instrumentor, final ClassLoader classLoader, final String className, final Class classBeingRedefined, - final ProtectionDomain protectionDomain, - final byte[] classfileBuffer) throws InstrumentException { + final ProtectionDomain protectionDomain, + final byte[] classfileBuffer) throws InstrumentException { final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - + // Support EJB final InstrumentMethod method = - target.getDeclaredMethod("invokeMethod", new String[] { "short", "org.jboss.as.ee.component.ComponentView", "java.lang.reflect.Method", "java.lang.Object[]", - "org.jboss.ejb.client.EJBLocator", "java.util.Map" }); + target.getDeclaredMethod("invokeMethod", new String[]{"short", "org.jboss.as.ee.component.ComponentView", "java.lang.reflect.Method", "java.lang.Object[]", + "org.jboss.ejb.client.EJBLocator", "java.util.Map"}); if (method != null) { method.addInterceptor("com.navercorp.pinpoint.plugin.jboss.interceptor.MethodInvocationHandlerInterceptor"); } @@ -130,18 +159,16 @@ public byte[] doInTransform(final Instrumentor instrumentor, final ClassLoader c /** * Adds the context invocation editor. - * - * */ private void addContextInvocationEditor() { transformTemplate.transform("org.jboss.as.ejb3.tx.EjbBMTInterceptor", new TransformCallback() { @Override public byte[] doInTransform(final Instrumentor instrumentor, final ClassLoader classLoader, final String className, final Class classBeingRedefined, - final ProtectionDomain protectionDomain, - final byte[] classfileBuffer) throws InstrumentException { + final ProtectionDomain protectionDomain, + final byte[] classfileBuffer) throws InstrumentException { final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - + // EJB final InstrumentMethod method = target.getDeclaredMethod("handleInvocation", "org.jboss.invocation.InterceptorContext"); if (method != null) { method.addInterceptor("com.navercorp.pinpoint.plugin.jboss.interceptor.ContextInvocationInterceptor"); @@ -150,27 +177,24 @@ public byte[] doInTransform(final Instrumentor instrumentor, final ClassLoader c return target.toBytecode(); } }); - } /** * Adds the standard host valve editor. - * */ private void addStandardHostValveEditor() { transformTemplate.transform("org.apache.catalina.core.StandardHostValve", new TransformCallback() { @Override public byte[] doInTransform(final Instrumentor instrumentor, final ClassLoader classLoader, final String className, final Class classBeingRedefined, - final ProtectionDomain protectionDomain, - final byte[] classfileBuffer) throws InstrumentException { + final ProtectionDomain protectionDomain, + final byte[] classfileBuffer) throws InstrumentException { final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - - final InstrumentMethod method = target.getDeclaredMethod("invoke", "org.apache.catalina.connector.Request", "org.apache.catalina.connector.Response"); - if (method != null) { - method.addInterceptor("com.navercorp.pinpoint.plugin.jboss.interceptor.StandardHostValveInvokeInterceptor"); + // Clear bind trace + final InstrumentMethod invokeMethod = target.getDeclaredMethod("invoke", "org.apache.catalina.connector.Request", "org.apache.catalina.connector.Response"); + if (invokeMethod != null) { + invokeMethod.addInterceptor("com.navercorp.pinpoint.plugin.jboss.interceptor.StandardHostValveInvokeInterceptor"); } - return target.toBytecode(); } }); @@ -178,7 +202,7 @@ public byte[] doInTransform(final Instrumentor instrumentor, final ClassLoader c /* * (non-Javadoc) - * + * * @see com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware#setTransformTemplate(com.navercorp. * pinpoint.bootstrap.instrument.transformer.TransformTemplate) */ diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/ServletAsyncMethodDescriptor.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/ServletAsyncMethodDescriptor.java deleted file mode 100644 index 78a74d0c37aa..000000000000 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/ServletAsyncMethodDescriptor.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2016 Pinpoint contributors and NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.jboss; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.common.trace.MethodType; - -/** - * The Class ServletAsyncMethodDescriptor. - * - * @author jaehong.kim - */ -public class ServletAsyncMethodDescriptor implements MethodDescriptor { - - /** The api id. */ - private int apiId = 0; - - /** The type. */ - private int type = MethodType.WEB_REQUEST; - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getMethodName() - */ - @Override - public String getMethodName() { - return ""; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getClassName() - */ - @Override - public String getClassName() { - return ""; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getParameterTypes() - */ - @Override - public String[] getParameterTypes() { - return null; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getParameterVariableName() - */ - @Override - public String[] getParameterVariableName() { - return null; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getParameterDescriptor() - */ - @Override - public String getParameterDescriptor() { - return "()"; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getLineNumber() - */ - @Override - public int getLineNumber() { - return -1; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getFullName() - */ - @Override - public String getFullName() { - return ServletAsyncMethodDescriptor.class.getName(); - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#setApiId(int) - */ - @Override - public void setApiId(final int apiId) { - this.apiId = apiId; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getApiId() - */ - @Override - public int getApiId() { - return apiId; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getApiDescriptor() - */ - @Override - public String getApiDescriptor() { - return "Jboss Servlet Asynchronous Process"; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getType() - */ - @Override - public int getType() { - return type; - } - - /** - * Sets the type. - * - * @param type the new type - */ - public void setType(final int type) { - this.type = type; - } -} \ No newline at end of file diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/ServletSyncMethodDescriptor.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/ServletSyncMethodDescriptor.java deleted file mode 100644 index b20384b3f3d4..000000000000 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/ServletSyncMethodDescriptor.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2016 Pinpoint contributors and NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.jboss; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.common.trace.MethodType; - -/** - * The Class ServletSyncMethodDescriptor. - * - * @author jaehong.kim - */ -public class ServletSyncMethodDescriptor implements MethodDescriptor { - - /** The api id. */ - private int apiId = 0; - - /** The type. */ - private int type = MethodType.WEB_REQUEST; - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getMethodName() - */ - @Override - public String getMethodName() { - return ""; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getClassName() - */ - @Override - public String getClassName() { - return ""; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getParameterTypes() - */ - @Override - public String[] getParameterTypes() { - return null; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getParameterVariableName() - */ - @Override - public String[] getParameterVariableName() { - return null; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getParameterDescriptor() - */ - @Override - public String getParameterDescriptor() { - return "()"; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getLineNumber() - */ - @Override - public int getLineNumber() { - return -1; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getFullName() - */ - @Override - public String getFullName() { - return ServletSyncMethodDescriptor.class.getName(); - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#setApiId(int) - */ - @Override - public void setApiId(final int apiId) { - this.apiId = apiId; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getApiId() - */ - @Override - public int getApiId() { - return apiId; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getApiDescriptor() - */ - @Override - public String getApiDescriptor() { - return "Jboss Servlet Process"; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.MethodDescriptor#getType() - */ - @Override - public int getType() { - return type; - } - - /** - * Sets the type. - * - * @param type the new type - */ - public void setType(final int type) { - this.type = type; - } -} \ No newline at end of file diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/TraceAccessor.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/TraceAccessor.java deleted file mode 100644 index a39a6f6a0682..000000000000 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/TraceAccessor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 Pinpoint contributors and NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.jboss; - -import com.navercorp.pinpoint.bootstrap.context.Trace; - -/** - * The Interface TraceAccessor. - * - */ -public interface TraceAccessor { - - /** - * $ PINPOIN t$ set trace. - * - * @param trace the trace - */ - void _$PINPOINT$_setTrace(final Trace trace); - - /** - * $ PINPOIN t$ get trace. - * - * @return the trace - */ - Trace _$PINPOINT$_getTrace(); -} \ No newline at end of file diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/aspect/RequestFacadeAspect.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/aspect/RequestFacadeAspect.java index c3972df2802d..8acbcaec66d4 100644 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/aspect/RequestFacadeAspect.java +++ b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/aspect/RequestFacadeAspect.java @@ -21,41 +21,17 @@ import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; import com.navercorp.pinpoint.common.util.DelegateEnumeration; -import com.navercorp.pinpoint.common.util.EmptyEnumeration; import java.util.Enumeration; /** - * filtering pinpoint header + * Filtering pinpoint header * * @author emeroad * @author jaehong.kim */ @Aspect public abstract class RequestFacadeAspect { - - @PointCut - public String getHeader(String name) { - if (Header.startWithPinpointHeader(name)) { - return null; - } - return __getHeader(name); - } - - @JointPoint - abstract String __getHeader(String name); - - @PointCut - public Enumeration getHeaders(String name) { - if (Header.startWithPinpointHeader(name)) { - return new EmptyEnumeration(); - } - return __getHeaders(name); - } - - @JointPoint - abstract Enumeration __getHeaders(String name); - @PointCut public Enumeration getHeaderNames() { return new DelegateEnumeration(__getHeaderNames(), Header.FILTER); diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/ContextInvocationInterceptor.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/ContextInvocationInterceptor.java index 769439605956..b2d6a8417c74 100644 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/ContextInvocationInterceptor.java +++ b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/ContextInvocationInterceptor.java @@ -23,46 +23,49 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.jboss.ContextInvocationMethodDescriptor; import com.navercorp.pinpoint.plugin.jboss.JbossConstants; /** * The Class ContextInvocationInterceptor. * * @author Suraj Raturi + * @author jaehong.kim */ public class ContextInvocationInterceptor implements AroundInterceptor { - - /** The Constant CONTEXT_INVOCATION_API_TAG. */ - public static final ContextInvocationMethodDescriptor CONTEXT_INVOCATION_API_TAG = new ContextInvocationMethodDescriptor(); - - /** The logger. */ + /** + * The logger. + */ private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); - /** The is debug. */ + /** + * The is debug. + */ private final boolean isDebug = logger.isDebugEnabled(); - /** The method descriptor. */ + /** + * The method descriptor. + */ private final MethodDescriptor methodDescriptor; - /** The trace context. */ + /** + * The trace context. + */ private final TraceContext traceContext; /** * Instantiates a new invoke context interceptor. * * @param traceContext the trace context - * @param descriptor the descriptor + * @param descriptor the descriptor */ public ContextInvocationInterceptor(final TraceContext traceContext, final MethodDescriptor descriptor) { this.traceContext = traceContext; this.methodDescriptor = descriptor; - traceContext.cacheApi(CONTEXT_INVOCATION_API_TAG); } /* * (non-Javadoc) - * + * * @see com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor#before(java.lang.Object, java.lang.Object[]) */ @Override @@ -89,7 +92,7 @@ public void before(final Object target, final Object[] args) { /* * (non-Javadoc) - * + * * @see com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor#after(java.lang.Object, java.lang.Object[], * java.lang.Object, java.lang.Throwable) */ @@ -104,7 +107,6 @@ public void after(final Object target, final Object[] args, final Object result, } if (!trace.canSampled()) { - traceContext.removeTraceObject(); return; } try { @@ -119,5 +121,4 @@ public void after(final Object target, final Object[] args, final Object result, trace.traceBlockEnd(); } } - -} +} \ No newline at end of file diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/MethodInvocationHandlerInterceptor.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/MethodInvocationHandlerInterceptor.java index 0a8dba846419..1557aa67933e 100644 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/MethodInvocationHandlerInterceptor.java +++ b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/MethodInvocationHandlerInterceptor.java @@ -37,6 +37,7 @@ * The Class MethodInvocationHandlerInterceptor. * * @author Suraj Raturi + * @author jaehong.kim */ public class MethodInvocationHandlerInterceptor implements AroundInterceptor { @@ -173,6 +174,7 @@ public void after(final Object target, final Object[] args, final Object result, if (!trace.canSampled()) { traceContext.removeTraceObject(); + trace.close(); return; } try { diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/RequestStartAsyncInterceptor.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/RequestStartAsyncInterceptor.java new file mode 100644 index 000000000000..76ac8ad6026b --- /dev/null +++ b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/RequestStartAsyncInterceptor.java @@ -0,0 +1,114 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jboss.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.jboss.JbossAsyncListener; +import com.navercorp.pinpoint.plugin.jboss.JbossConstants; + +import javax.servlet.AsyncContext; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletRequest; + +/** + * @author jaehong.kim + */ +public class RequestStartAsyncInterceptor implements AroundInterceptor { + + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor descriptor; + + public RequestStartAsyncInterceptor(TraceContext context, MethodDescriptor descriptor) { + this.traceContext = context; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + if (validate(target, result, throwable)) { + // Add async listener. Servlet 3.0 + final AsyncContext asyncContext = (AsyncContext) result; + final AsyncListener asyncListener = new JbossAsyncListener(this.traceContext, recorder.recordNextAsyncContext(true)); + asyncContext.addListener(asyncListener); + if (isDebug) { + logger.debug("Add async listener {}", asyncListener); + } + } + + recorder.recordServiceType(JbossConstants.JBOSS_METHOD); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + } catch (Throwable t) { + logger.warn("Failed to AFTER process. {}", t.getMessage(), t); + } finally { + trace.traceBlockEnd(); + } + } + + private boolean validate(final Object target, final Object result, final Throwable throwable) { + if (throwable != null || result == null) { + return false; + } + + if (!(target instanceof HttpServletRequest)) { + if (isDebug) { + logger.debug("Invalid target object, The javax.servlet.http.HttpServletRequest interface is not implemented. target={}", target); + } + return false; + } + if (!(result instanceof AsyncContext)) { + if (isDebug) { + logger.debug("Invalid result object, The javax.servlet.AsyncContext interface is not implemented. result={}.", result); + } + return false; + } + return true; + } +} \ No newline at end of file diff --git a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/StandardHostValveInvokeInterceptor.java b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/StandardHostValveInvokeInterceptor.java index 7c8bc6936e6e..7fa88e66987c 100644 --- a/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/StandardHostValveInvokeInterceptor.java +++ b/plugins/jboss/src/main/java/com/navercorp/pinpoint/plugin/jboss/interceptor/StandardHostValveInvokeInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 Pinpoint contributors and NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,559 +16,117 @@ package com.navercorp.pinpoint.plugin.jboss.interceptor; -import java.util.Enumeration; - -import javax.servlet.http.HttpServletRequest; - -import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.RemoteAddressResolver; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.SpanId; -import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; -import com.navercorp.pinpoint.bootstrap.context.Trace; import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.context.TraceId; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderHandler; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderRecorder; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; -import com.navercorp.pinpoint.bootstrap.util.NumberUtils; -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.plugin.jboss.AsyncAccessor; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServletRequestListenerInterceptorHelper; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.RemoteAddressResolverFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.ArgumentValidator; +import com.navercorp.pinpoint.plugin.common.servlet.util.HttpServletRequestAdaptor; +import com.navercorp.pinpoint.plugin.common.servlet.util.ParameterRecorderFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.ServletArgumentValidator; import com.navercorp.pinpoint.plugin.jboss.JbossConfig; import com.navercorp.pinpoint.plugin.jboss.JbossConstants; -import com.navercorp.pinpoint.plugin.jboss.ServletAsyncMethodDescriptor; -import com.navercorp.pinpoint.plugin.jboss.ServletSyncMethodDescriptor; -import com.navercorp.pinpoint.plugin.jboss.TraceAccessor; + +import javax.servlet.DispatcherType; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** * The Class StandardHostValveInvokeInterceptor. * + * @author Suraj Raturi * @author emeroad * @author jaehong.kim */ public class StandardHostValveInvokeInterceptor implements AroundInterceptor { - - /** The Constant SERVLET_SYNCHRONOUS_API_TAG. */ - public static final ServletSyncMethodDescriptor SERVLET_SYNCHRONOUS_API_TAG = new ServletSyncMethodDescriptor(); - - /** The Constant SERVLET_ASYNCHRONOUS_API_TAG. */ - public static final ServletAsyncMethodDescriptor SERVLET_ASYNCHRONOUS_API_TAG = new ServletAsyncMethodDescriptor(); - - /** The logger. */ private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); - - /** The is debug. */ private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); - /** The is trace. */ - private final boolean isTrace = logger.isTraceEnabled(); - - /** The is trace request param. */ - private final boolean isTraceRequestParam; - - /** The exclude url filter. */ - private final Filter excludeUrlFilter; - - /** The exclude profile method filter. */ - private final Filter excludeProfileMethodFilter; - - /** The remote address resolver. */ - private final RemoteAddressResolver remoteAddressResolver; - - /** The method descriptor. */ private final MethodDescriptor methodDescriptor; - - /** The trace context. */ - private final TraceContext traceContext; - - private final ProxyHttpHeaderRecorder proxyHttpHeaderRecorder; + private final ArgumentValidator argumentValidator; + private final ServletRequestListenerInterceptorHelper servletRequestListenerInterceptorHelper; /** * Instantiates a new standard host valve invoke interceptor. * * @param traceContext the trace context - * @param descriptor the descriptor + * @param descriptor the descriptor */ public StandardHostValveInvokeInterceptor(final TraceContext traceContext, final MethodDescriptor descriptor) { - this.traceContext = traceContext; this.methodDescriptor = descriptor; - - JbossConfig jbossConfig = new JbossConfig(traceContext.getProfilerConfig()); - this.excludeUrlFilter = jbossConfig.getJbossExcludeUrlFilter(); - - final String proxyIpHeader = jbossConfig.getJbossRealIpHeader(); - if (StringUtils.isEmpty(proxyIpHeader)) { - this.remoteAddressResolver = new Bypass(); - } else { - final String jbossRealIpEmptyValue = jbossConfig.getJbossRealIpEmptyValue(); - this.remoteAddressResolver = new RealIpHeaderResolver(proxyIpHeader, jbossRealIpEmptyValue); - } - this.isTraceRequestParam = jbossConfig.isJbossTraceRequestParam(); - this.excludeProfileMethodFilter = jbossConfig.getJbossExcludeProfileMethodFilter(); - this.proxyHttpHeaderRecorder = new ProxyHttpHeaderRecorder(traceContext.getProfilerConfig().isProxyHttpHeaderEnable()); - - traceContext.cacheApi(SERVLET_ASYNCHRONOUS_API_TAG); - traceContext.cacheApi(SERVLET_SYNCHRONOUS_API_TAG); + this.argumentValidator = new ServletArgumentValidator(logger, 0, HttpServletRequest.class, 1, HttpServletResponse.class); + final JbossConfig config = new JbossConfig(traceContext.getProfilerConfig()); + RequestAdaptor requestAdaptor = new HttpServletRequestAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, config.getRealIpHeader(), config.getRealIpEmptyValue()); + ParameterRecorder parameterRecorder = ParameterRecorderFactory.newParameterRecorderFactory(config.getExcludeProfileMethodFilter(), config.isTraceRequestParam()); + this.servletRequestListenerInterceptorHelper = new ServletRequestListenerInterceptorHelper(JbossConstants.JBOSS, traceContext, requestAdaptor, config.getExcludeUrlFilter(), parameterRecorder); } - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor#before(java.lang.Object, java.lang.Object[]) - */ @Override public void before(final Object target, final Object[] args) { if (isDebug) { logger.beforeInterceptor(target, args); } - try { - final Trace trace = createTrace(target, args); - if (trace == null) { - return; - } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - return; - } - // ------------------------------------------------------ - final SpanEventRecorder recorder = trace.traceBlockBegin(); - recorder.recordServiceType(JbossConstants.JBOSS_METHOD); - } catch (final Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("BEFORE. Caused:{}", th.getMessage(), th); - } - } - } - - /** - * The Class Bypass. - * - * @param the generic type - */ - public static class Bypass implements RemoteAddressResolver { - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.RemoteAddressResolver#resolve(java.lang.Object) - */ - @Override - public String resolve(final T servletRequest) { - return servletRequest.getRemoteAddr(); - } - } - - /** - * The Class RealIpHeaderResolver. - * - * @param the generic type - */ - public static class RealIpHeaderResolver implements RemoteAddressResolver { - - /** The Constant X_FORWARDED_FOR. */ - public static final String X_FORWARDED_FOR = "x-forwarded-for"; - - /** The Constant X_REAL_IP. */ - public static final String X_REAL_IP = "x-real-ip"; - - /** The Constant UNKNOWN. */ - public static final String UNKNOWN = "unknown"; - - /** The real ip header name. */ - private final String realIpHeaderName; - - /** The empty header value. */ - private final String emptyHeaderValue; - - /** - * Instantiates a new real ip header resolver. - */ - public RealIpHeaderResolver() { - this(X_FORWARDED_FOR, UNKNOWN); - } - - /** - * Instantiates a new real ip header resolver. - * - * @param realIpHeaderName the real ip header name - * @param emptyHeaderValue the empty header value - */ - public RealIpHeaderResolver(final String realIpHeaderName, final String emptyHeaderValue) { - if (realIpHeaderName == null) { - throw new NullPointerException("realIpHeaderName must not be null"); - } - this.realIpHeaderName = realIpHeaderName; - this.emptyHeaderValue = emptyHeaderValue; - } - - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.context.RemoteAddressResolver#resolve(java.lang.Object) - */ - @Override - public String resolve(final T httpServletRequest) { - final String realIp = httpServletRequest.getHeader(this.realIpHeaderName); - - if (StringUtils.isEmpty(realIp)) { - return httpServletRequest.getRemoteAddr(); - } - - if ((emptyHeaderValue != null) && emptyHeaderValue.equalsIgnoreCase(realIp)) { - return httpServletRequest.getRemoteAddr(); - } - - final int firstIndex = realIp.indexOf(','); - if (firstIndex == -1) { - return realIp; - } else { - return realIp.substring(0, firstIndex); - } - } - } - - /** - * Creates the trace. - * - * @param target the target - * @param args the args - * @return the trace - */ - private Trace createTrace(final Object target, final Object[] args) { - final HttpServletRequest request = (HttpServletRequest) args[0]; - if (isAsynchronousProcess(request)) { - // servlet 3.0 - final Trace trace = getTraceMetadata(request); - if (trace != null) { - // change api - final SpanRecorder recorder = trace.getSpanRecorder(); - recorder.recordApi(SERVLET_ASYNCHRONOUS_API_TAG); - // attach current thread local. - traceContext.continueTraceObject(trace); - - return trace; - } - } - - final String requestURI = request.getRequestURI(); - if (excludeUrlFilter.filter(requestURI)) { - if (isTrace) { - logger.trace("filter requestURI:{}", requestURI); - } - return null; - } - - // check sampling flag from client. If the flag is false, do not sample this request. - final boolean sampling = samplingEnable(request); - if (!sampling) { - // Even if this transaction is not a sampling target, we have to create Trace object to mark 'not sampling'. - // For example, if this transaction invokes rpc call, we can add parameter to tell remote node 'don't sample this - // transaction' - final Trace trace = traceContext.disableSampling(); - if (isDebug) { - logger.debug("remotecall sampling flag found. skip trace requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - return trace; + if (!argumentValidator.validate(args)) { + return; } - final TraceId traceId = populateTraceIdFromRequest(request); - if (traceId != null) { - // TODO Maybe we should decide to trace or not even if the sampling flag is true to prevent too many requests are - // traced. - final Trace trace = traceContext.continueTraceObject(traceId); - if (trace.canSampled()) { - final SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - setTraceMetadata(request, trace); - if (isDebug) { - logger.debug("TraceID exist. continue trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), request.getRemoteAddr()); - } - } else { - if (isDebug) { - logger.debug("TraceID exist. camSampled is false. skip trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), - request.getRemoteAddr()); - } - } - return trace; - } else { - final Trace trace = traceContext.newTraceObject(); - if (trace.canSampled()) { - final SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - setTraceMetadata(request, trace); - if (isDebug) { - logger.debug("TraceID not exist. start new trace. requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - } else { + try { + final HttpServletRequest request = (HttpServletRequest) args[0]; + if (request.isAsyncStarted() || request.getDispatcherType() == DispatcherType.ASYNC) { if (isDebug) { - logger.debug("TraceID not exist. camSampled is false. skip trace. requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); + logger.debug("Skip async servlet request event. isAsyncStarted={}, dispatcherType={}", request.isAsyncStarted(), request.getDispatcherType()); } + return; } - return trace; - } - } - - /** - * Sets the trace metadata. - * - * @param request the request - * @param trace the trace - */ - private void setTraceMetadata(final HttpServletRequest request, final Trace trace) { - if (request instanceof TraceAccessor) { - ((TraceAccessor) request)._$PINPOINT$_setTrace(trace); - } - } - - /** - * Gets the trace metadata. - * - * @param request the request - * @return the trace metadata - */ - private Trace getTraceMetadata(final HttpServletRequest request) { - if (!(request instanceof TraceAccessor)) { - return null; - } - - return ((TraceAccessor) request)._$PINPOINT$_getTrace(); - } - - /** - * Gets the async metadata. - * - * @param request the request - * @return the async metadata - */ - private boolean getAsyncMetadata(final HttpServletRequest request) { - if (!(request instanceof AsyncAccessor)) { - return false; - } - - return ((AsyncAccessor) request)._$PINPOINT$_isAsync(); - } - - /** - * Checks if is asynchronous process. - * - * @param request the request - * @return true, if is asynchronous process - */ - private boolean isAsynchronousProcess(final HttpServletRequest request) { - if (getTraceMetadata(request) == null) { - return false; - } - - return getAsyncMetadata(request); - } - - /** - * Record root span. - * - * @param recorder the recorder - * @param request the request - */ - private void recordRootSpan(final SpanRecorder recorder, final HttpServletRequest request) { - // root - recorder.recordServiceType(JbossConstants.JBOSS); - - final String requestURL = request.getRequestURI(); - recorder.recordRpcName(requestURL); - - final int port = request.getServerPort(); - final String endPoint = HostAndPort.toHostAndPortString(request.getServerName(), port); - recorder.recordEndPoint(endPoint); - - final String remoteAddress = remoteAddressResolver.resolve(request); - // TODO API safety check required - // Potential Risk - // 1. Implicit DNSLookup (InetAddress.getByName()) - // 2. DNSLookup can cause thread blocking. - // 3. difficult format parsing problem in collector -// recorder.recordRemoteAddress(JbossUtility.fetchRemoteAddressDetails(remoteAddress)); - recorder.recordRemoteAddress(remoteAddress); - if (!recorder.isRoot()) { - recordParentInfo(recorder, request); - } - recorder.recordApi(SERVLET_SYNCHRONOUS_API_TAG); - - // record proxy HTTP headers. - this.proxyHttpHeaderRecorder.record(recorder, new ProxyHttpHeaderHandler() { - @Override - public String read(String name) { - return request.getHeader(name); - } - }); - } - - /** - * Record parent info. - * - * @param recorder the recorder - * @param request the request - */ - private void recordParentInfo(final SpanRecorder recorder, final HttpServletRequest request) { - final String parentApplicationName = request.getHeader(Header.HTTP_PARENT_APPLICATION_NAME.toString()); - if (parentApplicationName != null) { - final String host = request.getHeader(Header.HTTP_HOST.toString()); - if (host != null) { - recorder.recordAcceptorHost(host); - } else { - recorder.recordAcceptorHost(NetworkUtils.getHostFromURL(request.getRequestURL().toString())); + this.servletRequestListenerInterceptorHelper.initialized(request, JbossConstants.JBOSS_METHOD, this.methodDescriptor); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); } - final String type = request.getHeader(Header.HTTP_PARENT_APPLICATION_TYPE.toString()); - final short parentApplicationType = NumberUtils.parseShort(type, ServiceType.UNDEFINED.getCode()); - recorder.recordParentApplication(parentApplicationName, parentApplicationType); } } - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor#after(java.lang.Object, java.lang.Object[], - * java.lang.Object, java.lang.Throwable) - */ @Override public void after(final Object target, final Object[] args, final Object result, final Throwable throwable) { if (isDebug) { logger.afterInterceptor(target, args, result, throwable); } - final Trace trace = traceContext.currentRawTraceObject(); - if (trace == null) { + if (!argumentValidator.validate(args)) { return; } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - traceContext.removeTraceObject(); - return; - } - // ------------------------------------------------------ try { - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - - if (this.isTraceRequestParam) { - final HttpServletRequest request = (HttpServletRequest) args[0]; - if (!excludeProfileMethodFilter.filter(request.getMethod())) { - final String parameters = getRequestParameter(request, 64, 512); - if (StringUtils.hasLength(parameters)) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM, parameters); - } + final HttpServletRequest request = (HttpServletRequest) args[0]; + final HttpServletResponse response = (HttpServletResponse) args[1]; + if (request.getDispatcherType() == DispatcherType.ASYNC) { + if (isDebug) { + logger.debug("Skip async servlet request event. isAsyncStarted={}, dispatcherType={}", request.isAsyncStarted(), request.getDispatcherType()); } + return; } - - recorder.recordApi(methodDescriptor); - recorder.recordException(throwable); - } catch (final Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("AFTER. Caused:{}", th.getMessage(), th); - } - } finally { - traceContext.removeTraceObject(); - deleteTrace(trace, target, args, result, throwable); - } - } - - /** - * Populate source trace from HTTP Header. - * - * @param request the request - * @return TraceId when it is possible to get a transactionId from Http header. if not possible return null - */ - private TraceId populateTraceIdFromRequest(final HttpServletRequest request) { - - final String transactionId = request.getHeader(Header.HTTP_TRACE_ID.toString()); - if (transactionId != null) { - - final long parentSpanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_PARENT_SPAN_ID.toString()), SpanId.NULL); - final long spanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_SPAN_ID.toString()), SpanId.NULL); - final short flags = NumberUtils.parseShort(request.getHeader(Header.HTTP_FLAGS.toString()), (short) 0); - - final TraceId id = traceContext.createTraceId(transactionId, parentSpanID, spanID, flags); - if (isDebug) { - logger.debug("TraceID exist. continue trace. {}", id); - } - return id; - } else { - return null; - } - } - - /** - * Sampling enable. - * - * @param request the request - * @return true, if successful - */ - private boolean samplingEnable(final HttpServletRequest request) { - // optional value - final String samplingFlag = request.getHeader(Header.HTTP_SAMPLED.toString()); - if (isDebug) { - logger.debug("SamplingFlag:{}", samplingFlag); - } - return SamplingFlagUtils.isSamplingFlag(samplingFlag); - } - - /** - * Gets the request parameter. - * - * @param request the request - * @param eachLimit the each limit - * @param totalLimit the total limit - * @return the request parameter - */ - private String getRequestParameter(final HttpServletRequest request, final int eachLimit, final int totalLimit) { - final Enumeration attrs = request.getParameterNames(); - final StringBuilder params = new StringBuilder(64); - - while (attrs.hasMoreElements()) { - if (params.length() != 0) { - params.append('&'); - } - // skip appending parameters if parameter size is bigger than totalLimit - if (params.length() > totalLimit) { - params.append("..."); - return params.toString(); - } - final String key = attrs.nextElement().toString(); - params.append(StringUtils.abbreviate(key, eachLimit)); - params.append('='); - final Object value = request.getParameter(key); - if (value != null) { - params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); + final int statusCode = getStatusCode(response); + this.servletRequestListenerInterceptorHelper.destroyed(request, throwable, statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); } } - return params.toString(); } - /** - * Delete trace. - * - * @param trace the trace - * @param target the target - * @param args the args - * @param result the result - * @param throwable the throwable - */ - private void deleteTrace(final Trace trace, final Object target, final Object[] args, final Object result, final Throwable throwable) { - trace.traceBlockEnd(); - - final HttpServletRequest request = (HttpServletRequest) args[0]; - if (!isAsynchronousProcess(request)) { - trace.close(); - // reset - setTraceMetadata(request, null); + private int getStatusCode(final HttpServletResponse response) { + try { + return response.getStatus(); + } catch (Exception ignored) { } + return 0; } -} +} \ No newline at end of file diff --git a/plugins/jboss/src/test/java/com/navercorp/pinpoint/plugin/jboss/InvokeMethodInterceptorTest.java b/plugins/jboss/src/test/java/com/navercorp/pinpoint/plugin/jboss/InvokeMethodInterceptorTest.java index c5f3c980e70d..30bbf7082a5e 100644 --- a/plugins/jboss/src/test/java/com/navercorp/pinpoint/plugin/jboss/InvokeMethodInterceptorTest.java +++ b/plugins/jboss/src/test/java/com/navercorp/pinpoint/plugin/jboss/InvokeMethodInterceptorTest.java @@ -25,6 +25,7 @@ import com.navercorp.pinpoint.bootstrap.context.TraceId; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; import com.navercorp.pinpoint.profiler.context.module.ApplicationContext; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.test.MockTraceContextFactory; import org.junit.After; import org.junit.Before; @@ -62,7 +63,7 @@ public class InvokeMethodInterceptorTest { private final MethodDescriptor descriptor = new DefaultMethodDescriptor("org.apache.catalina.core.StandardHostValve", "invoke", new String[] { "org.apache.catalina.connector.Request", "org.apache.catalina.connector.Response" }, new String[] { "request", "response" }); - private ApplicationContext applicationContext; + private DefaultApplicationContext applicationContext; /** * Before. @@ -120,12 +121,12 @@ public void testHeaderNOTExists() { interceptor.before("target", new Object[] { request, response }); interceptor.after("target", new Object[] { request, response }, new Object(), null); - verify(traceContext, times(1)).newTraceObject(); + verify(traceContext, times(1)).newAsyncTraceObject(); interceptor.before("target", new Object[] { request, response }); interceptor.after("target", new Object[] { request, response }, new Object(), null); - verify(traceContext, times(2)).newTraceObject(); + verify(traceContext, times(2)).newAsyncTraceObject(); } /** @@ -188,11 +189,11 @@ public void testValidHeaderExists() { interceptor.before("target", new Object[] { request, response }); interceptor.after("target", new Object[] { request, response }, new Object(), null); - verify(traceContext, times(1)).continueTraceObject(any(TraceId.class)); + verify(traceContext, times(1)).continueAsyncTraceObject((any(TraceId.class))); interceptor.before("target", new Object[] { request, response }); interceptor.after("target", new Object[] { request, response }, new Object(), null); - verify(traceContext, times(2)).continueTraceObject(any(TraceId.class)); + verify(traceContext, times(2)).continueAsyncTraceObject(any(TraceId.class)); } } diff --git a/plugins/jboss/src/test/java/com/navercorp/pinpoint/plugin/jboss/StandardHostValveInvokeModifierTest.java b/plugins/jboss/src/test/java/com/navercorp/pinpoint/plugin/jboss/StandardHostValveInvokeModifierTest.java deleted file mode 100644 index e2726fa1ffb6..000000000000 --- a/plugins/jboss/src/test/java/com/navercorp/pinpoint/plugin/jboss/StandardHostValveInvokeModifierTest.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright 2016 Pinpoint contributors and NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.jboss; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.when; - -import java.util.Enumeration; -import java.util.List; - -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.core.StandardHost; -import org.apache.commons.lang3.StringUtils; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import com.navercorp.pinpoint.bootstrap.context.Header; -import com.navercorp.pinpoint.common.server.bo.SpanBo; -import com.navercorp.pinpoint.common.server.bo.SpanEventBo; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.TransactionIdUtils; -import com.navercorp.pinpoint.test.junit4.BasePinpointTest; -import com.navercorp.pinpoint.test.junit4.IsRootSpan; - -/** - * The Class StandardHostValveInvokeModifierTest. - * - * @author hyungil.jeong - */ -public class StandardHostValveInvokeModifierTest extends BasePinpointTest { - - /** The Constant SERVICE_TYPE. */ - private static final ServiceType SERVICE_TYPE = JbossConstants.JBOSS; - - /** The Constant REQUEST_URI. */ - private static final String REQUEST_URI = "testRequestUri"; - - /** The Constant SERVER_NAME. */ - private static final String SERVER_NAME = "serverForTest"; - - /** The Constant SERVER_PORT. */ - private static final int SERVER_PORT = 19999; - - /** The Constant REMOTE_ADDRESS. */ - private static final String REMOTE_ADDRESS = "1.1.1.1"; - - /** The Constant EMPTY_PARAM_KEYS. */ - private static final Enumeration EMPTY_PARAM_KEYS = new Enumeration() { - @Override - public boolean hasMoreElements() { - return false; - } - - @Override - public String nextElement() { - return null; - } - }; - - /** The host. */ - private StandardHost host; - - /** The mock request. */ - @Mock - private Request mockRequest; - - /** The mock response. */ - @Mock - private Response mockResponse; - - /** - * Sets the up. - * - * @throws Exception the exception - */ - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - initMockRequest(); - // StandardHost's default constructor sets StandardHostValve as the first item in the pipeline. - host = new StandardHost(); - } - - /** - * Inits the mock request. - */ - private void initMockRequest() { - when(mockRequest.getRequestURI()).thenReturn(REQUEST_URI); - when(mockRequest.getServerName()).thenReturn(SERVER_NAME); - when(mockRequest.getServerPort()).thenReturn(SERVER_PORT); - when(mockRequest.getRemoteAddr()).thenReturn(REMOTE_ADDRESS); - when(mockRequest.getParameterNames()).thenReturn(EMPTY_PARAM_KEYS); - } - - /** - * Invoke should be traced. - * - * @throws Exception the exception - */ - @Test - @IsRootSpan - public void invokeShouldBeTraced() throws Exception { - // Given - // When - host.invoke(mockRequest, mockResponse); - // Then - final List rootSpans = getCurrentRootSpans(); - assertEquals(rootSpans.size(), 1); - - final SpanBo rootSpan = rootSpans.get(0); - assertEquals(rootSpan.getParentSpanId(), -1); - assertEquals(rootSpan.getServiceType(), SERVICE_TYPE.getCode()); - assertEquals(rootSpan.getRpc(), REQUEST_URI); - assertEquals(rootSpan.getEndPoint(), HostAndPort.toHostAndPortString(SERVER_NAME, SERVER_PORT)); - assertTrue(StringUtils.isNotBlank(rootSpan.getRemoteAddr())); - } - - /** - * Invoke should trace exceptions. - * - * @throws Exception the exception - */ - @Test - @IsRootSpan - public void invokeShouldTraceExceptions() throws Exception { - // Given - when(mockRequest.getContext()).thenThrow(new RuntimeException("expected exception.")); - // When - try { - host.invoke(mockRequest, mockResponse); - assertTrue(false); - } catch (final RuntimeException e) { - // Then - final List rootSpans = getCurrentRootSpans(); - assertEquals(rootSpans.size(), 1); - - final SpanBo rootSpan = rootSpans.get(0); - assertEquals(rootSpan.getParentSpanId(), -1); - assertEquals(rootSpan.getServiceType(), SERVICE_TYPE.getCode()); - - final List spanEvents = getCurrentSpanEvents(); - final SpanEventBo spanEvent = spanEvents.get(0); - - assertTrue(spanEvent.hasException()); - } - } - - /** - * Invoke should continue tracing from request. - * - * @throws Exception the exception - */ - @Test - @IsRootSpan - public void invokeShouldContinueTracingFromRequest() throws Exception { - // Given - // Set Transaction ID from remote source. - final String sourceAgentId = "agentId"; - final long sourceAgentStartTime = 1234567890123L; - final long sourceTransactionSequence = 12345678L; - final String sourceTransactionId = TransactionIdUtils.formatString(sourceAgentId, sourceAgentStartTime, sourceTransactionSequence); - when(mockRequest.getHeader(Header.HTTP_TRACE_ID.toString())).thenReturn(sourceTransactionId); - // Set parent Span ID from remote source. - final long sourceParentId = 99999; - when(mockRequest.getHeader(Header.HTTP_PARENT_SPAN_ID.toString())).thenReturn(String.valueOf(sourceParentId)); - // When - host.invoke(mockRequest, mockResponse); - // Then - final List rootSpans = getCurrentRootSpans(); - assertEquals(rootSpans.size(), 1); - - final SpanBo rootSpan = rootSpans.get(0); - // Check Transaction ID from remote source. - assertEquals(TransactionIdUtils.formatString(rootSpan.getTransactionId()), sourceTransactionId); - assertEquals(rootSpan.getTransactionId().getAgentId(), sourceAgentId); - assertEquals(rootSpan.getTransactionId().getAgentStartTime(), sourceAgentStartTime); - assertEquals(rootSpan.getTransactionId().getTransactionSequence(), sourceTransactionSequence); - // Check parent Span ID from remote source. - assertEquals(rootSpan.getParentSpanId(), sourceParentId); - } - -} diff --git a/plugins/jdk-http/clover.license b/plugins/jdk-http/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/plugins/jdk-http/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-jdk-http-plugin diff --git a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionClientHeaderAdaptor.java b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionClientHeaderAdaptor.java new file mode 100644 index 000000000000..a626d596315a --- /dev/null +++ b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/HttpURLConnectionClientHeaderAdaptor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk.http; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; + +import java.net.HttpURLConnection; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpURLConnectionClientHeaderAdaptor implements ClientHeaderAdaptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(HttpURLConnection httpURLConnection, String name, String value) { + httpURLConnection.setRequestProperty(name, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } +} diff --git a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpClientRequestAdaptor.java b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpClientRequestAdaptor.java new file mode 100644 index 000000000000..d7c54dc4a5c5 --- /dev/null +++ b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpClientRequestAdaptor.java @@ -0,0 +1,72 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jdk.http; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.common.util.Assert; + +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * @author jaehong.kim + */ +public class JdkHttpClientRequestAdaptor implements ClientRequestAdaptor { + + + public JdkHttpClientRequestAdaptor() { + } + + + @Override + public String getDestinationId(HttpURLConnection httpURLConnection) { + final URL url = httpURLConnection.getURL(); + if (url != null) { + final String host = url.getHost(); + final int port = url.getPort(); + return getEndpoint(host, port); + } + return "Unknown"; + } + + public static String getEndpoint(final String host, final int port) { + if (host == null) { + return "Unknown"; + } + if (port < 0) { + return host; + } + final StringBuilder sb = new StringBuilder(32); + sb.append(host); + sb.append(':'); + sb.append(port); + return sb.toString(); + } + + @Override + public String getUrl(HttpURLConnection httpURLConnection) { + final URL url = httpURLConnection.getURL(); + if (url != null) { + return url.toString(); + } + return null; + } + +} diff --git a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPlugin.java b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPlugin.java index ffaf679c4977..c842f96f8851 100644 --- a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPlugin.java +++ b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPlugin.java @@ -63,6 +63,19 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin return target.toBytecode(); } }); + + transformTemplate.transform("sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + final InstrumentMethod connectMethod = target.getDeclaredMethod("connect"); + if (connectMethod == null) { + return null; + } + connectMethod.addScopedInterceptor("com.navercorp.pinpoint.plugin.jdk.http.interceptor.HttpURLConnectionInterceptor", "HttpURLConnection"); + return target.toBytecode(); + } + }); } @Override diff --git a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPluginConfig.java b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPluginConfig.java index fc84b8b26f88..0b695c00a151 100644 --- a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPluginConfig.java +++ b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/JdkHttpPluginConfig.java @@ -1,26 +1,34 @@ package com.navercorp.pinpoint.plugin.jdk.http; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; /** - * Created by Naver on 2015-11-17. + * @author jaehong.kim */ public class JdkHttpPluginConfig { - private boolean param = true; + private final boolean param; + private final HttpDumpConfig httpDumpConfig; public JdkHttpPluginConfig(ProfilerConfig src) { this.param = src.readBoolean("profiler.jdk.http.param", true); + this.httpDumpConfig = HttpDumpConfig.getDefault(); } public boolean isParam() { return param; } + public HttpDumpConfig getHttpDumpConfig() { + return httpDumpConfig; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("JdkHttpPluginConfig{"); sb.append("param=").append(param); + sb.append(", httpDumpConfig=").append(httpDumpConfig); sb.append('}'); return sb.toString(); } diff --git a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/interceptor/HttpURLConnectionInterceptor.java b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/interceptor/HttpURLConnectionInterceptor.java index fc4346ccb810..2d3439669bd6 100644 --- a/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/interceptor/HttpURLConnectionInterceptor.java +++ b/plugins/jdk-http/src/main/java/com/navercorp/pinpoint/plugin/jdk/http/interceptor/HttpURLConnectionInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,26 +16,16 @@ package com.navercorp.pinpoint.plugin.jdk.http.interceptor; -import java.net.HttpURLConnection; -import java.net.URL; - -import com.navercorp.pinpoint.bootstrap.context.Header; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.Trace; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.context.*; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.plugin.jdk.http.ConnectedGetter; -import com.navercorp.pinpoint.plugin.jdk.http.ConnectingGetter; -import com.navercorp.pinpoint.plugin.jdk.http.JdkHttpConstants; -import com.navercorp.pinpoint.plugin.jdk.http.JdkHttpPluginConfig; +import com.navercorp.pinpoint.bootstrap.plugin.request.*; +import com.navercorp.pinpoint.plugin.jdk.http.*; + +import java.net.HttpURLConnection; +import java.net.URL; /** * @author netspider @@ -49,15 +39,22 @@ public class HttpURLConnectionInterceptor implements AroundInterceptor { private final TraceContext traceContext; private final MethodDescriptor descriptor; private final InterceptorScope scope; - private final boolean param; - + private final ClientRequestRecorder clientRequestRecorder; + + private final RequestTraceWriter requestTraceWriter; + public HttpURLConnectionInterceptor(TraceContext traceContext, MethodDescriptor descriptor, InterceptorScope scope) { this.traceContext = traceContext; this.descriptor = descriptor; this.scope = scope; final JdkHttpPluginConfig config = new JdkHttpPluginConfig(traceContext.getProfilerConfig()); - this.param = config.isParam(); + + ClientRequestAdaptor clientRequestAdaptor = new JdkHttpClientRequestAdaptor(); + this.clientRequestRecorder = new ClientRequestRecorder(config.isParam(), clientRequestAdaptor); + + ClientHeaderAdaptor clientHeaderAdaptor = new HttpURLConnectionClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } @Override @@ -71,7 +68,6 @@ public void before(Object target, Object[] args) { } final HttpURLConnection request = (HttpURLConnection) target; - boolean connected = false; if (target instanceof ConnectedGetter) { connected = ((ConnectedGetter) target)._$PINPOINT$_isConnected(); @@ -80,56 +76,43 @@ public void before(Object target, Object[] args) { if (target instanceof ConnectingGetter) { connecting = ((ConnectingGetter) target)._$PINPOINT$_isConnecting(); } - + if (connected || connecting) { return; } - + final boolean sampling = trace.canSampled(); if (!sampling) { - request.setRequestProperty(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); + if (request != null) { + this.requestTraceWriter.write(request); + } return; } scope.getCurrentInvocation().setAttachment(TRACE_BLOCK_BEGIN_MARKER); - - SpanEventRecorder recorder = trace.traceBlockBegin(); - TraceId nextId = trace.getTraceId().getNextTraceId(); + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(JdkHttpConstants.SERVICE_TYPE); + final TraceId nextId = trace.getTraceId().getNextTraceId(); recorder.recordNextSpanId(nextId.getSpanId()); - final URL url = request.getURL(); - final String host = url.getHost(); - final int port = url.getPort(); - // TODO How to represent protocol? - String endpoint = getEndpoint(host, port); - - request.setRequestProperty(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - request.setRequestProperty(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - request.setRequestProperty(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - - request.setRequestProperty(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - request.setRequestProperty(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - request.setRequestProperty(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - if(host != null) { - request.setRequestProperty(Header.HTTP_HOST.toString(), endpoint); + if (request != null) { + String host = getHost(request); + this.requestTraceWriter.write(request, nextId, host); } - - recorder.recordServiceType(JdkHttpConstants.SERVICE_TYPE); - - // Don't record end point because it's same with destination id. - recorder.recordDestinationId(endpoint); - recorder.recordAttribute(AnnotationKey.HTTP_URL, InterceptorUtils.getHttpUrl(url.toString(), param)); } - private String getEndpoint(String host, int port) { - if (port < 0) { - return host; + + private String getHost(HttpURLConnection httpURLConnection) { + final URL url = httpURLConnection.getURL(); + if (url != null) { + final String host = url.getHost(); + final int port = url.getPort(); + if (host != null) { + return JdkHttpClientRequestAdaptor.getEndpoint(host, port); + } } - StringBuilder sb = new StringBuilder(32); - sb.append(host); - sb.append(':'); - sb.append(port); - return sb.toString(); + return null; } @Override @@ -143,17 +126,20 @@ public void after(Object target, Object[] args, Object result, Throwable throwab if (trace == null) { return; } - + Object marker = scope.getCurrentInvocation().getAttachment(); - if (marker != TRACE_BLOCK_BEGIN_MARKER) { return; } try { - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordApi(descriptor); recorder.recordException(throwable); + final HttpURLConnection request = (HttpURLConnection) target; + if (request != null) { + this.clientRequestRecorder.record(recorder, request, throwable); + } } finally { trace.traceBlockEnd(); } diff --git a/plugins/jetty/clover.license b/plugins/jetty/clover.license deleted file mode 100644 index a26812effe7c..000000000000 --- a/plugins/jetty/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 @@ -5,7 +21,7 @@ com.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-jetty-plugin @@ -30,6 +46,13 @@ 9.2.11.v20150529 provided + + + com.navercorp.pinpoint + pinpoint-common-servlet + ${project.version} + compile + @@ -60,6 +83,31 @@ + + + org.apache.maven.plugins + maven-shade-plugin + ${plugin.shade.version} + + + package + + shade + + + + + com.navercorp.pinpoint.plugin.common.servlet + com.navercorp.pinpoint.plugin.jetty.common.servlet + + + + ${project.build.directory}/dependency-reduced-pom.xml + + + + + \ No newline at end of file diff --git a/plugins/jetty/src/main/java-jetty/org/eclipse/jetty/server/AbstractHttpConnection.java b/plugins/jetty/src/main/java-jetty/org/eclipse/jetty/server/AbstractHttpConnection.java index 8ceae1ceda89..ab44d5761985 100644 --- a/plugins/jetty/src/main/java-jetty/org/eclipse/jetty/server/AbstractHttpConnection.java +++ b/plugins/jetty/src/main/java-jetty/org/eclipse/jetty/server/AbstractHttpConnection.java @@ -22,8 +22,11 @@ * for 1.8.1, 1.8.2 */ public abstract class AbstractHttpConnection { - public Request getRequest() { return null; } + + public Response getResponse() { + return null; + } } \ No newline at end of file diff --git a/plugins/jetty/src/main/java-jetty/org/eclipse/jetty/server/HttpConnection.java b/plugins/jetty/src/main/java-jetty/org/eclipse/jetty/server/HttpConnection.java index 20eb67fe5d68..bbb39bf52f68 100644 --- a/plugins/jetty/src/main/java-jetty/org/eclipse/jetty/server/HttpConnection.java +++ b/plugins/jetty/src/main/java-jetty/org/eclipse/jetty/server/HttpConnection.java @@ -25,4 +25,8 @@ public class HttpConnection { public Request getRequest() { return null; } + + public Response getResponse() { + return null; + } } \ No newline at end of file diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyAsyncListener.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyAsyncListener.java new file mode 100644 index 000000000000..11feb90b5be3 --- /dev/null +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyAsyncListener.java @@ -0,0 +1,144 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jetty; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.AsyncListenerInterceptorHelper; + +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author jaehong.kim + */ +public class JettyAsyncListener implements AsyncListener { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private final AsyncListenerInterceptorHelper asyncListenerInterceptorHelper; + + public JettyAsyncListener(final TraceContext traceContext, final AsyncContext asyncContext) { + this.asyncListenerInterceptorHelper = new AsyncListenerInterceptorHelper(traceContext, asyncContext); + } + + @Override + public void onComplete(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Complete asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + final int statusCode = getStatusCode(asyncEvent); + final Throwable throwable = getThrowable(asyncEvent); + this.asyncListenerInterceptorHelper.complete(throwable, statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. asyncEvent={}", asyncEvent, t); + } + } + } + + @Override + public void onTimeout(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Timeout asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.timeout(asyncEvent.getThrowable()); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onError(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Error asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + final Throwable throwable = getThrowable(asyncEvent); + this.asyncListenerInterceptorHelper.error(throwable); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. asyncEvent={}", asyncEvent, t); + } + } + } + + @Override + public void onStartAsync(AsyncEvent asyncEvent) throws IOException { + } + + private int getStatusCode(AsyncEvent asyncEvent) { + try { + if (asyncEvent.getSuppliedResponse() instanceof HttpServletResponse) { + return ((HttpServletResponse) asyncEvent.getSuppliedResponse()).getStatus(); + } + } catch (Exception ignored) { + } + return 0; + } + + private Throwable getThrowable(AsyncEvent asyncEvent) { + try { + if (asyncEvent.getThrowable() != null) { + return asyncEvent.getThrowable(); + } + // Jetty 8.x + final ServletRequest request = asyncEvent.getSuppliedRequest(); + if (request != null) { + final Object errorException = request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); + if (errorException instanceof Throwable) { + return (Throwable) errorException; + } + } + } catch (Exception ignored) { + } + return null; + } +} \ No newline at end of file diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyConfiguration.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyConfiguration.java index c7f1237baaa7..511d79a61a02 100644 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyConfiguration.java +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyConfiguration.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,6 +14,7 @@ */ package com.navercorp.pinpoint.plugin.jetty; +import com.navercorp.pinpoint.bootstrap.config.ExcludeMethodFilter; import com.navercorp.pinpoint.bootstrap.config.ExcludePathFilter; import com.navercorp.pinpoint.bootstrap.config.Filter; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; @@ -21,43 +22,91 @@ import java.util.List; +/** + * @author Chaein Jung + * @author jaehong.kim + */ public class JettyConfiguration { - private final boolean jettyEnabled; - private final List jettyBootstrapMains; - private final Filter jettyExcludeUrlFilter; + private final boolean enable; + private final List bootstrapMains; + private final Filter excludeUrlFilter; private final boolean hidePinpointHeader; + private final String realIpHeader; + private final String realIpEmptyValue; + private final boolean traceRequestParam; + private final Filter excludeProfileMethodFilter; public JettyConfiguration(ProfilerConfig config) { - this.jettyEnabled = config.readBoolean("profiler.jetty.enable", true); - this.jettyBootstrapMains = config.readList("profiler.jetty.bootstrap.main"); + this.enable = config.readBoolean("profiler.jetty.enable", true); + this.bootstrapMains = config.readList("profiler.jetty.bootstrap.main"); final String jettyExcludeURL = config.readString("profiler.jetty.excludeurl", ""); if (!jettyExcludeURL.isEmpty()) { - this.jettyExcludeUrlFilter = new ExcludePathFilter(jettyExcludeURL); + this.excludeUrlFilter = new ExcludePathFilter(jettyExcludeURL); } else { - this.jettyExcludeUrlFilter = new SkipFilter(); + this.excludeUrlFilter = new SkipFilter(); } boolean hidePinpointHeader = config.readBoolean("profiler.jetty.hide-pinpoint-header", true); if (hidePinpointHeader) { hidePinpointHeader = config.readBoolean("profiler.jetty.hidepinpointheader", true); } this.hidePinpointHeader = hidePinpointHeader; + final String excludeProfileMethod = config.readString("profiler.jetty.excludemethod", ""); + if (!excludeProfileMethod.isEmpty()) { + this.excludeProfileMethodFilter = new ExcludeMethodFilter(excludeProfileMethod); + } else { + this.excludeProfileMethodFilter = new SkipFilter(); + } + this.traceRequestParam = config.readBoolean("profiler.jetty.tracerequestparam", true); + this.realIpHeader = config.readString("profiler.jetty.realipheader", null); + this.realIpEmptyValue = config.readString("profiler.jetty.realipemptyvalue", null); } - public boolean isJettyEnabled() { - return jettyEnabled; + public boolean isEnable() { + return enable; } - public List getJettyBootstrapMains() { - return jettyBootstrapMains; + public List getBootstrapMains() { + return bootstrapMains; } - public Filter getJettyExcludeUrlFilter() { - return jettyExcludeUrlFilter; + public Filter getExcludeUrlFilter() { + return excludeUrlFilter; } public boolean isHidePinpointHeader() { return hidePinpointHeader; } + + public String getRealIpHeader() { + return realIpHeader; + } + + public String getRealIpEmptyValue() { + return realIpEmptyValue; + } + + public boolean isTraceRequestParam() { + return traceRequestParam; + } + + public Filter getExcludeProfileMethodFilter() { + return excludeProfileMethodFilter; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("JettyConfiguration{"); + sb.append("enable=").append(enable); + sb.append(", bootstrapMains=").append(bootstrapMains); + sb.append(", excludeUrlFilter=").append(excludeUrlFilter); + sb.append(", hidePinpointHeader=").append(hidePinpointHeader); + sb.append(", realIpHeader='").append(realIpHeader).append('\''); + sb.append(", realIpEmptyValue='").append(realIpEmptyValue).append('\''); + sb.append(", traceRequestParam=").append(traceRequestParam); + sb.append(", excludeProfileMethodFilter=").append(excludeProfileMethodFilter); + sb.append('}'); + return sb.toString(); + } } diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyConstants.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyConstants.java index cbdf20cab172..e1c915f15529 100644 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyConstants.java +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyConstants.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,18 +19,13 @@ import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; +/** + * @author Chaein Jung + */ public final class JettyConstants { private JettyConstants() { } - public static final String TYPE_NAME = "JETTY"; - public static final ServiceType JETTY = ServiceTypeFactory.of(1030, "JETTY", RECORD_STATISTICS); public static final ServiceType JETTY_METHOD = ServiceTypeFactory.of(1031, "JETTY_METHOD"); - - public static final String METADATA_TRACE = "trace"; - public static final String METADATA_ASYNC = "async"; - public static final String METADATA_ASYNC_TRACE_ID = "asyncTraceId"; - - public static final String ATTRIBUTE_PINPOINT_TRACE = "PINPOINT_TRACE"; } diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyDetector.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyDetector.java index 550904c2901d..d23a30cb9ea6 100644 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyDetector.java +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyDetector.java @@ -22,6 +22,9 @@ import java.util.Arrays; import java.util.List; +/** + * @author Chaein Jung + */ public class JettyDetector implements ApplicationTypeDetector { private static final String DEFAULT_BOOTSTRAP_MAIN = "org.eclipse.jetty.start.Main"; diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyPlugin.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyPlugin.java index 2c5c62014611..b181fe72a27b 100644 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyPlugin.java +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyPlugin.java @@ -28,8 +28,10 @@ import java.security.ProtectionDomain; -import static com.navercorp.pinpoint.common.util.VarArgs.va; - +/** + * @author Chaein Jung + * @author jaehong.kim + */ public class JettyPlugin implements ProfilerPlugin, TransformTemplateAware { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); @@ -39,35 +41,44 @@ public class JettyPlugin implements ProfilerPlugin, TransformTemplateAware { @Override public void setup(ProfilerPluginSetupContext context) { JettyConfiguration config = new JettyConfiguration(context.getConfig()); - if (!config.isJettyEnabled()) { + if (!config.isEnable()) { logger.info("Disabled JettyPlugin."); return; } // 8.0 <= x <= 9.4 - logger.info("Enable JettyPlugin. version range=[8.0, 9.4]"); - context.addApplicationTypeDetector(new JettyDetector(config.getJettyBootstrapMains())); - if (config.isHidePinpointHeader()) { - requestAspect(); - } - addServerInterceptor(config); + logger.info("Enable JettyPlugin. version range=[8.0, 9.4], config={}", config); + context.addApplicationTypeDetector(new JettyDetector(config.getBootstrapMains())); + + // Add async listener. Servlet 3.0 + requestAspect(config); + // Entry Point + addServerInterceptor(); } - private void requestAspect() { + private void requestAspect(final JettyConfiguration config) { transformTemplate.transform("org.eclipse.jetty.server.Request", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - if (target != null && target.getDeclaredMethod("getHttpFields") != null) { - // 9.x + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + if (config.isHidePinpointHeader()) { + // Hide pinpoint header target.weave("com.navercorp.pinpoint.plugin.jetty.aspect.RequestAspect"); - return target.toBytecode(); } - return null; + // Add async listener. Servlet 3.0 + final InstrumentMethod startAsyncMethod = target.getDeclaredMethod("startAsync"); + if (startAsyncMethod != null) { + startAsyncMethod.addInterceptor("com.navercorp.pinpoint.plugin.jetty.interceptor.RequestStartAsyncInterceptor"); + } + final InstrumentMethod startAsyncMethodEditor = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); + if (startAsyncMethodEditor != null) { + startAsyncMethodEditor.addInterceptor("com.navercorp.pinpoint.plugin.jetty.interceptor.RequestStartAsyncInterceptor"); + } + return target.toBytecode(); } }); } - private void addServerInterceptor(final JettyConfiguration config) { + private void addServerInterceptor() { transformTemplate.transform("org.eclipse.jetty.server.Server", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { @@ -75,19 +86,19 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, // 9.x final InstrumentMethod handleMethodEditorBuilder = target.getDeclaredMethod("handle", "org.eclipse.jetty.server.HttpChannel"); if (handleMethodEditorBuilder != null) { - handleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.jetty.interceptor.ServerHandleInterceptor", va(config.getJettyExcludeUrlFilter())); + handleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.jetty.interceptor.Jetty9xServerHandleInterceptor"); return target.toBytecode(); } // 8.0 final InstrumentMethod jetty80HandleMethodEditorBuilder = target.getDeclaredMethod("handle", "org.eclipse.jetty.server.HttpConnection"); if (jetty80HandleMethodEditorBuilder != null) { - jetty80HandleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.jetty.interceptor.Jetty8ServerHandleInterceptor", va(config.getJettyExcludeUrlFilter())); + jetty80HandleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.jetty.interceptor.Jetty80ServerHandleInterceptor"); return target.toBytecode(); } // 8.1, 8.2 final InstrumentMethod jetty82HandleMethodEditorBuilder = target.getDeclaredMethod("handle", "org.eclipse.jetty.server.AbstractHttpConnection"); if (jetty82HandleMethodEditorBuilder != null) { - jetty82HandleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.jetty.interceptor.Jetty8xServerHandleInterceptor", va(config.getJettyExcludeUrlFilter())); + jetty82HandleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.jetty.interceptor.Jetty8xServerHandleInterceptor"); return target.toBytecode(); } diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettySyncMethodDescriptor.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettySyncMethodDescriptor.java deleted file mode 100644 index b339b62711eb..000000000000 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettySyncMethodDescriptor.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.jetty; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.common.trace.MethodType; - -public class JettySyncMethodDescriptor implements MethodDescriptor{ - - private int apiId = 0; - private int type = MethodType.WEB_REQUEST; - - @Override - public String getMethodName() { - return ""; - } - - @Override - public String getClassName() { - return ""; - } - - @Override - public String[] getParameterTypes() { - return null; - } - - @Override - public String[] getParameterVariableName() { - return null; - } - - @Override - public String getParameterDescriptor() { - return "()"; - } - - @Override - public int getLineNumber() { - return -1; - } - - @Override - public String getFullName() { - return JettySyncMethodDescriptor.class.getName(); - } - - @Override - public void setApiId(int apiId) { - this.apiId = apiId; - } - - @Override - public int getApiId() { - return apiId; - } - - @Override - public String getApiDescriptor() { - return "Jetty Servlet Process"; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } -} diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyTypeProvider.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyTypeProvider.java index 9164071febc4..5e17d9aeb3b5 100644 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyTypeProvider.java +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/JettyTypeProvider.java @@ -17,8 +17,10 @@ import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; +/** + * @author Chaein Jung + */ public class JettyTypeProvider implements TraceMetadataProvider { - @Override public void setup(TraceMetadataSetupContext context) { context.addServiceType(JettyConstants.JETTY); diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/aspect/RequestAspect.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/aspect/RequestAspect.java index 28cee90aa52d..659066e3aafd 100644 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/aspect/RequestAspect.java +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/aspect/RequestAspect.java @@ -20,7 +20,6 @@ import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; import com.navercorp.pinpoint.common.util.DelegateEnumeration; -import com.navercorp.pinpoint.common.util.EmptyEnumeration; import java.util.Enumeration; @@ -29,29 +28,6 @@ */ @Aspect public abstract class RequestAspect { - - @PointCut - public String getHeader(String name) { - if (Header.startWithPinpointHeader(name)) { - return null; - } - return __getHeader(name); - } - - @JointPoint - abstract String __getHeader(String name); - - @PointCut - public Enumeration getHeaders(String name) { - if (Header.startWithPinpointHeader(name)) { - return new EmptyEnumeration(); - } - return __getHeaders(name); - } - - @JointPoint - abstract Enumeration __getHeaders(String name); - @PointCut public Enumeration getHeaderNames() { return new DelegateEnumeration(__getHeaderNames(), Header.FILTER); diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/AbstractServerHandleInterceptor.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/AbstractServerHandleInterceptor.java index a14c7aff5302..835edb81b2c4 100644 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/AbstractServerHandleInterceptor.java +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/AbstractServerHandleInterceptor.java @@ -1,10 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -12,54 +13,52 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.navercorp.pinpoint.plugin.jetty.interceptor; -import com.navercorp.pinpoint.bootstrap.config.Filter; import com.navercorp.pinpoint.bootstrap.context.*; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderHandler; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderRecorder; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; -import com.navercorp.pinpoint.bootstrap.util.NumberUtils; -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServletRequestListenerInterceptorHelper; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.RemoteAddressResolverFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.HttpServletRequestAdaptor; +import com.navercorp.pinpoint.plugin.common.servlet.util.ParameterRecorderFactory; +import com.navercorp.pinpoint.plugin.jetty.JettyConfiguration; import com.navercorp.pinpoint.plugin.jetty.JettyConstants; -import com.navercorp.pinpoint.plugin.jetty.JettySyncMethodDescriptor; -import org.eclipse.jetty.server.Request; -import java.util.Enumeration; +import javax.servlet.DispatcherType; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** * @author Chaein Jung + * @author jaehong.kim */ public abstract class AbstractServerHandleInterceptor implements AroundInterceptor { - public static final JettySyncMethodDescriptor JETTY_SYNC_API_TAG = new JettySyncMethodDescriptor(); - protected PLogger logger = PLoggerFactory.getLogger(this.getClass()); + protected final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private final boolean isTrace = logger.isTraceEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); private final MethodDescriptor methodDescriptor; - private final TraceContext traceContext; - private final Filter excludeUrlFilter; - private final ProxyHttpHeaderRecorder proxyHttpHeaderRecorder; + private final ServletRequestListenerInterceptorHelper servletRequestListenerInterceptorHelper; - public AbstractServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor, Filter excludeFilter) { - this.traceContext = traceContext; - this.methodDescriptor = descriptor; - this.excludeUrlFilter = excludeFilter; - this.proxyHttpHeaderRecorder = new ProxyHttpHeaderRecorder(traceContext.getProfilerConfig().isProxyHttpHeaderEnable()); + public AbstractServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { - traceContext.cacheApi(JETTY_SYNC_API_TAG); + this.methodDescriptor = descriptor; + final JettyConfiguration config = new JettyConfiguration(traceContext.getProfilerConfig()); + RequestAdaptor requestRequestAdaptor = new HttpServletRequestAdaptor(); + requestRequestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestRequestAdaptor, config.getRealIpHeader(), config.getRealIpEmptyValue()); + ParameterRecorder parameterRecorder = ParameterRecorderFactory.newParameterRecorderFactory(config.getExcludeProfileMethodFilter(), config.isTraceRequestParam()); + this.servletRequestListenerInterceptorHelper = new ServletRequestListenerInterceptorHelper(JettyConstants.JETTY, traceContext, requestRequestAdaptor, config.getExcludeUrlFilter(), parameterRecorder); } - abstract Request getRequest(Object[] args); - abstract String getHeader(Request request, String name); + abstract HttpServletRequest toHttpServletRequest(Object[] args); + + abstract HttpServletResponse toHttpServletResponse(Object[] args); @Override public void before(Object target, Object[] args) { @@ -68,76 +67,16 @@ public void before(Object target, Object[] args) { } try { - final Trace trace = createTrace(target, args); - if (trace == null) { - return; - } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - return; - } - // ------------------------------------------------------ - SpanEventRecorder recorder = trace.traceBlockBegin(); - recorder.recordServiceType(JettyConstants.JETTY_METHOD); - } catch (Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("before. Caused:{}", th.getMessage(), th); - } - } - } - - - private Trace createTrace(Object target, Object[] args) { - final Request request = getRequest(args); - - final String requestURI = request.getRequestURI(); - if (excludeUrlFilter.filter(requestURI)) { - if (isTrace) { - logger.trace("filter requestURI:{}", requestURI); - } - return null; - } - // check sampling flag from client. If the flag is false, do not sample this request. - final boolean sampling = samplingEnable(request); - if (!sampling) { - // Even if this transaction is not a sampling target, we have to create Trace object to mark 'not sampling'. - // For example, if this transaction invokes rpc call, we can add parameter to tell remote node 'don't sample this transaction' - final Trace trace = traceContext.disableSampling(); - if (isDebug) { - logger.debug("remotecall sampling flag found. skip trace requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - return trace; - } - - final TraceId traceId = populateTraceIdFromRequest(request); - if (traceId != null) { - final Trace trace = traceContext.continueTraceObject(traceId); - if (trace.canSampled()) { - SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); + final HttpServletRequest request = toHttpServletRequest(args); + if (request.getDispatcherType() == DispatcherType.ASYNC || request.getDispatcherType() == DispatcherType.ERROR) { if (isDebug) { - logger.debug("TraceID exist. continue trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), request.getRemoteAddr()); - } - } else { - if (isDebug) { - logger.debug("TraceID exist. camSampled is false. skip trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), request.getRemoteAddr()); - } - } - return trace; - } else { - final Trace trace = traceContext.newTraceObject(); - if (trace.canSampled()) { - SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - if (isDebug) { - logger.debug("TraceID not exist. start new trace. requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - } else { - if (isDebug) { - logger.debug("TraceID not exist. camSampled is false. skip trace. requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); + logger.debug("Skip async servlet request event. isAsyncStarted={}, dispatcherType={}", request.isAsyncStarted(), request.getDispatcherType()); } + return; } - return trace; + this.servletRequestListenerInterceptorHelper.initialized(request, JettyConstants.JETTY_METHOD, this.methodDescriptor); + } catch (Throwable t) { + logger.info("Failed to servlet request event handle.", t); } } @@ -147,135 +86,29 @@ public void after(Object target, Object[] args, Object result, Throwable throwab logger.afterInterceptor(target, args, result, throwable); } - final Trace trace = traceContext.currentRawTraceObject(); - if (trace == null) { - return; - } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - traceContext.removeTraceObject(); - return; - } - // ------------------------------------------------------ try { - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - final Request request = getRequest(args); - final String parameters = getRequestParameter(request, 64, 512); - if (StringUtils.hasLength(parameters)) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM, parameters); - } - - recorder.recordApi(methodDescriptor); - recorder.recordException(throwable); - } catch (Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("after. Caused:{}", th.getMessage(), th); - } - } finally { - traceContext.removeTraceObject(); - deleteTrace(trace, target, args, result, throwable); - } - } - - private boolean samplingEnable(Request request) { - // optional value - final String samplingFlag = getHeader(request, Header.HTTP_SAMPLED.toString()); - if (isDebug) { - logger.debug("SamplingFlag:{}", samplingFlag); - } - return SamplingFlagUtils.isSamplingFlag(samplingFlag); - } - - private String getRequestParameter(Request request, int eachLimit, int totalLimit) { - Enumeration attrs = request.getParameterNames(); - final StringBuilder params = new StringBuilder(64); - while (attrs.hasMoreElements()) { - if (params.length() != 0) { - params.append('&'); - } - // skip appending parameters if parameter size is bigger than totalLimit - if (params.length() > totalLimit) { - params.append("..."); - return params.toString(); - } - String key = attrs.nextElement().toString(); - params.append(StringUtils.abbreviate(key, eachLimit)); - params.append('='); - Object value = request.getParameter(key); - if (value != null) { - params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); + final HttpServletRequest request = toHttpServletRequest(args); + final HttpServletResponse response = toHttpServletResponse(args); + if (request.getDispatcherType() == DispatcherType.ASYNC || request.getDispatcherType() == DispatcherType.ERROR) { + if (isDebug) { + logger.debug("Skip async servlet request event. isAsyncStarted={}, dispatcherType={}", request.isAsyncStarted(), request.getDispatcherType()); + } + return; } - } - return params.toString(); - } - - private void recordParentInfo(SpanRecorder recorder, Request request) { - String parentApplicationName = getHeader(request, Header.HTTP_PARENT_APPLICATION_NAME.toString()); - if (parentApplicationName != null) { - final String host = getHeader(request, Header.HTTP_HOST.toString()); - if (host != null) { - recorder.recordAcceptorHost(host); - } else { - recorder.recordAcceptorHost(NetworkUtils.getHostFromURL(request.getRequestURL().toString())); + final int statusCode = getStatusCode(response); + this.servletRequestListenerInterceptorHelper.destroyed(request, throwable, statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); } - final String type = getHeader(request, Header.HTTP_PARENT_APPLICATION_TYPE.toString()); - final short parentApplicationType = NumberUtils.parseShort(type, ServiceType.UNDEFINED.getCode()); - recorder.recordParentApplication(parentApplicationName, parentApplicationType); } } - private void recordRootSpan(final SpanRecorder recorder, final Request request) { - // root - recorder.recordServiceType(JettyConstants.JETTY); - - final String requestURL = request.getRequestURI(); - recorder.recordRpcName(requestURL); - - final int port = request.getServerPort(); - final String endPoint = HostAndPort.toHostAndPortString(request.getServerName(), port); - recorder.recordEndPoint(endPoint); - - final String remoteAddr = request.getRemoteAddr(); - recorder.recordRemoteAddress(remoteAddr); - - if (!recorder.isRoot()) { - recordParentInfo(recorder, request); - } - recorder.recordApi(JETTY_SYNC_API_TAG); - - // record proxy HTTP headers. - this.proxyHttpHeaderRecorder.record(recorder, new ProxyHttpHeaderHandler() { - @Override - public String read(String name) { - return getHeader(request, name); - } - }); - } - - /** - * Populate source trace from HTTP Header. - * - * @param request - * @return TraceId when it is possible to get a transactionId from Http header. if not possible return null - */ - private TraceId populateTraceIdFromRequest(Request request) { - String transactionId = getHeader(request, Header.HTTP_TRACE_ID.toString()); - if (transactionId != null) { - long parentSpanID = NumberUtils.parseLong(getHeader(request, Header.HTTP_PARENT_SPAN_ID.toString()), SpanId.NULL); - long spanID = NumberUtils.parseLong(getHeader(request, Header.HTTP_SPAN_ID.toString()), SpanId.NULL); - short flags = NumberUtils.parseShort(getHeader(request, Header.HTTP_FLAGS.toString()), (short) 0); - final TraceId id = traceContext.createTraceId(transactionId, parentSpanID, spanID, flags); - if (isDebug) { - logger.debug("TraceID exist. continue trace. {}", id); - } - return id; - } else { - return null; + private int getStatusCode(final HttpServletResponse response) { + try { + return response.getStatus(); + } catch (Exception ignored) { } - } - - private void deleteTrace(Trace trace, Object target, Object[] args, Object result, Throwable throwable) { - trace.traceBlockEnd(); - trace.close(); + return 0; } } \ No newline at end of file diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty80ServerHandleInterceptor.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty80ServerHandleInterceptor.java new file mode 100644 index 000000000000..f7daaa1959b7 --- /dev/null +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty80ServerHandleInterceptor.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jetty.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import org.eclipse.jetty.server.HttpConnection; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author Taejin Koo + * @author jaehong.kim + *

+ * jetty-8.0 + */ +public class Jetty80ServerHandleInterceptor extends AbstractServerHandleInterceptor { + + public Jetty80ServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + HttpServletRequest toHttpServletRequest(Object[] args) { + if (args == null || args.length < 1) { + return null; + } + + if (args[0] instanceof HttpConnection) { + try { + HttpConnection connection = (HttpConnection) args[0]; + return connection.getRequest(); + } catch (Throwable ignored) { + } + } + return null; + } + + @Override + HttpServletResponse toHttpServletResponse(Object[] args) { + if (args == null || args.length < 1) { + return null; + } + + if (args[0] instanceof HttpConnection) { + try { + HttpConnection connection = (HttpConnection) args[0]; + return connection.getResponse(); + } catch (Throwable ignored) { + } + } + return null; + + } +} diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty8ServerHandleInterceptor.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty8ServerHandleInterceptor.java deleted file mode 100644 index 23ce5017a3e4..000000000000 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty8ServerHandleInterceptor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2018 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.jetty.interceptor; - -import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import org.eclipse.jetty.server.HttpConnection; -import org.eclipse.jetty.server.Request; - -/** - * @author Taejin Koo - * @author jaehong.kim - * - * jetty-8.0 - */ -public class Jetty8ServerHandleInterceptor extends AbstractServerHandleInterceptor { - - public Jetty8ServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor, Filter excludeFilter) { - super(traceContext, descriptor, excludeFilter); - } - - @Override - protected Request getRequest(final Object[] args) { - if (args == null || args.length < 1) { - return null; - } - - if (args[0] instanceof HttpConnection) { - try { - HttpConnection connection = (HttpConnection) args[0]; - return connection.getRequest(); - } catch (Throwable ignored) { - } - } - return null; - } - - @Override - String getHeader(final Request request, final String name) { - if (request == null) { - return null; - } - return request.getHeader(name); - } -} \ No newline at end of file diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty8xServerHandleInterceptor.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty8xServerHandleInterceptor.java index b5fa79d0b000..61e174c41bc9 100644 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty8xServerHandleInterceptor.java +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty8xServerHandleInterceptor.java @@ -16,30 +16,28 @@ package com.navercorp.pinpoint.plugin.jetty.interceptor; -import com.navercorp.pinpoint.bootstrap.config.Filter; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import org.eclipse.jetty.server.AbstractHttpConnection; -import org.eclipse.jetty.server.Request; -import java.lang.reflect.Method; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + /** * @author Taejin Koo * @author jaehong.kim - * + *

* jetty-8.1, jetty-8.2 */ public class Jetty8xServerHandleInterceptor extends AbstractServerHandleInterceptor { - private volatile Method getRequestMethod; - - public Jetty8xServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor, Filter excludeFilter) { - super(traceContext, descriptor, excludeFilter); + public Jetty8xServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); } @Override - protected Request getRequest(final Object[] args) { + HttpServletRequest toHttpServletRequest(Object[] args) { if (args == null || args.length < 1) { return null; } @@ -55,10 +53,18 @@ protected Request getRequest(final Object[] args) { } @Override - String getHeader(final Request request, final String name) { - if (request == null) { + HttpServletResponse toHttpServletResponse(Object[] args) { + if (args == null || args.length < 1) { return null; } - return request.getHeader(name); + + if (args[0] instanceof AbstractHttpConnection) { + try { + AbstractHttpConnection connection = (AbstractHttpConnection) args[0]; + return connection.getResponse(); + } catch (Throwable ignored) { + } + } + return null; } } \ No newline at end of file diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty9xServerHandleInterceptor.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty9xServerHandleInterceptor.java new file mode 100644 index 000000000000..84d6394a13d1 --- /dev/null +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/Jetty9xServerHandleInterceptor.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jetty.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import org.eclipse.jetty.server.HttpChannel; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author Taejin Koo + * @author jaehong.kim + *

+ * jetty-9.x + */ +public class Jetty9xServerHandleInterceptor extends AbstractServerHandleInterceptor { + + public Jetty9xServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + HttpServletRequest toHttpServletRequest(Object[] args) { + if (args == null || args.length < 1) { + return null; + } + + if (args[0] instanceof HttpChannel) { + final HttpChannel channel = (HttpChannel) args[0]; + return channel.getRequest(); + } + return null; + } + + @Override + HttpServletResponse toHttpServletResponse(Object[] args) { + if (args == null || args.length < 1) { + return null; + } + + if (args[0] instanceof HttpChannel) { + final HttpChannel channel = (HttpChannel) args[0]; + return channel.getResponse(); + } + return null; + } +} diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/RequestStartAsyncInterceptor.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/RequestStartAsyncInterceptor.java new file mode 100644 index 000000000000..4c5966b0b622 --- /dev/null +++ b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/RequestStartAsyncInterceptor.java @@ -0,0 +1,111 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.jetty.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.jetty.JettyAsyncListener; +import com.navercorp.pinpoint.plugin.jetty.JettyConstants; + +import javax.servlet.AsyncContext; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletRequest; + +/** + * @author jaehong.kim + */ +public class RequestStartAsyncInterceptor implements AroundInterceptor { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor descriptor; + + public RequestStartAsyncInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + if (validate(target, result, throwable)) { + // Add async listener. Servlet 3.0 + final AsyncContext asyncContext = (AsyncContext) result; + final AsyncListener asyncListener = new JettyAsyncListener(this.traceContext, recorder.recordNextAsyncContext(true)); + asyncContext.addListener(asyncListener); + if (isDebug) { + logger.debug("Add async listener {}", asyncListener); + } + } + recorder.recordServiceType(JettyConstants.JETTY_METHOD); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + } catch (Throwable t) { + logger.warn("Failed to AFTER process. {}", t.getMessage(), t); + } finally { + trace.traceBlockEnd(); + } + } + + private boolean validate(final Object target, final Object result, final Throwable throwable) { + if (throwable != null || result == null) { + return false; + } + + if (!(target instanceof HttpServletRequest)) { + logger.debug("Invalid target object. {}", target); + return false; + } + + + if (!(result instanceof AsyncContext)) { + logger.debug("Invalid result object. {}.", result); + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/ServerHandleInterceptor.java b/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/ServerHandleInterceptor.java deleted file mode 100644 index 26278d24785e..000000000000 --- a/plugins/jetty/src/main/java/com/navercorp/pinpoint/plugin/jetty/interceptor/ServerHandleInterceptor.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.jetty.interceptor; - -import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import org.eclipse.jetty.server.HttpChannel; -import org.eclipse.jetty.server.Request; - -/** - * @author Taejin Koo - * @author jaehong.kim - * - * jetty-9.x - */ -public class ServerHandleInterceptor extends AbstractServerHandleInterceptor { - - public ServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor, Filter excludeFilter) { - super(traceContext, descriptor, excludeFilter); - } - - @Override - protected Request getRequest(final Object[] args) { - if (args == null || args.length < 1) { - return null; - } - - if (args[0] instanceof HttpChannel) { - final HttpChannel channel = (HttpChannel) args[0]; - return channel.getRequest(); - } - return null; - } - - @Override - String getHeader(final Request request, final String name) { - if (request == null || request.getHttpFields() == null) { - return null; - } - return request.getHttpFields().get(name); - } -} \ No newline at end of file diff --git a/plugins/json-lib/clover.license b/plugins/json-lib/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/json-lib/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-json-lib-plugin diff --git a/plugins/jsp/clover.license b/plugins/jsp/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/jsp/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-jsp-plugin @@ -16,6 +16,18 @@ ${env.JAVA_7_HOME} + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/jsp/src/main/java/com/navercorp/pinpoint/plugin/jsp/JspConstants.java b/plugins/jsp/src/main/java/com/navercorp/pinpoint/plugin/jsp/JspConstants.java index 392fa6195036..3c0f3d30c118 100644 --- a/plugins/jsp/src/main/java/com/navercorp/pinpoint/plugin/jsp/JspConstants.java +++ b/plugins/jsp/src/main/java/com/navercorp/pinpoint/plugin/jsp/JspConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,6 +21,9 @@ /** * @author jaehong.kim */ -public class JspConstants { +public final class JspConstants { + private JspConstants() { + } + public static final ServiceType SERVICE_TYPE = ServiceTypeFactory.of(5005, "JSP"); } diff --git a/plugins/jtds/clover.license b/plugins/jtds/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/jtds/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-jtds-plugin pinpoint-jtds-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/kafka/.gitignore b/plugins/kafka/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/kafka/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/kafka/pom.xml b/plugins/kafka/pom.xml new file mode 100644 index 000000000000..4701ed6c34ef --- /dev/null +++ b/plugins/kafka/pom.xml @@ -0,0 +1,45 @@ + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-kafka-plugin + pinpoint-kafka-plugin + jar + + + 1.6 + ${env.JAVA_8_HOME} + java18 + + + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + org.apache.kafka + kafka-clients + provided + + + \ No newline at end of file diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaConfig.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaConfig.java new file mode 100644 index 000000000000..7f8dd41aed3a --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaConfig.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +public class KafkaConfig { + + static final String PRODUCER_ENABLE = "profiler.kafka.producer.enable"; + static final String CONSUMER_ENABLE = "profiler.kafka.consumer.enable"; + static final String CONSUMER_ENTRY_POINT = "profiler.kafka.consumer.entryPoint"; + + private final boolean producerEnable; + private final boolean consumerEnable; + private final String kafkaEntryPoint; + + public KafkaConfig(ProfilerConfig config) { + /* + * kafka + */ + this.producerEnable = config.readBoolean(PRODUCER_ENABLE, false); + this.consumerEnable = config.readBoolean(CONSUMER_ENABLE, false); + this.kafkaEntryPoint = config.readString(CONSUMER_ENTRY_POINT, ""); + } + + public boolean isProducerEnable() { + return producerEnable; + } + + public boolean isConsumerEnable() { + return consumerEnable; + } + + public String getKafkaEntryPoint() { + return kafkaEntryPoint; + } + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaConstants.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaConstants.java new file mode 100644 index 000000000000..0f145d4f7f58 --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaConstants.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka; + +import com.navercorp.pinpoint.common.Charsets; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; + +import java.nio.charset.Charset; + +import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.QUEUE; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; + +public class KafkaConstants { + + public static final ServiceType KAFKA_CLIENT = ServiceTypeFactory.of(8660, "KAFKA_CLIENT", "KAFKA_CLIENT", QUEUE, RECORD_STATISTICS); + public static final ServiceType KAFKA_CLIENT_INTERNAL = ServiceTypeFactory.of(8661, "KAFKA_CLIENT_INTERNAL", "KAFKA_CLIENT"); + + public static final AnnotationKey KAFKA_TOPIC_ANNOTATION_KEY = AnnotationKeyFactory.of(140, "kafka.topic", VIEW_IN_RECORD_SET); + public static final AnnotationKey KAFKA_PARTITION_ANNOTATION_KEY = AnnotationKeyFactory.of(141, "kafka.partition", VIEW_IN_RECORD_SET); + public static final AnnotationKey KAFKA_OFFSET_ANNOTATION_KEY = AnnotationKeyFactory.of(142, "kafka.offset", VIEW_IN_RECORD_SET); + public static final AnnotationKey KAFKA_BATCH_ANNOTATION_KEY = AnnotationKeyFactory.of(143, "kafka.batch", VIEW_IN_RECORD_SET); + + public static final String REMOTE_ADDRESS_ACCESSOR = RemoteAddressFieldAccessor.class.getName(); + + public static final String PRODUCER_CONSTRUCTOR_INTERCEPTOR = "com.navercorp.pinpoint.plugin.kafka.interceptor.ProducerConstructorInterceptor"; + public static final String PRODUCER_SEND_INTERCEPTOR = "com.navercorp.pinpoint.plugin.kafka.interceptor.ProducerSendInterceptor"; + + public static final String CONSUMER_CONSTRUCTOR_INTERCEPTOR = "com.navercorp.pinpoint.plugin.kafka.interceptor.ConsumerConstructorInterceptor"; + + public static final String CONSUMER_POLL_INTERCEPTOR = "com.navercorp.pinpoint.plugin.kafka.interceptor.ConsumerPollInterceptor"; + + public static final String CONSUMER_RECORD_ENTRYPOINT_INTERCEPTOR = "com.navercorp.pinpoint.plugin.kafka.interceptor.ConsumerRecordEntryPointInterceptor"; + + public static final String CONSUMER_MULTI_RECORD_ENTRYPOINT_INTERCEPTOR = "com.navercorp.pinpoint.plugin.kafka.interceptor.ConsumerMultiRecordEntryPointInterceptor"; + + public static final String CONSUMER_MULTI_RECORD_CLASS_NAME = "org.apache.kafka.clients.consumer.ConsumerRecords"; + + public static final String CONSUMER_RECORD_CLASS_NAME = "org.apache.kafka.clients.consumer.ConsumerRecord"; + + public static final String UNKNOWN = "Unknown"; + + public static final Charset DEFAULT_PINPOINT_HEADER_CHARSET = Charsets.UTF_8; + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaMetadataProvider.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaMetadataProvider.java new file mode 100644 index 000000000000..39525038e01d --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaMetadataProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +public class KafkaMetadataProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(KafkaConstants.KAFKA_CLIENT); + context.addServiceType(KafkaConstants.KAFKA_CLIENT_INTERNAL); + + context.addAnnotationKey(KafkaConstants.KAFKA_TOPIC_ANNOTATION_KEY); + context.addAnnotationKey(KafkaConstants.KAFKA_PARTITION_ANNOTATION_KEY); + context.addAnnotationKey(KafkaConstants.KAFKA_OFFSET_ANNOTATION_KEY); + context.addAnnotationKey(KafkaConstants.KAFKA_BATCH_ANNOTATION_KEY); + } + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaPlugin.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaPlugin.java new file mode 100644 index 000000000000..fafdcb722110 --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/KafkaPlugin.java @@ -0,0 +1,159 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka; + +import com.navercorp.pinpoint.bootstrap.instrument.*; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import com.navercorp.pinpoint.common.util.StringUtils; + +import java.security.ProtectionDomain; + + +public class KafkaPlugin implements ProfilerPlugin, TransformTemplateAware { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private TransformTemplate transformTemplate; + + @Override + public void setup(ProfilerPluginSetupContext context) { + final KafkaConfig config = new KafkaConfig(context.getConfig()); + + if (config.isProducerEnable()) { + transformTemplate.transform("org.apache.kafka.clients.producer.KafkaProducer", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + InstrumentMethod constructor = target.getConstructor("org.apache.kafka.clients.producer.ProducerConfig", + "org.apache.kafka.common.serialization.Serializer", "org.apache.kafka.common.serialization.Serializer"); + constructor.addInterceptor(KafkaConstants.PRODUCER_CONSTRUCTOR_INTERCEPTOR); + + InstrumentMethod sendMethod = target.getDeclaredMethod("send", "org.apache.kafka.clients.producer.ProducerRecord", "org.apache.kafka.clients.producer.Callback"); + sendMethod.addInterceptor(KafkaConstants.PRODUCER_SEND_INTERCEPTOR); + + target.addField(KafkaConstants.REMOTE_ADDRESS_ACCESSOR); + return target.toBytecode(); + } + + }); + } + + if (config.isConsumerEnable()) { + if (StringUtils.isEmpty(config.getKafkaEntryPoint())) { + return; + } + + transformTemplate.transform("org.apache.kafka.clients.consumer.KafkaConsumer", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + InstrumentMethod constructor = target.getConstructor("org.apache.kafka.clients.consumer.ConsumerConfig", + "org.apache.kafka.common.serialization.Deserializer", "org.apache.kafka.common.serialization.Deserializer"); + constructor.addInterceptor(KafkaConstants.CONSUMER_CONSTRUCTOR_INTERCEPTOR); + + InstrumentMethod pollMethod = target.getDeclaredMethod("poll", "long"); + pollMethod.addInterceptor(KafkaConstants.CONSUMER_POLL_INTERCEPTOR); + + target.addField(KafkaConstants.REMOTE_ADDRESS_ACCESSOR); + + return target.toBytecode(); + } + }); + + transformTemplate.transform("org.apache.kafka.clients.consumer.ConsumerRecord", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(KafkaConstants.REMOTE_ADDRESS_ACCESSOR); + return target.toBytecode(); + } + }); + + transformEntryPoint(config.getKafkaEntryPoint()); + } + } + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } + + public void transformEntryPoint(String entryPoint) { + final String clazzName = toClassName(entryPoint); + final String methodName = toMethodName(entryPoint); + + transformTemplate.transform(clazzName, new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(methodName))) { + try { + String[] parameterTypes = method.getParameterTypes(); + + for (String parameterType : parameterTypes) { + if (KafkaConstants.CONSUMER_RECORD_CLASS_NAME.equals(parameterType)) { + method.addInterceptor(KafkaConstants.CONSUMER_RECORD_ENTRYPOINT_INTERCEPTOR); + break; + } else if (KafkaConstants.CONSUMER_MULTI_RECORD_CLASS_NAME.equals(parameterType)) { + method.addInterceptor(KafkaConstants.CONSUMER_MULTI_RECORD_ENTRYPOINT_INTERCEPTOR); + break; + } + } + + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + return target.toBytecode(); + } + + }); + } + + private String toClassName(String fullQualifiedMethodName) { + final int classEndPosition = fullQualifiedMethodName.lastIndexOf('.'); + if (classEndPosition <= 0) { + throw new IllegalArgumentException("invalid full qualified method name(" + fullQualifiedMethodName + "). not found method"); + } + + return fullQualifiedMethodName.substring(0, classEndPosition); + } + + private String toMethodName(String fullQualifiedMethodName) { + final int methodBeginPosition = fullQualifiedMethodName.lastIndexOf('.'); + if (methodBeginPosition <= 0 || methodBeginPosition + 1 >= fullQualifiedMethodName.length()) { + throw new IllegalArgumentException("invalid full qualified method name(" + fullQualifiedMethodName + "). not found method"); + } + + return fullQualifiedMethodName.substring(methodBeginPosition + 1); + } + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/descriptor/EntryPointMethodDescriptor.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/descriptor/EntryPointMethodDescriptor.java new file mode 100644 index 000000000000..b7004d3c293a --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/descriptor/EntryPointMethodDescriptor.java @@ -0,0 +1,89 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka.descriptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; + +/** + * @author Taejin Koo + */ +public class EntryPointMethodDescriptor implements MethodDescriptor { + + private int apiId = 0; + private int type = MethodType.WEB_REQUEST; + + @Override + public String getMethodName() { + return ""; + } + + @Override + public String getClassName() { + return ""; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return "()"; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return EntryPointMethodDescriptor.class.getName(); + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return apiId; + } + + @Override + public String getApiDescriptor() { + return "Kafka Consumer Invocation"; + } + + @Override + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/field/accessor/RemoteAddressFieldAccessor.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/field/accessor/RemoteAddressFieldAccessor.java new file mode 100644 index 000000000000..756237112e7f --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/field/accessor/RemoteAddressFieldAccessor.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka.field.accessor; + +/** + * @author Taejin Koo + */ +public interface RemoteAddressFieldAccessor { + + void _$PINPOINT$_setRemoteAddress(String remoteAddress); + String _$PINPOINT$_getRemoteAddress(); + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerConstructorInterceptor.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerConstructorInterceptor.java new file mode 100644 index 000000000000..31d59c61857e --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerConstructorInterceptor.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.plugin.kafka.KafkaConstants; +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.consumer.ConsumerConfig; + +import java.util.List; + +public class ConsumerConstructorInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + public ConsumerConstructorInterceptor() { + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + if (throwable != null) { + return; + } + + if (!(target instanceof RemoteAddressFieldAccessor)) { + return; + } + + ConsumerConfig consumerConfig = getConsumerConfig(args); + if (consumerConfig == null) { + return; + } + + String remoteAddress = getRemoteAddress(consumerConfig); + ((RemoteAddressFieldAccessor) target)._$PINPOINT$_setRemoteAddress(remoteAddress); + } + + private ConsumerConfig getConsumerConfig(Object args[]) { + if (ArrayUtils.isEmpty(args)) { + return null; + } + + if (args[0] instanceof ConsumerConfig) { + return (ConsumerConfig)args[0]; + } + + return null; + } + + private String getRemoteAddress(ConsumerConfig consumerConfig) { + List serverList = consumerConfig.getList("bootstrap.servers"); + String remoteAddress = KafkaConstants.UNKNOWN; + if (CollectionUtils.nullSafeSize(serverList) == 1) { + remoteAddress = serverList.get(0); + } else if (CollectionUtils.nullSafeSize(serverList) > 1) { + remoteAddress = serverList.toString(); + } + return remoteAddress; + } + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerMultiRecordEntryPointInterceptor.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerMultiRecordEntryPointInterceptor.java new file mode 100644 index 000000000000..aefebdfa653b --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerMultiRecordEntryPointInterceptor.java @@ -0,0 +1,174 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.plugin.kafka.KafkaConstants; +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; + +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicReference; + +/** + * The type Consumer multi record entry point interceptor. + * + * @author Victor.Zxy + */ +public class ConsumerMultiRecordEntryPointInterceptor extends ConsumerRecordEntryPointInterceptor { + + private final AtomicReference tracyFactoryReference = new AtomicReference(); + + /** + * Instantiates a new Consumer multi record entry point interceptor. + * + * @param traceContext the trace context + * @param methodDescriptor the method descriptor + */ + public ConsumerMultiRecordEntryPointInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected Trace createTrace(Object target, Object[] args) { + + ConsumerRecords consumerRecords = getConsumerRecords(args); + + if (consumerRecords == null || consumerRecords.isEmpty()) { + return null; + } + Trace newTrace = createTrace(consumerRecords); + + return newTrace; + } + + private ConsumerRecords getConsumerRecords(Object[] args) { + if (args == null) { + return null; + } + + for (Object arg : args) { + if (arg instanceof ConsumerRecords) { + return (ConsumerRecords) arg; + } + } + return null; + } + + private Trace createTrace(ConsumerRecords consumerRecords) { + TraceFactoryProvider.TraceFactory createTrace = tracyFactoryReference.get(); + if (createTrace == null) { + createTrace = TraceFactoryProvider.get(); + tracyFactoryReference.compareAndSet(null, createTrace); + } + return createTrace.createTrace(traceContext, consumerRecords); + } + + private static class TraceFactoryProvider { + + private static TraceFactory get() { + + return new DefaultTraceFactory(); + } + + private interface TraceFactory { + + /** + * Create trace trace. + * + * @param traceContext the trace context + * @param consumerRecords the consumer records + * @return the trace + */ + Trace createTrace(TraceContext traceContext, ConsumerRecords consumerRecords); + } + + private static class DefaultTraceFactory implements TraceFactory { + + /** + * The Logger. + */ + final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + @Override + public Trace createTrace(TraceContext traceContext, ConsumerRecords consumerRecords) { + + final Trace trace = traceContext.newTraceObject(); + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + recordRootSpan(recorder, consumerRecords); + if (logger.isDebugEnabled()) { + logger.debug("TraceID not exist. start new trace."); + } + return trace; + } else { + if (logger.isDebugEnabled()) { + logger.debug("TraceID not exist. camSampled is false. skip trace."); + } + return null; + } + } + + private void recordRootSpan(SpanRecorder recorder, ConsumerRecords consumerRecords) { + recorder.recordServiceType(KafkaConstants.KAFKA_CLIENT); + recorder.recordApi(ENTRY_POINT_METHOD_DESCRIPTOR); + + int count = consumerRecords.count(); + Iterator iterator = consumerRecords.iterator(); + ConsumerRecord consumerRecord = iterator.next(); + + String remoteAddress = getRemoteAddress(consumerRecord); + recorder.recordEndPoint(remoteAddress); + recorder.recordRemoteAddress(remoteAddress); + + String topic = consumerRecord.topic(); + recorder.recordRpcName(createRpcName(topic, count)); + recorder.recordAcceptorHost("topic:" + topic); + recorder.recordAttribute(KafkaConstants.KAFKA_TOPIC_ANNOTATION_KEY, topic); + recorder.recordAttribute(KafkaConstants.KAFKA_BATCH_ANNOTATION_KEY, count); + + } + + private String getRemoteAddress(Object remoteAddressFieldAccessor) { + String remoteAddress = null; + if (remoteAddressFieldAccessor instanceof RemoteAddressFieldAccessor) { + remoteAddress = ((RemoteAddressFieldAccessor) remoteAddressFieldAccessor)._$PINPOINT$_getRemoteAddress(); + } + + if (StringUtils.isEmpty(remoteAddress)) { + return KafkaConstants.UNKNOWN; + } else { + return remoteAddress; + } + } + + private String createRpcName(String topic, int count) { + StringBuilder rpcName = new StringBuilder("kafka://"); + rpcName.append("topic=").append(topic); + rpcName.append("?batch=").append(count); + return rpcName.toString(); + } + } + } +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerPollInterceptor.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerPollInterceptor.java new file mode 100644 index 000000000000..9ad4093a98da --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerPollInterceptor.java @@ -0,0 +1,80 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.plugin.kafka.KafkaConstants; +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.consumer.ConsumerRecords; + +import java.util.Iterator; + +/** + * @author Taejin Koo + */ +public class ConsumerPollInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + public ConsumerPollInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + if (!(target instanceof RemoteAddressFieldAccessor)) { + return; + } + + String remoteAddress = ((RemoteAddressFieldAccessor) target)._$PINPOINT$_getRemoteAddress(); + if (StringUtils.isEmpty(remoteAddress)) { + remoteAddress = KafkaConstants.UNKNOWN; + } + + if (result instanceof ConsumerRecords) { + Iterator consumerRecordIterator = ((ConsumerRecords) result).iterator(); + while (consumerRecordIterator.hasNext()) { + Object consumerRecord = consumerRecordIterator.next(); + if (consumerRecord instanceof RemoteAddressFieldAccessor) { + ((RemoteAddressFieldAccessor) consumerRecord)._$PINPOINT$_setRemoteAddress(remoteAddress); + } + } + } + } + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerRecordEntryPointInterceptor.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerRecordEntryPointInterceptor.java new file mode 100644 index 000000000000..6f817f66baf3 --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerRecordEntryPointInterceptor.java @@ -0,0 +1,290 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanRecursiveAroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.bootstrap.util.NumberUtils; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.plugin.kafka.KafkaConstants; +import com.navercorp.pinpoint.plugin.kafka.descriptor.EntryPointMethodDescriptor; +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.consumer.ConsumerRecord; + +import java.lang.reflect.Method; +import java.util.concurrent.atomic.AtomicReference; + +/** + * @author Taejin Koo + * @author Victor.Zxy + */ +public class ConsumerRecordEntryPointInterceptor extends SpanRecursiveAroundInterceptor { + + protected static final String SCOPE_NAME = "##KAFKA_ENTRY_POINT_START_TRACE"; + + protected static final EntryPointMethodDescriptor ENTRY_POINT_METHOD_DESCRIPTOR = new EntryPointMethodDescriptor(); + + private final AtomicReference tracyFactoryReference = new AtomicReference(); + + public ConsumerRecordEntryPointInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor, SCOPE_NAME); + traceContext.cacheApi(ENTRY_POINT_METHOD_DESCRIPTOR); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + recorder.recordServiceType(KafkaConstants.KAFKA_CLIENT_INTERNAL); + } + + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + + } + + @Override + protected Trace createTrace(Object target, Object[] args) { + + ConsumerRecord consumerRecord = getConsumerRecord(args); + + if (consumerRecord == null) { + return null; + } + Trace newTrace = createTrace(consumerRecord); + + return newTrace; + } + + private ConsumerRecord getConsumerRecord(Object[] args) { + if (args == null) { + return null; + } + + for (Object arg : args) { + if (arg instanceof ConsumerRecord) { + return (ConsumerRecord) arg; + } + } + return null; + } + + private Trace createTrace(ConsumerRecord consumerRecord) { + TraceFactoryProvider.TraceFactory createTrace = tracyFactoryReference.get(); + if (createTrace == null) { + createTrace = TraceFactoryProvider.get(consumerRecord); + tracyFactoryReference.compareAndSet(null, createTrace); + } + return createTrace.createTrace(traceContext, consumerRecord); + } + + private static class TraceFactoryProvider { + + private static TraceFactory get(Object object) { + try { + final Class aClass = object.getClass(); + final Method method = aClass.getMethod("headers"); + + if (method != null) { + return new SupportContinueTraceFactory(); + } + } catch (NoSuchMethodException e) { + // ignore + } + return new DefaultTraceFactory(); + } + + private interface TraceFactory { + + Trace createTrace(TraceContext traceContext, ConsumerRecord consumerRecord); + + } + + private static class DefaultTraceFactory implements TraceFactory { + + final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + final boolean isDebug = logger.isDebugEnabled(); + + @Override + public Trace createTrace(TraceContext traceContext, ConsumerRecord consumerRecord) { + return createTrace0(traceContext, consumerRecord); + } + + Trace createTrace0(TraceContext traceContext, ConsumerRecord consumerRecord) { + final Trace trace = traceContext.newTraceObject(); + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + recordRootSpan(recorder, consumerRecord); + if (isDebug) { + logger.debug("TraceID not exist. start new trace."); + } + return trace; + } else { + if (isDebug) { + logger.debug("TraceID not exist. camSampled is false. skip trace."); + } + return null; + } + } + + void recordRootSpan(SpanRecorder recorder, ConsumerRecord consumerRecord) { + recordRootSpan(recorder, consumerRecord, null, null); + } + + void recordRootSpan(SpanRecorder recorder, ConsumerRecord consumerRecord, String parentApplicationName, String parentApplicationType) { + recorder.recordServiceType(KafkaConstants.KAFKA_CLIENT); + recorder.recordApi(ConsumerRecordEntryPointInterceptor.ENTRY_POINT_METHOD_DESCRIPTOR); + + String remoteAddress = getRemoteAddress(consumerRecord); + recorder.recordEndPoint(remoteAddress); + recorder.recordRemoteAddress(remoteAddress); + + String topic = consumerRecord.topic(); + recorder.recordRpcName(createRpcName(consumerRecord)); + recorder.recordAcceptorHost("topic:" + topic); + recorder.recordAttribute(KafkaConstants.KAFKA_TOPIC_ANNOTATION_KEY, topic); + + recorder.recordAttribute(KafkaConstants.KAFKA_PARTITION_ANNOTATION_KEY, consumerRecord.partition()); + recorder.recordAttribute(KafkaConstants.KAFKA_OFFSET_ANNOTATION_KEY, consumerRecord.offset()); + + if (StringUtils.hasText(parentApplicationName) && StringUtils.hasText(parentApplicationType)) { + recorder.recordParentApplication(parentApplicationName, NumberUtils.parseShort(parentApplicationType, ServiceType.UNDEFINED.getCode())); + } + } + + private String getRemoteAddress(Object remoteAddressFieldAccessor) { + String remoteAddress = null; + if (remoteAddressFieldAccessor instanceof RemoteAddressFieldAccessor) { + remoteAddress = ((RemoteAddressFieldAccessor) remoteAddressFieldAccessor)._$PINPOINT$_getRemoteAddress(); + } + + if (StringUtils.isEmpty(remoteAddress)) { + return KafkaConstants.UNKNOWN; + } else { + return remoteAddress; + } + } + + private String createRpcName(ConsumerRecord consumerRecord) { + StringBuilder rpcName = new StringBuilder("kafka://"); + rpcName.append("topic=").append(consumerRecord.topic()); + rpcName.append("?partition=").append(consumerRecord.partition()); + rpcName.append("&offset=").append(consumerRecord.offset()); + + return rpcName.toString(); + } + + } + + private static class SupportContinueTraceFactory extends DefaultTraceFactory { + + @Override + public Trace createTrace(TraceContext traceContext, ConsumerRecord consumerRecord) { + org.apache.kafka.common.header.Headers headers = consumerRecord.headers(); + if (headers == null) { + return null; + } + + if (!isSampled(headers)) { + // Even if this transaction is not a sampling target, we have to create Trace object to mark 'not sampling'. + // For example, if this transaction invokes rpc call, we can add parameter to tell remote node 'don't sample this transaction' + final Trace trace = traceContext.disableSampling(); + if (isDebug) { + logger.debug("remotecall sampling flag found. skip trace"); + } + return trace; + } + + TraceId traceId = populateTraceIdFromHeaders(traceContext, headers); + if (traceId != null) { + return createContinueTrace(traceContext, consumerRecord, traceId); + } else { + return createTrace0(traceContext, consumerRecord); + } + } + + private boolean isSampled(org.apache.kafka.common.header.Headers headers) { + org.apache.kafka.common.header.Header sampledHeader = headers.lastHeader(Header.HTTP_SAMPLED.toString()); + if (sampledHeader == null) { + return true; + } + + String sampledFlag = new String(sampledHeader.value(), KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET); + return SamplingFlagUtils.isSamplingFlag(sampledFlag); + } + + private TraceId populateTraceIdFromHeaders(TraceContext traceContext, org.apache.kafka.common.header.Headers headers) { + String transactionId = null; + String spanID = null; + String parentSpanID = null; + String flags = null; + for (org.apache.kafka.common.header.Header header : headers.toArray()) { + if (header.key().equals(Header.HTTP_TRACE_ID.toString())) { + transactionId = new String(header.value(), KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET); + } else if (header.key().equals(Header.HTTP_PARENT_SPAN_ID.toString())) { + parentSpanID = new String(header.value(), KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET); + } else if (header.key().equals(Header.HTTP_SPAN_ID.toString())) { + spanID = new String(header.value(), KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET); + } else if (header.key().equals(Header.HTTP_FLAGS.toString())) { + flags = new String(header.value(), KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET); + } + } + + if (transactionId == null || spanID == null || parentSpanID == null || flags == null) { + return null; + } + + TraceId traceId = traceContext.createTraceId(transactionId, Long.parseLong(parentSpanID), Long.parseLong(spanID), Short.parseShort(flags)); + return traceId; + } + + private Trace createContinueTrace(TraceContext traceContext, ConsumerRecord consumerRecord, TraceId traceId) { + if (isDebug) { + logger.debug("TraceID exist. continue trace. traceId:{}", traceId); + } + + Trace trace = traceContext.continueTraceObject(traceId); + + String parentApplicationName = null; + String parentApplicationType = null; + + org.apache.kafka.common.header.Headers headers = consumerRecord.headers(); + for (org.apache.kafka.common.header.Header header : headers.toArray()) { + if (header.key().equals(Header.HTTP_PARENT_APPLICATION_NAME.toString())) { + parentApplicationName = new String(header.value(), KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET); + } else if (header.key().equals(Header.HTTP_PARENT_APPLICATION_TYPE.toString())) { + parentApplicationType = new String(header.value(), KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET); + } + } + + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + recordRootSpan(recorder, consumerRecord, parentApplicationName, parentApplicationType); + } + return trace; + } + + } + + } + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerConstructorInterceptor.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerConstructorInterceptor.java new file mode 100644 index 000000000000..ffb7b18cab12 --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerConstructorInterceptor.java @@ -0,0 +1,91 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.plugin.kafka.KafkaConstants; +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.producer.ProducerConfig; + +import java.util.List; + +/** + * @author Taejin Koo + */ +public class ProducerConstructorInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + if (throwable != null) { + return; + } + + if (!(target instanceof RemoteAddressFieldAccessor)) { + return; + } + + ProducerConfig producerConfig = getProducerConfig(args); + if (producerConfig == null) { + return; + } + + String remoteAddress = getRemoteAddress(producerConfig); + ((RemoteAddressFieldAccessor) target)._$PINPOINT$_setRemoteAddress(remoteAddress); + } + + private ProducerConfig getProducerConfig(Object args[]) { + if (ArrayUtils.isEmpty(args)) { + return null; + } + + if (args[0] instanceof ProducerConfig) { + return (ProducerConfig)args[0]; + } + + return null; + } + + private String getRemoteAddress(ProducerConfig producerConfig) { + List serverList = producerConfig.getList("bootstrap.servers"); + String remoteAddress = KafkaConstants.UNKNOWN; + if (CollectionUtils.nullSafeSize(serverList) == 1) { + remoteAddress = serverList.get(0); + } else if (CollectionUtils.nullSafeSize(serverList) > 1) { + remoteAddress = serverList.toString(); + } + return remoteAddress; + } + +} diff --git a/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerSendInterceptor.java b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerSendInterceptor.java new file mode 100644 index 000000000000..70b1e274df8b --- /dev/null +++ b/plugins/kafka/src/main/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerSendInterceptor.java @@ -0,0 +1,220 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.plugin.kafka.KafkaConstants; +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.producer.ProducerRecord; + +import java.lang.reflect.Method; +import java.util.concurrent.atomic.AtomicReference; + + +public class ProducerSendInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + private final AtomicReference headerSetterReference = new AtomicReference(); + + public ProducerSendInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (logger.isDebugEnabled()) { + logger.beforeInterceptor(target, args); + } + + ProducerRecord record = getProducerRecord(args); + if (record == null) { + return; + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if (trace.canSampled()) { + SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(KafkaConstants.KAFKA_CLIENT); + setPinpointHeaders(recorder, trace, record, true); + } else { + setPinpointHeaders(null, trace, record, false); + } + } + + private ProducerRecord getProducerRecord(Object args[]) { + if (ArrayUtils.isEmpty(args)) { + return null; + } + + if (args[0] instanceof ProducerRecord) { + return (ProducerRecord) args[0]; + } + + return null; + } + + private void setPinpointHeaders(SpanEventRecorder recorder, Trace trace, ProducerRecord record, boolean sample) { + HeaderSetter headerSetter = headerSetterReference.get(); + if (headerSetter == null) { + headerSetter = HeaderSetterProvider.get(record); + headerSetterReference.compareAndSet(null, headerSetter); + } + headerSetter.setPinpointHeaders(recorder, trace, record, sample, traceContext.getApplicationName(), traceContext.getServerTypeCode()); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (logger.isDebugEnabled()) { + logger.afterInterceptor(target, args, result, throwable); + } + + ProducerRecord record = getProducerRecord(args); + if (record == null) { + return; + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if (!trace.canSampled()) { + return; + } + + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(descriptor); + + if (throwable != null) { + recorder.recordException(throwable); + } else { + String remoteAddress = getRemoteAddress(target); + recorder.recordEndPoint(remoteAddress); + + String topic = record.topic(); + recorder.recordDestinationId("topic:" + topic); + recorder.recordAttribute(KafkaConstants.KAFKA_TOPIC_ANNOTATION_KEY, topic); + } + } finally { + trace.traceBlockEnd(); + } + } + + private String getRemoteAddress(Object remoteAddressFieldAccessor) { + String remoteAddress = null; + if (remoteAddressFieldAccessor instanceof RemoteAddressFieldAccessor) { + remoteAddress = ((RemoteAddressFieldAccessor) remoteAddressFieldAccessor)._$PINPOINT$_getRemoteAddress(); + } + + if (StringUtils.isEmpty(remoteAddress)) { + return KafkaConstants.UNKNOWN; + } else { + return remoteAddress; + } + } + + private static class HeaderSetterProvider { + + static HeaderSetter get(Object object) { + try { + final Class aClass = object.getClass(); + final Method method = aClass.getMethod("headers"); + if (method != null) { + return new DefaultHeaderSetter(); + } + } catch (NoSuchMethodException e) { + // ignore + } + return new DisabledHeaderSetter(); + } + + } + + private interface HeaderSetter { + + void setPinpointHeaders(SpanEventRecorder recorder, Trace trace, ProducerRecord record, boolean sample, String applicationName, short serverTypeCode); + + } + + private static class DisabledHeaderSetter implements HeaderSetter { + + @Override + public void setPinpointHeaders(SpanEventRecorder recorder, Trace trace, ProducerRecord record, boolean sample, String applicationName, short serverTypeCode) { + } + + } + + private static class DefaultHeaderSetter implements HeaderSetter { + + public void setPinpointHeaders(SpanEventRecorder recorder, Trace trace, ProducerRecord record, boolean sample, String applicationName, short serverTypeCode) { + org.apache.kafka.common.header.Headers kafkaHeaders = record.headers(); + if (kafkaHeaders == null) { + return; + } + + cleanPinpointHeader(kafkaHeaders); + if (sample) { + final TraceId nextId = trace.getTraceId().getNextTraceId(); + recorder.recordNextSpanId(nextId.getSpanId()); + + kafkaHeaders.add(new org.apache.kafka.common.header.internals.RecordHeader(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId().getBytes(KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET))); + kafkaHeaders.add(new org.apache.kafka.common.header.internals.RecordHeader(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId()).getBytes(KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET))); + kafkaHeaders.add(new org.apache.kafka.common.header.internals.RecordHeader(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId()).getBytes(KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET))); + kafkaHeaders.add(new org.apache.kafka.common.header.internals.RecordHeader(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags()).getBytes(KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET))); + kafkaHeaders.add(new org.apache.kafka.common.header.internals.RecordHeader(Header.HTTP_PARENT_APPLICATION_NAME.toString(), String.valueOf(applicationName).getBytes(KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET))); + kafkaHeaders.add(new org.apache.kafka.common.header.internals.RecordHeader(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(serverTypeCode).getBytes(KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET))); + } else { + kafkaHeaders.add(new org.apache.kafka.common.header.internals.RecordHeader(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE.getBytes(KafkaConstants.DEFAULT_PINPOINT_HEADER_CHARSET))); + } + } + + private void cleanPinpointHeader(org.apache.kafka.common.header.Headers kafkaHeaders) { + Assert.requireNonNull(kafkaHeaders, "kafkaHeaders must not be null"); + + for (org.apache.kafka.common.header.Header kafkaHeader : kafkaHeaders.toArray()) { + String kafkaHeaderKey = kafkaHeader.key(); + if (Header.startWithPinpointHeader(kafkaHeaderKey)) { + kafkaHeaders.remove(kafkaHeaderKey); + } + } + } + + } + +} diff --git a/plugins/kafka/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/kafka/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..dd4213703051 --- /dev/null +++ b/plugins/kafka/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.kafka.KafkaPlugin \ No newline at end of file diff --git a/plugins/kafka/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/kafka/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..c27e94312fed --- /dev/null +++ b/plugins/kafka/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.kafka.KafkaMetadataProvider \ No newline at end of file diff --git a/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/KafkaConfigTest.java b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/KafkaConfigTest.java new file mode 100644 index 000000000000..60143b9646c1 --- /dev/null +++ b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/KafkaConfigTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.kafka; + +import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Properties; + +/** + * @author Taejin Koo + */ +public class KafkaConfigTest { + + @Test + public void configTest1() throws Exception { + KafkaConfig config = createConfig("true", "true", "entryPoint"); + + Assert.assertTrue(config.isProducerEnable()); + Assert.assertTrue(config.isConsumerEnable()); + Assert.assertEquals("entryPoint", config.getKafkaEntryPoint()); + } + + @Test + public void configTest2() throws Exception { + KafkaConfig config = createConfig("true", "false"); + + Assert.assertTrue(config.isProducerEnable()); + Assert.assertFalse(config.isConsumerEnable()); + Assert.assertEquals("", config.getKafkaEntryPoint()); + } + + @Test + public void configTest3() throws Exception { + KafkaConfig config = createConfig("false", "true"); + + Assert.assertFalse(config.isProducerEnable()); + Assert.assertTrue(config.isConsumerEnable()); + Assert.assertEquals("", config.getKafkaEntryPoint()); + } + + @Test + public void configTest4() throws Exception { + KafkaConfig config = createConfig("false", "false"); + + Assert.assertFalse(config.isProducerEnable()); + Assert.assertFalse(config.isConsumerEnable()); + Assert.assertEquals("", config.getKafkaEntryPoint()); + } + + private KafkaConfig createConfig(String producerEnable, String consumerEnable) { + return createConfig(producerEnable, consumerEnable, ""); + } + + private KafkaConfig createConfig(String producerEnable, String consumerEnable, String consumerEntryPoint) { + Properties properties = new Properties(); + properties.put(KafkaConfig.PRODUCER_ENABLE, producerEnable); + properties.put(KafkaConfig.CONSUMER_ENABLE, consumerEnable); + properties.put(KafkaConfig.CONSUMER_ENTRY_POINT, consumerEntryPoint); + + ProfilerConfig profilerConfig = new DefaultProfilerConfig(properties); + + return new KafkaConfig(profilerConfig); + } + + +} diff --git a/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerConstructorInterceptorTest.java b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerConstructorInterceptorTest.java new file mode 100644 index 000000000000..6176a5e30c8f --- /dev/null +++ b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerConstructorInterceptorTest.java @@ -0,0 +1,44 @@ +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Collections; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ConsumerConstructorInterceptorTest { + + @Mock + private RemoteAddressFieldAccessor addressFieldAccessor; + + @Mock + private ConsumerConfig consumerConfig; + + @Test + public void before() { + + ConsumerConstructorInterceptor interceptor = new ConsumerConstructorInterceptor(); + Object target = new Object(); + Object[] args = new Object[]{}; + interceptor.before(target, args); + } + + @Test + public void after() { + + doReturn(Collections.singletonList("localhost:9092")).when(consumerConfig).getList("bootstrap.servers"); + + ConsumerConstructorInterceptor interceptor = new ConsumerConstructorInterceptor(); + Object[] args = new Object[]{consumerConfig}; + interceptor.after(addressFieldAccessor, args, null, null); + + verify(addressFieldAccessor)._$PINPOINT$_setRemoteAddress("localhost:9092"); + } +} \ No newline at end of file diff --git a/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerMultiRecordEntryPointInterceptorTest.java b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerMultiRecordEntryPointInterceptorTest.java new file mode 100644 index 000000000000..14494b3f06b5 --- /dev/null +++ b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerMultiRecordEntryPointInterceptorTest.java @@ -0,0 +1,63 @@ +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.kafka.KafkaConstants; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Iterator; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ConsumerMultiRecordEntryPointInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanRecorder recorder; + + @Mock + private ConsumerRecords consumerRecords; + + @Mock + private ConsumerRecord consumerRecord; + + @Mock + private Iterator iterator; + + @Test + public void createTrace() { + + doReturn(trace).when(traceContext).newTraceObject(); + doReturn(true).when(trace).canSampled(); + doReturn(recorder).when(trace).getSpanRecorder(); + doReturn(1).when(consumerRecords).count(); + doReturn(iterator).when(consumerRecords).iterator(); + doReturn(consumerRecord).when(iterator).next(); + doReturn("Test").when(consumerRecord).topic(); + + ConsumerMultiRecordEntryPointInterceptor interceptor = new ConsumerMultiRecordEntryPointInterceptor(traceContext, descriptor); + interceptor.createTrace(new Object(), new Object[]{consumerRecords}); + + verify(recorder).recordAcceptorHost("topic:Test"); + verify(recorder).recordAttribute(KafkaConstants.KAFKA_TOPIC_ANNOTATION_KEY, "Test"); + verify(recorder).recordAttribute(KafkaConstants.KAFKA_BATCH_ANNOTATION_KEY, 1); + verify(recorder).recordRpcName("kafka://topic=Test?batch=1"); + } +} \ No newline at end of file diff --git a/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerPollInterceptorTest.java b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerPollInterceptorTest.java new file mode 100644 index 000000000000..5fdaf9204ec4 --- /dev/null +++ b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerPollInterceptorTest.java @@ -0,0 +1,57 @@ +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Iterator; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ConsumerPollInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private RemoteAddressFieldAccessor addressFieldAccessor; + + @Mock + private ConsumerRecords consumerRecords; + + @Mock + private Iterator iterator; + + + @Test + public void before() { + ConsumerPollInterceptor interceptor = new ConsumerPollInterceptor(traceContext, descriptor); + Object target = new Object(); + Object[] args = new Object[]{}; + interceptor.before(target, args); + } + + @Test + public void after() { + + doReturn("localhost:9092").when(addressFieldAccessor)._$PINPOINT$_getRemoteAddress(); + doReturn(iterator).when(consumerRecords).iterator(); + doReturn(false).when(iterator).hasNext(); + + ConsumerPollInterceptor interceptor = new ConsumerPollInterceptor(traceContext, descriptor); + interceptor.after(addressFieldAccessor, new Object[]{}, consumerRecords, null); + + verify(addressFieldAccessor)._$PINPOINT$_getRemoteAddress(); + + } +} \ No newline at end of file diff --git a/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerRecordEntryPointInterceptorTest.java b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerRecordEntryPointInterceptorTest.java new file mode 100644 index 000000000000..457b7fc3c504 --- /dev/null +++ b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ConsumerRecordEntryPointInterceptorTest.java @@ -0,0 +1,82 @@ +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.plugin.kafka.KafkaConstants; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.common.header.Header; +import org.apache.kafka.common.header.Headers; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ConsumerRecordEntryPointInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private SpanRecorder recorder; + + @Mock + private SpanEventRecorder eventRecorder; + + @Mock + private ConsumerRecord consumerRecord; + + @Mock + private Headers headers; + + @Test + public void doInBeforeTrace() { + + ConsumerRecordEntryPointInterceptor interceptor = new ConsumerRecordEntryPointInterceptor(traceContext, descriptor); + + interceptor.doInBeforeTrace(eventRecorder, new Object(), new Object[]{}); + + verify(eventRecorder).recordServiceType(KafkaConstants.KAFKA_CLIENT_INTERNAL); + } + + @Test + public void doInAfterTrace() { + + ConsumerRecordEntryPointInterceptor interceptor = new ConsumerRecordEntryPointInterceptor(traceContext, descriptor); + + interceptor.doInAfterTrace(eventRecorder, new Object(), new Object[]{}, null, null); + + verify(eventRecorder).recordApi(descriptor); + verify(eventRecorder).recordException(null); + } + + @Test + public void createTrace() { + + doReturn(trace).when(traceContext).newTraceObject(); + doReturn(true).when(trace).canSampled(); + doReturn(recorder).when(trace).getSpanRecorder(); + + doReturn("Test").when(consumerRecord).topic(); + doReturn(1l).when(consumerRecord).offset(); + doReturn(0).when(consumerRecord).partition(); + doReturn(headers).when(consumerRecord).headers(); + doReturn(new Header[]{}).when(headers).toArray(); + + ConsumerRecordEntryPointInterceptor interceptor = new ConsumerRecordEntryPointInterceptor(traceContext, descriptor); + + interceptor.createTrace(new Object(), new Object[]{consumerRecord}); + + verify(recorder).recordAcceptorHost("topic:Test"); + verify(recorder).recordRpcName("kafka://topic=Test?partition=0&offset=1"); + + } +} \ No newline at end of file diff --git a/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerConstructorInterceptorTest.java b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerConstructorInterceptorTest.java new file mode 100644 index 000000000000..19d8c2693be5 --- /dev/null +++ b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerConstructorInterceptorTest.java @@ -0,0 +1,44 @@ +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Collections; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ProducerConstructorInterceptorTest { + + @Mock + private RemoteAddressFieldAccessor addressFieldAccessor; + @Mock + private ProducerConfig producerConfig; + + + @Test + public void before() { + + ProducerConstructorInterceptor interceptor = new ProducerConstructorInterceptor(); + Object target = new Object(); + Object[] args = new Object[]{}; + interceptor.before(target, args); + } + + @Test + public void after() { + + doReturn(Collections.singletonList("localhost:9092")).when(producerConfig).getList("bootstrap.servers"); + + ProducerConstructorInterceptor interceptor = new ProducerConstructorInterceptor(); + Object[] args = new Object[]{producerConfig}; + interceptor.after(addressFieldAccessor, args, null, null); + + verify(addressFieldAccessor)._$PINPOINT$_setRemoteAddress("localhost:9092"); + } +} \ No newline at end of file diff --git a/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerSendInterceptorTest.java b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerSendInterceptorTest.java new file mode 100644 index 000000000000..eadaa37052b2 --- /dev/null +++ b/plugins/kafka/src/test/java/com/navercorp/pinpoint/plugin/kafka/interceptor/ProducerSendInterceptorTest.java @@ -0,0 +1,87 @@ +package com.navercorp.pinpoint.plugin.kafka.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.plugin.kafka.KafkaConstants; +import com.navercorp.pinpoint.plugin.kafka.field.accessor.RemoteAddressFieldAccessor; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.header.Header; +import org.apache.kafka.common.header.Headers; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class ProducerSendInterceptorTest { + + @Mock + private TraceContext traceContext; + + @Mock + private MethodDescriptor descriptor; + + @Mock + private Trace trace; + + @Mock + private TraceId traceId; + + @Mock + private TraceId nextId; + + @Mock + private SpanEventRecorder recorder; + + @Mock + private ProducerRecord record; + + @Mock + private Headers headers; + + @Mock + private RemoteAddressFieldAccessor addressFieldAccessor; + + @Test + public void before() { + + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(true).when(trace).canSampled(); + doReturn(traceId).when(trace).getTraceId(); + doReturn(nextId).when(traceId).getNextTraceId(); + doReturn(recorder).when(trace).traceBlockBegin(); + doReturn(headers).when(record).headers(); + doReturn(new Header[]{}).when(headers).toArray(); + doReturn("test").when(nextId).getTransactionId(); + doReturn(0l).when(nextId).getSpanId(); + doReturn(0l).when(nextId).getParentSpanId(); + short s = 0; + doReturn(s).when(nextId).getFlags(); + + ProducerSendInterceptor interceptor = new ProducerSendInterceptor(traceContext, descriptor); + Object target = new Object(); + Object[] args = new Object[]{record}; + interceptor.before(target, args); + + verify(recorder).recordServiceType(KafkaConstants.KAFKA_CLIENT); + + } + + @Test + public void after() { + doReturn(trace).when(traceContext).currentTraceObject(); + doReturn(true).when(trace).canSampled(); + doReturn(recorder).when(trace).currentSpanEventRecorder(); + doReturn("test").when(record).topic(); + + ProducerSendInterceptor interceptor = new ProducerSendInterceptor(traceContext, descriptor); + Object[] args = new Object[]{record}; + interceptor.after(addressFieldAccessor, args, null, null); + + verify(recorder).recordEndPoint(KafkaConstants.UNKNOWN); + verify(recorder).recordDestinationId("topic:test"); + verify(recorder).recordAttribute(KafkaConstants.KAFKA_TOPIC_ANNOTATION_KEY, "test"); + } +} \ No newline at end of file diff --git a/plugins/log4j/clover.license b/plugins/log4j/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/log4j/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-log4j-plugin diff --git a/plugins/logback/clover.license b/plugins/logback/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/logback/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-logback-plugin diff --git a/plugins/mariadb-jdbc/clover.license b/plugins/mariadb-jdbc/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/mariadb-jdbc/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-mariadb-jdbc-driver-plugin pinpoint-mariadb-jdbc-driver-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBConfig.java b/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBConfig.java index 816b64a00ee5..30457677fa59 100644 --- a/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBConfig.java +++ b/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBConfig.java @@ -49,8 +49,7 @@ public boolean isProfileRollback() { @Override public String toString() { - return "MariaDBConfig [profileSetAutoCommit=" + profileSetAutoCommit + ", profileCommit=" + profileCommit - + ", profileRollback=" + profileRollback + "]"; + return "MariaDBConfig [" + super.toString() + ", profileSetAutoCommit=" + profileSetAutoCommit + ", profileCommit=" + profileCommit + ", profileRollback=" + profileRollback + "]"; } } diff --git a/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBJdbcUrlParser.java b/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBJdbcUrlParser.java index e47c3e11033b..881f9bbb75a8 100644 --- a/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBJdbcUrlParser.java +++ b/plugins/mariadb-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/mariadb/MariaDBJdbcUrlParser.java @@ -27,7 +27,9 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.EnumSet; import java.util.List; +import java.util.Set; /** * @author dawidmalina @@ -36,10 +38,11 @@ public class MariaDBJdbcUrlParser implements JdbcUrlParserV2 { // jdbc:(mysql|mariadb):[replication:|failover|loadbalance:|aurora:]//[,]/[database>] // jdbc:mariadb:loadbalance://10.22.33.44:3306,10.22.33.55:3306/MariaDB?characterEncoding=UTF-8 - private static final String URL_PREFIX = "jdbc:mariadb:"; - + private static final String MARIA_URL_PREFIX = "jdbc:mariadb:"; private static final String MYSQL_URL_PREFIX = "jdbc:mysql:"; + private static final Set TYPES = EnumSet.allOf(Type.class); + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); @Override @@ -49,20 +52,18 @@ public DatabaseInfo parse(String jdbcUrl) { return UnKnownDatabaseInfo.INSTANCE; } - Type type = Type.findType(jdbcUrl); + Type type = getType(jdbcUrl); if (type == null) { - logger.info("jdbcUrl has invalid prefix.(url:{}, prefix:{}, {})", jdbcUrl, URL_PREFIX, MYSQL_URL_PREFIX); + logger.info("jdbcUrl has invalid prefix.(url:{}, valid prefixes:{}, {})", jdbcUrl, MARIA_URL_PREFIX, MYSQL_URL_PREFIX); return UnKnownDatabaseInfo.INSTANCE; } - DatabaseInfo result = null; try { - result = parse0(jdbcUrl, type); + return parse0(jdbcUrl, type); } catch (Exception e) { logger.info("MaridDBJdbcUrl parse error. url: {}, Caused: {}", jdbcUrl, e.getMessage(), e); - result = UnKnownDatabaseInfo.createUnknownDataBase(MariaDBConstants.MARIADB, MariaDBConstants.MARIADB_EXECUTE_QUERY, jdbcUrl); + return UnKnownDatabaseInfo.createUnknownDataBase(MariaDBConstants.MARIADB, MariaDBConstants.MARIADB_EXECUTE_QUERY, jdbcUrl); } - return result; } private DatabaseInfo parse0(String url, Type type) { @@ -119,8 +120,17 @@ public ServiceType getServiceType() { return MariaDBConstants.MARIADB; } - private static enum Type { - MARIA(URL_PREFIX), + private static Type getType(String jdbcUrl) { + for (Type type : TYPES) { + if (jdbcUrl.startsWith(type.getUrlPrefix())) { + return type; + } + } + return null; + } + + private enum Type { + MARIA(MARIA_URL_PREFIX), MYSQL(MYSQL_URL_PREFIX); private final String urlPrefix; @@ -136,19 +146,7 @@ private String getUrlPrefix() { } private String getLoadbalanceUrlPrefix() { - return urlPrefix + "loadbalance:"; + return loadbalanceUrlPrefix; } - - private static Type findType(String jdbcUrl) { - for (Type type : Type.values()) { - if (jdbcUrl.startsWith(type.urlPrefix)) { - return type; - } - } - - return null; - } - } - } diff --git a/plugins/mongodb/.gitignore b/plugins/mongodb/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/mongodb/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/mongodb/pom.xml b/plugins/mongodb/pom.xml new file mode 100644 index 000000000000..74389bd583a4 --- /dev/null +++ b/plugins/mongodb/pom.xml @@ -0,0 +1,63 @@ + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-mongodb-driver-plugin + pinpoint-mongodb-driver-plugin + jar + + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + + org.mongodb + mongodb-driver + provided + + + + + org.slf4j + slf4j-api + test + + + org.slf4j + slf4j-log4j12 + test + + + log4j + log4j + test + + + com.fasterxml.jackson.core + jackson-databind + test + ${fastxml.jackson-jdk6.version} + + + diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoConfig.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoConfig.java new file mode 100644 index 000000000000..012816f51154 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoConfig.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.mongo; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +/** + * @author Roy Kimd + */ +public class MongoConfig{ + + private final boolean enable; + private final boolean collectJson; + private final boolean traceBsonBindValue; + + public MongoConfig(ProfilerConfig config) { + this.enable = config.readBoolean("profiler.mongo", false); + this.collectJson = config.readBoolean("profiler.mongo.collectjson", false); + this.traceBsonBindValue = config.readBoolean("profiler.mongo.tracebsonbindvalue", false); + } + + public boolean isEnable() { + return enable; + } + + public boolean isCollectJson() { + return collectJson; + } + + public boolean istraceBsonBindValue() { + return traceBsonBindValue; + } + + @Override + public String toString() { + return "MongoConfig{" + + "enable=" + enable + + '}'; + } + +} + diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoConstants.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoConstants.java new file mode 100644 index 000000000000..de5e93b4f565 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoConstants.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.mongo; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.*; + +/** + * @author Roy Kim + */ +public final class MongoConstants { + private MongoConstants() { + } + + public static final String MONGO_SCOPE = "MONGO_JAVA_DRIVER"; + + public static final AnnotationKey MONGO_JSON_DATA = AnnotationKeyFactory.of(150, "MONGO-JSON-Data"); + public static final AnnotationKey MONGO_COLLECTION_INFO = AnnotationKeyFactory.of(151, "Collection-Info", VIEW_IN_RECORD_SET); + public static final AnnotationKey MONGO_COLLECTION_OPTION = AnnotationKeyFactory.of(152, "Collection-Option"); + public static final AnnotationKey MONGO_JSON = AnnotationKeyFactory.of(153, "MONGO-JSON", VIEW_IN_RECORD_SET); + public static final AnnotationKey MONGO_JSON_BINDVALUE = AnnotationKeyFactory.of(154, "MONGO-JSON-BindValue", VIEW_IN_RECORD_SET); + + public static final ServiceType MONGODB = ServiceTypeFactory.of(2650, "MONGO", TERMINAL, INCLUDE_DESTINATION_ID); + public static final ServiceType MONGO_EXECUTE_QUERY = ServiceTypeFactory.of(2651, "MONGO_EXECUTE_QUERY", "MONGO", TERMINAL, RECORD_STATISTICS, INCLUDE_DESTINATION_ID); +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoPlugin.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoPlugin.java new file mode 100644 index 000000000000..f693789544d4 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoPlugin.java @@ -0,0 +1,375 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.mongo; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExecutionPolicy; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import com.navercorp.pinpoint.bootstrap.plugin.util.InstrumentUtils; + +import java.lang.reflect.Modifier; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static com.navercorp.pinpoint.common.util.VarArgs.va; + +/** + * @author Roy Kim + */ +public class MongoPlugin implements ProfilerPlugin, TransformTemplateAware { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private static final String MONGO_SCOPE = MongoConstants.MONGO_SCOPE; + + private TransformTemplate transformTemplate; + + @Override + public void setup(ProfilerPluginSetupContext context) { + MongoConfig config = new MongoConfig(context.getConfig()); + + if (!config.isEnable()) { + logger.info("MongoDB plugin is not executed because plugin enable value is false."); + return; + } + + addConnectionTransformer3_0_X(); + addConnectionTransformer3_7_X(); + addConnectionTransformer3_8_X(); + addSessionTransformer3_0_X(config); + addSessionTransformer3_7_X(config); + } + + private void addConnectionTransformer3_0_X() { + + // 3.0.0 ~ 3.6.4 + transformTemplate.transform("com.mongodb.Mongo", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (!target.isInterceptable()) { + return null; + } + + target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor"); + + InstrumentMethod connect = InstrumentUtils.findConstructor(target, "com.mongodb.connection.Cluster", "com.mongodb.MongoClientOptions", "java.util.List"); + + connect.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoDriverConnectInterceptor3_0", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + + InstrumentMethod close = InstrumentUtils.findMethod(target, "close"); + close.addScopedInterceptor( + "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.ConnectionCloseInterceptor", + MONGO_SCOPE); + + return target.toBytecode(); + } + }); + transformTemplate.transform("com.mongodb.MongoClient", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (!target.isInterceptable()) { + return null; + } + + target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor"); + + InstrumentMethod connectDeliver = InstrumentUtils.findMethod(target, "getDatabase", "java.lang.String"); + connectDeliver.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoDriverGetDatabaseInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + return target.toBytecode(); + } + }); + transformTemplate.transform("com.mongodb.MongoDatabaseImpl", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (!target.isInterceptable()) { + return null; + } + + target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor"); + + InstrumentMethod connect = InstrumentUtils.findMethod(target, "getCollection", "java.lang.String", "java.lang.Class"); + connect.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoDriverGetCollectionInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + InstrumentMethod getReadPreference = InstrumentUtils.findMethod(target, "withReadPreference", "com.mongodb.ReadPreference"); + getReadPreference.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoReadPreferenceInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + InstrumentMethod getWriteConcern = InstrumentUtils.findMethod(target, "withWriteConcern", "com.mongodb.WriteConcern"); + getWriteConcern.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoWriteConcernInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + return target.toBytecode(); + } + }); + } + private void addConnectionTransformer3_7_X(){ + //3.7.0+ + transformTemplate.transform("com.mongodb.client.MongoClients", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (!target.isInterceptable()) { + return null; + } + + target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor"); + + InstrumentMethod connect = InstrumentUtils.findMethod(target, "create", "com.mongodb.MongoClientSettings","com.mongodb.MongoDriverInformation"); + + connect.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoDriverConnectInterceptor3_7", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + return target.toBytecode(); + } + }); + transformTemplate.transform("com.mongodb.client.MongoClientImpl", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (!target.isInterceptable()) { + return null; + } + + target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor"); + + InstrumentMethod connect = InstrumentUtils.findMethod(target, "getDatabase", "java.lang.String"); + connect.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoDriverGetDatabaseInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + InstrumentMethod close = InstrumentUtils.findMethod(target, "close"); + close.addScopedInterceptor( + "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.ConnectionCloseInterceptor", + MONGO_SCOPE); + + return target.toBytecode(); + } + }); + transformTemplate.transform("com.mongodb.client.internal.MongoDatabaseImpl", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (!target.isInterceptable()) { + return null; + } + + target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor"); + + InstrumentMethod connect = InstrumentUtils.findMethod(target, "getCollection", "java.lang.String", "java.lang.Class"); + connect.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoDriverGetCollectionInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + + InstrumentMethod getReadPreference = InstrumentUtils.findMethod(target, "withReadPreference", "com.mongodb.ReadPreference"); + getReadPreference.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoReadPreferenceInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + InstrumentMethod getWriteConcern = InstrumentUtils.findMethod(target, "withWriteConcern", "com.mongodb.WriteConcern"); + getWriteConcern.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoWriteConcernInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + return target.toBytecode(); + } + }); + } + private void addConnectionTransformer3_8_X(){ + //3.8.0+ + transformTemplate.transform("com.mongodb.client.internal.MongoClientImpl", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (!target.isInterceptable()) { + return null; + } + + target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor"); + + InstrumentMethod connect = InstrumentUtils.findMethod(target, "getDatabase", "java.lang.String"); + connect.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoDriverGetDatabaseInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + InstrumentMethod close = InstrumentUtils.findMethod(target, "close"); + close.addScopedInterceptor( + "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.ConnectionCloseInterceptor", + MONGO_SCOPE); + + return target.toBytecode(); + } + }); + } + + private void addSessionTransformer3_0_X(final MongoConfig config) { + TransformCallback transformCallback = new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (!target.isInterceptable()) { + return null; + } + + target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor"); + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.chain(MethodFilters.modifier(Modifier.PUBLIC), MethodFilters.name(getMethodlistR3_0_x())))) { + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.mongo.interceptor.MongoRSessionInterceptor", va(config.isCollectJson(), config.istraceBsonBindValue()), MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + } + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.chain(MethodFilters.modifier(Modifier.PUBLIC), MethodFilters.name(getMethodlistCUD3_0_x())))) { + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.mongo.interceptor.MongoCUDSessionInterceptor", va(config.isCollectJson(), config.istraceBsonBindValue()) ,MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + } + + InstrumentMethod getReadPreference = InstrumentUtils.findMethod(target, "withReadPreference", "com.mongodb.ReadPreference"); + getReadPreference.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoReadPreferenceInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + InstrumentMethod getWriteConcern = InstrumentUtils.findMethod(target, "withWriteConcern", "com.mongodb.WriteConcern"); + getWriteConcern.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoWriteConcernInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + return target.toBytecode(); + } + }; + + // java driver 3.0.0 ~ 3.6.4 + transformTemplate.transform("com.mongodb.MongoCollectionImpl", transformCallback); + } + private void addSessionTransformer3_7_X(final MongoConfig config) { + TransformCallback transformCallback = new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + if (!target.isInterceptable()) { + return null; + } + + target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor"); + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.chain(MethodFilters.modifier(Modifier.PUBLIC), MethodFilters.name(getMethodlistR3_7_x())))) { + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.mongo.interceptor.MongoRSessionInterceptor", va(config.isCollectJson(), config.istraceBsonBindValue()), MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + } + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.chain(MethodFilters.modifier(Modifier.PUBLIC), MethodFilters.name(getMethodlistCUD3_7_x())))) { + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.mongo.interceptor.MongoCUDSessionInterceptor", va(config.isCollectJson(), config.istraceBsonBindValue()), MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + } + + InstrumentMethod getReadPreference = InstrumentUtils.findMethod(target, "withReadPreference", "com.mongodb.ReadPreference"); + getReadPreference.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoReadPreferenceInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + InstrumentMethod getWriteConcern = InstrumentUtils.findMethod(target, "withWriteConcern", "com.mongodb.WriteConcern"); + getWriteConcern.addScopedInterceptor( + "com.navercorp.pinpoint.plugin.mongo.interceptor.MongoWriteConcernInterceptor", + MONGO_SCOPE, ExecutionPolicy.BOUNDARY); + + + return target.toBytecode(); + } + }; + + // java driver 3.7+ + transformTemplate.transform("com.mongodb.client.internal.MongoCollectionImpl", transformCallback); + } + + private String[] getMethodlistR3_0_x(){ + + List methodlist = new ArrayList(); + // object methods. + methodlist.addAll(Arrays.asList("findOneAndUpdate","findOneAndReplace","findOneAndDelete","aggregate","find","distinct","count","mapReduce")); + + return methodlist.toArray(new String[0]); + } + + private String[] getMethodlistCUD3_0_x(){ + + List methodlist = new ArrayList(); + // object methods. + methodlist.addAll(Arrays.asList("dropIndexes","dropIndex","createIndexes","createIndex" + ,"updateMany","updateOne","replaceOne","deleteMany","deleteOne","insertMany","insertOne","bulkWrite")); + + return methodlist.toArray(new String[0]); + } + + private String[] getMethodlistR3_7_x(){ + + List methodlist = new ArrayList(); + // object methods. + methodlist.addAll(Arrays.asList("findOneAndUpdate","findOneAndReplace","findOneAndDelete","watch","aggregate","find","distinct","count","mapReduce")); + + return methodlist.toArray(new String[0]); + } + private String[] getMethodlistCUD3_7_x(){ + + List methodlist = new ArrayList(); + // object methods. + methodlist.addAll(Arrays.asList("dropIndexes","dropIndex","createIndexes","createIndex" + ,"updateMany","updateOne","replaceOne","deleteMany","deleteOne","insertMany","insertOne","bulkWrite")); + + return methodlist.toArray(new String[0]); + } + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoTypeProvider.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoTypeProvider.java new file mode 100644 index 000000000000..ba19742ff777 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoTypeProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.mongo; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyMatchers; +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * @author Roy Kim + */ +public class MongoTypeProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(MongoConstants.MONGODB, AnnotationKeyMatchers.exact(AnnotationKey.ARGS0)); + context.addServiceType(MongoConstants.MONGO_EXECUTE_QUERY, AnnotationKeyMatchers.exact(AnnotationKey.ARGS0)); + + context.addAnnotationKey(MongoConstants.MONGO_JSON_DATA); + context.addAnnotationKey(MongoConstants.MONGO_COLLECTION_INFO); + context.addAnnotationKey(MongoConstants.MONGO_COLLECTION_OPTION); + context.addAnnotationKey(MongoConstants.MONGO_JSON); + context.addAnnotationKey(MongoConstants.MONGO_JSON_BINDVALUE); + + } +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoUtil.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoUtil.java new file mode 100644 index 000000000000..3486bca5aff7 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoUtil.java @@ -0,0 +1,302 @@ +/* + * Copyright 2018 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.mongo; + +import com.mongodb.BasicDBObject; +import com.mongodb.WriteConcern; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringStringValue; +import com.navercorp.pinpoint.common.util.StringUtils; +import org.bson.BsonDocument; +import org.bson.BsonType; +import org.bson.BsonValue; +import org.bson.BsonWriter; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.bson.json.JsonWriter; + +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * @author Roy Kim + */ +public final class MongoUtil { + + public static final String SEPARATOR = ","; + private static final MongoWriteConcernMapper mongoWriteConcernMapper = new MongoWriteConcernMapper(); + + private static final boolean decimal128Enabled = decimal128Enabled(); + + private MongoUtil() { + } + + private static boolean decimal128Enabled() { + for (BsonType bsonType : BsonType.values()) { + if (bsonType.name().equalsIgnoreCase("DECIMAL128")) { + return true; + } + } + return false; + } + + public static void recordMongoCollection(SpanEventRecorder recorder, String collectionName, String readPreferenceOrWriteConcern) { + recorder.recordAttribute(MongoConstants.MONGO_COLLECTION_INFO, collectionName); + recorder.recordAttribute(MongoConstants.MONGO_COLLECTION_OPTION, readPreferenceOrWriteConcern); + } + + public static String getWriteConcern0(WriteConcern writeConcern) { + + return mongoWriteConcernMapper.getName(writeConcern); + } + + public static void recordParsedBson(SpanEventRecorder recorder, StringStringValue stringStringValue) { + if (stringStringValue != null) { + recorder.recordAttribute(MongoConstants.MONGO_JSON_DATA, stringStringValue); + } + } + + private static Map getBsonKeyValueMap(Object bson) { + if (bson instanceof BasicDBObject) { + return (BasicDBObject) bson; + } else if (bson instanceof BsonDocument) { + return (BsonDocument) bson; + } else if (bson instanceof Document) { + return (Document) bson; + } else { + return null; + } + //TODO leave comments for further use +// if(arg instanceof BsonDocumentWrapper) { +// bson.append(arg.toString()); +// } +// if(arg instanceof CommandResult) { +// bson.append(arg.toString()); +// } +// if(arg instanceof RawBsonDocument) { +// bson.append(arg.toString()); +// } + } + + public static StringStringValue parseBson(Object[] args, boolean traceBsonBindValue) { + + if (args == null) { + return null; + } + + final List parsedJson = new ArrayList(2); + final List jsonParameter = new ArrayList(16); + + for (Object arg : args) { + + WriteContext writeContext = new WriteContext(jsonParameter, decimal128Enabled, traceBsonBindValue); + String documentString = writeContext.parse(arg); + + parsedJson.add(documentString); + } + + String parsedJsonString = StringJoiner.join(parsedJson, SEPARATOR); + String jsonParameterString = StringJoiner.join(jsonParameter, SEPARATOR); + return new StringStringValue(parsedJsonString, jsonParameterString); + } + + private static class WriteContext { + + private final Writer writer = new StringWriter(); + private final BsonWriter bsonWriter = new JsonWriter(writer); + + private final List jsonParameter; + + private final boolean traceBsonBindValue; + private final boolean decimal128Enabled; + + public WriteContext(List jsonParameterAppender, boolean decimal128Enabled, boolean traceBsonBindValue) { + this.jsonParameter = Assert.requireNonNull(jsonParameterAppender, "jsonParameterAppender must not be null"); + this.decimal128Enabled = decimal128Enabled; + this.traceBsonBindValue = traceBsonBindValue; + } + + public String parse(Object arg) { + parseBsonObject(arg); + return writer.toString(); + } + + private void parseBsonObject(Object arg) { + final Map map = getBsonKeyValueMap(arg); + if (map == null) { + return; + } + + bsonWriter.writeStartDocument(); + for (Map.Entry entry : map.entrySet()) { + + bsonWriter.writeName(entry.getKey()); + + final Object value = entry.getValue(); + writeValue(value); + } + bsonWriter.writeEndDocument(); + } + + private void parsePrimitiveArrayObject(Object arg) { + bsonWriter.writeStartArray(); + + int length = Array.getLength(arg); + + for (int i = 0; i < length; i++) { + writeValue(Array.get(arg, i)); + } + bsonWriter.writeEndArray(); + } + + private void parseCollection(Collection arg) { + bsonWriter.writeStartArray(); + + for (T value : arg) { + writeValue(value); + } + bsonWriter.writeEndArray(); + } + + private void parseBsonValueObject(BsonValue arg) { + + BsonType bsonType = arg.getBsonType(); + + bsonWriter.writeStartDocument(); + + if (bsonType.equals(BsonType.DOUBLE)) { + + bsonWriter.writeName("value"); + writeValue(arg.asDouble().getValue()); + + } else if (bsonType.equals(BsonType.STRING)) { + + bsonWriter.writeName("value"); + writeValue(arg.asString().getValue()); + + } else if (bsonType.equals(BsonType.BINARY)) { + + bsonWriter.writeName("type"); + writeValue(arg.asBinary().getType()); + + bsonWriter.writeName("data"); + writeValue(arg.asBinary().getData()); + + } else if (bsonType.equals(BsonType.OBJECT_ID)) { + + bsonWriter.writeName("value"); + writeValue(arg.asObjectId().getValue()); + + } else if (bsonType.equals(BsonType.BOOLEAN)) { + + bsonWriter.writeName("value"); + writeValue(arg.asBoolean().getValue()); + + } else if (bsonType.equals(BsonType.DATE_TIME)) { + + bsonWriter.writeName("value"); + writeValue(arg.asDateTime().getValue()); + + } else if (bsonType.equals(BsonType.REGULAR_EXPRESSION)) { + + bsonWriter.writeName("pattern"); + writeValue(arg.asRegularExpression().getPattern()); + bsonWriter.writeName("options"); + writeValue(arg.asRegularExpression().getOptions()); + + } else if (bsonType.equals(BsonType.DB_POINTER)) { + + bsonWriter.writeName("namespace"); + writeValue(arg.asDBPointer().getNamespace()); + bsonWriter.writeName("id"); + writeValue(arg.asDBPointer().getId()); + + } else if (bsonType.equals(BsonType.JAVASCRIPT)) { + + bsonWriter.writeName("code"); + writeValue(arg.asJavaScript().getCode()); + + } else if (bsonType.equals(BsonType.SYMBOL)) { + + bsonWriter.writeName("symbol"); + writeValue(arg.asSymbol().getSymbol()); + + } else if (bsonType.equals(BsonType.JAVASCRIPT_WITH_SCOPE)) { + + bsonWriter.writeName("code"); + writeValue(arg.asJavaScriptWithScope().getCode()); + bsonWriter.writeName("scope"); + writeValue(arg.asJavaScriptWithScope().getScope()); + + } else if (bsonType.equals(BsonType.INT32)) { + + bsonWriter.writeName("value"); + writeValue(arg.asInt32().getValue()); + + } else if (bsonType.equals(BsonType.TIMESTAMP)) { + + bsonWriter.writeName("value"); + writeValue(arg.asTimestamp().getValue()); + + } else if (bsonType.equals(BsonType.INT64)) { + + bsonWriter.writeName("value"); + writeValue(arg.asInt64().getValue()); + + } else if (decimal128Enabled && bsonType.equals(BsonType.DECIMAL128)) { + + bsonWriter.writeName("value"); + writeValue(arg.asDecimal128().getValue()); + + } +// BsonType.DOCUMENT //taken care of in Bson +// BsonType.ARRAY //taken care of in collection +// BsonType.END_OF_DOCUMENT //do nothing +// BsonType.UNDEFINED //do nothing +// BsonType.NULL //do nothing + + bsonWriter.writeEndDocument(); + } + + private void writeValue(Object arg) { + if (arg instanceof String) { + bsonWriter.writeString("?"); + if (traceBsonBindValue) { + jsonParameter.add("\"" + StringUtils.replace((String) arg, "\"", "\"\"") + "\""); + } + } else if (arg.getClass().isArray()) { + parsePrimitiveArrayObject(arg); + } else if (arg instanceof Collection) { + parseCollection((Collection) arg); + } else if (arg instanceof Bson) { + parseBsonObject(arg); + } else if (arg instanceof BsonValue) { + parseBsonValueObject((BsonValue) arg); + } else { + bsonWriter.writeString("?"); + if (traceBsonBindValue) { + jsonParameter.add(String.valueOf(arg)); + } + } + } + } + +} \ No newline at end of file diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoWriteConcernMapper.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoWriteConcernMapper.java new file mode 100644 index 000000000000..d912810cda5a --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/MongoWriteConcernMapper.java @@ -0,0 +1,63 @@ +package com.navercorp.pinpoint.plugin.mongo; +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import com.mongodb.WriteConcern; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Roy Kim + */ + +public class MongoWriteConcernMapper { + + private final Map writeConcernMap; + + public MongoWriteConcernMapper() { + writeConcernMap = buildWriteConcern(); + } + + private Map buildWriteConcern() { + Map writeConcernMap = new HashMap(); + for (final Field f : WriteConcern.class.getFields()) { + if (Modifier.isStatic(f.getModifiers()) + && f.getType().equals(WriteConcern.class) + && f.getAnnotation(Deprecated.class) == null) { + + String value = f.getName(); + try { + WriteConcern key = (WriteConcern) f.get(null); + writeConcernMap.put(key, value); + } catch (IllegalAccessException e) { + PLogger logger = PLoggerFactory.getLogger(this.getClass()); + logger.warn("WriteConcern access error Caused by:" + e.getMessage(), e); + } + } + } + return writeConcernMap; + } + + public String getName(WriteConcern writeConcern) { + return writeConcernMap.get(writeConcern); + } +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/StringJoiner.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/StringJoiner.java new file mode 100644 index 000000000000..19218c739716 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/StringJoiner.java @@ -0,0 +1,80 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo; + +import com.navercorp.pinpoint.common.util.StringUtils; + +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class StringJoiner { + + private StringJoiner() { + } + + public static String join(final Collection collection, final String separator) { + if (collection == null) { + return null; + } + final int size = collection.size(); + if (size == 0) { + return ""; + } + if (size == 1) { + final Iterator iterator = collection.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + throw new ConcurrentModificationException("size:" + collection.size()); + } + } + + final int bufferSize = getBufferSize(collection, separator); + + final StringBuilder builder = new StringBuilder(bufferSize); + final Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + builder.append(iterator.next()); + if (!iterator.hasNext()) { + break; + } + builder.append(separator); + } + + return builder.toString(); + } + + private static int getBufferSize(Collection collection, String separator) { + int bufferSize = 0; + + final Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + final String value = iterator.next(); + // null == "null" + bufferSize += StringUtils.getLength(value, 4); + if (!iterator.hasNext()) { + break; + } + bufferSize += separator.length(); + } + return bufferSize; + } +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoCUDSessionInterceptor.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoCUDSessionInterceptor.java new file mode 100644 index 000000000000..1648626099f7 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoCUDSessionInterceptor.java @@ -0,0 +1,84 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; +import com.navercorp.pinpoint.common.util.StringStringValue; +import com.navercorp.pinpoint.plugin.mongo.MongoUtil; +import org.bson.conversions.Bson; + +/** + * @author Roy Kim + */ +public class MongoCUDSessionInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean collectJson; + private final boolean traceBsonBindValue; + + public MongoCUDSessionInterceptor(TraceContext traceContext, MethodDescriptor descriptor, boolean collectJson, boolean traceBsonBindValue) { + super(traceContext, descriptor); + this.collectJson = collectJson; + this.traceBsonBindValue = traceBsonBindValue; + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + + DatabaseInfo databaseInfo; + if (target instanceof DatabaseInfoAccessor) { + databaseInfo = ((DatabaseInfoAccessor) target)._$PINPOINT$_getDatabaseInfo(); + } else { + databaseInfo = UnKnownDatabaseInfo.INSTANCE; + } + + recorder.recordServiceType(databaseInfo.getExecuteQueryType()); + recorder.recordEndPoint(databaseInfo.getMultipleHost()); + recorder.recordDestinationId(databaseInfo.getDatabaseId()); + + recorder.recordApi(methodDescriptor); + MongoUtil.recordMongoCollection(recorder, ((MongoDatabaseInfo) databaseInfo).getCollectionName(), ((MongoDatabaseInfo) databaseInfo).getWriteConcern()); + } + + @Override + protected void prepareAfterTrace(Object target, Object[] args, Object result, Throwable throwable) { + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + if (collectJson) { + final boolean success = InterceptorUtils.isSuccess(throwable); + if (success) { + if (args != null) { + StringStringValue parsedBson = MongoUtil.parseBson(args, traceBsonBindValue); + MongoUtil.recordParsedBson(recorder, parsedBson); + } + } + } + recorder.recordException(throwable); + } +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverConnectInterceptor3_0.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverConnectInterceptor3_0.java new file mode 100644 index 000000000000..0f0ae569993e --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverConnectInterceptor3_0.java @@ -0,0 +1,157 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo.interceptor; + +import com.mongodb.MongoClientOptions; +import com.mongodb.ServerAddress; +import com.mongodb.connection.Cluster; +import com.mongodb.connection.ClusterDescription; +import com.mongodb.connection.ServerDescription; +import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.mongo.MongoConstants; +import com.navercorp.pinpoint.plugin.mongo.MongoUtil; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author Roy Kim + */ +public class MongoDriverConnectInterceptor3_0 extends SpanEventSimpleAroundInterceptorForPlugin { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + public MongoDriverConnectInterceptor3_0(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + } + + @Override + protected void prepareAfterTrace(Object target, Object[] args, Object result, Throwable throwable) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, + Throwable throwable) { + + final boolean success = InterceptorUtils.isSuccess(throwable); + // Must not check if current transaction is trace target or not. Connection can be made by other thread. + + if (success) { + if (args == null) { + return; + } + + final List hostList = getHostList(args[0]); + String readPreference = getReadPreference(args[1]); + String writeConcern = getWriteConcern(args[1]); + + DatabaseInfo databaseInfo = createDatabaseInfo(hostList, readPreference, writeConcern); + if (databaseInfo == null) { + databaseInfo = UnKnownDatabaseInfo.INSTANCE; + } + + if (target instanceof DatabaseInfoAccessor) { + ((DatabaseInfoAccessor) target)._$PINPOINT$_setDatabaseInfo(databaseInfo); + } + + recorder.recordServiceType(databaseInfo.getType()); + recorder.recordEndPoint(databaseInfo.getMultipleHost()); + recorder.recordDestinationId(databaseInfo.getDatabaseId()); + } + + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + } + + private DatabaseInfo createDatabaseInfo(List hostList, String readPreference, String writeConcern) { + + DatabaseInfo databaseInfo = new MongoDatabaseInfo(MongoConstants.MONGODB, MongoConstants.MONGO_EXECUTE_QUERY, + null, null, hostList, null, null, readPreference, writeConcern); + + if (isDebug) { + logger.debug("parse DatabaseInfo:{}", databaseInfo); + } + + return databaseInfo; + } + + private List getHostList(Object arg) { + if (!(arg instanceof Cluster)) { + return Collections.emptyList(); + } + + final Cluster cluster = (Cluster) arg; + + final List hostList = new ArrayList(); + + Collection serverDescriptions;// = cluster.getDescription().getAll();//.getServerDescriptions(); + + try { + ClusterDescription.class.getDeclaredMethod("getServerDescriptions"); + serverDescriptions = cluster.getDescription().getServerDescriptions(); + } catch (NoSuchMethodException e) { + serverDescriptions = cluster.getDescription().getAll(); + } + + for (ServerDescription serverDescription : serverDescriptions) { + + ServerAddress serverAddress = serverDescription.getAddress(); + final String hostAddress = HostAndPort.toHostAndPortString(serverAddress.getHost(), serverAddress.getPort()); + hostList.add(hostAddress); + } + + return hostList; + } + + private String getReadPreference(Object arg) { + if (!(arg instanceof MongoClientOptions)) { + return null; + } + + final MongoClientOptions mongoClientOptions = (MongoClientOptions) arg; + + return mongoClientOptions.getReadPreference().getName(); + } + + private String getWriteConcern(Object arg) { + if (!(arg instanceof MongoClientOptions)) { + return null; + } + + final MongoClientOptions mongoClientOptions = (MongoClientOptions) arg; + + return MongoUtil.getWriteConcern0(mongoClientOptions.getWriteConcern()); + } +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverConnectInterceptor3_7.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverConnectInterceptor3_7.java new file mode 100644 index 000000000000..d9ca3396abcb --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverConnectInterceptor3_7.java @@ -0,0 +1,143 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo.interceptor; + +import com.mongodb.MongoClientSettings; +import com.mongodb.ServerAddress; +import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.mongo.MongoConstants; +import com.navercorp.pinpoint.plugin.mongo.MongoUtil; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author Roy Kim + */ +public class MongoDriverConnectInterceptor3_7 extends SpanEventSimpleAroundInterceptorForPlugin { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + public MongoDriverConnectInterceptor3_7(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + } + + @Override + protected void prepareAfterTrace(Object target, Object[] args, Object result, Throwable throwable) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, + Throwable throwable) { + + final boolean success = InterceptorUtils.isSuccess(throwable); + // Must not check if current transaction is trace target or not. Connection can be made by other thread. + + if (success) { + if (args == null) { + return; + } + + final List hostList = getHostList(args[0]); + String readPreference = getReadPreference(args[0]); + String writeConcern = getWriteConcern(args[0]); + + DatabaseInfo databaseInfo = createDatabaseInfo(hostList, readPreference, writeConcern); + if (databaseInfo == null) { + databaseInfo = UnKnownDatabaseInfo.INSTANCE; + } + + if (result instanceof DatabaseInfoAccessor) { + ((DatabaseInfoAccessor) result)._$PINPOINT$_setDatabaseInfo(databaseInfo); + } + + recorder.recordServiceType(databaseInfo.getType()); + recorder.recordEndPoint(databaseInfo.getMultipleHost()); + recorder.recordDestinationId(databaseInfo.getDatabaseId()); + } + + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + } + + private DatabaseInfo createDatabaseInfo(List hostList, String readPreference, String writeConcern) { + + DatabaseInfo databaseInfo = new MongoDatabaseInfo(MongoConstants.MONGODB, MongoConstants.MONGO_EXECUTE_QUERY, + null, null, hostList, null, null, readPreference, writeConcern); + + if (isDebug) { + logger.debug("parse DatabaseInfo:{}", databaseInfo); + } + + return databaseInfo; + } + + private List getHostList(Object arg) { + if (!(arg instanceof MongoClientSettings)) { + return Collections.emptyList(); + } + + final MongoClientSettings mongoClientSettings = (MongoClientSettings) arg; + + List lists = mongoClientSettings.getClusterSettings().getHosts(); + + final List hostList = new ArrayList(); + for (ServerAddress sa : lists) { + final String hostAddress = HostAndPort.toHostAndPortString(sa.getHost(), sa.getPort()); + hostList.add(hostAddress); + } + + return hostList; + } + + private String getReadPreference(Object arg) { + if (!(arg instanceof MongoClientSettings)) { + return null; + } + + final MongoClientSettings mongoClientSettings = (MongoClientSettings) arg; + + return mongoClientSettings.getReadPreference().getName(); + } + + private String getWriteConcern(Object arg) { + if (!(arg instanceof MongoClientSettings)) { + return null; + } + + final MongoClientSettings mongoClientSettings = (MongoClientSettings) arg; + + return MongoUtil.getWriteConcern0(mongoClientSettings.getWriteConcern()); + } +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverGetCollectionInterceptor.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverGetCollectionInterceptor.java new file mode 100644 index 000000000000..5cb61f4eb3ab --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverGetCollectionInterceptor.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; + +/** + * @author Roy Kim + */ +public class MongoDriverGetCollectionInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + public MongoDriverGetCollectionInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + if (traceContext == null) { + throw new NullPointerException("traceContext must not be null"); + } + if (descriptor == null) { + throw new NullPointerException("descriptor must not be null"); + } + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + DatabaseInfo databaseInfo; + if (target instanceof DatabaseInfoAccessor) { + databaseInfo = ((DatabaseInfoAccessor) target)._$PINPOINT$_getDatabaseInfo(); + } else { + databaseInfo = UnKnownDatabaseInfo.INSTANCE; + } + + databaseInfo = new MongoDatabaseInfo(databaseInfo.getType(), databaseInfo.getExecuteQueryType(), + null, null, databaseInfo.getHost(), databaseInfo.getDatabaseId(), args[0].toString(), ((MongoDatabaseInfo) databaseInfo).getReadPreference(), ((MongoDatabaseInfo) databaseInfo).getWriteConcern()); + + if (result instanceof DatabaseInfoAccessor) { + ((DatabaseInfoAccessor) result)._$PINPOINT$_setDatabaseInfo(databaseInfo); + } + + } + + +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverGetDatabaseInterceptor.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverGetDatabaseInterceptor.java new file mode 100644 index 000000000000..9ad4eee99417 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoDriverGetDatabaseInterceptor.java @@ -0,0 +1,77 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; +import com.navercorp.pinpoint.plugin.mongo.MongoConstants; + +/** + * @author Roy Kim + */ +public class MongoDriverGetDatabaseInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + public MongoDriverGetDatabaseInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + if (traceContext == null) { + throw new NullPointerException("traceContext must not be null"); + } + if (descriptor == null) { + throw new NullPointerException("descriptor must not be null"); + } + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + DatabaseInfo databaseInfo; + if (target instanceof DatabaseInfoAccessor) { + databaseInfo = ((DatabaseInfoAccessor) target)._$PINPOINT$_getDatabaseInfo(); + } else { + databaseInfo = UnKnownDatabaseInfo.INSTANCE; + } + + databaseInfo = new MongoDatabaseInfo(MongoConstants.MONGODB, MongoConstants.MONGO_EXECUTE_QUERY, + null, null, databaseInfo.getHost(), args[0].toString(), null, ((MongoDatabaseInfo) databaseInfo).getReadPreference(), ((MongoDatabaseInfo) databaseInfo).getWriteConcern()); + + if (result instanceof DatabaseInfoAccessor) { + ((DatabaseInfoAccessor) result)._$PINPOINT$_setDatabaseInfo(databaseInfo); + } + + } + + +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoRSessionInterceptor.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoRSessionInterceptor.java new file mode 100644 index 000000000000..f0f7c23472f9 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoRSessionInterceptor.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; +import com.navercorp.pinpoint.common.util.StringStringValue; +import com.navercorp.pinpoint.plugin.mongo.MongoUtil; +import org.bson.conversions.Bson; + +/** + * @author Roy Kim + */ +public class MongoRSessionInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean collectJson; + private final boolean traceBsonBindValue; + + public MongoRSessionInterceptor(TraceContext traceContext, MethodDescriptor descriptor, boolean collectJson, boolean traceBsonBindValue) { + super(traceContext, descriptor); + this.collectJson = collectJson; + this.traceBsonBindValue = traceBsonBindValue; + } + + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + + DatabaseInfo databaseInfo; + if (target instanceof DatabaseInfoAccessor) { + databaseInfo = ((DatabaseInfoAccessor) target)._$PINPOINT$_getDatabaseInfo(); + } else { + databaseInfo = UnKnownDatabaseInfo.INSTANCE; + } + + recorder.recordServiceType(databaseInfo.getExecuteQueryType()); + recorder.recordEndPoint(databaseInfo.getMultipleHost()); + recorder.recordDestinationId(databaseInfo.getDatabaseId()); + + recorder.recordApi(methodDescriptor); + MongoUtil.recordMongoCollection(recorder, ((MongoDatabaseInfo) databaseInfo).getCollectionName(), ((MongoDatabaseInfo) databaseInfo).getReadPreference()); + } + + @Override + protected void prepareAfterTrace(Object target, Object[] args, Object result, Throwable throwable) { + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + if (collectJson) { + final boolean success = InterceptorUtils.isSuccess(throwable); + if (success) { + if (args != null) { + StringStringValue parsedBson = MongoUtil.parseBson(args, traceBsonBindValue); + MongoUtil.recordParsedBson(recorder, parsedBson); + } + } + } + recorder.recordException(throwable); + } +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoReadPreferenceInterceptor.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoReadPreferenceInterceptor.java new file mode 100644 index 000000000000..a89bf245acb7 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoReadPreferenceInterceptor.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo.interceptor; + +import com.mongodb.ReadPreference; +import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; + +/** + * @author Roy Kim + */ +public class MongoReadPreferenceInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + public MongoReadPreferenceInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + if (traceContext == null) { + throw new NullPointerException("traceContext must not be null"); + } + if (descriptor == null) { + throw new NullPointerException("descriptor must not be null"); + } + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + DatabaseInfo databaseInfo; + if (target instanceof DatabaseInfoAccessor) { + databaseInfo = ((DatabaseInfoAccessor) target)._$PINPOINT$_getDatabaseInfo(); + } else { + databaseInfo = UnKnownDatabaseInfo.INSTANCE; + } + + String readPreference = ((ReadPreference) args[0]).getName(); + + databaseInfo = new MongoDatabaseInfo(databaseInfo.getType(), databaseInfo.getExecuteQueryType() + , databaseInfo.getRealUrl(), databaseInfo.getUrl(), databaseInfo.getHost(), databaseInfo.getDatabaseId() + , ((MongoDatabaseInfo) databaseInfo).getCollectionName(), readPreference, ((MongoDatabaseInfo) databaseInfo).getWriteConcern()); + + if (result instanceof DatabaseInfoAccessor) { + ((DatabaseInfoAccessor) result)._$PINPOINT$_setDatabaseInfo(databaseInfo); + } + } + + +} diff --git a/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoWriteConcernInterceptor.java b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoWriteConcernInterceptor.java new file mode 100644 index 000000000000..0dd97dc10264 --- /dev/null +++ b/plugins/mongodb/src/main/java/com/navercorp/pinpoint/plugin/mongo/interceptor/MongoWriteConcernInterceptor.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo.interceptor; + +import com.mongodb.WriteConcern; +import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.MongoDatabaseInfo; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; +import com.navercorp.pinpoint.plugin.mongo.MongoUtil; + +/** + * @author Roy Kim + */ +public class MongoWriteConcernInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final MethodDescriptor methodDescriptor; + private final TraceContext traceContext; + + public MongoWriteConcernInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + if (traceContext == null) { + throw new NullPointerException("traceContext must not be null"); + } + if (descriptor == null) { + throw new NullPointerException("descriptor must not be null"); + } + this.traceContext = traceContext; + this.methodDescriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + DatabaseInfo databaseInfo; + if (target instanceof DatabaseInfoAccessor) { + databaseInfo = ((DatabaseInfoAccessor) target)._$PINPOINT$_getDatabaseInfo(); + } else { + databaseInfo = UnKnownDatabaseInfo.INSTANCE; + } + + String writeConcernStr = null; + if (args != null) { + writeConcernStr = MongoUtil.getWriteConcern0((WriteConcern) args[0]); + } + + databaseInfo = new MongoDatabaseInfo(databaseInfo.getType(), databaseInfo.getExecuteQueryType() + , databaseInfo.getRealUrl(), databaseInfo.getUrl(), databaseInfo.getHost(), databaseInfo.getDatabaseId() + , ((MongoDatabaseInfo) databaseInfo).getCollectionName(), ((MongoDatabaseInfo) databaseInfo).getReadPreference(), writeConcernStr); + + if (result instanceof DatabaseInfoAccessor) { + ((DatabaseInfoAccessor) result)._$PINPOINT$_setDatabaseInfo(databaseInfo); + } + } + + +} diff --git a/plugins/mongodb/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/mongodb/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..15e9f88cdac2 --- /dev/null +++ b/plugins/mongodb/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.mongo.MongoPlugin \ No newline at end of file diff --git a/plugins/mongodb/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/mongodb/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..eb6c9cd59319 --- /dev/null +++ b/plugins/mongodb/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.mongo.MongoTypeProvider \ No newline at end of file diff --git a/plugins/mongodb/src/test/java/com/navercorp/pinpoint/plugin/mongo/MongoUtilTest.java b/plugins/mongodb/src/test/java/com/navercorp/pinpoint/plugin/mongo/MongoUtilTest.java new file mode 100644 index 000000000000..af15cbd947d2 --- /dev/null +++ b/plugins/mongodb/src/test/java/com/navercorp/pinpoint/plugin/mongo/MongoUtilTest.java @@ -0,0 +1,231 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mongodb.BasicDBObject; +import com.navercorp.pinpoint.common.util.StringStringValue; +import org.bson.BsonArray; +import org.bson.BsonBinary; +import org.bson.BsonBinarySubType; +import org.bson.BsonBoolean; +import org.bson.BsonDateTime; +import org.bson.BsonDbPointer; +import org.bson.BsonDocument; +import org.bson.BsonDouble; +import org.bson.BsonInt32; +import org.bson.BsonInt64; +import org.bson.BsonJavaScript; +import org.bson.BsonJavaScriptWithScope; +import org.bson.BsonNull; +import org.bson.BsonObjectId; +import org.bson.BsonRegularExpression; +import org.bson.BsonString; +import org.bson.BsonSymbol; +import org.bson.BsonTimestamp; +import org.bson.BsonUndefined; +import org.bson.BsonValue; +import org.bson.types.ObjectId; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + + +/** + * @author Woonduk Kang(emeroad) + * @author Roy Kim + */ +public class MongoUtilTest { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + public void parseBsonNestedClass() throws IOException { + BasicDBObject query = new BasicDBObject(); + query.put("specialchar", new BasicDBObject("$gt", "1")); + logger.debug("query:{}", query); + + StringStringValue stringStringValue = MongoUtil.parseBson(new Object[]{query}, true); + logger.debug("parsedStringStringValue:{}", stringStringValue); + + List list = objectMapper.readValue("[" + stringStringValue.getStringValue1() + "]", List.class); + Assert.assertEquals(list.size(), 1); + Map query1Map = (Map) list.get(0); + Map query2Map = (Map) query1Map.get("specialchar"); + + checkValue(query2Map); + } + + @Test + public void parseArray() throws IOException { + + BasicDBObject query = new BasicDBObject(); + query.put("stringArray", new String[]{"\"a", "b", "c", "\"\"",""}); + logger.debug("query:{}", query); + + StringStringValue stringStringValue = MongoUtil.parseBson(new Object[]{query}, true); + logger.debug("parsedStringStringValue:{}", stringStringValue); + + List list = objectMapper.readValue("[" + stringStringValue.getStringValue1() + "]", List.class); + Assert.assertEquals(list.size(), 1); + Map query1Map = (Map) list.get(0); + ArrayList objectArray = (ArrayList) query1Map.get("stringArray"); + + checkValue(objectArray); + } + + @Test + public void parseBsonArrayWithValues() throws IOException { + + + BsonValue a = new BsonString("stest"); + BsonValue b = new BsonDouble(111); + BsonValue c = new BsonBoolean(true); + + BsonDocument document = new BsonDocument() + .append("int32", new BsonInt32(12)) + .append("int64", new BsonInt64(77L)) + .append("bo\"olean", new BsonBoolean(true)) + .append("date", new BsonDateTime(new Date().getTime())) + .append("double", new BsonDouble(12.3)) + .append("string", new BsonString("pinpoint")) + .append("objectId", new BsonObjectId(new ObjectId())) + .append("code", new BsonJavaScript("int i = 10;")) + .append("codeWithScope", new BsonJavaScriptWithScope("int x = y", new BsonDocument("y", new BsonInt32(1)))) + .append("regex", new BsonRegularExpression("^test.*regex.*xyz$", "big")) + .append("symbol", new BsonSymbol("wow")) + .append("timestamp", new BsonTimestamp(0x12345678, 5)) + .append("undefined", new BsonUndefined()) + .append("binary1", new BsonBinary(new byte[]{(byte) 0xe0, 0x4f, (byte) 0xd0, + 0x20, (byte) 0xea, 0x3a, 0x69, 0x10, (byte) 0xa2, (byte) 0xd8, 0x08, 0x00, 0x2b, + 0x30, 0x30, (byte) 0x9d})) + .append("oldBinary", new BsonBinary(BsonBinarySubType.OLD_BINARY, new byte[]{1, 1, 1, 1, 1})) + .append("arrayInt", new BsonArray(Arrays.asList(a, b, c, new BsonInt32(7)))) + .append("document", new BsonDocument("a", new BsonInt32(77))) + .append("dbPointer", new BsonDbPointer("db.coll", new ObjectId())) + .append("null", new BsonNull()); + + BasicDBObject query = new BasicDBObject(); + query.put("ComplexBson", document); + //logger.debug("query:{}", new Object[]{query}); + + StringStringValue stringStringValue = MongoUtil.parseBson(new Object[]{query}, true); + logger.debug("parsedStringStringValue:{}", stringStringValue); + + List list = objectMapper.readValue("[" + stringStringValue.getStringValue1() + "]", List.class); + Assert.assertEquals(list.size(), 1); + Map query1Map = (Map) list.get(0); + + checkValue(query1Map); + } + + @Test + public void parsePrimitiveIntArray() throws IOException { + + BasicDBObject query = new BasicDBObject(); + query.put("intArray", new int[]{1, 2, 3}); + + Object[] objArray = new Object[]{query,query}; + logger.debug("objArray:{}", objArray); + + StringStringValue stringStringValue = MongoUtil.parseBson(objArray, true); + logger.debug("parsedStringStringValue:{}", stringStringValue); + + List list = objectMapper.readValue("[" + stringStringValue.getStringValue1() + "]", List.class); + Assert.assertEquals(list.size(), objArray.length); + Map query1Map = (Map) list.get(0); + ArrayList objectArray = (ArrayList) query1Map.get("intArray"); + + checkValue(objectArray); + } + + @Test + public void parsePrimitiveDoubleArray() throws IOException { + + BasicDBObject query = new BasicDBObject(); + query.put("doubleArray", new double[]{1, 2, 3}); + logger.debug("query:{}", query); + + StringStringValue stringStringValue = MongoUtil.parseBson(new Object[]{query}, true); + logger.debug("parsedStringStringValue:{}", stringStringValue); + + List list = objectMapper.readValue("[" + stringStringValue.getStringValue1() + "]", List.class); + Assert.assertEquals(list.size(), 1); + Map query1Map = (Map) list.get(0); + ArrayList objectArray = (ArrayList) query1Map.get("doubleArray"); + + checkValue(objectArray); + } + + @Test + public void parseCollection() throws IOException { + + BasicDBObject query = new BasicDBObject(); + query.put("collection", Arrays.asList("naver", "apple")); + logger.debug("query:{}", query); + + StringStringValue stringStringValue = MongoUtil.parseBson(new Object[]{query}, true); + logger.debug("parsedStringStringValue:{}", stringStringValue); + + List list = objectMapper.readValue("[" + stringStringValue.getStringValue1() + "]", List.class); + Assert.assertEquals(list.size(), 1); + Map query1Map = (Map) list.get(0); + ArrayList objectArray = (ArrayList) query1Map.get("collection"); + + checkValue(objectArray); + } + + @Test + public void parseWithDoubleQuoteInKey() throws IOException { + BasicDBObject query = new BasicDBObject(); + query.put("\"query", new BasicDBObject("\"$gt", "1")); + logger.debug("query:{}", query); + + StringStringValue stringStringValue = MongoUtil.parseBson(new Object[]{query}, true); + logger.debug("parsedStringStringValue:{}", stringStringValue); + + List list = objectMapper.readValue("[" + stringStringValue.getStringValue1() + "]", List.class); + Assert.assertEquals(list.size(), 1); + Map query1Map = (Map) list.get(0); + Map query2Map = (Map) query1Map.get("\"query"); + + checkValue(query2Map); + } + + private void checkValue(Object object) { + if (object instanceof Map) { + for (Map.Entry entry : ((Map) object).entrySet()) { + checkValue(entry.getValue()); + } + } else if (object instanceof List) { + for (Object value : (List) object) { + checkValue(value); + } + } else { + Assert.assertEquals("?", object); + } + } +} \ No newline at end of file diff --git a/plugins/mongodb/src/test/java/com/navercorp/pinpoint/plugin/mongo/StringJoinerTest.java b/plugins/mongodb/src/test/java/com/navercorp/pinpoint/plugin/mongo/StringJoinerTest.java new file mode 100644 index 000000000000..591e68a19476 --- /dev/null +++ b/plugins/mongodb/src/test/java/com/navercorp/pinpoint/plugin/mongo/StringJoinerTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mongo; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * @author Woonduk Kang(emeroad) + */ +public class StringJoinerTest { + + @Test + public void join1() { + List stringList = new ArrayList(); + stringList.add("abc"); + + String join = StringJoiner.join(stringList, ","); + Assert.assertEquals(join, "abc"); + + } + + @Test + public void join2() { + List stringList = new ArrayList(); + stringList.add("abc"); + stringList.add("bcd"); + + String join = StringJoiner.join(stringList, ","); + Assert.assertEquals(join, "abc,bcd"); + + } + + @Test + public void join3() { + List stringList = new ArrayList(); + stringList.add("abc"); + stringList.add("bcd"); + stringList.add("f"); + + String join = StringJoiner.join(stringList, ","); + Assert.assertEquals(join, "abc,bcd,f"); + + } +} \ No newline at end of file diff --git a/plugins/mongodb/src/test/resources/log4j.xml b/plugins/mongodb/src/test/resources/log4j.xml new file mode 100644 index 000000000000..522006d4aa93 --- /dev/null +++ b/plugins/mongodb/src/test/resources/log4j.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/mybatis/clover.license b/plugins/mybatis/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/mybatis/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-mybatis-plugin diff --git a/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisConstants.java b/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisConstants.java new file mode 100644 index 000000000000..d43273b93fa3 --- /dev/null +++ b/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisConstants.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.mybatis; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class MyBatisConstants { + private MyBatisConstants() { + } + + public static final ServiceType MYBATIS = ServiceTypeFactory.of(5510, "MYBATIS"); +} diff --git a/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisMetadataProvider.java b/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisMetadataProvider.java index 7b48763e0fd5..fb4c37ababdf 100644 --- a/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisMetadataProvider.java +++ b/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisMetadataProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2015 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,7 +27,7 @@ public class MyBatisMetadataProvider implements TraceMetadataProvider { @Override public void setup(TraceMetadataSetupContext context) { - context.addServiceType(MyBatisPlugin.MYBATIS, AnnotationKeyMatchers.ARGS_MATCHER); + context.addServiceType(MyBatisConstants.MYBATIS, AnnotationKeyMatchers.ARGS_MATCHER); } } diff --git a/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisPlugin.java b/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisPlugin.java index dfb48cbf5d91..8a4aba9a7ccb 100644 --- a/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisPlugin.java +++ b/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/MyBatisPlugin.java @@ -1,11 +1,11 @@ /* - * Copyright 2015 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -33,16 +33,13 @@ import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + /** * @author HyunGil Jeong */ public class MyBatisPlugin implements ProfilerPlugin, TransformTemplateAware { - public static final ServiceType MYBATIS = ServiceTypeFactory.of(5510, "MYBATIS"); - private static final String MYBATIS_SCOPE = "MYBATIS_SCOPE"; private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); diff --git a/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/interceptor/SqlSessionOperationInterceptor.java b/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/interceptor/SqlSessionOperationInterceptor.java index 42c21fa90da6..ce7fed652ed2 100644 --- a/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/interceptor/SqlSessionOperationInterceptor.java +++ b/plugins/mybatis/src/main/java/com/navercorp/pinpoint/plugin/mybatis/interceptor/SqlSessionOperationInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2015 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,7 +21,8 @@ import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; import com.navercorp.pinpoint.common.util.ArrayUtils; -import com.navercorp.pinpoint.plugin.mybatis.MyBatisPlugin; +import com.navercorp.pinpoint.plugin.mybatis.MyBatisConstants; + /** * @author HyunGil Jeong @@ -40,7 +41,7 @@ protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object @Override protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { - recorder.recordServiceType(MyBatisPlugin.MYBATIS); + recorder.recordServiceType(MyBatisConstants.MYBATIS); recorder.recordException(throwable); if (ArrayUtils.hasLength(args)) { recorder.recordApiCachedString(getMethodDescriptor(), (String)args[0], 0); diff --git a/plugins/mysql-jdbc/clover.license b/plugins/mysql-jdbc/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/mysql-jdbc/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-mysql-jdbc-driver-plugin pinpoint-mysql-jdbc-driver-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/netty/clover.license b/plugins/netty/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/netty/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-netty-plugin diff --git a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyClientRequestWrapper.java b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyClientRequestWrapper.java new file mode 100644 index 000000000000..d047ac685eb2 --- /dev/null +++ b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyClientRequestWrapper.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.netty; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.common.util.Assert; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMessage; +import io.netty.handler.codec.http.HttpRequest; + +/** + * @author jaehong.kim + */ +public class NettyClientRequestWrapper implements ClientRequestWrapper { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final HttpMessage httpMessage; + private final ChannelHandlerContext channelHandlerContext; + + public NettyClientRequestWrapper(final HttpMessage httpMessage, final ChannelHandlerContext channelHandlerContext) { + this.httpMessage = Assert.requireNonNull(httpMessage, "httpMessage must not be null"); + this.channelHandlerContext = channelHandlerContext; + } + + + @Override + public String getDestinationId() { + if (this.channelHandlerContext != null) { + final Channel channel = this.channelHandlerContext.channel(); + if (channel != null) { + return NettyUtils.getEndPoint(channel.remoteAddress()); + } + } + return "Unknown"; + } + + @Override + public String getUrl() { + if (this.httpMessage instanceof HttpRequest) { + return ((HttpRequest) httpMessage).getUri(); + } + return null; + } + +} \ No newline at end of file diff --git a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyConfig.java b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyConfig.java index bc4b9b0bac7f..cee4a743fd29 100644 --- a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyConfig.java +++ b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyConfig.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.plugin.netty; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; /** @@ -30,10 +31,14 @@ public class NettyConfig { private final boolean pluginEnable; private final boolean httpCodecEnable; + private final boolean param; + private final HttpDumpConfig httpDumpConfig; public NettyConfig(ProfilerConfig config) { pluginEnable = config.readBoolean(PLUGIN_ENABLE, false); httpCodecEnable = config.readBoolean(HTTP_CODEC_ENABLE, false); + param = config.readBoolean("profiler.netty.http.param", false); + httpDumpConfig = HttpDumpConfig.getDefault(); } boolean isPluginEnable() { @@ -44,4 +49,22 @@ boolean isHttpCodecEnable() { return httpCodecEnable; } + public boolean isParam() { + return param; + } + + public HttpDumpConfig getHttpDumpConfig() { + return httpDumpConfig; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("NettyConfig{"); + sb.append("pluginEnable=").append(pluginEnable); + sb.append(", httpCodecEnable=").append(httpCodecEnable); + sb.append(", param=").append(param); + sb.append(", httpDumpConfig=").append(httpDumpConfig); + sb.append('}'); + return sb.toString(); + } } diff --git a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyConstants.java b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyConstants.java index 8ff0727dd021..723c89bf16c3 100644 --- a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyConstants.java +++ b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,7 +27,9 @@ /** * @author Taejin Koo */ -public class NettyConstants { +public final class NettyConstants { + private NettyConstants() { + } public static final ServiceType SERVICE_TYPE = ServiceTypeFactory.of(9150, "NETTY"); public static final ServiceType SERVICE_TYPE_INTERNAL = ServiceTypeFactory.of(9151, "NETTY_INTERNAL"); diff --git a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyPlugin.java b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyPlugin.java index fa3f7650b284..62dd11abc458 100644 --- a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyPlugin.java +++ b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/NettyPlugin.java @@ -42,7 +42,8 @@ */ public class NettyPlugin implements ProfilerPlugin, TransformTemplateAware { - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private static final PLogger LOGGER = PLoggerFactory.getLogger(NettyPlugin.class); + private static final boolean IS_DEBUG = LOGGER.isDebugEnabled(); private TransformTemplate transformTemplate; @@ -51,7 +52,7 @@ public class NettyPlugin implements ProfilerPlugin, TransformTemplateAware { public void setup(ProfilerPluginSetupContext context) { NettyConfig config = new NettyConfig(context.getConfig()); if (!config.isPluginEnable()) { - logger.info("Disable netty option. 'profiler.netty=false'"); + LOGGER.info("Disable netty option. 'profiler.netty=false'"); return; } @@ -79,24 +80,35 @@ private static class BootstrapTransformer implements TransformCallback { public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - final InstrumentMethod connectMethod = InstrumentUtils.findMethod(target, "connect"); + final InstrumentMethod connectMethod = target.getDeclaredMethod("connect"); if (connectMethod != null) { connectMethod.addScopedInterceptor(NettyConstants.INTERCEPTOR_BOOTSTRAP_CONNECT, NettyConstants.SCOPE, ExecutionPolicy.BOUNDARY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find connect method"); + } } - final InstrumentMethod connectMethod2 = InstrumentUtils.findMethod(target, "connect", "java.net.SocketAddress"); + final InstrumentMethod connectMethod2 = target.getDeclaredMethod("connect", "java.net.SocketAddress"); if (connectMethod2 != null) { connectMethod2.addScopedInterceptor(NettyConstants.INTERCEPTOR_BOOTSTRAP_CONNECT, NettyConstants.SCOPE, ExecutionPolicy.BOUNDARY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find connect(\"java.net.SocketAddress\") method"); + } } - final InstrumentMethod connectMethod3 = InstrumentUtils.findMethod(target, "connect", "java.net.SocketAddress", "java.net.SocketAddress"); + final InstrumentMethod connectMethod3 = target.getDeclaredMethod("connect", "java.net.SocketAddress", "java.net.SocketAddress"); if (connectMethod3 != null) { connectMethod3.addScopedInterceptor(NettyConstants.INTERCEPTOR_BOOTSTRAP_CONNECT, NettyConstants.SCOPE, ExecutionPolicy.BOUNDARY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find connect(\"java.net.SocketAddress\", \"java.net.SocketAddress\") method"); + } } return target.toBytecode(); } - } private static class ChannelPipelineTransformer implements TransformCallback { @@ -105,29 +117,44 @@ private static class ChannelPipelineTransformer implements TransformCallback { public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - final InstrumentMethod writeMethod1 = InstrumentUtils.findMethod(target, "write", "java.lang.Object"); + final InstrumentMethod writeMethod1 = target.getDeclaredMethod("write", "java.lang.Object"); if (writeMethod1 != null) { writeMethod1.addScopedInterceptor(NettyConstants.INTERCEPTOR_CHANNEL_PIPELINE_WRITE, NettyConstants.SCOPE_WRITE, ExecutionPolicy.BOUNDARY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find write(\"java.lang.Object\") method"); + } } - final InstrumentMethod writeMethod2 = InstrumentUtils.findMethod(target, "write", "java.lang.Object", "io.netty.channel.ChannelPromise"); + final InstrumentMethod writeMethod2 = target.getDeclaredMethod("write", "java.lang.Object", "io.netty.channel.ChannelPromise"); if (writeMethod2 != null) { writeMethod2.addScopedInterceptor(NettyConstants.INTERCEPTOR_CHANNEL_PIPELINE_WRITE, NettyConstants.SCOPE_WRITE, ExecutionPolicy.BOUNDARY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find write(\"java.lang.Object\", \"io.netty.channel.ChannelPromise\") method"); + } } - final InstrumentMethod writeAndFlushMethod1 = InstrumentUtils.findMethod(target, "writeAndFlush", "java.lang.Object"); + final InstrumentMethod writeAndFlushMethod1 = target.getDeclaredMethod("writeAndFlush", "java.lang.Object"); if (writeAndFlushMethod1 != null) { writeAndFlushMethod1.addScopedInterceptor(NettyConstants.INTERCEPTOR_CHANNEL_PIPELINE_WRITE, NettyConstants.SCOPE_WRITE, ExecutionPolicy.BOUNDARY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find writeAndFlush(\"java.lang.Object\") method"); + } } - final InstrumentMethod writeAndFlushMethod2 = InstrumentUtils.findMethod(target, "writeAndFlush", "java.lang.Object", "io.netty.channel.ChannelPromise"); + final InstrumentMethod writeAndFlushMethod2 = target.getDeclaredMethod("writeAndFlush", "java.lang.Object", "io.netty.channel.ChannelPromise"); if (writeAndFlushMethod2 != null) { writeAndFlushMethod2.addScopedInterceptor(NettyConstants.INTERCEPTOR_CHANNEL_PIPELINE_WRITE, NettyConstants.SCOPE_WRITE, ExecutionPolicy.BOUNDARY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find writeAndFlush(\"java.lang.Object\", \"io.netty.channel.ChannelPromise\") method"); + } } return target.toBytecode(); } - } private static class PromiseTransformer implements TransformCallback { @@ -137,20 +164,27 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); target.addField(AsyncContextAccessor.class.getName()); - InstrumentMethod notifyListenersNowMethod = InstrumentUtils.findMethod(target, "notifyListenersNow"); + InstrumentMethod notifyListenersNowMethod = target.getDeclaredMethod("notifyListenersNow"); if (notifyListenersNowMethod != null) { notifyListenersNowMethod.addInterceptor(NettyConstants.INTERCEPTOR_CHANNEL_PROMISE_NOTIFY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find notifyListenersNow method"); + } } - InstrumentMethod notifyListener0Method = InstrumentUtils.findMethod(target, "notifyListener0", "io.netty.util.concurrent.Future", "io.netty.util.concurrent.GenericFutureListener"); + InstrumentMethod notifyListener0Method = target.getDeclaredMethod("notifyListener0", "io.netty.util.concurrent.Future", "io.netty.util.concurrent.GenericFutureListener"); if (notifyListener0Method != null) { notifyListener0Method.addInterceptor(NettyConstants.INTERCEPTOR_BASIC, va(NettyConstants.SERVICE_TYPE_INTERNAL)); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find notifyListener0 method"); + } } return target.toBytecode(); } - } private static class ChannelPromiseTransformer implements TransformCallback { @@ -159,14 +193,22 @@ private static class ChannelPromiseTransformer implements TransformCallback { public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - final InstrumentMethod addListenerMethod1 = InstrumentUtils.findMethod(target, "addListener", "io.netty.util.concurrent.GenericFutureListener"); + final InstrumentMethod addListenerMethod1 = target.getDeclaredMethod("addListener", "io.netty.util.concurrent.GenericFutureListener"); if (addListenerMethod1 != null) { addListenerMethod1.addScopedInterceptor(NettyConstants.INTERCEPTOR_CHANNEL_PROMISE_ADD_LISTENER, NettyConstants.SCOPE, ExecutionPolicy.BOUNDARY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find addListener method"); + } } - final InstrumentMethod addListenerMethod2 = InstrumentUtils.findMethod(target, "addListeners", "io.netty.util.concurrent.GenericFutureListener[]"); + final InstrumentMethod addListenerMethod2 = target.getDeclaredMethod("addListeners", "io.netty.util.concurrent.GenericFutureListener[]"); if (addListenerMethod2 != null) { addListenerMethod2.addScopedInterceptor(NettyConstants.INTERCEPTOR_CHANNEL_PROMISE_ADD_LISTENER, NettyConstants.SCOPE, ExecutionPolicy.BOUNDARY); + } else { + if (IS_DEBUG) { + LOGGER.debug("can't find addListeners method"); + } } return target.toBytecode(); diff --git a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/interceptor/http/HttpEncoderInterceptor.java b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/interceptor/http/HttpEncoderInterceptor.java index 5a4a05def94f..4592c9222bc9 100644 --- a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/interceptor/http/HttpEncoderInterceptor.java +++ b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/interceptor/http/HttpEncoderInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,7 +19,6 @@ import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; import com.navercorp.pinpoint.bootstrap.context.AsyncContext; -import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -29,16 +28,21 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapperAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; +import com.navercorp.pinpoint.plugin.netty.NettyClientRequestWrapper; +import com.navercorp.pinpoint.plugin.netty.NettyConfig; import com.navercorp.pinpoint.plugin.netty.NettyConstants; import com.navercorp.pinpoint.plugin.netty.NettyUtils; import com.navercorp.pinpoint.plugin.netty.field.accessor.AsyncStartFlagFieldAccessor; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMessage; -import io.netty.handler.codec.http.HttpRequest; /** * @author Taejin Koo @@ -51,6 +55,8 @@ public class HttpEncoderInterceptor implements AroundInterceptor { private final TraceContext traceContext; protected final MethodDescriptor methodDescriptor; + private final ClientRequestRecorder clientRequestRecorder; + private final RequestTraceWriter requestTraceWriter; public HttpEncoderInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { if (traceContext == null) { @@ -62,6 +68,12 @@ public HttpEncoderInterceptor(TraceContext traceContext, MethodDescriptor method this.traceContext = traceContext; this.methodDescriptor = methodDescriptor; + final NettyConfig config = new NettyConfig(traceContext.getProfilerConfig()); + + ClientRequestAdaptor clientRequestAdaptor = ClientRequestWrapperAdaptor.INSTANCE; + this.clientRequestRecorder = new ClientRequestRecorder(config.isParam(), clientRequestAdaptor); + ClientHeaderAdaptor clientHeaderAdaptor = new HttpMessageClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } @Override @@ -84,9 +96,8 @@ public void before(Object target, Object[] args) { private void before0(Trace trace, Object target, Object[] args) { if (!trace.canSampled()) { - HttpMessage httpMessage = (HttpMessage) args[1]; - HttpHeaders headers = httpMessage.headers(); - addHeaderIfNotExist(headers, Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); + final HttpMessage httpMessage = (HttpMessage) args[1]; + this.requestTraceWriter.write(httpMessage); return; } final SpanEventRecorder recorder = trace.traceBlockBegin(); @@ -127,34 +138,20 @@ protected void doInBeforeTrace(SpanEventRecorder recorder, Trace trace, Object t recorder.recordNextSpanId(nextId.getSpanId()); recorder.recordServiceType(NettyConstants.SERVICE_TYPE_CODEC_HTTP); - ChannelHandlerContext channelHandlerContext = (ChannelHandlerContext) args[0]; - Channel channel = channelHandlerContext.channel(); - final String endpoint = NettyUtils.getEndPoint(channel.remoteAddress()); - recorder.recordDestinationId(endpoint); - - HttpMessage httpMessage = (HttpMessage) args[1]; - HttpHeaders headers = httpMessage.headers(); - - addHeaderIfNotExist(headers, Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - addHeaderIfNotExist(headers, Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - - addHeaderIfNotExist(headers, Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - - addHeaderIfNotExist(headers, Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - addHeaderIfNotExist(headers, Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - addHeaderIfNotExist(headers, Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - - addHeaderIfNotExist(headers, Header.HTTP_HOST.toString(), endpoint); - - if (httpMessage instanceof HttpRequest) { - recorder.recordAttribute(AnnotationKey.HTTP_URL, ((HttpRequest) httpMessage).getUri()); - } + final ChannelHandlerContext channelHandlerContext = (ChannelHandlerContext) args[0]; + final HttpMessage httpMessage = (HttpMessage) args[1]; + final String host = getHost(channelHandlerContext); + this.requestTraceWriter.write(httpMessage, nextId, host); } - private void addHeaderIfNotExist(HttpHeaders headers, String key, Object value) { - if (!headers.contains(key)) { - headers.set(key, value); + private String getHost(ChannelHandlerContext channelHandlerContext) { + if (channelHandlerContext != null) { + final Channel channel = channelHandlerContext.channel(); + if (channel != null) { + return NettyUtils.getEndPoint(channel.remoteAddress()); + } } + return null; } @Override @@ -171,11 +168,11 @@ public void after(Object target, Object[] args, Object result, Throwable throwab if (async) { afterAsync(target, args, result, throwable); } else { - after0(throwable); + after0(target, args, result, throwable); } } - private void after0(Throwable throwable) { + private void after0(Object target, Object[] args, Object result, Throwable throwable) { final Trace trace = traceContext.currentRawTraceObject(); if (trace == null) { return; @@ -185,7 +182,7 @@ private void after0(Throwable throwable) { } final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); try { - doInAfterTrace(recorder, throwable); + doInAfterTrace(recorder, target, args, result, throwable); } finally { trace.traceBlockEnd(); } @@ -215,7 +212,7 @@ private void afterAsync(Object target, Object[] args, Object result, Throwable t try { final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - doInAfterTrace(recorder, throwable); + doInAfterTrace(recorder, target, args, result, throwable); } catch (Throwable th) { if (logger.isWarnEnabled()) { logger.warn("AFTER error. Caused:{}", th.getMessage(), th); @@ -228,9 +225,12 @@ private void afterAsync(Object target, Object[] args, Object result, Throwable t } } - protected void doInAfterTrace(SpanEventRecorder recorder, Throwable throwable) { - recorder.recordApi(methodDescriptor); - recorder.recordException(throwable); + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + final ChannelHandlerContext channelHandlerContext = (ChannelHandlerContext) args[0]; + final HttpMessage httpMessage = (HttpMessage) args[1]; + this.clientRequestRecorder.record(recorder, new NettyClientRequestWrapper(httpMessage, channelHandlerContext), throwable); } protected AsyncContext getAsyncContext(Object target) { @@ -319,5 +319,4 @@ private boolean validate(Object[] args) { return true; } - -} +} \ No newline at end of file diff --git a/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/interceptor/http/HttpMessageClientHeaderAdaptor.java b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/interceptor/http/HttpMessageClientHeaderAdaptor.java new file mode 100644 index 000000000000..fb91a7121d64 --- /dev/null +++ b/plugins/netty/src/main/java/com/navercorp/pinpoint/plugin/netty/interceptor/http/HttpMessageClientHeaderAdaptor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.netty.interceptor.http; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMessage; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpMessageClientHeaderAdaptor implements ClientHeaderAdaptor { + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(HttpMessage httpMessage, String name, String value) { + final HttpHeaders headers = httpMessage.headers(); + if (headers != null && !headers.contains(name)) { + headers.set(name, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } + } +} diff --git a/plugins/ning-asynchttpclient/clover.license b/plugins/ning-asynchttpclient/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/ning-asynchttpclient/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-ning-asynchttpclient-plugin pinpoint-ning-asynchttpclient-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + 1.6 diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientConstants.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientConstants.java new file mode 100644 index 000000000000..ba841252ad2c --- /dev/null +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientConstants.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ning.asynchttpclient; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class NingAsyncHttpClientConstants { + private NingAsyncHttpClientConstants() { + } + + public static final ServiceType ASYNC_HTTP_CLIENT = ServiceTypeFactory.of(9056, "ASYNC_HTTP_CLIENT", RECORD_STATISTICS); + public static final ServiceType ASYNC_HTTP_CLIENT_INTERNAL = ServiceTypeFactory.of(9057, "ASYNC_HTTP_CLIENT_INTERNAL", "ASYNC_HTTP_CLIENT"); +} diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientMetadataProvider.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientMetadataProvider.java index e956efc8e209..03e926e3729e 100644 --- a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientMetadataProvider.java +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientMetadataProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -29,7 +29,7 @@ public class NingAsyncHttpClientMetadataProvider implements TraceMetadataProvide @Override public void setup(TraceMetadataSetupContext context) { - context.addServiceType(NingAsyncHttpClientPlugin.ASYNC_HTTP_CLIENT, AnnotationKeyMatchers.exact(AnnotationKey.HTTP_URL)); - context.addServiceType(NingAsyncHttpClientPlugin.ASYNC_HTTP_CLIENT_INTERNAL, AnnotationKeyMatchers.exact(AnnotationKey.HTTP_INTERNAL_DISPLAY)); + context.addServiceType(NingAsyncHttpClientConstants.ASYNC_HTTP_CLIENT, AnnotationKeyMatchers.exact(AnnotationKey.HTTP_URL)); + context.addServiceType(NingAsyncHttpClientConstants.ASYNC_HTTP_CLIENT_INTERNAL, AnnotationKeyMatchers.exact(AnnotationKey.HTTP_INTERNAL_DISPLAY)); } } diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientPlugin.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientPlugin.java index 03f49592d2d0..58ac20eac1cd 100644 --- a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientPlugin.java +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientPlugin.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -31,8 +31,6 @@ import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; import com.navercorp.pinpoint.bootstrap.plugin.util.InstrumentUtils; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; /** * @author netspider @@ -42,8 +40,6 @@ */ public class NingAsyncHttpClientPlugin implements ProfilerPlugin, TransformTemplateAware { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); - public static final ServiceType ASYNC_HTTP_CLIENT = ServiceTypeFactory.of(9056, "ASYNC_HTTP_CLIENT", RECORD_STATISTICS); - public static final ServiceType ASYNC_HTTP_CLIENT_INTERNAL = ServiceTypeFactory.of(9057, "ASYNC_HTTP_CLIENT_INTERNAL", "ASYNC_HTTP_CLIENT"); private TransformTemplate transformTemplate; diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientPluginConfig.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientPluginConfig.java index 42857f233c9e..06ba6a48da77 100644 --- a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientPluginConfig.java +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientPluginConfig.java @@ -16,96 +16,50 @@ package com.navercorp.pinpoint.plugin.ning.asynchttpclient; import com.navercorp.pinpoint.bootstrap.config.DumpType; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; /** - * * @author jaehong.kim - * */ public class NingAsyncHttpClientPluginConfig { private final boolean enable; - private final boolean profileCookie; - private final DumpType cookieDumpType; - private final int cookieDumpSize; - private final int cookieSamplingRate; - private final boolean profileEntity; - private final DumpType entityDumpType; - private final int entityDumpSize; - private final int entitySamplingRate; - private final boolean profileParam; - private final DumpType paramDumpType; - private final int paramDumpSize; - private final int paramSamplingRate; + private final boolean param; + private final HttpDumpConfig httpDumpConfig; public NingAsyncHttpClientPluginConfig(ProfilerConfig src) { this.enable = src.readBoolean("profiler.ning.asynchttpclient", true); - - this.profileCookie = src.readBoolean("profiler.ning.asynchttpclient.cookie", false); - this.cookieDumpType = src.readDumpType("profiler.ning.asynchttpclient.cookie.dumptype", DumpType.EXCEPTION); - this.cookieDumpSize = src.readInt("profiler.ning.asynchttpclient.cookie.dumpsize", 1024); - this.cookieSamplingRate = src.readInt("profiler.ning.asynchttpclient.cookie.sampling.rate", 1); - - this.profileEntity = src.readBoolean("profiler.ning.asynchttpclient.entity", false); - this.entityDumpType = src.readDumpType("profiler.ning.asynchttpclient.entity.dumptype", DumpType.EXCEPTION); - this.entityDumpSize = src.readInt("profiler.ning.asynchttpclient.entity.dumpsize", 1024); - this.entitySamplingRate = src.readInt("profiler.ning.asynchttpclient.entity.sampling.rate", 1); - - this.profileParam = src.readBoolean("profiler.ning.asynchttpclient.param", false); - this.paramDumpType = src.readDumpType("profiler.ning.asynchttpclient.param.dumptype", DumpType.EXCEPTION); - this.paramDumpSize = src.readInt("profiler.ning.asynchttpclient.param.dumpsize", 1024); - this.paramSamplingRate = src.readInt("profiler.ning.asynchttpclient.param.sampling.rate", 1); + this.param = src.readBoolean("profiler.ning.asynchttpclient.param", false); + boolean profileCookie = src.readBoolean("profiler.ning.asynchttpclient.cookie", false); + DumpType cookieDumpType = src.readDumpType("profiler.ning.asynchttpclient.cookie.dumptype", DumpType.EXCEPTION); + int cookieDumpSize = src.readInt("profiler.ning.asynchttpclient.cookie.dumpsize", 1024); + int cookieSamplingRate = src.readInt("profiler.ning.asynchttpclient.cookie.sampling.rate", 1); + boolean profileEntity = src.readBoolean("profiler.ning.asynchttpclient.entity", false); + DumpType entityDumpType = src.readDumpType("profiler.ning.asynchttpclient.entity.dumptype", DumpType.EXCEPTION); + int entityDumpSize = src.readInt("profiler.ning.asynchttpclient.entity.dumpsize", 1024); + int entitySamplingRate = src.readInt("profiler.ning.asynchttpclient.entity.sampling.rate", 1); + this.httpDumpConfig = HttpDumpConfig.get(profileCookie, cookieDumpType, cookieSamplingRate, cookieDumpSize, profileEntity, entityDumpType, entitySamplingRate, entityDumpSize); } public boolean isEnable() { return enable; } - public boolean isProfileCookie() { - return profileCookie; - } - - public DumpType getCookieDumpType() { - return cookieDumpType; - } - - public int getCookieDumpSize() { - return cookieDumpSize; - } - - public int getCookieSamplingRate() { - return cookieSamplingRate; - } - - public boolean isProfileEntity() { - return profileEntity; - } - - public DumpType getEntityDumpType() { - return entityDumpType; - } - - public int getEntityDumpSize() { - return entityDumpSize; - } - - public int getEntitySamplingRate() { - return entitySamplingRate; - } - - public boolean isProfileParam() { - return profileParam; - } - - public DumpType getParamDumpType() { - return paramDumpType; + public boolean isParam() { + return param; } - public int getParamDumpSize() { - return paramDumpSize; + public HttpDumpConfig getHttpDumpConfig() { + return httpDumpConfig; } - public int getParamSamplingRate() { - return paramSamplingRate; + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("NingAsyncHttpClientPluginConfig{"); + sb.append("enable=").append(enable); + sb.append(", param=").append(param); + sb.append(", httpDumpConfig=").append(httpDumpConfig); + sb.append('}'); + return sb.toString(); } } diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientRequestAdaptorV1.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientRequestAdaptorV1.java new file mode 100644 index 000000000000..962b4f5ec588 --- /dev/null +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientRequestAdaptorV1.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ning.asynchttpclient; + +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.ning.http.client.Request; + +/** + * @author jaehong.kim + */ +public class NingAsyncHttpClientRequestAdaptorV1 implements ClientRequestAdaptor { + + public NingAsyncHttpClientRequestAdaptorV1() { + } + + + @Override + public String getDestinationId(Request request) { + return EndPointUtils.getEndPoint(request.getUrl(), "Unknown"); + } + + @Override + public String getUrl(Request request) { + return request.getUrl(); + } + + + +} \ No newline at end of file diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientRequestAdaptorV2.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientRequestAdaptorV2.java new file mode 100644 index 000000000000..451ce91388ab --- /dev/null +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingAsyncHttpClientRequestAdaptorV2.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ning.asynchttpclient; + +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import org.asynchttpclient.Request; + +/** + * @author jaehong.kim + */ +public class NingAsyncHttpClientRequestAdaptorV2 implements ClientRequestAdaptor { + + @Override + public String getDestinationId(final Request httpRequest) { + return EndPointUtils.getEndPoint(httpRequest.getUrl(), "Unknown"); + } + + @Override + public String getUrl(final Request httpRequest) { + return httpRequest.getUrl(); + } + + +} \ No newline at end of file diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingCookieExtractorV1.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingCookieExtractorV1.java new file mode 100644 index 000000000000..e70adb97f176 --- /dev/null +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingCookieExtractorV1.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ning.asynchttpclient; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.ning.http.client.Request; +import com.ning.http.client.cookie.Cookie; + +import java.util.Collection; +import java.util.Iterator; + +/** + * @author Woonduk Kang(emeroad) + */ +public class NingCookieExtractorV1 implements CookieExtractor { + + public static final CookieExtractor INSTANCE = new NingCookieExtractorV1(); + + @Override + public String getCookie(Request request) { + final Collection cookies = request.getCookies(); + if (cookies.isEmpty()) { + return null; + } + final StringBuilder sb = new StringBuilder(); + Iterator iterator = cookies.iterator(); + while (iterator.hasNext()) { + final Cookie cookie = iterator.next(); + sb.append(cookie.getName()); + sb.append('='); + sb.append(cookie.getValue()); + if (iterator.hasNext()) { + sb.append(','); + } + } + return sb.toString(); + } +} diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingCookieExtractorV2.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingCookieExtractorV2.java new file mode 100644 index 000000000000..b96030ecdd3a --- /dev/null +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingCookieExtractorV2.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ning.asynchttpclient; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import org.asynchttpclient.Request; +import org.asynchttpclient.cookie.Cookie; + +import java.util.Iterator; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class NingCookieExtractorV2 implements CookieExtractor { + + public static final CookieExtractor INSTANCE = new NingCookieExtractorV2(); + + @Override + public String getCookie(Request httpRequest) { + List cookies = httpRequest.getCookies(); + if (cookies.isEmpty()) { + return null; + } + + final StringBuilder sb = new StringBuilder(); + Iterator iterator = cookies.iterator(); + while (iterator.hasNext()) { + Cookie cookie = iterator.next(); + sb.append(cookie.getName()); + sb.append('='); + sb.append(cookie.getValue()); + if (iterator.hasNext()) { + sb.append(','); + } + } + return sb.toString(); + } +} diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingEntityExtractorV1.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingEntityExtractorV1.java new file mode 100644 index 000000000000..af51c3c14713 --- /dev/null +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingEntityExtractorV1.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ning.asynchttpclient; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityExtractor; +import com.ning.http.client.Request; + +import java.io.InputStream; + +/** + * @author Woonduk Kang(emeroad) + */ +public class NingEntityExtractorV1 implements EntityExtractor { + public static final EntityExtractor INSTANCE = new NingEntityExtractorV1(); + + @Override + public String getEntity(Request request) { + final String stringData = request.getStringData(); + if (stringData != null) { + return stringData; + } + + final byte[] byteData = request.getByteData(); + if (byteData != null) { + return "BYTE_DATA"; + } + + final InputStream streamData = request.getStreamData(); + if (streamData != null) { + return "STREAM_DATA"; + } + + return null; + } +} diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingEntityExtractorV2.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingEntityExtractorV2.java new file mode 100644 index 000000000000..737075e11601 --- /dev/null +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/NingEntityExtractorV2.java @@ -0,0 +1,93 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ning.asynchttpclient; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityExtractor; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import org.asynchttpclient.Request; +import org.asynchttpclient.request.body.multipart.ByteArrayPart; +import org.asynchttpclient.request.body.multipart.FilePart; +import org.asynchttpclient.request.body.multipart.Part; +import org.asynchttpclient.request.body.multipart.StringPart; + +import java.io.InputStream; +import java.util.Iterator; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class NingEntityExtractorV2 implements EntityExtractor { + + public static final EntityExtractor INSTANCE = new NingEntityExtractorV2(); + + private static final int MAX_READ_SIZE = 1024; + @Override + public String getEntity(Request httpRequest) { + + final String stringData = httpRequest.getStringData(); + if (stringData != null) { + return stringData; + } + + final byte[] byteData = httpRequest.getByteData(); + if (byteData != null) { + return "BYTE_DATA"; + } + + final InputStream streamData = httpRequest.getStreamData(); + if (streamData != null) { + return "STREAM_DATA"; + } + + List parts = httpRequest.getBodyParts(); + // bug fix : parts != null && ****!parts.isEmpty() + if (CollectionUtils.hasLength(parts)) { + StringBuilder sb = new StringBuilder(); + Iterator iterator = parts.iterator(); + while (iterator.hasNext()) { + Part part = iterator.next(); + if (part instanceof ByteArrayPart) { + ByteArrayPart p = (ByteArrayPart) part; + sb.append(part.getName()); + sb.append("=BYTE_ARRAY_"); + sb.append(p.getBytes().length); + } else if (part instanceof FilePart) { + FilePart p = (FilePart) part; + sb.append(part.getName()); + sb.append("=FILE_"); + sb.append(p.getContentType()); + } else if (part instanceof StringPart) { + StringPart p = (StringPart) part; + sb.append(part.getName()); + sb.append("=STRING"); + } + + if (sb.length() >= MAX_READ_SIZE) { + break; + } + + if (iterator.hasNext()) { + sb.append(','); + } + } + return sb.toString(); + } + + return null; + } +} diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/RequestHeaderAdaptorV1.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/RequestHeaderAdaptorV1.java new file mode 100644 index 000000000000..e96445fec8c3 --- /dev/null +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/RequestHeaderAdaptorV1.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ning.asynchttpclient; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.Request; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RequestHeaderAdaptorV1 implements ClientHeaderAdaptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(Request request, String name, String value) { + final FluentCaseInsensitiveStringsMap httpRequestHeaders = request.getHeaders(); + final List valueList = new ArrayList(); + valueList.add(value); + httpRequestHeaders.put(name, valueList); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } +} diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/RequestHeaderAdaptorV2.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/RequestHeaderAdaptorV2.java new file mode 100644 index 000000000000..22418c78cf0a --- /dev/null +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/RequestHeaderAdaptorV2.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.ning.asynchttpclient; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import io.netty.handler.codec.http.HttpHeaders; +import org.asynchttpclient.Request; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RequestHeaderAdaptorV2 implements ClientHeaderAdaptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(Request request, String name, String value) { + final HttpHeaders httpRequestHeaders = request.getHeaders(); + if (httpRequestHeaders != null) { + httpRequestHeaders.set(name, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } + } +} diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/interceptor/ExecuteInterceptor.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/interceptor/ExecuteInterceptor.java index 54eeea18298e..1ebb9a035e4c 100644 --- a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/interceptor/ExecuteInterceptor.java +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/interceptor/ExecuteInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,7 +15,6 @@ */ package com.navercorp.pinpoint.plugin.ning.asynchttpclient.interceptor; -import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -24,53 +23,57 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.bootstrap.util.SimpleSampler; -import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.util.CollectionUtils; -import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorderFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityRecorderFactory; import com.navercorp.pinpoint.plugin.ning.asynchttpclient.EndPointUtils; -import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingAsyncHttpClientPlugin; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingAsyncHttpClientConstants; import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingAsyncHttpClientPluginConfig; -import io.netty.handler.codec.http.HttpHeaders; -import org.asynchttpclient.Param; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingAsyncHttpClientRequestAdaptorV2; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingCookieExtractorV2; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingEntityExtractorV2; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.RequestHeaderAdaptorV2; import org.asynchttpclient.Request; -import org.asynchttpclient.cookie.Cookie; -import org.asynchttpclient.request.body.multipart.ByteArrayPart; -import org.asynchttpclient.request.body.multipart.FilePart; -import org.asynchttpclient.request.body.multipart.Part; -import org.asynchttpclient.request.body.multipart.StringPart; - -import java.io.InputStream; -import java.util.Iterator; -import java.util.List; /** * @author jaehong.kim */ public class ExecuteInterceptor implements AroundInterceptor { - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final TraceContext traceContext; private final MethodDescriptor descriptor; - private final NingAsyncHttpClientPluginConfig config; - private final SimpleSampler cookieSampler; - private final SimpleSampler entitySampler; - private final SimpleSampler paramSampler; + private final ClientRequestRecorder clientRequestRecorder; + private final RequestTraceWriter requestTraceWriter; + private final CookieRecorder cookieRecorder; + private final EntityRecorder entityRecorder; public ExecuteInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { this.traceContext = traceContext; this.descriptor = descriptor; - this.config = new NingAsyncHttpClientPluginConfig(traceContext.getProfilerConfig()); + final NingAsyncHttpClientPluginConfig config = new NingAsyncHttpClientPluginConfig(traceContext.getProfilerConfig()); + + ClientRequestAdaptor clientRequestAdaptor = new NingAsyncHttpClientRequestAdaptorV2(); + this.clientRequestRecorder = new ClientRequestRecorder(config.isParam(), clientRequestAdaptor); + + CookieExtractor cookieExtractor = NingCookieExtractorV2.INSTANCE; + this.cookieRecorder = CookieRecorderFactory.newCookieRecorder(config.getHttpDumpConfig(), cookieExtractor); - this.cookieSampler = config.isProfileCookie() ? SimpleSamplerFactory.createSampler(true, config.getCookieSamplingRate()) : null; - this.entitySampler = config.isProfileEntity() ? SimpleSamplerFactory.createSampler(true, config.getEntitySamplingRate()) : null; - this.paramSampler = config.isProfileParam() ? SimpleSamplerFactory.createSampler(true, config.getParamSamplingRate()) : null; + EntityExtractor entityExtractor = NingEntityExtractorV2.INSTANCE; + this.entityRecorder = EntityRecorderFactory.newEntityRecorder(config.getHttpDumpConfig(), entityExtractor); + + ClientHeaderAdaptor clientHeaderAdaptor = new RequestHeaderAdaptorV2(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } @Override @@ -91,12 +94,8 @@ public void before(Object target, Object[] args) { final Request httpRequest = (Request) args[0]; final boolean sampling = trace.canSampled(); if (!sampling) { - if (isDebug) { - logger.debug("set Sampling flag=false"); - } if (httpRequest != null) { - final HttpHeaders httpRequestHeaders = httpRequest.getHeaders(); - httpRequestHeaders.set(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); + this.requestTraceWriter.write(httpRequest); } return; } @@ -105,23 +104,18 @@ public void before(Object target, Object[] args) { final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); final TraceId nextId = trace.getTraceId().getNextTraceId(); recorder.recordNextSpanId(nextId.getSpanId()); - recorder.recordServiceType(NingAsyncHttpClientPlugin.ASYNC_HTTP_CLIENT); - + recorder.recordServiceType(NingAsyncHttpClientConstants.ASYNC_HTTP_CLIENT); if (httpRequest != null) { - final HttpHeaders httpRequestHeaders = httpRequest.getHeaders(); - httpRequestHeaders.set(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - httpRequestHeaders.set(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - httpRequestHeaders.set(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - httpRequestHeaders.set(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - httpRequestHeaders.set(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - httpRequestHeaders.set(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - final String hostString = EndPointUtils.getEndPoint(httpRequest.getUrl(), null); - if (hostString != null) { - httpRequestHeaders.set(Header.HTTP_HOST.toString(), hostString); - } + String host = getHost(httpRequest); + this.requestTraceWriter.write(httpRequest, nextId, host); } } + private String getHost(Request httpRequest) { + return EndPointUtils.getEndPoint(httpRequest.getUrl(), null); + } + + @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { @@ -143,10 +137,9 @@ public void after(Object target, Object[] args, Object result, Throwable throwab final Request httpRequest = (Request) args[0]; if (httpRequest != null) { // Accessing httpRequest here not BEFORE() because it can cause side effect. - recorder.recordAttribute(AnnotationKey.HTTP_URL, InterceptorUtils.getHttpUrl(httpRequest.getUrl(), config.isProfileParam())); - final String endpoint = EndPointUtils.getEndPoint(httpRequest.getUrl(), "UnknownHttpClient"); - recorder.recordDestinationId(endpoint); - recordHttpRequest(recorder, httpRequest, throwable); + this.clientRequestRecorder.record(recorder, httpRequest, throwable); + this.cookieRecorder.record(recorder, httpRequest, throwable); + this.entityRecorder.record(recorder, httpRequest, throwable); } recorder.recordApi(descriptor); recorder.recordException(throwable); @@ -165,170 +158,4 @@ private boolean validate(final Object[] args) { return true; } - - private void recordHttpRequest(SpanEventRecorder recorder, Request httpRequest, Throwable throwable) { - final boolean isException = InterceptorUtils.isThrowable(throwable); - if (config.isProfileCookie()) { - switch (config.getCookieDumpType()) { - case ALWAYS: - recordCookie(httpRequest, recorder); - break; - case EXCEPTION: - if (isException) { - recordCookie(httpRequest, recorder); - } - break; - } - } - if (config.isProfileEntity()) { - switch (config.getEntityDumpType()) { - case ALWAYS: - recordEntity(httpRequest, recorder); - break; - case EXCEPTION: - if (isException) { - recordEntity(httpRequest, recorder); - } - break; - } - } - if (config.isProfileParam()) { - switch (config.getParamDumpType()) { - case ALWAYS: - recordParam(httpRequest, recorder); - break; - case EXCEPTION: - if (isException) { - recordParam(httpRequest, recorder); - } - break; - } - } - } - - protected void recordCookie(Request httpRequest, SpanEventRecorder recorder) { - if (cookieSampler.isSampling()) { - List cookies = httpRequest.getCookies(); - if (cookies.isEmpty()) { - return; - } - - StringBuilder sb = new StringBuilder(config.getCookieDumpSize() * 2); - Iterator iterator = cookies.iterator(); - while (iterator.hasNext()) { - Cookie cookie = iterator.next(); - sb.append(cookie.getName()).append('=').append(cookie.getValue()); - if (iterator.hasNext()) { - sb.append(','); - } - } - recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, StringUtils.abbreviate(sb.toString(), config.getCookieDumpSize())); - } - } - - protected void recordEntity(final Request httpRequest, final SpanEventRecorder recorder) { - if (entitySampler.isSampling()) { - recordNonMultipartData(httpRequest, recorder); - recordMultipartData(httpRequest, recorder); - } - } - - /** - *
-     * Body could be String, byte array, Stream or EntityWriter.
-     * We collect String data only.
-     * 
- * - * @param httpRequest - * @param recorder - */ - protected void recordNonMultipartData(final Request httpRequest, final SpanEventRecorder recorder) { - final String stringData = httpRequest.getStringData(); - if (stringData != null) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, StringUtils.abbreviate(stringData, config.getEntityDumpSize())); - return; - } - - final byte[] byteData = httpRequest.getByteData(); - if (byteData != null) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, "BYTE_DATA"); - return; - } - - final InputStream streamData = httpRequest.getStreamData(); - if (streamData != null) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, "STREAM_DATA"); - return; - } - } - - protected void recordMultipartData(final Request httpRequest, final SpanEventRecorder recorder) { - List parts = httpRequest.getBodyParts(); - // bug fix : parts != null && ****!parts.isEmpty() - if (CollectionUtils.isNotEmpty(parts)) { - StringBuilder sb = new StringBuilder(config.getEntityDumpSize() * 2); - Iterator iterator = parts.iterator(); - while (iterator.hasNext()) { - Part part = iterator.next(); - if (part instanceof ByteArrayPart) { - ByteArrayPart p = (ByteArrayPart) part; - sb.append(part.getName()); - sb.append("=BYTE_ARRAY_"); - sb.append(p.getBytes().length); - } else if (part instanceof FilePart) { - FilePart p = (FilePart) part; - sb.append(part.getName()); - sb.append("=FILE_"); - sb.append(p.getContentType()); - } else if (part instanceof StringPart) { - StringPart p = (StringPart) part; - sb.append(part.getName()); - sb.append("=STRING"); - } - - if (sb.length() >= config.getEntityDumpSize()) { - break; - } - - if (iterator.hasNext()) { - sb.append(','); - } - } - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, StringUtils.abbreviate(sb.toString(), config.getEntityDumpSize())); - } - } - - protected void recordParam(final Request httpRequest, final SpanEventRecorder recorder) { - if (paramSampler.isSampling()) { - List requestParams = httpRequest.getFormParams(); - if (requestParams != null && !requestParams.isEmpty()) { - String params = paramsToString(requestParams, config.getParamDumpSize()); - recorder.recordAttribute(AnnotationKey.HTTP_PARAM, StringUtils.abbreviate(params, config.getParamDumpSize())); - } - } - } - - /** - * Returns string without double quotations marks, spaces, semi-colons from com.ning.http.client.FluentStringsMap.toString() - * - * @param params - * @param limit - * @return - */ - private String paramsToString(List params, int limit) { - StringBuilder result = new StringBuilder(limit * 2); - - for (Param param : params) { - if (result.length() > 0) { - result.append(','); - } - result.append(param.getName()); - result.append('='); - result.append(param.getValue()); - if (result.length() >= limit) { - break; - } - } - return result.toString(); - } } \ No newline at end of file diff --git a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/interceptor/ExecuteRequestInterceptor.java b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/interceptor/ExecuteRequestInterceptor.java index d292c28b4a73..416eb45fbe06 100644 --- a/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/interceptor/ExecuteRequestInterceptor.java +++ b/plugins/ning-asynchttpclient/src/main/java/com/navercorp/pinpoint/plugin/ning/asynchttpclient/interceptor/ExecuteRequestInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,13 +15,6 @@ */ package com.navercorp.pinpoint.plugin.ning.asynchttpclient.interceptor; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -30,48 +23,63 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.bootstrap.util.SimpleSampler; -import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorderFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.EntityRecorderFactory; import com.navercorp.pinpoint.plugin.ning.asynchttpclient.EndPointUtils; -import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingAsyncHttpClientPlugin; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingAsyncHttpClientConstants; import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingAsyncHttpClientPluginConfig; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingAsyncHttpClientRequestAdaptorV1; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingCookieExtractorV1; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.NingEntityExtractorV1; +import com.navercorp.pinpoint.plugin.ning.asynchttpclient.RequestHeaderAdaptorV1; import com.ning.http.client.Request; -import com.ning.http.client.cookie.Cookie; /** * intercept com.ning.http.client.AsyncHttpClient.executeRequest(Request, * AsyncHandler) - * + * * @author netspider * @author jaehong.kim */ public class ExecuteRequestInterceptor implements AroundInterceptor { - private final PLogger logger = PLoggerFactory.getLogger(ExecuteRequestInterceptor.class); private final boolean isDebug = logger.isDebugEnabled(); private final TraceContext traceContext; private final MethodDescriptor descriptor; - private final NingAsyncHttpClientPluginConfig config; - - private final SimpleSampler cookieSampler; - private final SimpleSampler entitySampler; - private final SimpleSampler paramSampler; + + private final ClientRequestRecorder clientRequestRecorder; + private final CookieRecorder cookieRecorder; + private final EntityRecorder entityRecorder; + + private final RequestTraceWriter requestTraceWriter; // for 1.8.x and 1.9.x public ExecuteRequestInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { this.traceContext = traceContext; this.descriptor = descriptor; - this.config = new NingAsyncHttpClientPluginConfig(traceContext.getProfilerConfig()); - - this.cookieSampler = config.isProfileCookie() ? SimpleSamplerFactory.createSampler(true, config.getCookieSamplingRate()) : null; - this.entitySampler = config.isProfileEntity() ? SimpleSamplerFactory.createSampler(true, config.getEntitySamplingRate()) : null; - this.paramSampler = config.isProfileParam() ? SimpleSamplerFactory.createSampler(true, config.getParamSamplingRate()) : null; + final NingAsyncHttpClientPluginConfig config = new NingAsyncHttpClientPluginConfig(traceContext.getProfilerConfig()); + + ClientRequestAdaptor clientRequestAdaptor = new NingAsyncHttpClientRequestAdaptorV1(); + this.clientRequestRecorder = new ClientRequestRecorder(config.isParam(), clientRequestAdaptor); + + CookieExtractor cookieExtractor = NingCookieExtractorV1.INSTANCE; + this.cookieRecorder = CookieRecorderFactory.newCookieRecorder(config.getHttpDumpConfig(), cookieExtractor); + + EntityExtractor entityExtractor = NingEntityExtractorV1.INSTANCE; + this.entityRecorder = EntityRecorderFactory.newEntityRecorder(config.getHttpDumpConfig(), entityExtractor); + + ClientHeaderAdaptor clientHeaderAdaptor = new RequestHeaderAdaptorV1(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } @Override @@ -92,12 +100,8 @@ public void before(Object target, Object[] args) { final Request httpRequest = (Request) args[0]; final boolean sampling = trace.canSampled(); if (!sampling) { - if (isDebug) { - logger.debug("set Sampling flag=false"); - } if (httpRequest != null) { - final FluentCaseInsensitiveStringsMap httpRequestHeaders = httpRequest.getHeaders(); - putHeader(httpRequestHeaders, Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); + this.requestTraceWriter.write(httpRequest); } return; } @@ -106,27 +110,16 @@ public void before(Object target, Object[] args) { final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); final TraceId nextId = trace.getTraceId().getNextTraceId(); recorder.recordNextSpanId(nextId.getSpanId()); - recorder.recordServiceType(NingAsyncHttpClientPlugin.ASYNC_HTTP_CLIENT); + recorder.recordServiceType(NingAsyncHttpClientConstants.ASYNC_HTTP_CLIENT); if (httpRequest != null) { - final FluentCaseInsensitiveStringsMap httpRequestHeaders = httpRequest.getHeaders(); - putHeader(httpRequestHeaders, Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - putHeader(httpRequestHeaders, Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - putHeader(httpRequestHeaders, Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - putHeader(httpRequestHeaders, Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - putHeader(httpRequestHeaders, Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - putHeader(httpRequestHeaders, Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - final String hostString = EndPointUtils.getEndPoint(httpRequest.getUrl(), null); - if (hostString != null) { - putHeader(httpRequestHeaders, Header.HTTP_HOST.toString(), hostString); - } + String host = getHost(httpRequest); + requestTraceWriter.write(httpRequest, nextId, host); } } - private void putHeader(FluentCaseInsensitiveStringsMap httpRequestHeaders, String key, String value) { - final List valueList = new ArrayList(); - valueList.add(value); - httpRequestHeaders.put(key, valueList); + private String getHost(Request httpRequest) { + return EndPointUtils.getEndPoint(httpRequest.getUrl(), null); } @Override @@ -150,10 +143,9 @@ public void after(Object target, Object[] args, Object result, Throwable throwab final Request httpRequest = (Request) args[0]; if (httpRequest != null) { // Accessing httpRequest here not BEFORE() because it can cause side effect. - recorder.recordAttribute(AnnotationKey.HTTP_URL, InterceptorUtils.getHttpUrl(httpRequest.getUrl(), config.isProfileParam())); - String endpoint = EndPointUtils.getEndPoint(httpRequest.getUrl(), "UnknownHttpClient"); - recorder.recordDestinationId(endpoint); - recordHttpRequest(recorder, httpRequest, throwable); + this.clientRequestRecorder.record(recorder, httpRequest, throwable); + this.cookieRecorder.record(recorder, httpRequest, throwable); + this.entityRecorder.record(recorder, httpRequest, throwable); } recorder.recordApi(descriptor); recorder.recordException(throwable); @@ -172,91 +164,4 @@ private boolean validate(final Object[] args) { return true; } - - private void recordHttpRequest(SpanEventRecorder recorder, Request httpRequest, Throwable throwable) { - final boolean isException = InterceptorUtils.isThrowable(throwable); - if (config.isProfileCookie()) { - switch (config.getCookieDumpType()) { - case ALWAYS: - recordCookie(httpRequest, recorder); - break; - case EXCEPTION: - if (isException) { - recordCookie(httpRequest, recorder); - } - break; - } - } - if (config.isProfileEntity()) { - switch (config.getEntityDumpType()) { - case ALWAYS: - recordEntity(httpRequest, recorder); - break; - case EXCEPTION: - if (isException) { - recordEntity(httpRequest, recorder); - } - break; - } - } - if (config.isProfileParam()) { - // nothing. - } - } - - private void recordCookie(Request httpRequest, SpanEventRecorder recorder) { - if (cookieSampler.isSampling()) { - Collection cookies = httpRequest.getCookies(); - - if (cookies.isEmpty()) { - return; - } - - StringBuilder sb = new StringBuilder(config.getCookieDumpSize() * 2); - Iterator iterator = cookies.iterator(); - while (iterator.hasNext()) { - Cookie cookie = iterator.next(); - sb.append(cookie.getName()).append('=').append(cookie.getValue()); - if (iterator.hasNext()) { - sb.append(','); - } - } - recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, StringUtils.abbreviate(sb.toString(), config.getCookieDumpSize())); - } - } - - private void recordEntity(final Request httpRequest, final SpanEventRecorder recorder) { - if (entitySampler.isSampling()) { - recordNonMultipartData(httpRequest, recorder); - } - } - - /** - *
-     * Body could be String, byte array, Stream or EntityWriter.
-     * We collect String data only.
-     * 
- * - * @param httpRequest - * @param recorder - */ - private void recordNonMultipartData(final Request httpRequest, final SpanEventRecorder recorder) { - final String stringData = httpRequest.getStringData(); - if (stringData != null) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, StringUtils.abbreviate(stringData, config.getEntityDumpSize())); - return; - } - - final byte[] byteData = httpRequest.getByteData(); - if (byteData != null) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, "BYTE_DATA"); - return; - } - - final InputStream streamData = httpRequest.getStreamData(); - if (streamData != null) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM_ENTITY, "STREAM_DATA"); - return; - } - } } \ No newline at end of file diff --git a/plugins/okhttp/clover.license b/plugins/okhttp/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/okhttp/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-okhttp-plugin pinpoint-okhttp-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpConstants.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpConstants.java index fa7c724fc0d6..80d06aea5194 100644 --- a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpConstants.java +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpConstants.java @@ -41,9 +41,11 @@ private OkHttpConstants() { public static final String FIELD_CONNECTION = "connection"; public static final String FIELD_HTTP_URL = "url"; - public static final String CONNECTION_GETTER = "com.navercorp.pinpoint.plugin.okhttp.v2.ConnectionGetter"; + public static final String CONNECTION_GETTER_V2 = "com.navercorp.pinpoint.plugin.okhttp.v2.ConnectionGetter"; public static final String HTTP_URL_GETTER = "com.navercorp.pinpoint.plugin.okhttp.v2.HttpUrlGetter"; public static final String URL_GETTER = "com.navercorp.pinpoint.plugin.okhttp.v2.UrlGetter"; - public static final String USER_REQUEST_GETTER = "com.navercorp.pinpoint.plugin.okhttp.v2.UserRequestGetter"; - public static final String USER_RESPONSE_GETTER = "com.navercorp.pinpoint.plugin.okhttp.v2.UserResponseGetter"; + public static final String USER_REQUEST_GETTER_V2 = "com.navercorp.pinpoint.plugin.okhttp.v2.UserRequestGetter"; + public static final String USER_REQUEST_GETTER_V3 = "com.navercorp.pinpoint.plugin.okhttp.v3.UserRequestGetter"; + public static final String USER_RESPONSE_GETTER_V2 = "com.navercorp.pinpoint.plugin.okhttp.v2.UserResponseGetter"; + public static final String USER_RESPONSE_GETTER_V3 = "com.navercorp.pinpoint.plugin.okhttp.v3.UserResponseGetter"; } diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPluginConfig.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPluginConfig.java index 057ae26a4db0..1e8a86e9cbcd 100644 --- a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPluginConfig.java +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/OkHttpPluginConfig.java @@ -16,29 +16,30 @@ package com.navercorp.pinpoint.plugin.okhttp; import com.navercorp.pinpoint.bootstrap.config.DumpType; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; /** - * * @author jaehong.kim - * */ public class OkHttpPluginConfig { private final boolean enable; private final boolean param; - private final boolean cookie; - private final int cookieSamplingRate; private final boolean statusCode; private final boolean async; - private DumpType cookieDumpType; + private HttpDumpConfig httpDumpConfig; public OkHttpPluginConfig(ProfilerConfig src) { this.enable = src.readBoolean("profiler.okhttp.enable", true); this.param = src.readBoolean("profiler.okhttp.param", false); - this.cookie = src.readBoolean("profiler.okhttp.cookie", false); - this.cookieDumpType = src.readDumpType("profiler.okhttp.cookie.dumptype", DumpType.EXCEPTION); - this.cookieSamplingRate = src.readInt("profiler.okhttp.cookie.sampling.rate", 1); + + boolean cookie = src.readBoolean("profiler.okhttp.cookie", false); + DumpType cookieDumpType = src.readDumpType("profiler.okhttp.cookie.dumptype", DumpType.EXCEPTION); + int cookieSamplingRate = src.readInt("profiler.okhttp.cookie.sampling.rate", 1); + int cookieDumpSize = src.readInt("profiler.okhttp.cookie.dumpsize", 1024); + this.httpDumpConfig = HttpDumpConfig.get(cookie, cookieDumpType, cookieSamplingRate, cookieDumpSize, false, cookieDumpType, 1, 1024); + this.statusCode = src.readBoolean("profiler.okhttp.entity.statuscode", true); this.async = src.readBoolean("profiler.okhttp.async", true); } @@ -55,16 +56,8 @@ public boolean isAsync() { return async; } - public DumpType getCookieDumpType() { - return cookieDumpType; - } - - public boolean isCookie() { - return cookie; - } - - public int getCookieSamplingRate() { - return cookieSamplingRate; + public HttpDumpConfig getHttpDumpConfig() { + return httpDumpConfig; } public boolean isStatusCode() { @@ -74,12 +67,11 @@ public boolean isStatusCode() { @Override public String toString() { final StringBuilder sb = new StringBuilder("OkHttpPluginConfig{"); - sb.append("param=").append(param); - sb.append(", cookie=").append(cookie); - sb.append(", cookieDumpType=").append(cookieDumpType); - sb.append(", cookieSamplingRate=").append(cookieSamplingRate); + sb.append("enable=").append(enable); + sb.append(", param=").append(param); sb.append(", statusCode=").append(statusCode); sb.append(", async=").append(async); + sb.append(", httpDumpConfig=").append(httpDumpConfig); sb.append('}'); return sb.toString(); } diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpClientRequestAdaptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpClientRequestAdaptor.java new file mode 100644 index 000000000000..f661b5b87387 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpClientRequestAdaptor.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v2; + +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.okhttp.EndPointUtils; +import com.squareup.okhttp.Request; + +import java.net.URL; + +/** + * @author jaehong.kim + */ +public class OkHttpClientRequestAdaptor implements ClientRequestAdaptor { + + public OkHttpClientRequestAdaptor() { + } + + @Override + public String getDestinationId(Request request) { + final URL httpUrl = request.url(); + if (httpUrl == null || httpUrl.getHost() == null) { + return "Unknown"; + } + final int port = EndPointUtils.getPort(httpUrl.getPort(), httpUrl.getDefaultPort()); + return HostAndPort.toHostAndPortString(httpUrl.getHost(), port); + } + + @Override + public String getUrl(Request request) { + return request.urlString(); + } + + +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpCookieExtractor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpCookieExtractor.java new file mode 100644 index 000000000000..01693e80d7ba --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpCookieExtractor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v2; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.squareup.okhttp.Request; + +/** + * @author Woonduk Kang(emeroad) + */ +public class OkHttpCookieExtractor implements CookieExtractor { + @Override + public String getCookie(Request request) { + for (String cookie : request.headers("Cookie")) { + if (StringUtils.hasLength(cookie)) { + return cookie; + } + } + return null; + } + +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpPlugin.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpPlugin.java index 09631377d2e8..7b45eeaf533b 100644 --- a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpPlugin.java +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/OkHttpPlugin.java @@ -122,20 +122,36 @@ private void addHttpEngine(final OkHttpPluginConfig config) { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - target.addGetter(OkHttpConstants.USER_REQUEST_GETTER, OkHttpConstants.FIELD_USER_REQUEST); - target.addGetter(OkHttpConstants.USER_RESPONSE_GETTER, OkHttpConstants.FIELD_USER_RESPONSE); - target.addGetter(OkHttpConstants.CONNECTION_GETTER, OkHttpConstants.FIELD_CONNECTION); + target.addGetter(OkHttpConstants.USER_REQUEST_GETTER_V2, OkHttpConstants.FIELD_USER_REQUEST); + target.addGetter(OkHttpConstants.USER_RESPONSE_GETTER_V2, OkHttpConstants.FIELD_USER_RESPONSE); final InstrumentMethod sendRequestMethod = target.getDeclaredMethod("sendRequest"); if (sendRequestMethod != null) { sendRequestMethod.addScopedInterceptor("com.navercorp.pinpoint.plugin.okhttp.v2.interceptor.HttpEngineSendRequestMethodInterceptor", OkHttpConstants.SEND_REQUEST_SCOPE); } - final InstrumentMethod connectMethod = target.getDeclaredMethod("connect"); - if (connectMethod != null) { - connectMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v2.interceptor.HttpEngineConnectMethodInterceptor"); + // pre-2.7.0 + if (target.hasField("connection", "com.squareup.okhttp.Connection")) { + target.addGetter(OkHttpConstants.CONNECTION_GETTER_V2, OkHttpConstants.FIELD_CONNECTION); + // 2.3.0+ + final InstrumentMethod connectMethod = target.getDeclaredMethod("connect"); + if (connectMethod != null) { + connectMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v2.interceptor.HttpEngineConnectMethodInterceptor"); + } + // pre-2.3.0 + final InstrumentMethod connectMethodWithParam = target.getDeclaredMethod("connect", "com.squareup.okhttp.Request"); + if (connectMethodWithParam != null) { + connectMethodWithParam.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v2.interceptor.HttpEngineConnectMethodInterceptor"); + } + } else { + // 2.7.0+ + final InstrumentMethod connectMethod = target.getDeclaredMethod("connect"); + if (connectMethod != null) { + connectMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v2.interceptor.HttpEngineConnectMethodFromUserRequestInterceptor"); + } } + final InstrumentMethod readResponseMethod = target.getDeclaredMethod("readResponse"); if (readResponseMethod != null) { readResponseMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v2.interceptor.HttpEngineReadResponseMethodInterceptor", va(config.isStatusCode())); @@ -155,7 +171,7 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin final InstrumentMethod buildMethod = target.getDeclaredMethod("build"); if (buildMethod != null) { - if (instrumentor.exist(loader, "com.squareup.okhttp.HttpUrl")) { + if (instrumentor.exist(loader, "com.squareup.okhttp.HttpUrl", protectionDomain)) { // over 2.4.0 target.addGetter(OkHttpConstants.HTTP_URL_GETTER, OkHttpConstants.FIELD_HTTP_URL); buildMethod.addScopedInterceptor("com.navercorp.pinpoint.plugin.okhttp.v2.interceptor.RequestBuilderBuildMethodInterceptor", OkHttpConstants.SEND_REQUEST_SCOPE, ExecutionPolicy.INTERNAL); diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/RequestBuilder2ClientHeaderAdaptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/RequestBuilder2ClientHeaderAdaptor.java new file mode 100644 index 000000000000..d97ee8b48dbe --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/RequestBuilder2ClientHeaderAdaptor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v2; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.squareup.okhttp.Request; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RequestBuilder2ClientHeaderAdaptor implements ClientHeaderAdaptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(Request.Builder builder, String name, String value) { + builder.header(name, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/AbstractRequestBuilderBuildMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/AbstractRequestBuilderBuildMethodInterceptor.java index a74abc3249b6..bde6ac2d8542 100644 --- a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/AbstractRequestBuilderBuildMethodInterceptor.java +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/AbstractRequestBuilderBuildMethodInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,6 @@ package com.navercorp.pinpoint.plugin.okhttp.v2.interceptor; -import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.Trace; import com.navercorp.pinpoint.bootstrap.context.TraceContext; @@ -26,25 +25,31 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; +import com.navercorp.pinpoint.plugin.okhttp.v2.RequestBuilder2ClientHeaderAdaptor; import com.squareup.okhttp.Request; /** * @author jaehong.kim */ public abstract class AbstractRequestBuilderBuildMethodInterceptor implements AroundInterceptor { - protected final PLogger logger = PLoggerFactory.getLogger(this.getClass()); protected final boolean isDebug = logger.isDebugEnabled(); protected final TraceContext traceContext; protected final MethodDescriptor methodDescriptor; protected final InterceptorScope interceptorScope; + protected final RequestTraceWriter requestTraceWriter; public AbstractRequestBuilderBuildMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorScope interceptorScope) { this.traceContext = traceContext; this.methodDescriptor = methodDescriptor; this.interceptorScope = interceptorScope; + + ClientHeaderAdaptor clientHeaderAdaptor = new RequestBuilder2ClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } abstract String toHost(Object target); @@ -67,9 +72,8 @@ public void before(Object target, Object[] args) { final Request.Builder builder = ((Request.Builder) target); if (!trace.canSampled()) { - builder.header(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); - if (isDebug) { - logger.debug("Set HTTP header. sampled=false"); + if (builder != null) { + this.requestTraceWriter.write(builder); } return; } @@ -84,23 +88,8 @@ public void before(Object target, Object[] args) { } final TraceId nextId = (TraceId) attachment; - builder.header(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - builder.header(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - builder.header(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - builder.header(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - builder.header(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - builder.header(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - if (isDebug) { - logger.debug("Set HTTP headers. traceId={}, spanId={}, parentSpanId={}", nextId.getTransactionId(), nextId.getSpanId(), nextId.getParentSpanId()); - } - final String host = toHost(target); - if (host != null) { - builder.header(Header.HTTP_HOST.toString(), host); - if (isDebug) { - logger.debug("Set HTTP header. host={}", host); - } - } + this.requestTraceWriter.write(builder, nextId, host); } catch (Throwable t) { logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); } diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineConnectMethodFromUserRequestInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineConnectMethodFromUserRequestInterceptor.java new file mode 100644 index 000000000000..eb103a1fa83d --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineConnectMethodFromUserRequestInterceptor.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v2.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; +import com.navercorp.pinpoint.plugin.okhttp.v2.UserRequestGetter; +import com.squareup.okhttp.HttpUrl; +import com.squareup.okhttp.Request; + +/** + * @author HyunGil Jeong + */ +public class HttpEngineConnectMethodFromUserRequestInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + public HttpEngineConnectMethodFromUserRequestInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(OkHttpConstants.OK_HTTP_CLIENT_INTERNAL); + recorder.recordException(throwable); + + if (target instanceof UserRequestGetter) { + final Request request = ((UserRequestGetter)target)._$PINPOINT$_getUserRequest(); + if (request != null && request.httpUrl() != null) { + final HttpUrl httpUrl = request.httpUrl(); + final String hostAndPort = HostAndPort.toHostAndPortString(httpUrl.host(), httpUrl.port()); + recorder.recordAttribute(AnnotationKey.HTTP_INTERNAL_DISPLAY, hostAndPort); + } + } + } +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineReadResponseMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineReadResponseMethodInterceptor.java index eeb65d3c8f2a..3ed4f3e17da0 100644 --- a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineReadResponseMethodInterceptor.java +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineReadResponseMethodInterceptor.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.navercorp.pinpoint.plugin.okhttp.v2.interceptor; import com.navercorp.pinpoint.bootstrap.context.*; @@ -20,7 +21,6 @@ import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.plugin.okhttp.v2.ConnectionGetter; import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; import com.navercorp.pinpoint.plugin.okhttp.v2.UserRequestGetter; import com.navercorp.pinpoint.plugin.okhttp.v2.UserResponseGetter; @@ -77,13 +77,6 @@ private boolean validate(Object target) { return false; } - if (!(target instanceof ConnectionGetter)) { - if (isDebug) { - logger.debug("Invalid target object. Need field accessor({}).", OkHttpConstants.FIELD_CONNECTION); - } - return false; - } - return true; } diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineSendRequestMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineSendRequestMethodInterceptor.java index 7c7079939b4c..cf64892c702e 100644 --- a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineSendRequestMethodInterceptor.java +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v2/interceptor/HttpEngineSendRequestMethodInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.navercorp.pinpoint.plugin.okhttp.v2.interceptor; -import com.navercorp.pinpoint.bootstrap.config.DumpType; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -27,22 +27,19 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.bootstrap.util.SimpleSampler; -import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.plugin.okhttp.v2.ConnectionGetter; -import com.navercorp.pinpoint.plugin.okhttp.EndPointUtils; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorderFactory; import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; import com.navercorp.pinpoint.plugin.okhttp.OkHttpPluginConfig; +import com.navercorp.pinpoint.plugin.okhttp.v2.OkHttpClientRequestAdaptor; +import com.navercorp.pinpoint.plugin.okhttp.v2.OkHttpCookieExtractor; import com.navercorp.pinpoint.plugin.okhttp.v2.UserRequestGetter; import com.navercorp.pinpoint.plugin.okhttp.v2.UserResponseGetter; import com.squareup.okhttp.Request; -import java.net.URL; - /** * @author jaehong.kim */ @@ -54,10 +51,8 @@ public class HttpEngineSendRequestMethodInterceptor implements AroundInterceptor private final MethodDescriptor methodDescriptor; private final InterceptorScope interceptorScope; - private final boolean param; - private final boolean cookie; - private final DumpType cookieDumpType; - private final SimpleSampler cookieSampler; + private final ClientRequestRecorder clientRequestRecorder; + private final CookieRecorder cookieRecorder; public HttpEngineSendRequestMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorScope interceptorScope) { this.traceContext = traceContext; @@ -65,14 +60,12 @@ public HttpEngineSendRequestMethodInterceptor(TraceContext traceContext, MethodD this.interceptorScope = interceptorScope; final OkHttpPluginConfig config = new OkHttpPluginConfig(traceContext.getProfilerConfig()); - this.param = config.isParam(); - this.cookie = config.isCookie(); - this.cookieDumpType = config.getCookieDumpType(); - if (cookie) { - cookieSampler = SimpleSamplerFactory.createSampler(cookie, config.getCookieSamplingRate()); - } else { - this.cookieSampler = null; - } + + ClientRequestAdaptor clientRequestAdaptor = new OkHttpClientRequestAdaptor(); + this.clientRequestRecorder = new ClientRequestRecorder(config.isParam(), clientRequestAdaptor); + + CookieExtractor cookieExtractor = new OkHttpCookieExtractor(); + this.cookieRecorder = CookieRecorderFactory.newCookieRecorder(config.getHttpDumpConfig(), cookieExtractor); } @Override @@ -125,13 +118,6 @@ private boolean validate(Object target) { return false; } - if (!(target instanceof ConnectionGetter)) { - if (isDebug) { - logger.debug("Invalid target object. Need field accessor({}).", OkHttpConstants.FIELD_CONNECTION); - } - return false; - } - return true; } @@ -165,16 +151,9 @@ public void after(Object target, Object[] args, Object result, Throwable throwab // typeCheck validate(); final Request request = ((UserRequestGetter) target)._$PINPOINT$_getUserRequest(); if (request != null) { - try { - recorder.recordAttribute(AnnotationKey.HTTP_URL, InterceptorUtils.getHttpUrl(request.urlString(), param)); - final String endpoint = getDestinationId(request.url()); - recorder.recordDestinationId(endpoint); - } catch (Exception ignored) { - logger.warn("Failed to invoke of request.url(). {}", ignored.getMessage()); - } - recordRequest(trace, request, throwable); + this.clientRequestRecorder.record(recorder, request, throwable); + this.cookieRecorder.record(recorder, request, throwable); } - } finally { trace.traceBlockEnd(); } @@ -186,35 +165,4 @@ private Object getAttachment(InterceptorScopeInvocation invocation) { } return invocation.getAttachment(); } - - private String getDestinationId(URL httpUrl) { - if (httpUrl == null || httpUrl.getHost() == null) { - return "UnknownHttpClient"; - } - final int port = EndPointUtils.getPort(httpUrl.getPort(), httpUrl.getDefaultPort()); - return HostAndPort.toHostAndPortString(httpUrl.getHost(), port); - } - - - private void recordRequest(Trace trace, Request request, Throwable throwable) { - final boolean isException = InterceptorUtils.isThrowable(throwable); - if (cookie) { - if (DumpType.ALWAYS == cookieDumpType) { - recordCookie(request, trace); - } else if (DumpType.EXCEPTION == cookieDumpType && isException) { - recordCookie(request, trace); - } - } - } - - private void recordCookie(Request request, Trace trace) { - for (String cookie : request.headers("Cookie")) { - if (cookieSampler.isSampling()) { - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, StringUtils.abbreviate(cookie, 1024)); - } - - return; - } - } } \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpClientCookieExtractor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpClientCookieExtractor.java new file mode 100644 index 000000000000..5d3e12549d96 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpClientCookieExtractor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v3; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.common.util.StringUtils; +import okhttp3.Request; + +/** + * @author Woonduk Kang(emeroad) + */ +public class OkHttpClientCookieExtractor implements CookieExtractor { + @Override + public String getCookie(Request request) { + for (String cookie : request.headers("Cookie")) { + if (StringUtils.hasLength(cookie)) { + return cookie; + } + } + return null; + } + +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpClientRequestAdaptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpClientRequestAdaptor.java new file mode 100644 index 000000000000..cc1c073f6479 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpClientRequestAdaptor.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v3; + +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.okhttp.EndPointUtils; +import okhttp3.HttpUrl; +import okhttp3.Request; + +import java.net.URL; + +/** + * @author jaehong.kim + */ +public class OkHttpClientRequestAdaptor implements ClientRequestAdaptor { + + public OkHttpClientRequestAdaptor() { + } + + + @Override + public String getDestinationId(Request request) { + final HttpUrl httpUrl = request.url(); + if (httpUrl != null) { + URL url = httpUrl.url(); + if (url != null && url.getHost() != null) { + final int port = EndPointUtils.getPort(url.getPort(), url.getDefaultPort()); + return HostAndPort.toHostAndPortString(url.getHost(), port); + } + } + return "Unknown"; + } + + @Override + public String getUrl(Request request) { + final HttpUrl httpUrl = request.url(); + if (httpUrl != null) { + return httpUrl.url().toString(); + } + return null; + } + +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpPlugin.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpPlugin.java index c38b3b837c45..22b77a5d1e96 100644 --- a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpPlugin.java +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/OkHttpPlugin.java @@ -65,6 +65,9 @@ public void setup(ProfilerPluginSetupContext context) { addBridegInterceptor(); addRequestBuilder(); addRealConnection(); + + // 3.0 ~ 3.3 + addHttpEngine(config); } private void addRealCall() { @@ -122,6 +125,36 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin }); } + private void addHttpEngine(final OkHttpPluginConfig config) { + transformTemplate.transform("okhttp3.internal.http.HttpEngine", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + target.addGetter(OkHttpConstants.USER_REQUEST_GETTER_V3, OkHttpConstants.FIELD_USER_REQUEST); + target.addGetter(OkHttpConstants.USER_RESPONSE_GETTER_V3, OkHttpConstants.FIELD_USER_RESPONSE); + + final InstrumentMethod sendRequestMethod = target.getDeclaredMethod("sendRequest"); + if (sendRequestMethod != null) { + sendRequestMethod.addScopedInterceptor("com.navercorp.pinpoint.plugin.okhttp.v3.interceptor.HttpEngineSendRequestMethodInterceptor", OkHttpConstants.SEND_REQUEST_SCOPE); + } + + final InstrumentMethod connectMethod = target.getDeclaredMethod("connect"); + if (connectMethod != null) { + connectMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v3.interceptor.HttpEngineConnectMethodInterceptor"); + } + + final InstrumentMethod readResponseMethod = target.getDeclaredMethod("readResponse"); + if (readResponseMethod != null) { + readResponseMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v3.interceptor.HttpEngineReadResponseMethodInterceptor", va(config.isStatusCode())); + } + + return target.toBytecode(); + } + }); + } + + private void addBridegInterceptor() { transformTemplate.transform("okhttp3.internal.http.BridgeInterceptor", new TransformCallback() { @@ -164,10 +197,34 @@ private void addRealConnection() { public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - final InstrumentMethod connectMethod = target.getDeclaredMethod("connect", "int", "int", "int", "boolean"); - if (connectMethod != null) { + boolean addRouteGetter = false; + // 3.4.x, 3.5.x + final InstrumentMethod connectMethod1 = target.getDeclaredMethod("connect", "int", "int", "int", "java.util.List", "boolean"); + if (connectMethod1 != null) { + connectMethod1.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v3.interceptor.RealConnectionConnectMethodInterceptor"); + addRouteGetter = true; + } + // 3.6.x - 3.8.x + final InstrumentMethod connectMethod2 = target.getDeclaredMethod("connect", "int", "int", "int", "boolean"); + if (connectMethod2 != null) { + connectMethod2.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v3.interceptor.RealConnectionConnectMethodInterceptor"); + addRouteGetter = true; + } + // 3.9.0 + final InstrumentMethod connectMethod3 = target.getDeclaredMethod("connect", "int", "int", "int", "boolean", "okhttp3.Call", "okhttp3.EventListener"); + if (connectMethod3 != null) { + connectMethod3.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v3.interceptor.RealConnectionConnectMethodInterceptor"); + addRouteGetter = true; + } + // 3.10.0+ + final InstrumentMethod connectMethod4 = target.getDeclaredMethod("connect", "int", "int", "int", "int", "boolean", "okhttp3.Call", "okhttp3.EventListener"); + if (connectMethod4 != null) { + connectMethod4.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v3.interceptor.RealConnectionConnectMethodInterceptor"); + addRouteGetter = true; + } + + if (addRouteGetter) { target.addGetter("com.navercorp.pinpoint.plugin.okhttp.v3.RouteGetter", "route"); - connectMethod.addInterceptor("com.navercorp.pinpoint.plugin.okhttp.v3.interceptor.RealConnectionConnectMethodInterceptor"); } return target.toBytecode(); diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/RequestBuilder3ClientHeaderAdaptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/RequestBuilder3ClientHeaderAdaptor.java new file mode 100644 index 000000000000..b36ad739ccf5 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/RequestBuilder3ClientHeaderAdaptor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v3; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import okhttp3.Request; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RequestBuilder3ClientHeaderAdaptor implements ClientHeaderAdaptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(Request.Builder builder, String name, String value) { + builder.header(name, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/UserRequestGetter.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/UserRequestGetter.java new file mode 100644 index 000000000000..ed1ce7538418 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/UserRequestGetter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v3; + +import okhttp3.Request; + +/** + * @author jaehong.kim + */ +public interface UserRequestGetter { + Request _$PINPOINT$_getUserRequest(); +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/UserResponseGetter.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/UserResponseGetter.java new file mode 100644 index 000000000000..4c0a21cce484 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/UserResponseGetter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v3; + +import okhttp3.Response; + +/** + * @author jaehong.kim + */ +public interface UserResponseGetter { + Response _$PINPOINT$_getUserResponse(); +} diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/BridgeInterceptorInterceptMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/BridgeInterceptorInterceptMethodInterceptor.java index 8ecc3008a664..c68a12e551a5 100644 --- a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/BridgeInterceptorInterceptMethodInterceptor.java +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/BridgeInterceptorInterceptMethodInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,6 @@ package com.navercorp.pinpoint.plugin.okhttp.v3.interceptor; -import com.navercorp.pinpoint.bootstrap.config.DumpType; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -28,22 +27,20 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.bootstrap.util.SimpleSampler; -import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorderFactory; import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.plugin.okhttp.EndPointUtils; import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; import com.navercorp.pinpoint.plugin.okhttp.OkHttpPluginConfig; -import okhttp3.HttpUrl; +import com.navercorp.pinpoint.plugin.okhttp.v3.OkHttpClientCookieExtractor; +import com.navercorp.pinpoint.plugin.okhttp.v3.OkHttpClientRequestAdaptor; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; -import java.net.URL; - /** * @author jaehong.kim */ @@ -55,10 +52,8 @@ public class BridgeInterceptorInterceptMethodInterceptor implements AroundInterc private final MethodDescriptor methodDescriptor; private final InterceptorScope interceptorScope; - private final boolean param; - private final boolean cookie; - private final DumpType cookieDumpType; - private final SimpleSampler cookieSampler; + private final ClientRequestRecorder clientRequestRecorder; + private final CookieRecorder cookieRecorder; public BridgeInterceptorInterceptMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorScope interceptorScope) { this.traceContext = traceContext; @@ -66,14 +61,12 @@ public BridgeInterceptorInterceptMethodInterceptor(TraceContext traceContext, Me this.interceptorScope = interceptorScope; final OkHttpPluginConfig config = new OkHttpPluginConfig(traceContext.getProfilerConfig()); - this.param = config.isParam(); - this.cookie = config.isCookie(); - this.cookieDumpType = config.getCookieDumpType(); - if (cookie) { - cookieSampler = SimpleSamplerFactory.createSampler(cookie, config.getCookieSamplingRate()); - } else { - this.cookieSampler = null; - } + + ClientRequestAdaptor clientRequestAdaptor = new OkHttpClientRequestAdaptor(); + this.clientRequestRecorder = new ClientRequestRecorder(config.isParam(), clientRequestAdaptor); + + CookieExtractor cookieExtractor = new OkHttpClientCookieExtractor(); + this.cookieRecorder = CookieRecorderFactory.newCookieRecorder(config.getHttpDumpConfig(), cookieExtractor); } @Override @@ -141,17 +134,8 @@ public void after(Object target, Object[] args, Object result, Throwable throwab final Interceptor.Chain chain = (Interceptor.Chain) args[0]; final Request request = chain.request(); if (request != null) { - final HttpUrl httpUrl = request.url(); - if (httpUrl != null) { - try { - recorder.recordAttribute(AnnotationKey.HTTP_URL, InterceptorUtils.getHttpUrl(httpUrl.url().toString(), param)); - final String endpoint = getDestinationId(httpUrl.url()); - recorder.recordDestinationId(endpoint); - } catch (Exception ignored) { - logger.warn("Failed to invoke of request.url(). {}", ignored.getMessage()); - } - } - recordRequest(trace, request, throwable); + this.clientRequestRecorder.record(recorder, request, throwable); + this.cookieRecorder.record(recorder, request, throwable); } if (result instanceof Response) { @@ -181,40 +165,10 @@ private boolean validate(final Object[] args) { return true; } - private String getDestinationId(URL httpUrl) { - if (httpUrl == null || httpUrl.getHost() == null) { - return "UnknownHttpClient"; - } - final int port = EndPointUtils.getPort(httpUrl.getPort(), httpUrl.getDefaultPort()); - return HostAndPort.toHostAndPortString(httpUrl.getHost(), port); - } - private Object getAttachment(InterceptorScopeInvocation invocation) { if (invocation == null) { return null; } return invocation.getAttachment(); } - - private void recordRequest(Trace trace, Request request, Throwable throwable) { - final boolean isException = InterceptorUtils.isThrowable(throwable); - if (cookie) { - if (DumpType.ALWAYS == cookieDumpType) { - recordCookie(request, trace); - } else if (DumpType.EXCEPTION == cookieDumpType && isException) { - recordCookie(request, trace); - } - } - } - - private void recordCookie(Request request, Trace trace) { - for (String cookie : request.headers("Cookie")) { - if (cookieSampler.isSampling()) { - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, StringUtils.abbreviate(cookie, 1024)); - } - - return; - } - } } \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/HttpEngineConnectMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/HttpEngineConnectMethodInterceptor.java new file mode 100644 index 000000000000..633dde483596 --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/HttpEngineConnectMethodInterceptor.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v3.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; +import com.navercorp.pinpoint.plugin.okhttp.v3.UserRequestGetter; +import okhttp3.HttpUrl; +import okhttp3.Request; + +/** + * @author jaehong.kim + */ +public class HttpEngineConnectMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + public HttpEngineConnectMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(OkHttpConstants.OK_HTTP_CLIENT_INTERNAL); + recorder.recordException(throwable); + + if (target instanceof UserRequestGetter) { + final Request request = ((UserRequestGetter)target)._$PINPOINT$_getUserRequest(); + if (request != null && request.url() != null) { + final HttpUrl httpUrl = request.url(); + final String hostAndPort = HostAndPort.toHostAndPortString(httpUrl.host(), httpUrl.port()); + recorder.recordAttribute(AnnotationKey.HTTP_INTERNAL_DISPLAY, hostAndPort); + } + } + } +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/HttpEngineReadResponseMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/HttpEngineReadResponseMethodInterceptor.java new file mode 100644 index 000000000000..0a40f7552f7a --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/HttpEngineReadResponseMethodInterceptor.java @@ -0,0 +1,117 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v3.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; +import com.navercorp.pinpoint.plugin.okhttp.v3.UserRequestGetter; +import com.navercorp.pinpoint.plugin.okhttp.v3.UserResponseGetter; +import okhttp3.Response; + +/** + * @author jaehong.kim + */ +public class HttpEngineReadResponseMethodInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final MethodDescriptor methodDescriptor; + private final boolean statusCode; + + public HttpEngineReadResponseMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, boolean statusCode) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; + this.statusCode = statusCode; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if (!validate(target)) { + return; + } + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(OkHttpConstants.OK_HTTP_CLIENT_INTERNAL); + } + + private boolean validate(Object target) { + if (!(target instanceof UserRequestGetter)) { + if (isDebug) { + logger.debug("Invalid target object. Need field accessor({}).", OkHttpConstants.FIELD_USER_REQUEST); + } + return false; + } + + if (!(target instanceof UserResponseGetter)) { + if (isDebug) { + logger.debug("Invalid target object. Need field accessor({}).", OkHttpConstants.FIELD_USER_RESPONSE); + } + return false; + } + + return true; + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if (!validate(target)) { + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + + if (statusCode) { + // type check validate(); + final Response response = ((UserResponseGetter) target)._$PINPOINT$_getUserResponse(); + if (response != null) { + recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, response.code()); + } + } + } finally { + trace.traceBlockEnd(); + } + } +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/HttpEngineSendRequestMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/HttpEngineSendRequestMethodInterceptor.java new file mode 100644 index 000000000000..862a1a6fa32b --- /dev/null +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/HttpEngineSendRequestMethodInterceptor.java @@ -0,0 +1,167 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.okhttp.v3.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.AttachmentFactory; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorderFactory; +import com.navercorp.pinpoint.plugin.okhttp.OkHttpConstants; +import com.navercorp.pinpoint.plugin.okhttp.OkHttpPluginConfig; +import com.navercorp.pinpoint.plugin.okhttp.v3.OkHttpClientCookieExtractor; +import com.navercorp.pinpoint.plugin.okhttp.v3.OkHttpClientRequestAdaptor; +import com.navercorp.pinpoint.plugin.okhttp.v3.UserRequestGetter; +import com.navercorp.pinpoint.plugin.okhttp.v3.UserResponseGetter; +import okhttp3.Request; + +/** + * @author jaehong.kim + */ +public class HttpEngineSendRequestMethodInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final MethodDescriptor methodDescriptor; + private final InterceptorScope interceptorScope; + private final ClientRequestRecorder clientRequestRecorder; + private final CookieRecorder cookieRecorder; + + public HttpEngineSendRequestMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorScope interceptorScope) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; + this.interceptorScope = interceptorScope; + + final OkHttpPluginConfig config = new OkHttpPluginConfig(traceContext.getProfilerConfig()); + ClientRequestAdaptor clientRequestAdaptor = new OkHttpClientRequestAdaptor(); + this.clientRequestRecorder = new ClientRequestRecorder(config.isParam(), clientRequestAdaptor); + + CookieExtractor cookieExtractor = new OkHttpClientCookieExtractor(); + this.cookieRecorder = CookieRecorderFactory.newCookieRecorder(config.getHttpDumpConfig(), cookieExtractor); + + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if (!validate(target)) { + return; + } + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + try { + final TraceId nextId = trace.getTraceId().getNextTraceId(); + recorder.recordNextSpanId(nextId.getSpanId()); + recorder.recordServiceType(OkHttpConstants.OK_HTTP_CLIENT); + + final InterceptorScopeInvocation invocation = interceptorScope.getCurrentInvocation(); + if (invocation != null) { + invocation.getOrCreateAttachment(new AttachmentFactory() { + @Override + public Object createAttachment() { + return nextId; + } + }); + } + } catch (Throwable t) { + logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); + } + } + + private boolean validate(Object target) { + if (!(target instanceof UserRequestGetter)) { + if (isDebug) { + logger.debug("Invalid target object. Need field accessor({}).", OkHttpConstants.FIELD_USER_REQUEST); + } + return false; + } + + if (!(target instanceof UserResponseGetter)) { + if (isDebug) { + logger.debug("Invalid target object. Need field accessor({}).", OkHttpConstants.FIELD_USER_RESPONSE); + } + return false; + } + + return true; + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if (!validate(target)) { + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + + // clear attachment. + final InterceptorScopeInvocation invocation = interceptorScope.getCurrentInvocation(); + final Object attachment = getAttachment(invocation); + if (attachment != null) { + invocation.removeAttachment(); + } + + // typeCheck validate(); + final Request request = ((UserRequestGetter) target)._$PINPOINT$_getUserRequest(); + if (request != null) { + this.clientRequestRecorder.record(recorder, request, throwable); + this.cookieRecorder.record(recorder, request, throwable); + } + } finally { + trace.traceBlockEnd(); + } + } + + private Object getAttachment(InterceptorScopeInvocation invocation) { + if (invocation == null) { + return null; + } + return invocation.getAttachment(); + } +} \ No newline at end of file diff --git a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/RequestBuilderBuildMethodInterceptor.java b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/RequestBuilderBuildMethodInterceptor.java index a1cf62d3e90b..15bb3981d3f0 100644 --- a/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/RequestBuilderBuildMethodInterceptor.java +++ b/plugins/okhttp/src/main/java/com/navercorp/pinpoint/plugin/okhttp/v3/interceptor/RequestBuilderBuildMethodInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,6 @@ package com.navercorp.pinpoint.plugin.okhttp.v3.interceptor; -import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.Trace; import com.navercorp.pinpoint.bootstrap.context.TraceContext; @@ -26,10 +25,13 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; import com.navercorp.pinpoint.common.plugin.util.HostAndPort; import com.navercorp.pinpoint.plugin.okhttp.EndPointUtils; import com.navercorp.pinpoint.plugin.okhttp.v3.HttpUrlGetter; +import com.navercorp.pinpoint.plugin.okhttp.v3.RequestBuilder3ClientHeaderAdaptor; import okhttp3.HttpUrl; import okhttp3.Request; @@ -43,11 +45,15 @@ public class RequestBuilderBuildMethodInterceptor implements AroundInterceptor { private final TraceContext traceContext; private final MethodDescriptor methodDescriptor; private final InterceptorScope interceptorScope; + private final RequestTraceWriter requestTraceWriter;; public RequestBuilderBuildMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorScope interceptorScope) { this.traceContext = traceContext; this.methodDescriptor = methodDescriptor; this.interceptorScope = interceptorScope; + + ClientHeaderAdaptor clientHeaderAdaptor = new RequestBuilder3ClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } @Override @@ -67,9 +73,8 @@ public void before(Object target, Object[] args) { } final Request.Builder builder = ((Request.Builder) target); if (!trace.canSampled()) { - builder.header(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); - if (isDebug) { - logger.debug("Set HTTP headers. sampled=false"); + if (builder != null) { + this.requestTraceWriter.write(builder); } return; } @@ -82,28 +87,9 @@ public void before(Object target, Object[] args) { } return; } - final TraceId nextId = (TraceId) attachment; - builder.header(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - builder.header(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - builder.header(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - builder.header(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - builder.header(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - builder.header(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - if (isDebug) { - logger.debug("Set HTTP Headers. transactionId={}, spanId={}, parentSpanId={}", nextId.getTransactionId(), nextId.getSpanId(), nextId.getParentSpanId()); - } - - if (target instanceof HttpUrlGetter) { - final HttpUrl url = ((HttpUrlGetter) target)._$PINPOINT$_getHttpUrl(); - if (url != null) { - final String endpoint = getDestinationId(url); - builder.header(Header.HTTP_HOST.toString(), endpoint); - if (isDebug) { - logger.debug("Set HTTP header. host={}", endpoint); - } - } - } + final String host = getHost(target); + this.requestTraceWriter.write(builder, nextId, host); } catch (Throwable t) { logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); } @@ -116,9 +102,19 @@ private Object getAttachment(InterceptorScopeInvocation invocation) { return invocation.getAttachment(); } + private String getHost(Object target) { + if (target instanceof HttpUrlGetter) { + final HttpUrl url = ((HttpUrlGetter) target)._$PINPOINT$_getHttpUrl(); + if (url != null) { + return getDestinationId(url); + } + } + return null; + } + private String getDestinationId(HttpUrl httpUrl) { if (httpUrl == null || httpUrl.host() == null) { - return "UnknownHttpClient"; + return "Unknown"; } final int port = EndPointUtils.getPort(httpUrl.port(), HttpUrl.defaultPort(httpUrl.scheme())); return HostAndPort.toHostAndPortString(httpUrl.host(), port); diff --git a/plugins/openwhisk/.gitignore b/plugins/openwhisk/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/openwhisk/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/openwhisk/lib/openwhisk-common.jar b/plugins/openwhisk/lib/openwhisk-common.jar new file mode 100644 index 000000000000..6351a512a00d Binary files /dev/null and b/plugins/openwhisk/lib/openwhisk-common.jar differ diff --git a/plugins/openwhisk/pom.xml b/plugins/openwhisk/pom.xml new file mode 100644 index 000000000000..6c3ee4b7dc2b --- /dev/null +++ b/plugins/openwhisk/pom.xml @@ -0,0 +1,58 @@ + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-openwhisk-plugin + pinpoint-openwhisk-plugin + jar + + + 1.6 + + ${env.JAVA_8_HOME} + java18 + + + + + openwhisk + whisk.core + 1.0 + system + ${pom.basedir}/lib/openwhisk-common.jar + + + com.typesafe.akka + akka-http-core_2.12 + 10.1.0-RC1 + provided + + + com.typesafe.akka + akka-http_2.12 + 10.1.0-RC1 + provided + + + org.scala-lang + scala-library + 2.11.11 + + + io.spray + spray-json_2.12 + 1.3.4 + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + \ No newline at end of file diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskConfig.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskConfig.java new file mode 100644 index 000000000000..b8beafbc2774 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskConfig.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +/** + * @author Seonghyun Oh + */ +public class OpenwhiskConfig { + + private final boolean enable; + + private final boolean loggingMessage; + + private final String transformTargetName; + + static final String KEY_TRANSFORM_TARGET_NAME = "profiler.openwhisk.transform.targetname"; + private static final String DEFAULT_TRANSFORM_TARGET_NAME = "whisk.http.BasicHttpService$$anonfun$assignId$1$$anonfun$apply$13"; + + + public OpenwhiskConfig(ProfilerConfig config) { + /* + * openwhisk + */ + this.enable = config.readBoolean("profiler.openwhisk.enable", false); + this.loggingMessage = config.readBoolean("profiler.openwhisk.logging.message", false); + + this.transformTargetName = config.readString(KEY_TRANSFORM_TARGET_NAME, DEFAULT_TRANSFORM_TARGET_NAME); + } + + public String getTransformTargetName() { + return transformTargetName; + } + + public boolean isEnable() { + return enable; + } + + public boolean isLoggingMessage() { + return loggingMessage; + } +} diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskConstants.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskConstants.java new file mode 100644 index 000000000000..cd47c33bc946 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskConstants.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk; + +import com.navercorp.pinpoint.common.trace.*; + +import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.INCLUDE_DESTINATION_ID; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.TERMINAL; + +/** + * @author Seonghyun Oh + */ +public class OpenwhiskConstants { + public static final ServiceType OPENWHISK_INTERNAL = ServiceTypeFactory.of(1620, "OPENWHISK_INTERNAL", "OPENWHISK_INTERNAL"); + public static final ServiceType OPENWHISK_CONTROLLER = ServiceTypeFactory.of(1621, "OPENWHISK_CONTROLLER", "OPENWHISK_CONTROLLER", ServiceTypeProperty.RECORD_STATISTICS); + public static final ServiceType OPENWHISK_INVOKER = ServiceTypeFactory.of(1622, "OPENWHISK_INVOKER", "OPENWHISK_INVOKER", ServiceTypeProperty.RECORD_STATISTICS); + public static final ServiceType OPENWHISK_CLIENT = ServiceTypeFactory.of(9622, "OPENWHISK_CLIENT", "OPENWHISK_CLIENT", ServiceTypeProperty.RECORD_STATISTICS); + + public static final ServiceType COUCHDB = ServiceTypeFactory.of(2700, "COUCHDB", TERMINAL, INCLUDE_DESTINATION_ID); + public static final ServiceType COUCHDB_EXECUTE_QUERY = ServiceTypeFactory.of(2701, "COUCHDB_EXECUTE_QUERY", "COUCHDB", TERMINAL, RECORD_STATISTICS, INCLUDE_DESTINATION_ID); + + public static final AnnotationKey MARKER_MESSAGE = AnnotationKeyFactory.of(923, "marker.message", VIEW_IN_RECORD_SET); +} diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskDetector.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskDetector.java new file mode 100644 index 000000000000..f745fb124f9d --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskDetector.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk; + +import com.navercorp.pinpoint.bootstrap.plugin.ApplicationTypeDetector; +import com.navercorp.pinpoint.bootstrap.resolver.ConditionProvider; +import com.navercorp.pinpoint.common.trace.ServiceType; + +/** + * @author Seonghyun Oh + */ +public class OpenwhiskDetector implements ApplicationTypeDetector { + + private static final String CONTROLLER_REQUIRED_CLASS = "whisk.core.controller.Controller"; + + private static final String INVOKER_REQUIRED_CLASS = "whisk.core.invoker.Invoker"; + + private ServiceType applicationType = OpenwhiskConstants.OPENWHISK_INTERNAL; + + @Override + public ServiceType getApplicationType() { + return this.applicationType; + } + + @Override + public boolean detect(ConditionProvider provider) { + setOpenwhiskApplicationType(provider); + return true; + } + + private void setOpenwhiskApplicationType(ConditionProvider provider) { + if (provider.checkForClass(CONTROLLER_REQUIRED_CLASS)) { + this.applicationType = OpenwhiskConstants.OPENWHISK_CONTROLLER; + } else if (provider.checkForClass(INVOKER_REQUIRED_CLASS)) { + this.applicationType = OpenwhiskConstants.OPENWHISK_INVOKER; + } + } + +} diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskMetadataProvider.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskMetadataProvider.java new file mode 100644 index 000000000000..7c8d2d54cce4 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskMetadataProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyMatchers; +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * @author Seonghyun Oh + */ +public class OpenwhiskMetadataProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(OpenwhiskConstants.OPENWHISK_INTERNAL); + context.addServiceType(OpenwhiskConstants.OPENWHISK_CONTROLLER); + context.addServiceType(OpenwhiskConstants.OPENWHISK_INVOKER); + context.addServiceType(OpenwhiskConstants.OPENWHISK_CLIENT); + + context.addServiceType(OpenwhiskConstants.COUCHDB, AnnotationKeyMatchers.exact(AnnotationKey.ARGS0)); + context.addServiceType(OpenwhiskConstants.COUCHDB_EXECUTE_QUERY, AnnotationKeyMatchers.exact(AnnotationKey.ARGS0)); + + context.addAnnotationKey(OpenwhiskConstants.MARKER_MESSAGE); + } + +} diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskPlugin.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskPlugin.java new file mode 100644 index 000000000000..772769e7cf98 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/OpenwhiskPlugin.java @@ -0,0 +1,230 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.instrument.*; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import com.navercorp.pinpoint.plugin.openwhisk.accessor.PinpointTraceAccessor; + +import java.security.ProtectionDomain; + +/** + * @author Seonghyun Oh + */ +public class OpenwhiskPlugin implements ProfilerPlugin, TransformTemplateAware { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private TransformTemplate transformTemplate; + + @Override + public void setup(ProfilerPluginSetupContext context) { + final OpenwhiskConfig config = new OpenwhiskConfig(context.getConfig()); + if (!config.isEnable()) { + return; + } + + OpenwhiskDetector openwhiskDetector = new OpenwhiskDetector(); + context.addApplicationTypeDetector(openwhiskDetector); + + + transformTemplate.transform(config.getTransformTargetName(), new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + final InstrumentMethod method = target.getDeclaredMethod("apply", "akka.http.scaladsl.server.RequestContext"); + method.addInterceptor("com.navercorp.pinpoint.plugin.openwhisk.interceptor.TransactionIdCreateInterceptor"); + + return target.toBytecode(); + } + }); + + transformTemplate.transform("whisk.connector.kafka.KafkaProducerConnector", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + // add `apply` method interceptor + final MethodFilter applyMethodFilter = MethodFilters.chain( + MethodFilters.name("send") + ); + for (InstrumentMethod method : target.getDeclaredMethods(applyMethodFilter)) { + try { + method.addInterceptor("com.navercorp.pinpoint.plugin.openwhisk.interceptor.KafkaProducerSendInterceptor"); + break; + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + return target.toBytecode(); + } + }); + + transformTemplate.transform("whisk.core.connector.ActivationMessage", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addSetter("com.navercorp.pinpoint.plugin.openwhisk.setter.TraceContextSetter", "traceContext", true); + return target.toBytecode(); + } + }); + + transformTemplate.transform("whisk.common.tracing.NoopTracer$", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + // add `apply` method interceptor + final MethodFilter applyMethodFilter = MethodFilters.chain( + MethodFilters.name("setTraceContext") + ); + for (InstrumentMethod method : target.getDeclaredMethods(applyMethodFilter)) { + try { + method.addInterceptor("com.navercorp.pinpoint.plugin.openwhisk.interceptor.NoopTracerSetTraceContextInterceptor"); + break; + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + return target.toBytecode(); + } + }); + + transformTemplate.transform("whisk.common.TransactionId$", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + + // add `started` method interceptor + final MethodFilter startedMethodFilter = MethodFilters.chain( + MethodFilters.name("started$extension"), + MethodFilters.argAt(2, "whisk.common.LogMarkerToken"), + MethodFilters.argAt(3, "scala.Function0") + ); + for (InstrumentMethod method : target.getDeclaredMethods(startedMethodFilter)) { + try { + method.addInterceptor("com.navercorp.pinpoint.plugin.openwhisk.interceptor.TransactionIdStartedInterceptor"); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + + // add `finished` method interceptor + final MethodFilter finishedMethodFilter = MethodFilters.chain( + MethodFilters.name("finished$extension"), + MethodFilters.argAt(2, "whisk.common.StartMarker") + ); + for (InstrumentMethod method : target.getDeclaredMethods(finishedMethodFilter)) { + try { + method.addInterceptor("com.navercorp.pinpoint.plugin.openwhisk.interceptor.TransactionIdFinishedInterceptor"); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + + // add `failed` method interceptor + final MethodFilter failedMethodFilter = MethodFilters.chain( + MethodFilters.name("failed$extension"), + MethodFilters.argAt(2, "whisk.common.StartMarker"), + MethodFilters.argAt(3, "scala.Function0") + ); + for (InstrumentMethod method : target.getDeclaredMethods(failedMethodFilter)) { + try { + method.addInterceptor("com.navercorp.pinpoint.plugin.openwhisk.interceptor.TransactionIdFailedInterceptor"); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + + // add `mark` method interceptor + final MethodFilter markMethodFilter = MethodFilters.chain( + MethodFilters.name("mark$extension"), + MethodFilters.argAt(2, "whisk.common.LogMarkerToken"), + MethodFilters.argAt(3, "scala.Function0") + ); + for (InstrumentMethod method : target.getDeclaredMethods(markMethodFilter)) { + try { + method.addInterceptor("com.navercorp.pinpoint.plugin.openwhisk.interceptor.TransactionIdMarkInterceptor"); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + + return target.toBytecode(); + } + }); + + transformTemplate.transform("whisk.common.StartMarker", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(AsyncContextAccessor.class.getName()); + target.addField(PinpointTraceAccessor.class.getName()); + + // add `copy` method interceptor + final MethodFilter copyMethodFilter = MethodFilters.chain( + MethodFilters.name("copy") + ); + for (InstrumentMethod method : target.getDeclaredMethods(copyMethodFilter)) { + try { + method.addInterceptor("com.navercorp.pinpoint.plugin.openwhisk.interceptor.StartMarkerCopyInterceptor"); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method " + method, e); + } + } + } + + return target.toBytecode(); + } + }); + + transformTemplate.transform("whisk.common.TransactionMetadata", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(AsyncContextAccessor.class.getName()); + return target.toBytecode(); + } + }); + + } + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } + +} diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/accessor/PinpointTraceAccessor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/accessor/PinpointTraceAccessor.java new file mode 100644 index 000000000000..a3132fdf5689 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/accessor/PinpointTraceAccessor.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.accessor; + +import com.navercorp.pinpoint.bootstrap.context.Trace; + +/** + * @author Seonghyun Oh + */ +public interface PinpointTraceAccessor { + void _$PINPOINT$_setPinpointTrace(Trace trace); + Trace _$PINPOINT$_getPinpointTrace(); +} diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/descriptor/DefaultMethodDescriptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/descriptor/DefaultMethodDescriptor.java new file mode 100644 index 000000000000..cdc6f771e822 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/descriptor/DefaultMethodDescriptor.java @@ -0,0 +1,89 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.openwhisk.descriptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; + +public class DefaultMethodDescriptor implements MethodDescriptor { + private int apiId = 0; + private int type = MethodType.INVOCATION; + + private String fullName; + + public DefaultMethodDescriptor(String fullName) { + this.fullName = fullName; + } + + @Override + public String getMethodName() { + return ""; + } + + @Override + public String getClassName() { + return ""; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return "()"; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return this.fullName; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return apiId; + } + + @Override + public String getApiDescriptor() { + return "Transaction Start"; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/descriptor/LogMarkerMethodDescriptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/descriptor/LogMarkerMethodDescriptor.java new file mode 100644 index 000000000000..49c34d7e6398 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/descriptor/LogMarkerMethodDescriptor.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.openwhisk.descriptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; +import whisk.common.LogMarkerToken; + +public class LogMarkerMethodDescriptor implements MethodDescriptor { + private int apiId = 0; + private int type = MethodType.INVOCATION; + + private String fullName; + + private String className; + + private String methodName; + + private String apiDescriptor; + + public LogMarkerMethodDescriptor(LogMarkerToken logMarkerToken) { + this.className = logMarkerToken.component(); + this.methodName = logMarkerToken.action(); + this.fullName = className + "_" + methodName; + } + + @Override + public String getMethodName() { + return methodName; + } + + @Override + public String getClassName() { + return className; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return "()"; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return this.fullName; + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return apiId; + } + + @Override + public String getApiDescriptor() { + return apiDescriptor; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/KafkaProducerSendInterceptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/KafkaProducerSendInterceptor.java new file mode 100644 index 000000000000..90b8b9a1312f --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/KafkaProducerSendInterceptor.java @@ -0,0 +1,114 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.openwhisk.OpenwhiskConstants; +import com.navercorp.pinpoint.plugin.openwhisk.setter.TraceContextSetter; +import scala.collection.immutable.Map; +import whisk.core.connector.ActivationMessage; + +/** + * @author Seonghyun Oh + */ +public class KafkaProducerSendInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + protected final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + public KafkaProducerSendInterceptor(final TraceContext traceContext, final MethodDescriptor methodDescriptor) { + this.traceContext = traceContext; + this.descriptor = methodDescriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (!(args[1] instanceof ActivationMessage)) { + logger.debug("It is not ActivationMessage"); + return; + } + + ActivationMessage activationMessage = (ActivationMessage) args[1]; + + AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext((activationMessage).transid()); + if (asyncContext == null) { + logger.debug("Not found asynchronous invocation metadata"); + return; + } + + final Trace trace = asyncContext.continueAsyncTraceObject(); + if (trace == null) { + return; + } + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + + TraceId nextId = trace.getTraceId().getNextTraceId(); + String applicationName = traceContext.getApplicationName(); + String serverTypeCode = Short.toString(traceContext.getServerTypeCode()); + String entityPath = String.valueOf((Object)activationMessage.action()); + String endPoint = args[0].toString(); + + recorder.recordServiceType(OpenwhiskConstants.OPENWHISK_CLIENT); + recorder.recordApi(descriptor); + recorder.recordNextSpanId(nextId.getSpanId()); + recorder.recordEndPoint(endPoint); + recorder.recordDestinationId(endPoint); + + Map map = new Map.Map4( + "transactionId", nextId.getTransactionId(), + "spanId", String.valueOf(nextId.getSpanId()), + "parentSpanId", String.valueOf(nextId.getParentSpanId()), + "flag", String.valueOf(nextId.getFlags()) + ); + Map traceMetadata = new Map.Map4( + "applicationName", applicationName, + "serverTypeCode", serverTypeCode, + "entityPath", entityPath, + "endPoint", endPoint + ); + + map = map.$plus$plus(traceMetadata.toSeq()); + ((TraceContextSetter)activationMessage)._$PINPOINT$_setTraceContext(scala.Option.apply(map)); + + trace.traceBlockEnd(); + deleteTrace(trace); + asyncContext.close(); + } + + private void deleteTrace(final Trace trace) { + traceContext.removeTraceObject(); + trace.close(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + } +} + diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/NoopTracerSetTraceContextInterceptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/NoopTracerSetTraceContextInterceptor.java new file mode 100644 index 000000000000..22fee1012112 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/NoopTracerSetTraceContextInterceptor.java @@ -0,0 +1,143 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.util.NumberUtils; +import com.navercorp.pinpoint.plugin.openwhisk.OpenwhiskConstants; +import com.navercorp.pinpoint.plugin.openwhisk.descriptor.DefaultMethodDescriptor; +import scala.collection.JavaConversions; + +import java.util.Map; + + +/** + * @author Seonghyun Oh + */ +public class NoopTracerSetTraceContextInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + protected final boolean isDebug = logger.isDebugEnabled(); + + private static final DefaultMethodDescriptor METHOD_DESCRIPTOR = new DefaultMethodDescriptor("Openwhisk Entry Point"); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + + public NoopTracerSetTraceContextInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + traceContext.cacheApi(METHOD_DESCRIPTOR); + } + + @Override + public void before(Object target, Object[] args) { + + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + AsyncContext currentContext = ((AsyncContextAccessor) args[0])._$PINPOINT$_getAsyncContext(); + if (currentContext != null) { + return; + } + + if (((scala.Option)args[1]).isEmpty()) { + return; + } + + Trace trace = populateTraceId((scala.Option)args[1]); + if (trace == null) { + return; + } + + try { + final SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(OpenwhiskConstants.OPENWHISK_INTERNAL); + recorder.recordApi(METHOD_DESCRIPTOR); + + final AsyncContext asyncContext = recorder.recordNextAsyncContext(); + ((AsyncContextAccessor) args[0])._$PINPOINT$_setAsyncContext(asyncContext); + + } catch (Throwable t) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER. Caused:{}", t.getMessage(), t); + } + } finally { + trace.traceBlockEnd(); + deleteTrace(trace); + } + + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + } + + + private Trace populateTraceId(scala.Option context) { + + scala.collection.Map traceContextMap = (scala.collection.Map)context.get(); + Map map = JavaConversions.mapAsJavaMap(traceContextMap); + + String transactionId = (String)map.get("transactionId"); + String spanId = (String)map.get("spanId"); + String parentSpanId = (String)map.get("parentSpanId"); + String flag = (String)map.get("flag"); + String applicationName = (String)map.get("applicationName"); + String serverTypeCode = (String)map.get("serverTypeCode"); + String entityPath = (String)map.get("entityPath"); + String endPoint = (String)map.get("endPoint"); + + TraceId traceId = traceContext.createTraceId( + transactionId, + NumberUtils.parseLong(parentSpanId, SpanId.NULL), + NumberUtils.parseLong(spanId, SpanId.NULL), + NumberUtils.parseShort(flag, (short) 0) + ); + + if (traceId != null) { + Trace trace = traceContext.continueAsyncTraceObject(traceId); + + final SpanRecorder recorder = trace.getSpanRecorder(); + recorder.recordServiceType(OpenwhiskConstants.OPENWHISK_INVOKER); + recorder.recordApi(descriptor); + + recorder.recordAcceptorHost(endPoint); + recorder.recordRpcName(entityPath); + + // Record parent application + recorder.recordParentApplication(applicationName, Short.valueOf(serverTypeCode)); + return trace; + } + return null; + } + + + private void deleteTrace(final Trace trace) { + traceContext.removeTraceObject(); + trace.close(); + } + +} + diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/StartMarkerCopyInterceptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/StartMarkerCopyInterceptor.java new file mode 100644 index 000000000000..72d4fb2135f1 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/StartMarkerCopyInterceptor.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.openwhisk.accessor.PinpointTraceAccessor; + +/** + * @author Seonghyun Oh + */ +public class StartMarkerCopyInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + public StartMarkerCopyInterceptor(final TraceContext traceContext, final MethodDescriptor methodDescriptor) { + this.traceContext = traceContext; + this.descriptor = methodDescriptor; + } + + @Override + public void before(Object target, Object[] args) { + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + ((AsyncContextAccessor) (result))._$PINPOINT$_setAsyncContext(((AsyncContextAccessor) (target))._$PINPOINT$_getAsyncContext()); + ((PinpointTraceAccessor) (result))._$PINPOINT$_setPinpointTrace(((PinpointTraceAccessor) (target))._$PINPOINT$_getPinpointTrace()); + } +} + diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdCreateInterceptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdCreateInterceptor.java new file mode 100644 index 000000000000..3c7a092c2b0d --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdCreateInterceptor.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; + +/** + * @author Seonghyun Oh + */ +public class TransactionIdCreateInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + public TransactionIdCreateInterceptor(final TraceContext traceContext, final MethodDescriptor methodDescriptor) { + this.traceContext = traceContext; + this.descriptor = methodDescriptor; + } + + @Override + public void before(Object target, Object[] args) { + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (args[0] instanceof AsyncContextAccessor) { + + AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(args[0]); + if (asyncContext == null) { + return; + } + ((AsyncContextAccessor) (result))._$PINPOINT$_setAsyncContext(asyncContext); + } + } +} + diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdFailedInterceptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdFailedInterceptor.java new file mode 100644 index 000000000000..8fea98b6f137 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdFailedInterceptor.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.openwhisk.accessor.PinpointTraceAccessor; +import scala.runtime.AbstractFunction0; + +/** + * @author Seonghyun Oh + */ +public class TransactionIdFailedInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + public TransactionIdFailedInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + + AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(args[2]); + final Trace trace = ((PinpointTraceAccessor) (args[2]))._$PINPOINT$_getPinpointTrace(); + + if (asyncContext == null || trace == null) { + return; + } + + // set error message + String message = ((AbstractFunction0) args[3]).apply().toString(); + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + + recorder.recordException(new Throwable(message)); + logger.debug("Record failed message : {}", message); + + // close trace block and context + trace.traceBlockEnd(); + trace.close(); + asyncContext.close(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + } + +} + diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdFinishedInterceptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdFinishedInterceptor.java new file mode 100644 index 000000000000..55fe8c2e96fe --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdFinishedInterceptor.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.openwhisk.accessor.PinpointTraceAccessor; + +/** + * @author Seonghyun Oh + */ +public class TransactionIdFinishedInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + protected final boolean isDebug = logger.isDebugEnabled(); + + public TransactionIdFinishedInterceptor(TraceContext traceContext, MethodDescriptor descriptor) {} + + @Override + public void before(Object target, Object[] args) { + + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(args[2]); + final Trace trace = ((PinpointTraceAccessor) (args[2]))._$PINPOINT$_getPinpointTrace(); + + if (asyncContext == null || trace == null) { + return; + } + trace.traceBlockEnd(); + trace.close(); + asyncContext.close(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + + } + +} + diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdMarkInterceptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdMarkInterceptor.java new file mode 100644 index 000000000000..6863b24a6ac6 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdMarkInterceptor.java @@ -0,0 +1,96 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.openwhisk.OpenwhiskConfig; +import com.navercorp.pinpoint.plugin.openwhisk.OpenwhiskConstants; +import com.navercorp.pinpoint.plugin.openwhisk.descriptor.LogMarkerMethodDescriptor; +import scala.runtime.AbstractFunction0; +import whisk.common.LogMarkerToken; + +/** + * @author Seonghyun Oh + */ +public class TransactionIdMarkInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + protected final boolean isDebug = logger.isDebugEnabled(); + private final boolean isLoggingMessage; + + public TransactionIdMarkInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + + final OpenwhiskConfig config = new OpenwhiskConfig(traceContext.getProfilerConfig()); + this.isLoggingMessage = config.isLoggingMessage(); + } + + /** + * + * @param target + * @param args TransactionMetadata, Identify, LogMarkerToken + */ + @Override + public void before(Object target, Object[] args) { + + if (isDebug) { + logger.beforeInterceptor(target, args); + } + AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(args[0]); + if (asyncContext == null) { + logger.debug("Not found asynchronous invocation metadata {}", (LogMarkerToken)args[2]); + return; + } + + Trace trace = asyncContext.continueAsyncTraceObject(); + if (trace == null) { + logger.debug("trace object null"); + return; + } + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(OpenwhiskConstants.OPENWHISK_INTERNAL); + + try { + LogMarkerToken logMarkerToken = (LogMarkerToken) args[2]; + String message = ((AbstractFunction0) args[3]).apply().toString(); + recorder.recordApi(new LogMarkerMethodDescriptor(logMarkerToken)); + + if (isLoggingMessage && message.length() > 0) { + recorder.recordAttribute(OpenwhiskConstants.MARKER_MESSAGE, message); + } + } finally { + trace.traceBlockEnd(); + trace.close(); + asyncContext.close(); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + } + +} + diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdStartedInterceptor.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdStartedInterceptor.java new file mode 100644 index 000000000000..a0312a7d0fbf --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/interceptor/TransactionIdStartedInterceptor.java @@ -0,0 +1,140 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.openwhisk.OpenwhiskConfig; +import com.navercorp.pinpoint.plugin.openwhisk.OpenwhiskConstants; +import com.navercorp.pinpoint.plugin.openwhisk.accessor.PinpointTraceAccessor; +import com.navercorp.pinpoint.plugin.openwhisk.descriptor.LogMarkerMethodDescriptor; +import scala.runtime.AbstractFunction0; +import whisk.common.LogMarkerToken; + +/** + * @author Seonghyun Oh + */ +public class TransactionIdStartedInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private final TraceContext traceContext; + private final MethodDescriptor descriptor; + + protected final boolean isDebug = logger.isDebugEnabled(); + private final boolean isLoggingMessage; + + public TransactionIdStartedInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + + final OpenwhiskConfig config = new OpenwhiskConfig(traceContext.getProfilerConfig()); + this.isLoggingMessage = config.isLoggingMessage(); + } + + /** + * + * @param target + * @param args TransactionMetadata, Identify, LogMarkerToken + */ + @Override + public void before(Object target, Object[] args) { + + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(args[0]); + if (asyncContext == null) { + logger.debug("Not found asynchronous invocation metadata {}", (LogMarkerToken)args[2]); + return; + } + + Trace trace = asyncContext.continueAsyncTraceObject(); + if (trace == null) { + logger.debug("trace object null"); + } + + try { + trace.traceBlockBegin(); + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("BEFORE. Caused:{}", th.getMessage(), th); + } + } + } + + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(args[0]); + if (asyncContext == null) { + logger.debug("Not found asynchronous invocation metadata"); + return; + } + if (isDebug) { + logger.debug("Asynchronous invocation. asyncContext={}", asyncContext); + } + + final Trace trace = asyncContext.currentAsyncTraceObject(); + if (trace == null) { + return; + } + if (isDebug) { + logger.debug("Asynchronous invocation. asyncTraceId={}, trace={}", asyncContext, trace); + } + traceContext.removeTraceObject(); + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + + LogMarkerToken logMarkerToken = (LogMarkerToken) args[2]; + String message = ((AbstractFunction0) args[3]).apply().toString(); + recorder.recordApi(new LogMarkerMethodDescriptor(logMarkerToken)); + + if (logMarkerToken.component().equals("database")) { + recorder.recordServiceType(OpenwhiskConstants.COUCHDB_EXECUTE_QUERY); + recorder.recordDestinationId("COUCHDB"); + recorder.recordAttribute(OpenwhiskConstants.MARKER_MESSAGE, message); + } else { + recorder.recordServiceType(OpenwhiskConstants.OPENWHISK_INTERNAL); + if (isLoggingMessage && message.length() > 0) { + recorder.recordAttribute(OpenwhiskConstants.MARKER_MESSAGE, message); + } + } + + if (result instanceof AsyncContextAccessor) { + ((AsyncContextAccessor) (result))._$PINPOINT$_setAsyncContext(asyncContext); + ((PinpointTraceAccessor) (result))._$PINPOINT$_setPinpointTrace(trace); + } + + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER error. Caused:{}", th.getMessage(), th); + } + } + } + +} + diff --git a/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/setter/TraceContextSetter.java b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/setter/TraceContextSetter.java new file mode 100644 index 000000000000..095d64800db5 --- /dev/null +++ b/plugins/openwhisk/src/main/java/com/navercorp/pinpoint/plugin/openwhisk/setter/TraceContextSetter.java @@ -0,0 +1,23 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.openwhisk.setter; + +/** + * @author Seonghyun Oh + */ +public interface TraceContextSetter { + void _$PINPOINT$_setTraceContext(scala.Option traceContext); +} diff --git a/plugins/openwhisk/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/openwhisk/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..89d879ad3d7f --- /dev/null +++ b/plugins/openwhisk/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.openwhisk.OpenwhiskPlugin \ No newline at end of file diff --git a/plugins/openwhisk/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/openwhisk/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..a79eb3cae150 --- /dev/null +++ b/plugins/openwhisk/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.openwhisk.OpenwhiskMetadataProvider \ No newline at end of file diff --git a/plugins/oracle-jdbc/clover.license b/plugins/oracle-jdbc/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/oracle-jdbc/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-oracle-jdbc-driver-plugin diff --git a/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/OraclePlugin.java b/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/OraclePlugin.java index c55415000cf1..3174ba4013c7 100644 --- a/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/OraclePlugin.java +++ b/plugins/oracle-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/oracle/OraclePlugin.java @@ -159,7 +159,7 @@ private void addPreparedStatementTransformer(final OracleConfig config) { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { if (className.equals(CLASS_PREPARED_STATEMENT)) { - if (instrumentor.exist(loader, CLASS_PREPARED_STATEMENT_WRAPPER)) { + if (instrumentor.exist(loader, CLASS_PREPARED_STATEMENT_WRAPPER, protectionDomain)) { return null; } } @@ -203,7 +203,7 @@ private void addCallableStatementTransformer() { public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); if (className.equals(CLASS_CALLABLE_STATEMENT)) { - if (instrumentor.exist(loader, CLASS_CALLABLE_STATEMENT_WRAPPER)) { + if (instrumentor.exist(loader, CLASS_CALLABLE_STATEMENT_WRAPPER, protectionDomain)) { return null; } } @@ -234,7 +234,7 @@ private void addStatementTransformer() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { if (className.equals(CLASS_STATEMENT)) { - if (instrumentor.exist(loader, CLASS_STATEMENT_WRAPPER)) { + if (instrumentor.exist(loader, CLASS_STATEMENT_WRAPPER, protectionDomain)) { return null; } } diff --git a/plugins/php/.gitignore b/plugins/php/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/php/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/php/pom.xml b/plugins/php/pom.xml new file mode 100644 index 000000000000..9a9e40fa6def --- /dev/null +++ b/plugins/php/pom.xml @@ -0,0 +1,40 @@ + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-php-plugin + pinpoint-php-plugin + jar + + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + + com.navercorp.pinpoint + pinpoint-profiler + test + + + com.navercorp.pinpoint + pinpoint-test + test + + + com.navercorp.pinpoint + pinpoint-commons-server + test + + + + diff --git a/plugins/php/src/main/java/com/navercorp/pinpoint/plugin/php/PhpConstants.java b/plugins/php/src/main/java/com/navercorp/pinpoint/plugin/php/PhpConstants.java new file mode 100644 index 000000000000..d2c5de787641 --- /dev/null +++ b/plugins/php/src/main/java/com/navercorp/pinpoint/plugin/php/PhpConstants.java @@ -0,0 +1,37 @@ +/** + * Copyright 2014 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.php; + +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.*; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; +import com.navercorp.pinpoint.common.trace.AnnotationKeyMatchers; +import com.navercorp.pinpoint.common.trace.AnnotationKeyProperty; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +/** + * @author chenguoxi + * + */ +public final class PhpConstants { + private PhpConstants() { + } + + public static final ServiceType PHP = ServiceTypeFactory.of(1500, "PHP", RECORD_STATISTICS); + public static final ServiceType PHP_METHOD = ServiceTypeFactory.of(1501, "PHP_METHOD"); + public static final ServiceType PHP_REMOTE_METHOD = ServiceTypeFactory.of(9700, "PHP_REMOTE_METHOD", RECORD_STATISTICS); +} diff --git a/plugins/php/src/main/java/com/navercorp/pinpoint/plugin/php/PhpPlugin.java b/plugins/php/src/main/java/com/navercorp/pinpoint/plugin/php/PhpPlugin.java new file mode 100644 index 000000000000..e78bfa8ca3a4 --- /dev/null +++ b/plugins/php/src/main/java/com/navercorp/pinpoint/plugin/php/PhpPlugin.java @@ -0,0 +1,51 @@ +/** + * Copyright 2014 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.php; + +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; + + +/** + * @author chenguoxi + * + */ +public class PhpPlugin implements ProfilerPlugin, TransformTemplateAware { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private TransformTemplate transformTemplate; + + /* + * (non-Javadoc) + * + * @see com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin#setUp(com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext) + */ + @Override + public void setup(ProfilerPluginSetupContext context) { + + } + + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } +} + diff --git a/plugins/php/src/main/java/com/navercorp/pinpoint/plugin/php/PhpTypeProvider.java b/plugins/php/src/main/java/com/navercorp/pinpoint/plugin/php/PhpTypeProvider.java new file mode 100644 index 000000000000..28496f5debf4 --- /dev/null +++ b/plugins/php/src/main/java/com/navercorp/pinpoint/plugin/php/PhpTypeProvider.java @@ -0,0 +1,33 @@ +/** + * Copyright 2014 NAVER Corp. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.php; + +import com.navercorp.pinpoint.common.trace.AnnotationKeyMatchers; +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * @author chenguoxi + * + */ +public class PhpTypeProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(PhpConstants.PHP); + context.addServiceType(PhpConstants.PHP_METHOD, AnnotationKeyMatchers.ARGS_MATCHER); + context.addServiceType(PhpConstants.PHP_REMOTE_METHOD, AnnotationKeyMatchers.ARGS_MATCHER); + } +} diff --git a/plugins/php/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/php/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..1aacf221bce5 --- /dev/null +++ b/plugins/php/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.php.PhpPlugin \ No newline at end of file diff --git a/plugins/php/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/php/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..a3461b9e8362 --- /dev/null +++ b/plugins/php/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.php.PhpTypeProvider \ No newline at end of file diff --git a/plugins/pom.xml b/plugins/pom.xml index 1825d220248b..e5364f8d86dd 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -1,10 +1,26 @@ + + 4.0.0 com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-plugins @@ -12,6 +28,9 @@ pom + bom + common-servlet + httpclient3 httpclient4 ning-asynchttpclient @@ -36,6 +55,7 @@ user arcus google-httpclient + grpc jetty websphere spring @@ -56,6 +76,16 @@ jsp rxjava rabbitmq + weblogic + php + akka-http + undertow + kafka + mongodb + fastjson + druid + hbase + openwhisk @@ -184,6 +214,11 @@ pinpoint-google-httpclient-plugin ${project.version} + + com.navercorp.pinpoint + pinpoint-grpc-plugin + ${project.version} + com.navercorp.pinpoint pinpoint-jetty-plugin @@ -279,6 +314,56 @@ pinpoint-rabbitmq-plugin ${project.version} + + com.navercorp.pinpoint + pinpoint-weblogic-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-php-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-akka-http-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-undertow-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-kafka-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-mongodb-driver-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-fastjson-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-druid-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-hbase-plugin + ${project.version} + + + com.navercorp.pinpoint + pinpoint-openwhisk-plugin + ${project.version} + diff --git a/plugins/postgresql-jdbc/clover.license b/plugins/postgresql-jdbc/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/postgresql-jdbc/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-postgresql-jdbc-driver-plugin pinpoint-postgresql-jdbc-driver-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlConfig.java b/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlConfig.java index 833263f8a642..534d9ac9b09f 100644 --- a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlConfig.java +++ b/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlConfig.java @@ -15,28 +15,24 @@ package com.navercorp.pinpoint.plugin.jdbc.postgresql; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.JdbcConfig; /** * @author Brad Hong * */ -public class PostgreSqlConfig { - private final boolean pluginEnable; +public class PostgreSqlConfig extends JdbcConfig { private final boolean profileSetAutoCommit; private final boolean profileCommit; private final boolean profileRollback; - private final int maxSqlBindValueSize; public PostgreSqlConfig(ProfilerConfig config) { - this.pluginEnable = config.readBoolean("profiler.jdbc.postgresql", false); + super(config.readBoolean("profiler.jdbc.postgresql", false), + config.readBoolean("profiler.jdbc.postgresql.tracesqlbindvalue", config.isTraceSqlBindValue()), + config.getMaxSqlBindValueSize()); this.profileSetAutoCommit = config.readBoolean("profiler.jdbc.postgresql.setautocommit", false); this.profileCommit = config.readBoolean("profiler.jdbc.postgresql.commit", false); this.profileRollback = config.readBoolean("profiler.jdbc.postgresql.rollback", false); - this.maxSqlBindValueSize = config.readInt("profiler.jdbc.maxsqlbindvaluesize", 1024); - } - - public boolean isPluginEnable() { - return pluginEnable; } public boolean isProfileSetAutoCommit() { @@ -51,12 +47,8 @@ public boolean isProfileRollback() { return profileRollback; } - public int getMaxSqlBindValueSize() { - return maxSqlBindValueSize; - } - @Override public String toString() { - return "PostgreSqlConfig [pluginEnable="+ pluginEnable + ",profileSetAutoCommit=" + profileSetAutoCommit + ", profileCommit=" + profileCommit + ", profileRollback=" + profileRollback + ", maxSqlBindValueSize=" + maxSqlBindValueSize + "]"; + return "PostgreSqlConfig [" + super.toString() + ", profileSetAutoCommit=" + profileSetAutoCommit + ", profileCommit=" + profileCommit + ", profileRollback=" + profileRollback + "]"; } } diff --git a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java b/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java index 6c7f732b2738..79e35d54b35b 100644 --- a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java +++ b/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java @@ -193,8 +193,10 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin InstrumentUtils.findMethod(target, "executeUpdate") .addScopedInterceptor(preparedStatementInterceptor, va(maxBindValueSize), POSTGRESQL_SCOPE); - for (InstrumentMethod method : declaredMethods) { - method.addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementBindVariableInterceptor", POSTGRESQL_SCOPE, ExecutionPolicy.BOUNDARY); + if (config.isTraceSqlBindValue()) { + for (InstrumentMethod method : declaredMethods) { + method.addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementBindVariableInterceptor", POSTGRESQL_SCOPE, ExecutionPolicy.BOUNDARY); + } } } @@ -230,8 +232,10 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin InstrumentUtils.findMethod(target, "executeUpdate") .addScopedInterceptor(preparedStatementInterceptor, va(maxBindValueSize), POSTGRESQL_SCOPE); - for (InstrumentMethod method : declaredMethods) { - method.addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementBindVariableInterceptor", POSTGRESQL_SCOPE, ExecutionPolicy.BOUNDARY); + if (config.isTraceSqlBindValue()) { + for (InstrumentMethod method : declaredMethods) { + method.addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementBindVariableInterceptor", POSTGRESQL_SCOPE, ExecutionPolicy.BOUNDARY); + } } } @@ -380,10 +384,12 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin InstrumentUtils.findMethod(target, "execute", "java.lang.String") .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE); - final PreparedStatementBindingMethodFilter excludes = PreparedStatementBindingMethodFilter.excludes("setRowId", "setNClob", "setSQLXML"); - final List declaredMethods = target.getDeclaredMethods(excludes); - for (InstrumentMethod method : declaredMethods) { - method.addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementBindVariableInterceptor", POSTGRESQL_SCOPE, ExecutionPolicy.BOUNDARY); + if (config.isTraceSqlBindValue()) { + final PreparedStatementBindingMethodFilter excludes = PreparedStatementBindingMethodFilter.excludes("setRowId", "setNClob", "setSQLXML"); + final List declaredMethods = target.getDeclaredMethods(excludes); + for (InstrumentMethod method : declaredMethods) { + method.addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementBindVariableInterceptor", POSTGRESQL_SCOPE, ExecutionPolicy.BOUNDARY); + } } return target.toBytecode(); diff --git a/plugins/rabbitmq/README.md b/plugins/rabbitmq/README.md new file mode 100644 index 000000000000..95f0c651795c --- /dev/null +++ b/plugins/rabbitmq/README.md @@ -0,0 +1,40 @@ +### Pinpoint RabbitMQ Plugin + +#### Tracing custom Consumers +RabbitMQ plugin traces `Consumer.handleDelivery(...)` implementations to record calls made when a *basic.deliver* is +received by a consumer. + +This is done automatically for consumers implemented in RabbitMQ Java Client (**DefaultConsumer**, **QueueingConsumer**) +or in Spring-rabbit (**BlockingQueueConsumer$InternalConsumer**, **RabbitTemplate$TemplateConsumer**). + +However, if you implemented your own **Consumer** and registered to a channel like below, you must tell the agent what +these consumers are unless the consumer explicitly calls `super.handleDelivery(...)`. +``` +Consumer customConsumer = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + // code + } +}; +channel.basicConsume(queue, customConsumer); +``` +To trace such consumers, please configure the following option in *pinpoint.config* with the fully qualified class name +of the consumer. +``` +profiler.rabbitmq.client.consumer.classes= +``` + +#### Excluding exchanges +If you would like to exclude certain exchanges from being traced, please configure the following option in +*pinpoint.config*. +``` +profiler.rabbitmq.client.exchange.exclude= +``` + +#### Supported libraries +The plugin has been tested on the following libraries. +``` +com.rabbitmq:amqp-client - 2.7.0+ +org.springframework.amqp:spring-rabbit - 1.3.3+ +``` +*(Pinpoint 1.7.2 supports up to org.springframework.amqp:spring-rabbit 1.3.3 ~ 1.7.2, 2.0.1 and 2.0.2)* \ No newline at end of file diff --git a/plugins/rabbitmq/clover.license b/plugins/rabbitmq/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/rabbitmq/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-rabbitmq-plugin pinpoint-rabbitmq-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQClientPluginConfig.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQClientPluginConfig.java deleted file mode 100644 index cd1193932dd2..000000000000 --- a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQClientPluginConfig.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.navercorp.pinpoint.plugin.rabbitmq; - -import com.navercorp.pinpoint.bootstrap.config.ExcludePathFilter; -import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.bootstrap.config.SkipFilter; -import com.navercorp.pinpoint.bootstrap.util.StringUtils; - -/** - * @author Jiaqi Feng - */ -public class RabbitMQClientPluginConfig { - - private final boolean traceRabbitMQClient; - private final boolean traceRabbitMQClientProducer; - private final Boolean traceRabbitMQClientConsumer; - private final Filter excludeExchangeFilter; - - public RabbitMQClientPluginConfig(ProfilerConfig config) { - this.traceRabbitMQClient = config.readBoolean("profiler.rabbitmq.client.enable", true); - this.traceRabbitMQClientProducer = config.readBoolean("profiler.rabbitmq.client.producer.enable", true); - this.traceRabbitMQClientConsumer = config.readBoolean("profiler.rabbitmq.client.consumer.enable", true); - - String excludeExchnage = config.readString("profiler.rabbitmq.client.exchange.exclude", ""); - if (!excludeExchnage.isEmpty()) { - this.excludeExchangeFilter = new ExcludePathFilter(excludeExchnage); - } else { - this.excludeExchangeFilter = new SkipFilter(); - } - } - - public boolean isTraceRabbitMQClient() { - return this.traceRabbitMQClient; - } - - public boolean isTraceRabbitMQClientProducer() { - return this.traceRabbitMQClientProducer; - } - - public boolean isTraceRabbitMQClientConsumer() { - return this.traceRabbitMQClientConsumer; - } - - public Filter getExcludeExchangeFilter() { - return this.excludeExchangeFilter; - } - - public static boolean isExchangeExcluded(String exchange, Filter filter) { - if (exchange == null || filter == null) - return false; - try { - if (filter.filter(exchange)) - return true; - } catch (Exception e) { - } - - return false; - } -} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQConstants.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQConstants.java deleted file mode 100644 index 877fa8546775..000000000000 --- a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQConstants.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.navercorp.pinpoint.plugin.rabbitmq; - -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; - -import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET; -import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; -import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.TERMINAL; -import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.QUEUE; - -/** - * @author Jinkai.Ma - */ -public interface RabbitMQConstants { - ServiceType RABBITMQ_SERVICE_TYPE = ServiceTypeFactory.of(8300, "RABBITMQ", QUEUE, RECORD_STATISTICS); - String RABBITMQ_SCOPE = "rabbitmqScope"; - - AnnotationKey RABBITMQ_EXCHANGE_ANNOTATION_KEY = AnnotationKeyFactory.of(130, "rabbitmq.exchange", VIEW_IN_RECORD_SET); - AnnotationKey RABBITMQ_ROUTINGKEY_ANNOTATION_KEY = AnnotationKeyFactory.of(131, "rabbitmq.routingkey", VIEW_IN_RECORD_SET); - AnnotationKey RABBITMQ_PROPERTIES_ANNOTATION_KEY = AnnotationKeyFactory.of(132, "rabbitmq.properties"); - AnnotationKey RABBITMQ_BODY_ANNOTATION_KEY = AnnotationKeyFactory.of(133, "rabbitmq.body"); - - String META_DO_NOT_TRACE = "_RABBITMQ_DO_NOT_TRACE"; - String META_TRANSACTION_ID = "_RABBITMQ_TRASACTION_ID"; - String META_SPAN_ID = "_RABBITMQ_SPAN_ID"; - String META_PARENT_SPAN_ID = "_RABBITMQ_PARENT_SPAN_ID"; - String META_PARENT_APPLICATION_NAME = "_RABBITMQ_PARENT_APPLICATION_NAME"; - String META_PARENT_APPLICATION_TYPE = "_RABBITMQ_PARENT_APPLICATION_TYPE"; - String META_FLAGS = "_RABBITMQ_FLAGS"; -} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQPlugin.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQPlugin.java deleted file mode 100644 index a340e4ddb15c..000000000000 --- a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQPlugin.java +++ /dev/null @@ -1,127 +0,0 @@ -package com.navercorp.pinpoint.plugin.rabbitmq; - -import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; -import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; -import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; -import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; -import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; -import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; -import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; -import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; -import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; - -import java.security.ProtectionDomain; - -/** - * @author Jinkai.Ma - * @author Jiaqi Feng - */ -public class RabbitMQPlugin implements ProfilerPlugin, TransformTemplateAware { - - private static final String PUBLISHER_INTERCEPTOR_FQCN = "com.navercorp.pinpoint.plugin.rabbitmq.interceptor.RabbitMQPublishInterceptor"; - private static final String CONSUMER_INTERCEPTOR_FQCN = "com.navercorp.pinpoint.plugin.rabbitmq.interceptor.RabbitMQConsumeInterceptor"; - - private TransformTemplate transformTemplate; - - @Override - public void setup(ProfilerPluginSetupContext context) { - RabbitMQClientPluginConfig config = new RabbitMQClientPluginConfig(context.getConfig()); - if (!config.isTraceRabbitMQClient()) { - return; - } - if (config.isTraceRabbitMQClientConsumer() || config.isTraceRabbitMQClientProducer()) { - if (config.isTraceRabbitMQClientProducer()) { - addPublisher(); - } - if (config.isTraceRabbitMQClientConsumer()) { - addConsumer(); - } - } - } - - private void addPublisher() { - transformTemplate.transform("com.rabbitmq.client.impl.recovery.AutorecoveringChannel", new TransformCallback() { - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - - final InstrumentMethod method = target.getDeclaredMethod("basicPublish", "java.lang.String", "java.lang.String", "boolean", "boolean", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); - if (method != null) { - method.addScopedInterceptor(PUBLISHER_INTERCEPTOR_FQCN, RabbitMQConstants.RABBITMQ_SCOPE); - } - - return target.toBytecode(); - } - }); - transformTemplate.transform("com.rabbitmq.client.impl.ChannelN", new TransformCallback() { - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - - final InstrumentMethod method = target.getDeclaredMethod("basicPublish", "java.lang.String", "java.lang.String", "boolean", "boolean", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); - if (method != null) { - method.addScopedInterceptor(PUBLISHER_INTERCEPTOR_FQCN, RabbitMQConstants.RABBITMQ_SCOPE); - } - - return target.toBytecode(); - } - }); - transformTemplate.transform("com.rabbitmq.client.AMQP$BasicProperties", new TransformCallback() { - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - - target.addSetter("com.navercorp.pinpoint.plugin.rabbitmq.field.setter.HeadersFieldSetter", "headers"); - - return target.toBytecode(); - } - }); - } - - private void addConsumer() { - transformTemplate.transform("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$InternalConsumer", new TransformCallback() { - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - - final InstrumentMethod method = target.getDeclaredMethod("handleDelivery", "java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); - if (method != null) { - method.addInterceptor(CONSUMER_INTERCEPTOR_FQCN); - } - - return target.toBytecode(); - } - }); - transformTemplate.transform("com.rabbitmq.client.QueueingConsumer", new TransformCallback() { - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - - final InstrumentMethod method = target.getDeclaredMethod("handleDelivery", "java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); - if (method != null) { - method.addInterceptor(CONSUMER_INTERCEPTOR_FQCN); - } - - return target.toBytecode(); - } - }); - transformTemplate.transform("com.rabbitmq.client.DefaultConsumer", new TransformCallback() { - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - - final InstrumentMethod method = target.getDeclaredMethod("handleDelivery", "java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); - if (method != null) { - method.addInterceptor(CONSUMER_INTERCEPTOR_FQCN); - } - - return target.toBytecode(); - } - }); - } - - @Override - public void setTransformTemplate(TransformTemplate transformTemplate) { - this.transformTemplate = transformTemplate; - } -} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQTraceMetadataProvider.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQTraceMetadataProvider.java deleted file mode 100644 index 54e5f7c06a06..000000000000 --- a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/RabbitMQTraceMetadataProvider.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.navercorp.pinpoint.plugin.rabbitmq; - -import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; -import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; - -/** - * @author Jinkai.Ma - */ -public class RabbitMQTraceMetadataProvider implements TraceMetadataProvider { - @Override - public void setup(TraceMetadataSetupContext context) { - context.addServiceType(RabbitMQConstants.RABBITMQ_SERVICE_TYPE); - - context.addAnnotationKey(RabbitMQConstants.RABBITMQ_EXCHANGE_ANNOTATION_KEY); - context.addAnnotationKey(RabbitMQConstants.RABBITMQ_ROUTINGKEY_ANNOTATION_KEY); - context.addAnnotationKey(RabbitMQConstants.RABBITMQ_PROPERTIES_ANNOTATION_KEY); - context.addAnnotationKey(RabbitMQConstants.RABBITMQ_BODY_ANNOTATION_KEY); - } -} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientConstants.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientConstants.java new file mode 100644 index 000000000000..e3046c0b4f6d --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientConstants.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client; + +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.AnnotationKeyFactory; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +import static com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.QUEUE; + +/** + * @author Jinkai.Ma + * @author HyunGil Jeong + */ +public final class RabbitMQClientConstants { + private RabbitMQClientConstants() { + } + + public static final ServiceType RABBITMQ_CLIENT = ServiceTypeFactory.of(8300, "RABBITMQ_CLIENT", QUEUE, RECORD_STATISTICS); + public static final ServiceType RABBITMQ_CLIENT_INTERNAL = ServiceTypeFactory.of(8301, "RABBITMQ_CLIENT_INTERNAL", "RABBITMQ_CLIENT"); + + public static final String RABBITMQ_PRODUCER_SCOPE = "rabbitmqProducerScope"; + public static final String RABBITMQ_CONSUMER_SCOPE = "rabbitmqConsumerScope"; + public static final String RABBITMQ_FRAME_HANDLER_CREATION_SCOPE = "rabbitmqFrameHandlerCreationScope"; + public static final String RABBITMQ_TEMPLATE_API_SCOPE = "rabbitmqTemplateApiScope"; + + public static final AnnotationKey RABBITMQ_EXCHANGE_ANNOTATION_KEY = AnnotationKeyFactory.of(130, "rabbitmq.exchange", VIEW_IN_RECORD_SET); + public static final AnnotationKey RABBITMQ_ROUTINGKEY_ANNOTATION_KEY = AnnotationKeyFactory.of(131, "rabbitmq.routingkey", VIEW_IN_RECORD_SET); + public static final AnnotationKey RABBITMQ_PROPERTIES_ANNOTATION_KEY = AnnotationKeyFactory.of(132, "rabbitmq.properties"); + public static final AnnotationKey RABBITMQ_BODY_ANNOTATION_KEY = AnnotationKeyFactory.of(133, "rabbitmq.body"); + + public static final String UNKNOWN = "Unknown"; + + public static final String META_TRACE_ID = "Pinpoint-TraceID"; + public static final String META_SPAN_ID = "Pinpoint-SpanID"; + public static final String META_PARENT_SPAN_ID = "Pinpoint-pSpanID"; + public static final String META_SAMPLED = "Pinpoint-Sampled"; + public static final String META_FLAGS = "Pinpoint-Flags"; + public static final String META_PARENT_APPLICATION_NAME = "Pinpoint-pAppName"; + public static final String META_PARENT_APPLICATION_TYPE = "Pinpoint-pAppType"; +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientPlugin.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientPlugin.java new file mode 100644 index 000000000000..930eb5699c53 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientPlugin.java @@ -0,0 +1,451 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.instrument.ClassFilters; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.interceptor.BasicMethodInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExecutionPolicy; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; + +import java.lang.reflect.Modifier; +import java.security.ProtectionDomain; +import java.util.List; + +import static com.navercorp.pinpoint.common.util.VarArgs.va; + +/** + * @author Jinkai.Ma + * @author Jiaqi Feng + * @author HyunGil Jeong + */ +public class RabbitMQClientPlugin implements ProfilerPlugin, TransformTemplateAware { + + private TransformTemplate transformTemplate; + + @Override + public void setup(ProfilerPluginSetupContext context) { + RabbitMQClientPluginConfig config = new RabbitMQClientPluginConfig(context.getConfig()); + if (!config.isTraceRabbitMQClient()) { + return; + } + + addCommonEditors(config.isTraceRabbitMQClientProducer(), config.isTraceRabbitMQClientConsumer()); + if (config.isTraceRabbitMQClientProducer()) { + addAmqpBasicPropertiesEditor(); + } + if (config.isTraceRabbitMQClientConsumer()) { + addAMQChannelEditor(config.getExcludeExchangeFilter()); + addConsumerDispatchEditor(config.getExcludeExchangeFilter()); + addConsumerEditors(); + addCustomConsumerEditors(config.getConsumerClasses()); + } + + addSpringAmqpSupport(config.isTraceRabbitMQClientProducer(), config.isTraceRabbitMQClientConsumer()); + } + + private void addAmqpBasicPropertiesEditor() { + transformTemplate.transform("com.rabbitmq.client.AMQP$BasicProperties", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + target.addSetter("com.navercorp.pinpoint.plugin.rabbitmq.client.field.setter.HeadersFieldSetter", "headers"); + return target.toBytecode(); + } + }); + } + + private static class ChannelTransformCallback implements TransformCallback { + private final boolean traceProducer; + private final boolean traceConsumer; + + private ChannelTransformCallback(boolean traceProducer, boolean traceConsumer) { + this.traceProducer = traceProducer; + this.traceConsumer = traceConsumer; + } + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + if (traceProducer) { + // copy AMQP.BasicProperties + target.weave("com.navercorp.pinpoint.plugin.rabbitmq.client.aspect.ChannelAspect"); + + final InstrumentMethod basicPublish = target.getDeclaredMethod("basicPublish", "java.lang.String", "java.lang.String", "boolean", "boolean", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); + if (basicPublish != null) { + basicPublish.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.ChannelBasicPublishInterceptor", RabbitMQClientConstants.RABBITMQ_PRODUCER_SCOPE, ExecutionPolicy.BOUNDARY); + } + } + if (traceConsumer) { + final InstrumentMethod basicGet = target.getDeclaredMethod("basicGet", "java.lang.String", "boolean"); + if (basicGet != null) { + basicGet.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.ChannelBasicGetInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE); + } + } + return target.toBytecode(); + } + } + + private void addCommonEditors(final boolean traceProducer, final boolean traceConsumer) { + if (!traceProducer && !traceConsumer) { + return; + } + // Channels + transformTemplate.transform("com.rabbitmq.client.impl.ChannelN", new ChannelTransformCallback(traceProducer, traceConsumer)); + transformTemplate.transform("com.rabbitmq.client.impl.recovery.AutorecoveringChannel", new ChannelTransformCallback(traceProducer, traceConsumer)); + // FrameHandler implementations for end point and remote address + transformTemplate.transform("com.rabbitmq.client.impl.SocketFrameHandler", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + target.addField("com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.LocalAddressAccessor"); + target.addField("com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.RemoteAddressAccessor"); + final InstrumentMethod constructor1 = target.getConstructor("java.net.Socket"); + if (constructor1 != null) { + constructor1.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.SocketFrameHandlerConstructInterceptor", RabbitMQClientConstants.RABBITMQ_FRAME_HANDLER_CREATION_SCOPE); + } + final InstrumentMethod constructor2 = target.getConstructor("java.net.Socket", "java.util.concurrent.ExecutorService"); + if (constructor2 != null) { + constructor2.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.SocketFrameHandlerConstructInterceptor", RabbitMQClientConstants.RABBITMQ_FRAME_HANDLER_CREATION_SCOPE); + } + return target.toBytecode(); + } + }); + transformTemplate.transform("com.rabbitmq.client.impl.nio.SocketChannelFrameHandler", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + target.addField("com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.LocalAddressAccessor"); + target.addField("com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.RemoteAddressAccessor"); + final InstrumentMethod constructor = target.getConstructor("com.rabbitmq.client.impl.nio.SocketChannelFrameHandlerState"); + if (constructor != null) { + constructor.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.SocketChannelFrameHandlerConstructInterceptor", RabbitMQClientConstants.RABBITMQ_FRAME_HANDLER_CREATION_SCOPE); + } + return target.toBytecode(); + } + }); + // Envelope - for asynchrnous trace propagation for consumers + transformTemplate.transform("com.rabbitmq.client.Envelope", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + target.addField(AsyncContextAccessor.class.getName()); + return target.toBytecode(); + } + }); + // AMQCommand - for pinpoint header propagation + transformTemplate.transform("com.rabbitmq.client.impl.AMQCommand", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + InstrumentMethod constructor = target.getConstructor("com.rabbitmq.client.Method", "com.rabbitmq.client.impl.AMQContentHeader", "byte[]"); + if (constructor != null) { + constructor.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.AMQCommandConstructInterceptor", RabbitMQClientConstants.RABBITMQ_PRODUCER_SCOPE, ExecutionPolicy.INTERNAL); + } + return target.toBytecode(); + } + }); + } + + private void addAMQChannelEditor(final Filter excludeExchangeFilter) { + transformTemplate.transform("com.rabbitmq.client.impl.AMQChannel", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + final InstrumentMethod handleCompleteInboundCommand = target.getDeclaredMethod("handleCompleteInboundCommand", "com.rabbitmq.client.impl.AMQCommand"); + if (handleCompleteInboundCommand != null) { + handleCompleteInboundCommand.addInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.RabbitMQConsumerHandleCompleteInboundCommandInterceptor", va(excludeExchangeFilter)); + } + return target.toBytecode(); + } + }); + } + + private void addConsumerDispatchEditor(final Filter excludeExchangeFilter) { + transformTemplate.transform("com.rabbitmq.client.impl.ConsumerDispatcher", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + final InstrumentMethod handleDelivery = target.getDeclaredMethod("handleDelivery", "com.rabbitmq.client.Consumer", "java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); + if (handleDelivery == null) { + return null; + } + handleDelivery.addInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.RabbitMQConsumerDispatchInterceptor", va(excludeExchangeFilter)); + target.addGetter("com.navercorp.pinpoint.plugin.rabbitmq.client.field.getter.ChannelGetter", "channel"); + return target.toBytecode(); + } + }); + } + + private boolean addConsumerHandleDeliveryInterceptor(InstrumentClass target) throws InstrumentException { + if (target == null) { + return false; + } + final InstrumentMethod handleDelivery = target.getDeclaredMethod("handleDelivery", "java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); + if (handleDelivery == null) { + return false; + } + handleDelivery.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.ConsumerHandleDeliveryInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE); + return true; + } + + private void addConsumerEditors() { + // DefaultConsumer + transformTemplate.transform("com.rabbitmq.client.DefaultConsumer", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + if (addConsumerHandleDeliveryInterceptor(target)) { + return target.toBytecode(); + } + return null; + } + }); + // QueueingConsumer + transformTemplate.transform("com.rabbitmq.client.QueueingConsumer$Delivery", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + InstrumentMethod constructor = target.getConstructor("com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); + if (constructor == null) { + return null; + } + constructor.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.DeliveryConstructInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE, ExecutionPolicy.INTERNAL); + target.addField(AsyncContextAccessor.class.getName()); + return target.toBytecode(); + } + }); + transformTemplate.transform("com.rabbitmq.client.QueueingConsumer", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + if (addConsumerHandleDeliveryInterceptor(target)) { + InstrumentMethod nextDelivery = target.getDeclaredMethod("nextDelivery"); + if (nextDelivery != null) { + nextDelivery.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.QueueingConsumerOnNextInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE); + } + InstrumentMethod nextDeliveryTimeout = target.getDeclaredMethod("nextDelivery", "long"); + if (nextDeliveryTimeout != null) { + nextDeliveryTimeout.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.QueueingConsumerOnNextInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE); + } + InstrumentMethod handle = target.getDeclaredMethod("handle", "com.rabbitmq.client.QueueingConsumer$Delivery"); + if (handle != null) { + handle.addInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.QueueingConsumerHandleInterceptor"); + } + return target.toBytecode(); + } + return null; + } + }); + } + + private void addCustomConsumerEditors(List customConsumers) { + for (String customConsumer : customConsumers) { + transformTemplate.transform(customConsumer, new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + if (addConsumerHandleDeliveryInterceptor(target)) { + return target.toBytecode(); + } + // Check inner classes for consumer implementations + for (InstrumentClass potentialConsumer : target.getNestedClasses(ClassFilters.ACCEPT_ALL)) { + if (potentialConsumer.hasMethod("handleDelivery", "java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]")) { + instrumentor.transform(loader, potentialConsumer.getName(), new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + if (addConsumerHandleDeliveryInterceptor(target)) { + return target.toBytecode(); + } + return null; + } + }); + } + } + return null; + } + }); + } + } + + private void addSpringAmqpSupport(final boolean traceProducer, final boolean traceConsumer) { + if (!traceProducer && !traceConsumer) { + return; + } + // RabbitTemplate + // public APIs + final MethodFilter publicApiFilter = MethodFilters.chain( + MethodFilters.name("execute", "convertAndSend", "convertSendAndReceive", "convertSendAndReceiveAsType", + "correlationConvertAndSend", "doSend", "send", "sendAndReceive", + "receive", "receiveAndConvert", "receiveAndReply"), + MethodFilters.modifier(Modifier.PUBLIC)); + transformTemplate.transform("org.springframework.amqp.rabbit.core.RabbitTemplate", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + + for (InstrumentMethod publicApi : target.getDeclaredMethods(publicApiFilter)) { + publicApi.addScopedInterceptor(BasicMethodInterceptor.class.getName(), va(RabbitMQClientConstants.RABBITMQ_CLIENT_INTERNAL), RabbitMQClientConstants.RABBITMQ_TEMPLATE_API_SCOPE); + } + InstrumentMethod invoke = target.getDeclaredMethod("invoke", "org.springframework.amqp.rabbit.core.RabbitOperations$OperationsCallback"); + if (invoke != null) { + invoke.addInterceptor(BasicMethodInterceptor.class.getName(), va(RabbitMQClientConstants.RABBITMQ_CLIENT_INTERNAL)); + } + + if (traceConsumer) { + // Internal consumer implementations + if (!addConsumerHandleDeliveryInterceptor(target)) { + // Check inner classes for consumer implementations + for (InstrumentClass potentialConsumer : target.getNestedClasses(ClassFilters.ACCEPT_ALL)) { + if (potentialConsumer.hasMethod("handleDelivery", "java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]")) { + instrumentor.transform(loader, potentialConsumer.getName(), new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + if (addConsumerHandleDeliveryInterceptor(target)) { + return target.toBytecode(); + } + return null; + } + }); + } + } + } + } + + return target.toBytecode(); + } + }); + + // Spring-amqp rabbit client transformation + if (traceConsumer) { + // Message + transformTemplate.transform("org.springframework.amqp.core.Message", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + target.addField(AsyncContextAccessor.class.getName()); + return target.toBytecode(); + } + }); + + // Delivery + // spring-rabbit pre-1.7.0 + transformTemplate.transform("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$Delivery", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + // spring-rabbit pre-1.4.2 + InstrumentMethod constructor1 = target.getConstructor("com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); + if (constructor1 != null) { + constructor1.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.DeliveryConstructInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE, ExecutionPolicy.INTERNAL); + } + // spring-rabbit 1.4.2 to 1.6.x + InstrumentMethod constructor2 = target.getConstructor("java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); + if (constructor2 != null) { + constructor2.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.DeliveryConstructInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE, ExecutionPolicy.INTERNAL); + } + target.addField(AsyncContextAccessor.class.getName()); + return target.toBytecode(); + } + }); + // spring-rabbit 1.7.0+ + transformTemplate.transform("org.springframework.amqp.rabbit.support.Delivery", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + InstrumentMethod constructor = target.getConstructor("java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]"); + if (constructor != null) { + constructor.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.DeliveryConstructInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE, ExecutionPolicy.INTERNAL); + } + // spring-rabbit 2.1.0+ + InstrumentMethod constructor_2_1_0 = target.getConstructor("java.lang.String", "com.rabbitmq.client.Envelope", "com.rabbitmq.client.AMQP$BasicProperties", "byte[]", "java.lang.String"); + if (constructor_2_1_0 != null) { + constructor_2_1_0.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.DeliveryConstructInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE, ExecutionPolicy.INTERNAL); + } + target.addField(AsyncContextAccessor.class.getName()); + return target.toBytecode(); + } + }); + + // BlockingQueueConsumer + transformTemplate.transform("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + InstrumentMethod nextMessage = target.getDeclaredMethod("nextMessage"); + if (nextMessage != null) { + nextMessage.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.QueueingConsumerOnNextInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE); + } + InstrumentMethod nextMessageTimeout = target.getDeclaredMethod("nextMessage", "long"); + if (nextMessageTimeout != null) { + nextMessageTimeout.addScopedInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.QueueingConsumerOnNextInterceptor", RabbitMQClientConstants.RABBITMQ_CONSUMER_SCOPE); + } + // spring-rabbit pre-1.7.0 + InstrumentMethod handle1 = target.getDeclaredMethod("handle", "org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$Delivery"); + if (handle1 != null) { + handle1.addInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.QueueingConsumerHandleInterceptor"); + } + // spring-rabbit 1.7.0+ + InstrumentMethod handle2 = target.getDeclaredMethod("handle", "org.springframework.amqp.rabbit.support.Delivery"); + if (handle2 != null) { + handle2.addInterceptor("com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor.QueueingConsumerHandleInterceptor"); + } + return target.toBytecode(); + } + }); + transformTemplate.transform("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$InternalConsumer", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + if (addConsumerHandleDeliveryInterceptor(target)) { + return target.toBytecode(); + } + return null; + } + }); + // Spring-rabbit 1.7.7+, 2.0.3+ + transformTemplate.transform("org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$ConsumerDecorator", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + if (addConsumerHandleDeliveryInterceptor(target)) { + return target.toBytecode(); + } + return null; + } + }); + } + } + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientPluginConfig.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientPluginConfig.java new file mode 100644 index 000000000000..8d2ec2ca479a --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientPluginConfig.java @@ -0,0 +1,82 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client; + +import com.navercorp.pinpoint.bootstrap.config.ExcludePathFilter; +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.bootstrap.config.SkipFilter; + +import java.util.List; + +/** + * @author Jiaqi Feng + */ +public class RabbitMQClientPluginConfig { + + private final boolean traceRabbitMQClient; + private final boolean traceRabbitMQClientProducer; + private final boolean traceRabbitMQClientConsumer; + private final List consumerClasses; + private final Filter excludeExchangeFilter; + + public RabbitMQClientPluginConfig(ProfilerConfig config) { + this.traceRabbitMQClient = config.readBoolean("profiler.rabbitmq.client.enable", true); + this.traceRabbitMQClientProducer = config.readBoolean("profiler.rabbitmq.client.producer.enable", true); + this.traceRabbitMQClientConsumer = config.readBoolean("profiler.rabbitmq.client.consumer.enable", true); + this.consumerClasses = config.readList("profiler.rabbitmq.client.consumer.classes"); + + String excludeExchange = config.readString("profiler.rabbitmq.client.exchange.exclude", ""); + if (!excludeExchange.isEmpty()) { + this.excludeExchangeFilter = new ExcludePathFilter(excludeExchange); + } else { + this.excludeExchangeFilter = new SkipFilter(); + } + } + + public boolean isTraceRabbitMQClient() { + return this.traceRabbitMQClient; + } + + public boolean isTraceRabbitMQClientProducer() { + return this.traceRabbitMQClientProducer; + } + + public boolean isTraceRabbitMQClientConsumer() { + return this.traceRabbitMQClientConsumer; + } + + public List getConsumerClasses() { + return consumerClasses; + } + + public Filter getExcludeExchangeFilter() { + return this.excludeExchangeFilter; + } + + public static boolean isExchangeExcluded(String exchange, Filter filter) { + if (exchange == null || filter == null) + return false; + try { + if (filter.filter(exchange)) + return true; + } catch (Exception e) { + } + + return false; + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientTraceMetadataProvider.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientTraceMetadataProvider.java new file mode 100644 index 000000000000..d87afb24d354 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/RabbitMQClientTraceMetadataProvider.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * @author Jinkai.Ma + */ +public class RabbitMQClientTraceMetadataProvider implements TraceMetadataProvider { + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT); + context.addServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT_INTERNAL); + + context.addAnnotationKey(RabbitMQClientConstants.RABBITMQ_EXCHANGE_ANNOTATION_KEY); + context.addAnnotationKey(RabbitMQClientConstants.RABBITMQ_ROUTINGKEY_ANNOTATION_KEY); + context.addAnnotationKey(RabbitMQClientConstants.RABBITMQ_PROPERTIES_ANNOTATION_KEY); + context.addAnnotationKey(RabbitMQClientConstants.RABBITMQ_BODY_ANNOTATION_KEY); + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/aspect/ChannelAspect.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/aspect/ChannelAspect.java new file mode 100644 index 000000000000..810ceb40bdbd --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/aspect/ChannelAspect.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.aspect; + +import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.MessageProperties; + +/** + * Make a copy of {@code AMQP.BasicProperties} to inject pinpoint headers. + * + * @author HyunGil Jeong + */ +@Aspect +public abstract class ChannelAspect { + @PointCut + public void basicPublish(String exchange, String routingKey, + boolean mandatory, boolean immediate, + AMQP.BasicProperties props, byte[] body) { + AMQP.BasicProperties sourceProps = props; + if (sourceProps == null) { + sourceProps = MessageProperties.MINIMAL_BASIC; + } + AMQP.BasicProperties useProps = copy(sourceProps); + __basicPublish(exchange, routingKey, mandatory, immediate, useProps, body); + } + + private AMQP.BasicProperties copy(AMQP.BasicProperties source) { + AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder(); + builder.contentType(source.getContentType()); + builder.contentEncoding(source.getContentEncoding()); + builder.headers(source.getHeaders()); + builder.deliveryMode(source.getDeliveryMode()); + builder.priority(source.getPriority()); + builder.correlationId(source.getCorrelationId()); + builder.replyTo(source.getReplyTo()); + builder.expiration(source.getExpiration()); + builder.messageId(source.getMessageId()); + builder.timestamp(source.getTimestamp()); + builder.type(source.getType()); + builder.userId(source.getUserId()); + builder.appId(source.getAppId()); + builder.clusterId(source.getClusterId()); + return builder.build(); + } + + @JointPoint + abstract void __basicPublish(String exchange, String routingKey, + boolean mandatory, boolean immediate, + AMQP.BasicProperties props, byte[] body); +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/descriptor/RabbitMQConsumerEntryMethodDescriptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/descriptor/RabbitMQConsumerEntryMethodDescriptor.java new file mode 100644 index 000000000000..52571529b3b8 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/descriptor/RabbitMQConsumerEntryMethodDescriptor.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.descriptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.common.trace.MethodType; + +/** + * @author HyunGil Jeong + */ +public class RabbitMQConsumerEntryMethodDescriptor implements MethodDescriptor { + + private int apiId = 0; + private int type = MethodType.WEB_REQUEST; + + @Override + public String getMethodName() { + return ""; + } + + @Override + public String getClassName() { + return ""; + } + + @Override + public String[] getParameterTypes() { + return null; + } + + @Override + public String[] getParameterVariableName() { + return null; + } + + @Override + public String getParameterDescriptor() { + return "()"; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public String getFullName() { + return RabbitMQConsumerEntryMethodDescriptor.class.getName(); + } + + @Override + public void setApiId(int apiId) { + this.apiId = apiId; + } + + @Override + public int getApiId() { + return apiId; + } + + @Override + public String getApiDescriptor() { + return "RabbitMQ Consumer Invocation"; + } + + @Override + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/accessor/LocalAddressAccessor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/accessor/LocalAddressAccessor.java new file mode 100644 index 000000000000..1ac97a8607c7 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/accessor/LocalAddressAccessor.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor; + +/** + * @author HyunGil Jeong + */ +public interface LocalAddressAccessor { + void _$PINPOINT$_setLocalAddress(String localAddress); + String _$PINPOINT$_getLocalAddress(); +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/accessor/RemoteAddressAccessor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/accessor/RemoteAddressAccessor.java new file mode 100644 index 000000000000..f15ebc253bb9 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/accessor/RemoteAddressAccessor.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor; + +/** + * @author HyunGil Jeong + */ +public interface RemoteAddressAccessor { + void _$PINPOINT$_setRemoteAddress(String localAddress); + String _$PINPOINT$_getRemoteAddress(); +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/getter/ChannelGetter.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/getter/ChannelGetter.java new file mode 100644 index 000000000000..36bbc1d33cbf --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/getter/ChannelGetter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.field.getter; + +import com.rabbitmq.client.Channel; + +/** + * @author HyunGil Jeong + */ +public interface ChannelGetter { + Channel _$PINPOINT$_getChannel(); +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/setter/HeadersFieldSetter.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/setter/HeadersFieldSetter.java new file mode 100644 index 000000000000..6fe266c5779f --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/field/setter/HeadersFieldSetter.java @@ -0,0 +1,10 @@ +package com.navercorp.pinpoint.plugin.rabbitmq.client.field.setter; + +import java.util.Map; + +/** + * @author Jinkai.Ma + */ +public interface HeadersFieldSetter { + void _$PINPOINT$_setHeaders(Map headers); +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/AMQCommandConstructInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/AMQCommandConstructInterceptor.java new file mode 100644 index 000000000000..948e6333cd50 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/AMQCommandConstructInterceptor.java @@ -0,0 +1,181 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.MapUtils; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.setter.HeadersFieldSetter; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Method; + +import java.util.HashMap; +import java.util.Map; + +/** + *

{@code AMQContentHeader} received as an argument to the constructor is sharable and can be reused, such as + * {@code MessageProperties.MINIMAL_BASIC}. Any changes made to it (ie injecting pinpoint headers) may have undesirable + * consequences. + * + *

Hence, we make a copy via {@code ChannelAspect} and add pinpoint headers to it when propagating trace, and have + * {@code AMQCommand} use this. + * + * @author HyunGil Jeong + * + * @see com.navercorp.pinpoint.plugin.rabbitmq.client.aspect.ChannelAspect + */ +public class AMQCommandConstructInterceptor implements AroundInterceptor { + + // AMQP spec + private static final String AMQP_METHOD_TO_INTERCEPT = "basic.publish"; + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final InterceptorScope scope; + + public AMQCommandConstructInterceptor(TraceContext traceContext, InterceptorScope scope) { + this.traceContext = traceContext; + this.scope = scope; + } + + @Override + public void before(Object target, Object[] args) { + if (!validate(target, args)) { + return; + } + + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + Trace trace = traceContext.currentRawTraceObject(); + if (trace == null) { + return; + } + + final AMQP.BasicProperties properties = (AMQP.BasicProperties) args[1]; + final Map headers = createHeader(properties, trace); + if (headers != null) { + ((HeadersFieldSetter) properties)._$PINPOINT$_setHeaders(headers); + } + } + + private Map createHeader(AMQP.BasicProperties properties, Trace trace) { + final Map headers = copyHeader(properties); + if (trace.canSampled()) { + TraceId nextId = retrieveNextTraceId(); + if (nextId == null) { + return null; + } + headers.put(RabbitMQClientConstants.META_TRACE_ID, nextId.getTransactionId()); + headers.put(RabbitMQClientConstants.META_SPAN_ID, Long.toString(nextId.getSpanId())); + headers.put(RabbitMQClientConstants.META_PARENT_SPAN_ID, Long.toString(nextId.getParentSpanId())); + headers.put(RabbitMQClientConstants.META_PARENT_APPLICATION_TYPE, Short.toString(traceContext.getServerTypeCode())); + headers.put(RabbitMQClientConstants.META_PARENT_APPLICATION_NAME, traceContext.getApplicationName()); + headers.put(RabbitMQClientConstants.META_FLAGS, Short.toString(nextId.getFlags())); + } else { + headers.put(RabbitMQClientConstants.META_SAMPLED, "1"); + } + return headers; + } + + private Map copyHeader(AMQP.BasicProperties properties) { + final Map headers = properties.getHeaders(); + if (MapUtils.isEmpty(headers)) { + return new HashMap(); + } + // headers wrapped as unmodifiable map + return new HashMap(headers); + } + + private TraceId retrieveNextTraceId() { + Object attachment = scope.getCurrentInvocation().getAttachment(); + if (attachment == null) { + if (isDebug) { + logger.debug("Invalid attachment. Expected {}, but got null", TraceId.class.getName()); + } + return null; + } + if (!(attachment instanceof TraceId)) { + if (isDebug) { + logger.debug("Invalid attachment. Expected {}, but got {}", TraceId.class.getName(), attachment.getClass()); + } + return null; + } + return (TraceId) attachment; + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (!validate(target, args)) { + return; + } + + if (isDebug) { + logger.afterInterceptor(target, args); + } + } + + private boolean validate(Object target, Object[] args) { + if (args == null) { + if (isDebug) { + logger.debug("Expected arguments, but found none."); + } + return false; + } + if (args.length != 3) { + if (isDebug) { + logger.debug("Expected 3 arguments, but found {}", args.length); + } + return false; + } + Object method = args[0]; + if (method == null) { + // valid, but this won't be null producer side + return false; + } + if (!(method instanceof Method)) { + if (isDebug) { + logger.debug("Expected args[0] to be {}, but was {}", Method.class.getName(), method.getClass().getName()); + } + return false; + } + if (!AMQP_METHOD_TO_INTERCEPT.equals(((Method) method).protocolMethodName())) { + return false; + } + Object contentHeader = args[1]; + if (!(contentHeader instanceof AMQP.BasicProperties)) { + // skip header injection for null, or non AMQP.BasicProperties header + return false; + } + if (!(contentHeader instanceof HeadersFieldSetter)) { + if (isDebug) { + logger.debug("Invalid args[1]({}) object. Need field setter({})", contentHeader, HeadersFieldSetter.class.getName()); + } + return false; + } + return true; + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ChannelBasicGetInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ChannelBasicGetInterceptor.java new file mode 100644 index 000000000000..f4b2a31c9ed6 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ChannelBasicGetInterceptor.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; + +/** + * @author HyunGil Jeong + */ +public class ChannelBasicGetInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + public ChannelBasicGetInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + public void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT_INTERNAL); + recorder.recordApi(getMethodDescriptor()); + recorder.recordException(throwable); + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ChannelBasicPublishInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ChannelBasicPublishInterceptor.java new file mode 100644 index 000000000000..c3e0050d3469 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ChannelBasicPublishInterceptor.java @@ -0,0 +1,151 @@ +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScopeInvocation; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientPluginConfig; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.RemoteAddressAccessor; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.FrameHandler; + +/** + * @author Jinkai.Ma + * @author Jiaqi Feng + * @author HyunGil Jeong + */ +public class ChannelBasicPublishInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final MethodDescriptor descriptor; + private final TraceContext traceContext; + private final InterceptorScope scope; + private final Filter excludeExchangeFilter; + + public ChannelBasicPublishInterceptor(TraceContext traceContext, MethodDescriptor descriptor, InterceptorScope scope) { + this.descriptor = descriptor; + this.traceContext = traceContext; + this.scope = scope; + + RabbitMQClientPluginConfig rabbitMQClientPluginConfig = new RabbitMQClientPluginConfig(traceContext.getProfilerConfig()); + this.excludeExchangeFilter = rabbitMQClientPluginConfig.getExcludeExchangeFilter(); + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (!validate(target, args)) { + if (isDebug) + logger.debug("validate argument failed!"); + return; + } + + String exchange = (String) args[0]; + if (RabbitMQClientPluginConfig.isExchangeExcluded(exchange, excludeExchangeFilter)) { + return; + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + if (trace.canSampled()) { + SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT); + + TraceId nextId = trace.getTraceId().getNextTraceId(); + + recorder.recordNextSpanId(nextId.getSpanId()); + + InterceptorScopeInvocation invocation = scope.getCurrentInvocation(); + invocation.setAttachment(nextId); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args); + } + + if (!validate(target, args)) { + return; + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null || !trace.canSampled()) { + return; + } + + try { + String exchange = (String) args[0]; + String routingKey = (String) args[1]; + + if (exchange == null || exchange.equals("")) { + exchange = RabbitMQClientConstants.UNKNOWN; + } + + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(descriptor); + if (throwable == null) { + String endPoint = RabbitMQClientConstants.UNKNOWN; + // Producer's endPoint should be the socket address of where the producer is actually connected to. + final Connection connection = ((Channel) target).getConnection(); + if (connection instanceof AMQConnection) { + AMQConnection amqConnection = (AMQConnection) connection; + FrameHandler frameHandler = amqConnection.getFrameHandler(); + if (frameHandler instanceof RemoteAddressAccessor) { + endPoint = ((RemoteAddressAccessor) frameHandler)._$PINPOINT$_getRemoteAddress(); + } + } + recorder.recordEndPoint(endPoint); + // DestinationId is used to render the virtual queue node. + // We choose the exchange name as the logical name of the queue node. + recorder.recordDestinationId("exchange-" + exchange); + + recorder.recordAttribute(RabbitMQClientConstants.RABBITMQ_EXCHANGE_ANNOTATION_KEY, exchange); + recorder.recordAttribute(RabbitMQClientConstants.RABBITMQ_ROUTINGKEY_ANNOTATION_KEY, routingKey); + } else { + recorder.recordException(throwable); + } + } finally { + trace.traceBlockEnd(); + } + } + + private boolean validate(Object target, Object[] args) { + if (!(target instanceof Channel)) { + return false; + } + if (args == null || args.length < 6) { + return false; + } + if (args[0] !=null && !(args[0] instanceof String)) { + return false; + } + if (args[1] !=null && !(args[1] instanceof String)) { + return false; + } + if (args[4] !=null && !(args[4] instanceof AMQP.BasicProperties)) { + return false; + } + return true; + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ConsumerHandleDeliveryInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ConsumerHandleDeliveryInterceptor.java new file mode 100644 index 000000000000..c02d68c0f1bc --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/ConsumerHandleDeliveryInterceptor.java @@ -0,0 +1,184 @@ +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.context.scope.TraceScope; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.Envelope; + +/** + * @author Jinkai.Ma + * @author Jiaqi Feng + * @author HyunGil Jeong + */ +public class ConsumerHandleDeliveryInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private static final String ASYNC_TRACE_SCOPE = AsyncContext.ASYNC_TRACE_SCOPE; + + private final MethodDescriptor methodDescriptor; + + public ConsumerHandleDeliveryInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + if (traceContext == null) { + throw new NullPointerException("traceContext must not be null"); + } + if (methodDescriptor == null) { + throw new NullPointerException("methodDescriptor must not be null"); + } + this.methodDescriptor = methodDescriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (!validate(target, args)) { + return; + } + final AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(args[1]); + if (asyncContext == null) { + return; + } + + final Trace trace = getAsyncTrace(asyncContext); + if (trace == null) { + return; + } + + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + // entry scope. + entryAsyncTraceScope(trace); + + try { + // trace event for default & async + final SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT_INTERNAL); + recorder.recordApi(methodDescriptor); + } catch (Throwable t) { + if (logger.isWarnEnabled()) { + logger.warn("BEFORE error.", t); + } + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (!validate(target, args)) { + return; + } + final AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(args[1]); + if (asyncContext == null) { + return; + } + + final Trace trace = asyncContext.currentAsyncTraceObject(); + if (trace == null) { + return; + } + + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + // leave scope + if (!leaveAsyncTraceScope(trace)) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to leave scope of async trace {}.", trace); + } + // delete unstable trace + deleteAsyncContext(trace, asyncContext); + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + if (throwable != null) { + recorder.recordException(throwable); + } + } catch (Throwable t) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER error.", t); + } + } finally { + trace.traceBlockEnd(); + if (isAsyncTraceDestination(trace)) { + deleteAsyncContext(trace, asyncContext); + } + } + } + + private boolean validate(Object target, Object[] args) { + if (!(target instanceof Consumer)) { + return false; + } + if (args == null || args.length < 2) { + return false; + } + if (!(args[1] instanceof Envelope)) { + return false; + } + if (!(args[1] instanceof AsyncContextAccessor)) { + if (isDebug) { + logger.debug("Invalid args[1] object. Need accessor({}).", AsyncContextAccessor.class.getName()); + } + return false; + } + return true; + } + + private Trace getAsyncTrace(AsyncContext asyncContext) { + final Trace trace = asyncContext.continueAsyncTraceObject(); + if (trace == null) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to continue async trace. 'result is null'"); + } + return null; + } + if (isDebug) { + logger.debug("getAsyncTrace() trace {}, asyncContext={}", trace, asyncContext); + } + return trace; + } + + private void deleteAsyncContext(Trace trace, AsyncContext asyncContext) { + if (isDebug) { + logger.debug("Delete async trace {}.", trace); + } + trace.close(); + asyncContext.close(); + } + + private void entryAsyncTraceScope(final Trace trace) { + final TraceScope scope = trace.getScope(ASYNC_TRACE_SCOPE); + if (scope != null) { + scope.tryEnter(); + } + } + + private boolean leaveAsyncTraceScope(final Trace trace) { + final TraceScope scope = trace.getScope(ASYNC_TRACE_SCOPE); + if (scope != null) { + if (scope.canLeave()) { + scope.leave(); + } else { + return false; + } + } + return true; + } + + private boolean isAsyncTraceDestination(final Trace trace) { + if (!trace.isAsync()) { + return false; + } + final TraceScope scope = trace.getScope(ASYNC_TRACE_SCOPE); + return scope != null && !scope.isActive(); + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/DeliveryConstructInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/DeliveryConstructInterceptor.java new file mode 100644 index 000000000000..a5a691f93440 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/DeliveryConstructInterceptor.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; + +/** + * @author HyunGil Jeong + */ +public class DeliveryConstructInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + public DeliveryConstructInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + // do nothing + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT_INTERNAL); + recorder.recordApi(methodDescriptor); + recorder.recordException(throwable); + + if (target instanceof AsyncContextAccessor) { + AsyncContext asyncContext = recorder.recordNextAsyncContext(); + ((AsyncContextAccessor) target)._$PINPOINT$_setAsyncContext(asyncContext); + } + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/QueueingConsumerHandleInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/QueueingConsumerHandleInterceptor.java new file mode 100644 index 000000000000..9be14938a630 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/QueueingConsumerHandleInterceptor.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; + +/** + * @author HyunGil Jeong + */ +public class QueueingConsumerHandleInterceptor implements AroundInterceptor { + + @Override + public void before(Object target, Object[] args) { + // do nothing + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (args == null || args.length < 1) { + return; + } + if (!(args[0] instanceof AsyncContextAccessor)) { + return; + } + if (!(result instanceof AsyncContextAccessor)) { + return; + } + AsyncContext asyncContext = ((AsyncContextAccessor) args[0])._$PINPOINT$_getAsyncContext(); + ((AsyncContextAccessor) result)._$PINPOINT$_setAsyncContext(asyncContext); + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/QueueingConsumerOnNextInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/QueueingConsumerOnNextInterceptor.java new file mode 100644 index 000000000000..2f7ff6fe4627 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/QueueingConsumerOnNextInterceptor.java @@ -0,0 +1,64 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; + +/** + * @author HyunGil Jeong + */ +public class QueueingConsumerOnNextInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + + public QueueingConsumerOnNextInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + // These methods may be polled, producing a lot of garbage log. + // Instead, only log when the method is actually traced. + @Override + protected void logBeforeInterceptor(Object target, Object[] args) { + } + + @Override + public void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + if (isDebug) { + super.logBeforeInterceptor(target, args); + } + } + + // These methods may be polled, producing a lot of garbage log. + // Instead, only log when the method is actually traced. + @Override + protected void logAfterInterceptor(Object target, Object[] args, Object result, Throwable throwable) { + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + super.logAfterInterceptor(target, args, result, throwable); + } + recorder.recordServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT_INTERNAL); + recorder.recordApi(getMethodDescriptor()); + if (throwable != null) { + recorder.recordException(throwable); + } + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/RabbitMQConsumerDispatchInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/RabbitMQConsumerDispatchInterceptor.java new file mode 100644 index 000000000000..6089e1d94757 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/RabbitMQConsumerDispatchInterceptor.java @@ -0,0 +1,270 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanId; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.util.NumberUtils; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.MapUtils; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientPluginConfig; +import com.navercorp.pinpoint.plugin.rabbitmq.client.descriptor.RabbitMQConsumerEntryMethodDescriptor; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.LocalAddressAccessor; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.RemoteAddressAccessor; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.getter.ChannelGetter; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.Envelope; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.FrameHandler; + +import java.util.Collections; +import java.util.Map; + +/** + * Consumer entry point interceptor for basic deliveries where messages will be delivered to a Consumer. + * + * @author Jinkai.Ma + * @author Jiaqi Feng + * @author HyunGil Jeong + */ +public class RabbitMQConsumerDispatchInterceptor implements AroundInterceptor { + + private static final RabbitMQConsumerEntryMethodDescriptor CONSUMER_ENTRY_METHOD_DESCRIPTOR = new RabbitMQConsumerEntryMethodDescriptor(); + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final MethodDescriptor methodDescriptor; + private final Filter excludeExchangeFilter; + + public RabbitMQConsumerDispatchInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, Filter excludeExchangeFilter) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; + this.excludeExchangeFilter = excludeExchangeFilter; + this.traceContext.cacheApi(CONSUMER_ENTRY_METHOD_DESCRIPTOR); + } + + @Override + public void before(Object target, Object[] args) { + if (!validate(target, args)) { + return; + } + if (isDebug) { + logger.beforeInterceptor(target, args); + } + try { + final Trace trace = createTrace(target, args); + if (trace == null) { + return; + } + if (!trace.canSampled()) { + return; + } + SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT_INTERNAL); + // args[2] would be com.rabbitmq.client.Envelope, implementing AsyncContextAccessor via plugin + if (args[2] instanceof AsyncContextAccessor) { + AsyncContext asyncContext = recorder.recordNextAsyncContext(); + ((AsyncContextAccessor) args[2])._$PINPOINT$_setAsyncContext(asyncContext); + } + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("BEFORE. Caused:{}", th.getMessage(), th); + } + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (!validate(target, args)) { + return; + } + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + final Trace trace = traceContext.currentRawTraceObject(); + if (trace == null) { + return; + } + if (!trace.canSampled()) { + traceContext.removeTraceObject(); + return; + } + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(methodDescriptor); + if (throwable != null) { + recorder.recordException(throwable); + } + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER. Caused:{}", th.getMessage(), th); + } + } finally { + traceContext.removeTraceObject(); + trace.traceBlockEnd(); + trace.close(); + } + } + + private Trace createTrace(Object target, Object[] args) { + final Channel channel = ((ChannelGetter) target)._$PINPOINT$_getChannel(); + if (channel == null) { + logger.debug("channel is null, skipping trace"); + return null; + } + final Connection connection = channel.getConnection(); + if (connection == null) { + logger.debug("connection is null, skipping trace"); + return null; + } + + Envelope envelope = (Envelope) args[2]; + String exchange = envelope.getExchange(); + if (RabbitMQClientPluginConfig.isExchangeExcluded(exchange, excludeExchangeFilter)) { + if (isDebug) { + logger.debug("exchange {} is excluded", exchange); + } + return null; + } + + // args[3] may be null + AMQP.BasicProperties properties = (AMQP.BasicProperties) args[3]; + Map headers = getHeadersFromBasicProperties(properties); + + // If this transaction is not traceable, mark as disabled. + if (headers.get(RabbitMQClientConstants.META_SAMPLED) != null) { + return traceContext.disableSampling(); + } + + final TraceId traceId = populateTraceIdFromRequest(headers); + // If there's no trasanction id, a new trasaction begins here. + final Trace trace = traceId == null ? traceContext.newTraceObject() : traceContext.continueTraceObject(traceId); + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + recordRootSpan(recorder, connection, envelope, headers); + } + return trace; + } + + private Map getHeadersFromBasicProperties(AMQP.BasicProperties properties) { + if (properties == null) { + return Collections.emptyMap(); + } + Map headers = properties.getHeaders(); + if (headers == null) { + return Collections.emptyMap(); + } + return headers; + } + + private TraceId populateTraceIdFromRequest(Map headers) { + Object transactionId = headers.get(RabbitMQClientConstants.META_TRACE_ID); + if (transactionId == null) { + return null; + } + long parentSpanId = NumberUtils.parseLong(headers.get(RabbitMQClientConstants.META_PARENT_SPAN_ID).toString(), SpanId.NULL); + long spanId = NumberUtils.parseLong(headers.get(RabbitMQClientConstants.META_SPAN_ID).toString(), SpanId.NULL); + short flags = NumberUtils.parseShort(headers.get(RabbitMQClientConstants.META_FLAGS).toString(), (short) 0); + return traceContext.createTraceId(transactionId.toString(), parentSpanId, spanId, flags); + } + + private void recordRootSpan(SpanRecorder recorder, Connection connection, Envelope envelope, Map headers) { + recorder.recordServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT); + recorder.recordApi(CONSUMER_ENTRY_METHOD_DESCRIPTOR); + + String endPoint = RabbitMQClientConstants.UNKNOWN; + String remoteAddress = RabbitMQClientConstants.UNKNOWN; + if (connection instanceof AMQConnection) { + AMQConnection amqConnection = (AMQConnection) connection; + FrameHandler frameHandler = amqConnection.getFrameHandler(); + // Endpoint should be the local socket address of the consumer. + if (frameHandler instanceof LocalAddressAccessor) { + endPoint = ((LocalAddressAccessor) frameHandler)._$PINPOINT$_getLocalAddress(); + } + // Remote address is the socket address of where the consumer is connected to. + if (frameHandler instanceof RemoteAddressAccessor) { + remoteAddress = ((RemoteAddressAccessor) frameHandler)._$PINPOINT$_getRemoteAddress(); + } + } + recorder.recordEndPoint(endPoint); + recorder.recordRemoteAddress(remoteAddress); + + String exchange = envelope.getExchange(); + if (StringUtils.isEmpty(exchange)) { + exchange = RabbitMQClientConstants.UNKNOWN; + } + recorder.recordRpcName("rabbitmq://exchange=" + exchange); + recorder.recordAcceptorHost("exchange-" + exchange); + if (isDebug) { + logger.debug("endPoint={}->{}", envelope.getExchange(), exchange); + } + recorder.recordAttribute(RabbitMQClientConstants.RABBITMQ_ROUTINGKEY_ANNOTATION_KEY, envelope.getRoutingKey()); + + if (!MapUtils.isEmpty(headers)) { + Object parentApplicationName = headers.get(RabbitMQClientConstants.META_PARENT_APPLICATION_NAME); + if (!recorder.isRoot() && parentApplicationName != null) { + Object parentApplicationType = headers.get(RabbitMQClientConstants.META_PARENT_APPLICATION_TYPE); + recorder.recordParentApplication(parentApplicationName.toString(), NumberUtils.parseShort(parentApplicationType.toString(), ServiceType.UNDEFINED.getCode())); + } + } + } + + private boolean validate(Object target, Object[] args) { + if (args == null || args.length < 4) { + return false; + } + if (!(target instanceof ChannelGetter)) { + if (isDebug) { + logger.debug("Invalid target object. Need field accessor({}).", ChannelGetter.class.getName()); + } + return false; + } + if (!(args[2] instanceof Envelope)) { + if (isDebug) { + String args2 = args[2] == null ? "null" : args[2].getClass().getName(); + logger.debug("Expected args[2] to be an instance of {}, but was {}", Envelope.class.getName(), args2); + } + return false; + } + // args[3] may be null + if (args[3] != null && !(args[3] instanceof AMQP.BasicProperties)) { + if (isDebug) { + String args3 = args[3].getClass().getName(); + logger.debug("Expected args[3] to be an instance of {}, but was {}", AMQP.BasicProperties.class.getName(), args3); + } + return false; + } + return true; + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/RabbitMQConsumerHandleCompleteInboundCommandInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/RabbitMQConsumerHandleCompleteInboundCommandInterceptor.java new file mode 100644 index 000000000000..7686d12b6fbb --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/RabbitMQConsumerHandleCompleteInboundCommandInterceptor.java @@ -0,0 +1,258 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanId; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.util.NumberUtils; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.MapUtils; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientPluginConfig; +import com.navercorp.pinpoint.plugin.rabbitmq.client.descriptor.RabbitMQConsumerEntryMethodDescriptor; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.LocalAddressAccessor; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.RemoteAddressAccessor; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.impl.AMQChannel; +import com.rabbitmq.client.impl.AMQCommand; +import com.rabbitmq.client.impl.AMQConnection; +import com.rabbitmq.client.impl.AMQContentHeader; +import com.rabbitmq.client.impl.FrameHandler; +import com.rabbitmq.client.impl.Method; + +import java.util.Collections; +import java.util.Map; + +/** + * Consumer entry point interceptor for basic.get-ok. + * The interception point does feel a bit forced and could use some improvment if possible. + * + * @author HyunGil Jeong + */ +public class RabbitMQConsumerHandleCompleteInboundCommandInterceptor implements AroundInterceptor { + + private static final RabbitMQConsumerEntryMethodDescriptor CONSUMER_ENTRY_METHOD_DESCRIPTOR = new RabbitMQConsumerEntryMethodDescriptor(); + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final MethodDescriptor methodDescriptor; + private final Filter excludeExchangeFilter; + + public RabbitMQConsumerHandleCompleteInboundCommandInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, Filter excludeExchangeFilter) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; + this.excludeExchangeFilter = excludeExchangeFilter; + this.traceContext.cacheApi(CONSUMER_ENTRY_METHOD_DESCRIPTOR); + } + + @Override + public void before(Object target, Object[] args) { + if (!validate(target, args)) { + return; + } + AMQCommand command = (AMQCommand) args[0]; + Method method = command.getMethod(); + if (!(method instanceof AMQP.Basic.GetOk)) { + return; + } + if (isDebug) { + logger.beforeInterceptor(target, args); + } + try { + AMQChannel channel = (AMQChannel) target; + final Trace trace = createTrace(channel, command); + if (trace == null) { + return; + } + if (!trace.canSampled()) { + return; + } + SpanEventRecorder recorder = trace.traceBlockBegin(); + recorder.recordServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT_INTERNAL); + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("BEFORE. Caused:{}", th.getMessage(), th); + } + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (!validate(target, args)) { + return; + } + AMQCommand command = (AMQCommand) args[0]; + Method method = command.getMethod(); + if (!(method instanceof AMQP.Basic.GetOk)) { + return; + } + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + final Trace trace = traceContext.currentRawTraceObject(); + if (trace == null) { + return; + } + if (!trace.canSampled()) { + traceContext.removeTraceObject(); + } + try { + SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(methodDescriptor); + if (throwable != null) { + recorder.recordException(throwable); + } + } catch (Throwable th) { + if (logger.isWarnEnabled()) { + logger.warn("AFTER. Caused:{}", th.getMessage(), th); + } + } finally { + traceContext.removeTraceObject(); + trace.traceBlockEnd(); + trace.close(); + } + } + + private Trace createTrace(AMQChannel amqChannel, AMQCommand amqCommand) { + AMQConnection connection = amqChannel.getConnection(); + if (connection == null) { + logger.debug("connection is null, skipping trace"); + } + + Method method = amqCommand.getMethod(); + AMQP.Basic.GetOk getOk = (AMQP.Basic.GetOk) method; + String exchange = getOk.getExchange(); + if (RabbitMQClientPluginConfig.isExchangeExcluded(exchange, excludeExchangeFilter)) { + if (isDebug) { + logger.debug("exchange {} is excluded", exchange); + } + return null; + } + String routingKey = getOk.getRoutingKey(); + + Map headers = getHeadersFromContentHeader(amqCommand.getContentHeader()); + + // If this transaction is not traceable, mark as disabled. + if (headers.get(RabbitMQClientConstants.META_SAMPLED) != null) { + return traceContext.disableSampling(); + } + + final TraceId traceId = populateTraceIdFromRequest(headers); + // If there's no trasanction id, a new trasaction begins here. + final Trace trace = traceId == null ? traceContext.newTraceObject() : traceContext.continueTraceObject(traceId); + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + recordRootSpan(recorder, connection, exchange, routingKey, headers); + } + return trace; + } + + private Map getHeadersFromContentHeader(AMQContentHeader amqContentHeader) { + if (!(amqContentHeader instanceof AMQP.BasicProperties)) { + return Collections.emptyMap(); + } + AMQP.BasicProperties properties = (AMQP.BasicProperties) amqContentHeader; + Map headers = properties.getHeaders(); + if (headers == null) { + return Collections.emptyMap(); + } + return headers; + } + + private TraceId populateTraceIdFromRequest(Map headers) { + Object transactionId = headers.get(RabbitMQClientConstants.META_TRACE_ID); + if (transactionId == null) { + return null; + } + long parentSpanId = NumberUtils.parseLong(headers.get(RabbitMQClientConstants.META_PARENT_SPAN_ID).toString(), SpanId.NULL); + long spanId = NumberUtils.parseLong(headers.get(RabbitMQClientConstants.META_SPAN_ID).toString(), SpanId.NULL); + short flags = NumberUtils.parseShort(headers.get(RabbitMQClientConstants.META_FLAGS).toString(), (short) 0); + return traceContext.createTraceId(transactionId.toString(), parentSpanId, spanId, flags); + } + + private void recordRootSpan(SpanRecorder recorder, AMQConnection amqConnection, String exchange, String routingKey, Map headers) { + recorder.recordServiceType(RabbitMQClientConstants.RABBITMQ_CLIENT); + recorder.recordApi(CONSUMER_ENTRY_METHOD_DESCRIPTOR); + + String endPoint = RabbitMQClientConstants.UNKNOWN; + String remoteAddress = RabbitMQClientConstants.UNKNOWN; + if (amqConnection != null) { + FrameHandler frameHandler = amqConnection.getFrameHandler(); + // Endpoint should be the local socket address of the consumer. + if (frameHandler instanceof LocalAddressAccessor) { + endPoint = ((LocalAddressAccessor) frameHandler)._$PINPOINT$_getLocalAddress(); + } + // Remote address is the socket address of where the consumer is connected to. + if (frameHandler instanceof RemoteAddressAccessor) { + remoteAddress = ((RemoteAddressAccessor) frameHandler)._$PINPOINT$_getRemoteAddress(); + } + } + recorder.recordEndPoint(endPoint); + recorder.recordRemoteAddress(remoteAddress); + + String convertedExchange = exchange; + if (StringUtils.isEmpty(convertedExchange)) { + convertedExchange = RabbitMQClientConstants.UNKNOWN; + } + recorder.recordRpcName("rabbitmq://exchange=" + convertedExchange); + recorder.recordAcceptorHost("exchange-" + convertedExchange); + if (isDebug) { + logger.debug("endPoint={}->{}", exchange, convertedExchange); + } + recorder.recordAttribute(RabbitMQClientConstants.RABBITMQ_ROUTINGKEY_ANNOTATION_KEY, routingKey); + + if (!MapUtils.isEmpty(headers)) { + Object parentApplicationName = headers.get(RabbitMQClientConstants.META_PARENT_APPLICATION_NAME); + if (!recorder.isRoot() && parentApplicationName != null) { + Object parentApplicationType = headers.get(RabbitMQClientConstants.META_PARENT_APPLICATION_TYPE); + recorder.recordParentApplication(parentApplicationName.toString(), NumberUtils.parseShort(parentApplicationType.toString(), ServiceType.UNDEFINED.getCode())); + } + } + } + + private boolean validate(Object target, Object[] args) { + if (args == null || args.length < 1) { + return false; + } + if (!(target instanceof AMQChannel)) { + if (isDebug) { + logger.debug("Expected target to be of type AMQChannel, but was {}", target.getClass().getName()); + } + return false; + } + if (!(args[0] instanceof AMQCommand)) { + if (isDebug) { + String args0 = args[0] == null ? "null" : args[0].getClass().getName(); + logger.debug("Expected args[0] to be of type AMQCommand, but was {}", args0); + } + return false; + } + return true; + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/SocketChannelFrameHandlerConstructInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/SocketChannelFrameHandlerConstructInterceptor.java new file mode 100644 index 000000000000..0e9b849b6392 --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/SocketChannelFrameHandlerConstructInterceptor.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.LocalAddressAccessor; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.RemoteAddressAccessor; +import com.rabbitmq.client.impl.nio.SocketChannelFrameHandler; + +/** + * @author HyunGil Jeong + */ +public class SocketChannelFrameHandlerConstructInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + @Override + public void before(Object target, Object[] args) { + // do nothing + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (!validate(target)) { + return; + } + String localAddress = RabbitMQClientConstants.UNKNOWN; + String remoteAddress = RabbitMQClientConstants.UNKNOWN; + if (target instanceof SocketChannelFrameHandler) { + SocketChannelFrameHandler frameHandler = (SocketChannelFrameHandler) target; + localAddress = HostAndPort.toHostAndPortString(frameHandler.getLocalAddress().getHostAddress(), frameHandler.getLocalPort()); + remoteAddress = HostAndPort.toHostAndPortString(frameHandler.getAddress().getHostAddress(), frameHandler.getPort()); + } + ((LocalAddressAccessor) target)._$PINPOINT$_setLocalAddress(localAddress); + ((RemoteAddressAccessor) target)._$PINPOINT$_setRemoteAddress(remoteAddress); + } + + private boolean validate(Object target) { + if (!(target instanceof LocalAddressAccessor)) { + logger.debug("Invalid target object. Need field accessor({})", LocalAddressAccessor.class.getName()); + return false; + } + if (!(target instanceof RemoteAddressAccessor)) { + logger.debug("Invalid target object. Need field accessor({})", RemoteAddressAccessor.class.getName()); + return false; + } + return true; + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/SocketFrameHandlerConstructInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/SocketFrameHandlerConstructInterceptor.java new file mode 100644 index 000000000000..dbcac722e63f --- /dev/null +++ b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/client/interceptor/SocketFrameHandlerConstructInterceptor.java @@ -0,0 +1,71 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.rabbitmq.client.interceptor; + +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientConstants; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.LocalAddressAccessor; +import com.navercorp.pinpoint.plugin.rabbitmq.client.field.accessor.RemoteAddressAccessor; + +import java.net.Socket; + +/** + * @author HyunGil Jeong + */ +public class SocketFrameHandlerConstructInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + @Override + public void before(Object target, Object[] args) { + // do nothing + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (!validate(target, args)) { + return; + } + String localAddress = RabbitMQClientConstants.UNKNOWN; + String remoteAddress = RabbitMQClientConstants.UNKNOWN; + if (args[0] instanceof Socket) { + Socket socket = (Socket) args[0]; + localAddress = HostAndPort.toHostAndPortString(socket.getLocalAddress().getHostAddress(), socket.getLocalPort()); + remoteAddress = HostAndPort.toHostAndPortString(socket.getInetAddress().getHostAddress(), socket.getPort()); + } + ((LocalAddressAccessor) target)._$PINPOINT$_setLocalAddress(localAddress); + ((RemoteAddressAccessor) target)._$PINPOINT$_setRemoteAddress(remoteAddress); + } + + private boolean validate(Object target, Object[] args) { + if (args == null || args.length < 1) { + return false; + } + if (!(target instanceof LocalAddressAccessor)) { + logger.debug("Invalid target object. Need field accessor({})", LocalAddressAccessor.class.getName()); + return false; + } + if (!(target instanceof RemoteAddressAccessor)) { + logger.debug("Invalid target object. Need field accessor({})", RemoteAddressAccessor.class.getName()); + return false; + } + return true; + } +} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/field/setter/HeadersFieldSetter.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/field/setter/HeadersFieldSetter.java deleted file mode 100644 index ddb6c25bce3e..000000000000 --- a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/field/setter/HeadersFieldSetter.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.navercorp.pinpoint.plugin.rabbitmq.field.setter; - -import java.util.Map; - -/** - * @author Jinkai.Ma - */ -public interface HeadersFieldSetter { - void _$PINPOINT$_setHeaders(Map headers); -} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/interceptor/RabbitMQConsumeInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/interceptor/RabbitMQConsumeInterceptor.java deleted file mode 100644 index cecf0ba82c5e..000000000000 --- a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/interceptor/RabbitMQConsumeInterceptor.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.navercorp.pinpoint.plugin.rabbitmq.interceptor; - -import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.context.*; -import com.navercorp.pinpoint.bootstrap.interceptor.SpanSimpleAroundInterceptor; -import com.navercorp.pinpoint.bootstrap.util.NumberUtils; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.plugin.rabbitmq.RabbitMQClientPluginConfig; -import com.navercorp.pinpoint.plugin.rabbitmq.RabbitMQConstants; -import com.rabbitmq.client.AMQP; -import com.rabbitmq.client.Connection; -import com.rabbitmq.client.DefaultConsumer; -import com.rabbitmq.client.Envelope; - -import java.util.Map; - -/** - * @author Jinkai.Ma - * @author Jiaqi Feng - */ -public class RabbitMQConsumeInterceptor extends SpanSimpleAroundInterceptor { - private final Filter excludeExchangeFilter; - - public RabbitMQConsumeInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { - super(traceContext, descriptor, RabbitMQConsumeInterceptor.class); - - RabbitMQClientPluginConfig rabbitMQClientPluginConfig = new RabbitMQClientPluginConfig(traceContext.getProfilerConfig()); - this.excludeExchangeFilter = rabbitMQClientPluginConfig.getExcludeExchangeFilter(); - } - - @Override - protected Trace createTrace(Object target, Object[] args) { - Envelope envelope = (Envelope) args[1]; - String exchange = envelope.getExchange(); - - if (RabbitMQClientPluginConfig.isExchangeExcluded(exchange, excludeExchangeFilter)) { - if (isDebug) - logger.debug("exchange {} is excluded", exchange); - return null; - } - - AMQP.BasicProperties properties = (AMQP.BasicProperties) args[2]; - Map headers = properties.getHeaders(); - - // If this transaction is not traceable, mark as disabled. - if (headers.get(RabbitMQConstants.META_DO_NOT_TRACE) != null) { - return traceContext.disableSampling(); - } - - Object transactionId = headers.get(RabbitMQConstants.META_TRANSACTION_ID); - // If there's no trasanction id, a new trasaction begins here. - if (transactionId == null) { - return traceContext.newTraceObject(); - } - - // otherwise, continue tracing with given data. - long parentSpanID = NumberUtils.parseLong(headers.get(RabbitMQConstants.META_PARENT_SPAN_ID).toString(), SpanId.NULL); - long spanID = NumberUtils.parseLong(headers.get(RabbitMQConstants.META_SPAN_ID).toString(), SpanId.NULL); - short flags = NumberUtils.parseShort(headers.get(RabbitMQConstants.META_FLAGS).toString(), (short) 0); - TraceId traceId = traceContext.createTraceId(transactionId.toString(), parentSpanID, spanID, flags); - - return traceContext.continueTraceObject(traceId); - } - - - @Override - protected void doInBeforeTrace(SpanRecorder recorder, Object target, Object[] args) { - AMQP.BasicProperties properties = (AMQP.BasicProperties) args[2]; - Map headers = properties.getHeaders(); - Envelope envelope = (Envelope) args[1]; - - String exchange=envelope.getExchange(); - if (exchange == null || exchange.equals("")) - exchange = "unknown"; - - recorder.recordServiceType(RabbitMQConstants.RABBITMQ_SERVICE_TYPE); - recorder.recordEndPoint("exchange:"+exchange); - - if (headers != null) { - Object parentApplicationName = headers.get(RabbitMQConstants.META_PARENT_APPLICATION_NAME); - Object parentApplicationType = headers.get(RabbitMQConstants.META_PARENT_APPLICATION_TYPE); - if (parentApplicationName != null) { - recorder.recordParentApplication(parentApplicationName.toString(), NumberUtils.parseShort(parentApplicationType.toString(), ServiceType.UNDEFINED.getCode())); - } - } - recorder.recordRpcName("rabbitmq://exchange="+exchange); - recorder.recordAcceptorHost("exchange-" + exchange); - if (isDebug) - logger.debug("endPoint=" + envelope.getExchange() + ",=" + exchange); - } - - @Override - protected void doInAfterTrace(SpanRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { - DefaultConsumer consumer = (DefaultConsumer) target; - Connection connection = consumer.getChannel().getConnection(); - Envelope envelope = (Envelope) args[1]; - AMQP.BasicProperties properties = (AMQP.BasicProperties) args[2]; - byte[] body = (byte[]) args[3]; - - String exchange=envelope.getExchange(); - if (exchange == null || exchange.equals("")) - exchange = "unknown"; - - recorder.recordApi(methodDescriptor); - recorder.recordAttribute(RabbitMQConstants.RABBITMQ_ROUTINGKEY_ANNOTATION_KEY, envelope.getRoutingKey()); - recorder.recordRemoteAddress(connection.getAddress().getHostAddress() + ":" + connection.getPort()); - - if (throwable != null) { - recorder.recordException(throwable); - } - } - -} diff --git a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/interceptor/RabbitMQPublishInterceptor.java b/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/interceptor/RabbitMQPublishInterceptor.java deleted file mode 100644 index feb8e91311bc..000000000000 --- a/plugins/rabbitmq/src/main/java/com/navercorp/pinpoint/plugin/rabbitmq/interceptor/RabbitMQPublishInterceptor.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.navercorp.pinpoint.plugin.rabbitmq.interceptor; - -import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.Trace; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; -import com.navercorp.pinpoint.bootstrap.interceptor.annotation.Scope; -import com.navercorp.pinpoint.bootstrap.logging.PLogger; -import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.rabbitmq.RabbitMQClientPluginConfig; -import com.navercorp.pinpoint.plugin.rabbitmq.RabbitMQConstants; -import com.navercorp.pinpoint.plugin.rabbitmq.field.setter.HeadersFieldSetter; -import com.rabbitmq.client.AMQP; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author Jinkai.Ma - * @author Jiaqi Feng - */ -public class RabbitMQPublishInterceptor implements AroundInterceptor { - - private final PLogger logger = PLoggerFactory.getLogger(getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - - private final MethodDescriptor descriptor; - private final TraceContext traceContext; - private final Filter excludeExchangeFilter; - - public RabbitMQPublishInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { - this.descriptor = descriptor; - this.traceContext = traceContext; - - RabbitMQClientPluginConfig rabbitMQClientPluginConfig = new RabbitMQClientPluginConfig(traceContext.getProfilerConfig()); - this.excludeExchangeFilter = rabbitMQClientPluginConfig.getExcludeExchangeFilter(); - } - - @Override - public void before(Object target, Object[] args) { - if (isDebug) { - logger.beforeInterceptor(target, args); - } - - if (!validate(target, args)) { - if (isDebug) - logger.debug("validate argument failed!"); - return; - } - - String exchange = (String) args[0]; - if (RabbitMQClientPluginConfig.isExchangeExcluded(exchange, excludeExchangeFilter)) { - return; - } - - Trace trace = traceContext.currentTraceObject(); - if (trace == null) { - return; - } - AMQP.BasicProperties properties = (AMQP.BasicProperties) args[4]; - Map headers = new HashMap(); - if (properties != null && properties.getHeaders() != null && properties.getHeaders().keySet() != null) { - for (String key : properties.getHeaders().keySet()) { - headers.put(key, properties.getHeaders().get(key)); - } - } - if (trace.canSampled()) { - SpanEventRecorder recorder = trace.traceBlockBegin(); - recorder.recordServiceType(RabbitMQConstants.RABBITMQ_SERVICE_TYPE); - - TraceId nextId = trace.getTraceId().getNextTraceId(); - - recorder.recordNextSpanId(nextId.getSpanId()); - - headers.put(RabbitMQConstants.META_TRANSACTION_ID, nextId.getTransactionId()); - headers.put(RabbitMQConstants.META_SPAN_ID, Long.toString(nextId.getSpanId())); - headers.put(RabbitMQConstants.META_PARENT_SPAN_ID, Long.toString(nextId.getParentSpanId())); - headers.put(RabbitMQConstants.META_PARENT_APPLICATION_TYPE, Short.toString(traceContext.getServerTypeCode())); - headers.put(RabbitMQConstants.META_PARENT_APPLICATION_NAME, traceContext.getApplicationName()); - headers.put(RabbitMQConstants.META_FLAGS, Short.toString(nextId.getFlags())); - } else { - headers.put(RabbitMQConstants.META_DO_NOT_TRACE, "1"); - } - - ((HeadersFieldSetter) properties)._$PINPOINT$_setHeaders(headers); - } - - @Override - public void after(Object target, Object[] args, Object result, Throwable throwable) { - if (isDebug) { - logger.afterInterceptor(target, args); - } - - if (!validate(target, args)) { - return; - } - - Trace trace = traceContext.currentTraceObject(); - if (trace == null || !trace.canSampled()) { - return; - } - - try { - String exchange = (String) args[0]; - String routingKey = (String) args[1]; - AMQP.BasicProperties properties = (AMQP.BasicProperties) args[4]; - byte[] body = (byte[]) args[5]; - - if (exchange == null || exchange.equals("")) exchange = "unknown"; - - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordApi(descriptor); - if (throwable == null) { - recorder.recordEndPoint("exchange:"+exchange); - recorder.recordDestinationId("exchange-" + exchange); - - recorder.recordAttribute(RabbitMQConstants.RABBITMQ_EXCHANGE_ANNOTATION_KEY, exchange); - recorder.recordAttribute(RabbitMQConstants.RABBITMQ_ROUTINGKEY_ANNOTATION_KEY, routingKey); - } else { - recorder.recordException(throwable); - } - } finally { - trace.traceBlockEnd(); - } - } - - private boolean validate(Object target, Object[] args) { - if (!(target instanceof com.rabbitmq.client.Channel)) { - return false; - } - if (args == null || args.length < 6) { - return false; - } - if (!(args[0] instanceof String)) { - return false; - } - if (!(args[1] instanceof String)) { - return false; - } - if (!(args[4] instanceof AMQP.BasicProperties)) { - return false; - } - if (!(args[5] instanceof byte[])) { - return false; - } - return true; - } -} diff --git a/plugins/rabbitmq/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/rabbitmq/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin index e7a9aac241a7..84b8920ae842 100644 --- a/plugins/rabbitmq/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin +++ b/plugins/rabbitmq/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -1 +1 @@ -com.navercorp.pinpoint.plugin.rabbitmq.RabbitMQPlugin \ No newline at end of file +com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientPlugin \ No newline at end of file diff --git a/plugins/rabbitmq/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/rabbitmq/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider index 7b37a4919903..5f815d4f6467 100644 --- a/plugins/rabbitmq/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider +++ b/plugins/rabbitmq/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -1 +1 @@ -com.navercorp.pinpoint.plugin.rabbitmq.RabbitMQTraceMetadataProvider \ No newline at end of file +com.navercorp.pinpoint.plugin.rabbitmq.client.RabbitMQClientTraceMetadataProvider \ No newline at end of file diff --git a/plugins/redis/clover.license b/plugins/redis/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/redis/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-redis-plugin @@ -13,9 +13,22 @@ jar - ${env.JAVA_7_HOME} + ${env.JAVA_8_HOME} + ${env.JAVA_8_HOME} + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint @@ -43,5 +56,12 @@ jedis provided + + + io.lettuce + lettuce-core + provided + + diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/LettuceMethodNameFilter.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/LettuceMethodNameFilter.java new file mode 100644 index 000000000000..ff4b9eb48c04 --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/LettuceMethodNameFilter.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.redis; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter; + +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * @author jaehong.kim + */ +public class LettuceMethodNameFilter implements MethodFilter { + + private final Set excludeMethodNames = new HashSet(); + + public LettuceMethodNameFilter() { + this.excludeMethodNames.addAll(Arrays.asList("clone", "equals", "finalize", "getClass", "hashCode", "notify", "notifyAll", "toString", "wait")); + this.excludeMethodNames.addAll(Arrays.asList("dispatch", "getConnection", "setAutoFlushCommands", "setTimeout", "createMono", "createDissolvingFlux")); + } + + @Override + public boolean accept(InstrumentMethod method) { + if (method != null) { + final int modifiers = method.getModifiers(); + // only public. + if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers) || Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + return false; + } + + final String name = method.getName(); + // skip pinpoint and object methods. + if (!name.startsWith("_$PINPOINT$_") && !this.excludeMethodNames.contains(name)) { + return true; + } + } + return false; + } +} diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/AttachEndPointInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/AttachEndPointInterceptor.java deleted file mode 100644 index f7bc89d09634..000000000000 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/AttachEndPointInterceptor.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.redis.interceptor; - -import redis.clients.jedis.Client; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; -import com.navercorp.pinpoint.bootstrap.logging.PLogger; -import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; - -/** - * @author jaehong.kim - */ -public class AttachEndPointInterceptor implements AroundInterceptor { - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - - public AttachEndPointInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { - } - - @Override - public void before(Object target, Object[] args) { - if (isDebug) { - logger.beforeInterceptor(target, args); - } - - try { - if (!validate(target, args)) { - return; - } - - final String endPoint = ((EndPointAccessor) args[0])._$PINPOINT$_getEndPoint(); - if (endPoint != null) { - ((EndPointAccessor) target)._$PINPOINT$_setEndPoint(endPoint); - } - } catch (Throwable t) { - logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); - } - } - - private boolean validate(final Object target, final Object[] args) { - if (args == null || args.length == 0 || args[0] == null) { - if (isDebug) { - logger.debug("Invalid arguments. Null or not found args({}).", args); - } - return false; - } - - if (!(args[0] instanceof Client)) { - if (isDebug) { - logger.debug("Invalid arguments. Expect Client but args[0]({}).", args[0]); - } - return false; - } - - if (!(args[0] instanceof EndPointAccessor)) { - if (isDebug) { - logger.debug("Invalid args[0] object. Need field accessor({}).", EndPointAccessor.class.getName()); - } - return false; - } - - if (!(target instanceof EndPointAccessor)) { - if (isDebug) { - logger.debug("Invalid target object. Need field accessor({}).", EndPointAccessor.class.getName()); - } - return false; - } - - return true; - } - - @Override - public void after(Object target, Object[] args, Object result, Throwable throwable) { - } -} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/JedisMethodNameFilter.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/JedisMethodNameFilter.java similarity index 94% rename from plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/JedisMethodNameFilter.java rename to plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/JedisMethodNameFilter.java index a203b4cd7977..8cd986a9d1e5 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/JedisMethodNameFilter.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/JedisMethodNameFilter.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.navercorp.pinpoint.plugin.redis; +package com.navercorp.pinpoint.plugin.redis.jedis; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter; diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/RedisPlugin.java similarity index 92% rename from plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java rename to plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/RedisPlugin.java index a180a48cdc98..7d21109bf522 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/RedisPlugin.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/RedisPlugin.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.navercorp.pinpoint.plugin.redis; +package com.navercorp.pinpoint.plugin.redis.jedis; import java.lang.reflect.Modifier; import java.security.ProtectionDomain; @@ -31,6 +31,9 @@ import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import com.navercorp.pinpoint.plugin.redis.LettuceMethodNameFilter; +import com.navercorp.pinpoint.plugin.redis.RedisConstants; +import com.navercorp.pinpoint.plugin.redis.RedisPluginConfig; import static com.navercorp.pinpoint.common.util.VarArgs.va; @@ -39,7 +42,7 @@ */ public class RedisPlugin implements ProfilerPlugin, TransformTemplateAware { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); - private final JedisMethodNameFilter methodNameFilter = new JedisMethodNameFilter(); + private final JedisMethodNameFilter jedisMethodNameFilter = new JedisMethodNameFilter(); private TransformTemplate transformTemplate; @Override @@ -161,7 +164,7 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, private void addSetEndPointInterceptor(final InstrumentClass target, final String... parameterTypes) throws InstrumentException { final InstrumentMethod method = target.getConstructor(parameterTypes); if (method != null) { - method.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.SetEndPointInterceptor"); + method.addInterceptor("com.navercorp.pinpoint.plugin.redis.jedis.interceptor.SetEndPointInterceptor"); } } @@ -172,7 +175,7 @@ private void addProtocol() { public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.chain(MethodFilters.name("sendCommand", "read"), MethodFilters.modifierNot(Modifier.PRIVATE)))) { - method.addScopedInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.ProtocolSendCommandAndReadMethodInterceptor", RedisConstants.REDIS_SCOPE, ExecutionPolicy.INTERNAL); + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.redis.jedis.interceptor.ProtocolSendCommandAndReadMethodInterceptor", RedisConstants.REDIS_SCOPE, ExecutionPolicy.INTERNAL); } return target.toBytecode(); @@ -196,12 +199,12 @@ public void handle(InstrumentClass target) throws InstrumentException { final InstrumentMethod setClientMethod = target.getDeclaredMethod("setClient", "redis.clients.jedis.Client"); if (setClientMethod != null) { - setClientMethod.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.AttachEndPointInterceptor"); + setClientMethod.addInterceptor("com.navercorp.pinpoint.plugin.redis.jedis.interceptor.AttachEndPointInterceptor"); } final InstrumentMethod constructor = target.getConstructor("redis.clients.jedis.Client"); if (constructor != null) { - constructor.addInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.AttachEndPointInterceptor"); + constructor.addInterceptor("com.navercorp.pinpoint.plugin.redis.jedis.interceptor.AttachEndPointInterceptor"); } } }); @@ -226,9 +229,9 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, } private void addJedisMethodInterceptor(final InstrumentClass target, final RedisPluginConfig config, final String scope) { - for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.chain(this.methodNameFilter, MethodFilters.modifierNot(MethodFilters.SYNTHETIC)))) { + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.chain(this.jedisMethodNameFilter, MethodFilters.modifierNot(MethodFilters.SYNTHETIC)))) { try { - method.addScopedInterceptor("com.navercorp.pinpoint.plugin.redis.interceptor.JedisMethodInterceptor", va(config.isIo()), scope); + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.redis.jedis.interceptor.JedisMethodInterceptor", va(config.isIo()), scope); } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn("Unsupported method {}", method, e); diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/AttachEndPointInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/AttachEndPointInterceptor.java new file mode 100644 index 000000000000..130d4592b666 --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/AttachEndPointInterceptor.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.redis.jedis.interceptor; + +import redis.clients.jedis.Client; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; + +/** + * @author jaehong.kim + */ +public class AttachEndPointInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + public AttachEndPointInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + try { + if (!validate(target, args)) { + return; + } + + final String endPoint = ((EndPointAccessor) args[0])._$PINPOINT$_getEndPoint(); + if (endPoint != null) { + ((EndPointAccessor) target)._$PINPOINT$_setEndPoint(endPoint); + } + } catch (Throwable t) { + logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); + } + } + + private boolean validate(final Object target, final Object[] args) { + if (args == null || args.length == 0 || args[0] == null) { + if (isDebug) { + logger.debug("Invalid arguments. Null or not found args({}).", args); + } + return false; + } + + if (!(args[0] instanceof Client)) { + if (isDebug) { + logger.debug("Invalid arguments. Expect Client but args[0]({}).", args[0]); + } + return false; + } + + if (!(args[0] instanceof EndPointAccessor)) { + if (isDebug) { + logger.debug("Invalid args[0] object. Need field accessor({}).", EndPointAccessor.class.getName()); + } + return false; + } + + if (!(target instanceof EndPointAccessor)) { + if (isDebug) { + logger.debug("Invalid target object. Need field accessor({}).", EndPointAccessor.class.getName()); + } + return false; + } + + return true; + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + } +} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisMethodInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/JedisMethodInterceptor.java similarity index 96% rename from plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisMethodInterceptor.java rename to plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/JedisMethodInterceptor.java index d1727d6d22ad..50d89f48d93b 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/JedisMethodInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/JedisMethodInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.navercorp.pinpoint.plugin.redis.interceptor; +package com.navercorp.pinpoint.plugin.redis.jedis.interceptor; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java similarity index 96% rename from plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java rename to plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java index 648e59efd177..165613cb116a 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/ProtocolSendCommandAndReadMethodInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.navercorp.pinpoint.plugin.redis.interceptor; +package com.navercorp.pinpoint.plugin.redis.jedis.interceptor; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.Trace; diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/SetEndPointInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/SetEndPointInterceptor.java similarity index 95% rename from plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/SetEndPointInterceptor.java rename to plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/SetEndPointInterceptor.java index 185421761255..6e83673b0889 100644 --- a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/interceptor/SetEndPointInterceptor.java +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/jedis/interceptor/SetEndPointInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.navercorp.pinpoint.plugin.redis.interceptor; +package com.navercorp.pinpoint.plugin.redis.jedis.interceptor; import java.net.URI; diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/LettucePlugin.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/LettucePlugin.java new file mode 100644 index 000000000000..a141a643b7f0 --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/LettucePlugin.java @@ -0,0 +1,176 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.redis.lettuce; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import com.navercorp.pinpoint.plugin.redis.LettuceMethodNameFilter; +import com.navercorp.pinpoint.plugin.redis.RedisConstants; +import com.navercorp.pinpoint.plugin.redis.RedisPluginConfig; + +import java.security.ProtectionDomain; + +import static com.navercorp.pinpoint.common.util.VarArgs.va; + +/** + * @author jaehong.kim + */ +public class LettucePlugin implements ProfilerPlugin, TransformTemplateAware { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final LettuceMethodNameFilter lettuceMethodNameFilter = new LettuceMethodNameFilter(); + private TransformTemplate transformTemplate; + + @Override + public void setup(ProfilerPluginSetupContext context) { + final RedisPluginConfig config = new RedisPluginConfig(context.getConfig()); + if (!config.isEnable()) { + if (logger.isInfoEnabled()) { + logger.info("Disable RedisPlugin."); + } + return; + } + if (logger.isInfoEnabled()) { + logger.info("Enable RedisPlugin. version range=[5.0.0.RELEASE, 5.1.2.RELEASE]"); + } + + // Set endpoint + addRedisClient(); + + // Attach endpoint + addDefaultConnectionFuture(); + addStatefulRedisConnection(); + + // Commands + addRedisCommands(config); + } + + private void addRedisClient() { + transformTemplate.transform("io.lettuce.core.RedisClient", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(RedisConstants.END_POINT_ACCESSOR); + + // Set endpoint + final InstrumentMethod constructor = target.getConstructor("io.lettuce.core.resource.ClientResources", "io.lettuce.core.RedisURI"); + if (constructor != null) { + constructor.addInterceptor("com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.RedisClientConstructorInterceptor"); + } + + // Attach endpoint + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("connect", "connectAsync", "connectPubSub", "connectPubSubAsync", "connectSentinel", "connectSentinelAsync"))) { + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.AttachEndPointInterceptor", RedisConstants.REDIS_SCOPE); + } + + return target.toBytecode(); + } + }); + } + + private void addDefaultConnectionFuture() { + transformTemplate.transform("io.lettuce.core.DefaultConnectionFuture", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(RedisConstants.END_POINT_ACCESSOR); + + // Attach endpoint + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("get", "join"))) { + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.AttachEndPointInterceptor", RedisConstants.REDIS_SCOPE); + } + + return target.toBytecode(); + } + }); + } + + private void addStatefulRedisConnection() { + addStatefulRedisConnection("io.lettuce.core.StatefulRedisConnectionImpl"); + addStatefulRedisConnection("io.lettuce.core.pubsub.StatefulRedisPubSubConnectionImpl"); + addStatefulRedisConnection("io.lettuce.core.pubsub.StatefulRedisClusterPubSubConnectionImpl"); + addStatefulRedisConnection("io.lettuce.core.masterslave.StatefulRedisMasterSlaveConnectionImpl"); + addStatefulRedisConnection("io.lettuce.core.sentinel.StatefulRedisSentinelConnectionImpl"); + } + + private void addStatefulRedisConnection(final String className) { + transformTemplate.transform(className, new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(RedisConstants.END_POINT_ACCESSOR); + return target.toBytecode(); + } + }); + } + + private void addRedisCommands(final RedisPluginConfig config) { + // Commands + addAbstractRedisCommands("io.lettuce.core.AbstractRedisAsyncCommands", true, config); + + addAbstractRedisCommands("io.lettuce.core.RedisAsyncCommandsImpl", false, config); + addAbstractRedisCommands("io.lettuce.core.cluster.RedisAdvancedClusterAsyncCommandsImpl", false, config); + addAbstractRedisCommands("io.lettuce.core.cluster.RedisClusterPubSubAsyncCommandsImpl", false, config); + addAbstractRedisCommands("io.lettuce.core.pubsub.RedisPubSubAsyncCommandsImpl", false, config); + + // Reactive + addAbstractRedisCommands("io.lettuce.core.AbstractRedisReactiveCommands", true, config); + + addAbstractRedisCommands("io.lettuce.core.cluster.RedisAdvancedClusterReactiveCommandsImpl", false, config); + addAbstractRedisCommands("io.lettuce.core.cluster.RedisClusterPubSubReactiveCommandsImpl", false, config); + addAbstractRedisCommands("io.lettuce.core.pubsub.RedisPubSubReactiveCommandsImpl", false, config); + addAbstractRedisCommands("io.lettuce.core.RedisReactiveCommandsImpl", false, config); + addAbstractRedisCommands("io.lettuce.core.sentinel.RedisSentinelReactiveCommandsImpl", false, config); + } + + private void addAbstractRedisCommands(final String className, final boolean getter, final RedisPluginConfig config) { + transformTemplate.transform(className, new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + if (getter) { + target.addGetter("com.navercorp.pinpoint.plugin.redis.lettuce.StatefulConnectionGetter", "connection"); + } + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.chain(lettuceMethodNameFilter, MethodFilters.modifierNot(MethodFilters.SYNTHETIC)))) { + try { + method.addScopedInterceptor("com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.LettuceMethodInterceptor", va(config.isIo()), RedisConstants.REDIS_SCOPE); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Unsupported method {}", method, e); + } + } + } + return target.toBytecode(); + } + }); + } + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } +} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/StatefulConnectionGetter.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/StatefulConnectionGetter.java new file mode 100644 index 000000000000..94f06b55bcc5 --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/StatefulConnectionGetter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.redis.lettuce; + +import io.lettuce.core.api.StatefulConnection; + +/** + * @author jaehong.kim + */ +public interface StatefulConnectionGetter { + StatefulConnection _$PINPOINT$_getConnection(); +} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/AttachEndPointInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/AttachEndPointInterceptor.java new file mode 100644 index 000000000000..f2b0192253f8 --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/AttachEndPointInterceptor.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.redis.lettuce.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; + +/** + * @author jaehong.kim + */ +public class AttachEndPointInterceptor implements AroundInterceptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final TraceContext traceContext; + private final MethodDescriptor methodDescriptor; + + public AttachEndPointInterceptor(final TraceContext traceContext, final MethodDescriptor methodDescriptor) { + this.traceContext = traceContext; + this.methodDescriptor = methodDescriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + try { + if (!validate(target, result)) { + return; + } + + final String endPoint = ((EndPointAccessor) target)._$PINPOINT$_getEndPoint(); + ((EndPointAccessor) result)._$PINPOINT$_setEndPoint(endPoint); + } catch (Throwable t) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to AFTER process. {}", t.getMessage(), t); + } + } + } + + private boolean validate(final Object target, final Object result) { + if (!(target instanceof EndPointAccessor)) { + if (isDebug) { + logger.debug("Invalid target object. Need field accessor={}, target={}", EndPointAccessor.class.getName(), target); + } + return false; + } + + if (!(result instanceof EndPointAccessor)) { + if (isDebug) { + logger.debug("Invalid result object. Need field accessor={}, result={}", EndPointAccessor.class.getName(), result); + } + return false; + } + return true; + } +} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/LettuceMethodInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/LettuceMethodInterceptor.java new file mode 100644 index 000000000000..2fa643bbe198 --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/LettuceMethodInterceptor.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.redis.lettuce.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin; +import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; +import com.navercorp.pinpoint.plugin.redis.RedisConstants; +import com.navercorp.pinpoint.plugin.redis.lettuce.StatefulConnectionGetter; + +/** + * @author jaehong.kim + */ +public class LettuceMethodInterceptor extends SpanEventSimpleAroundInterceptorForPlugin { + private InterceptorScope interceptorScope; + private boolean io; + + public LettuceMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorScope interceptorScope, boolean io) { + super(traceContext, methodDescriptor); + this.interceptorScope = interceptorScope; + this.io = io; + } + + @Override + public void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args) { + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + final String endPoint = toEndPoint(target); + recorder.recordApi(getMethodDescriptor()); + recorder.recordEndPoint(endPoint != null ? endPoint : "Unknown"); + recorder.recordDestinationId(RedisConstants.REDIS.getName()); + recorder.recordServiceType(RedisConstants.REDIS); + recorder.recordException(throwable); + } + + private String toEndPoint(final Object target) { + if (!(target instanceof StatefulConnectionGetter)) { + return null; + } + + final Object connection = ((StatefulConnectionGetter) target)._$PINPOINT$_getConnection(); + if (!(connection instanceof EndPointAccessor)) { + return null; + } + + return ((EndPointAccessor) connection)._$PINPOINT$_getEndPoint(); + } +} \ No newline at end of file diff --git a/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RedisClientConstructorInterceptor.java b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RedisClientConstructorInterceptor.java new file mode 100644 index 000000000000..2e4f759120d3 --- /dev/null +++ b/plugins/redis/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RedisClientConstructorInterceptor.java @@ -0,0 +1,87 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.redis.lettuce.interceptor; + +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import io.lettuce.core.RedisURI; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.redis.EndPointAccessor; + +/** + * @author jaehong.kim + */ +public class RedisClientConstructorInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + public RedisClientConstructorInterceptor(final TraceContext traceContext, final MethodDescriptor methodDescriptor) { + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + try { + if (!validate(target, args)) { + return; + } + + final RedisURI redisURI = (RedisURI) args[1]; + final String endPoint = HostAndPort.toHostAndPortString(redisURI.getHost(), redisURI.getPort()); + ((EndPointAccessor) target)._$PINPOINT$_setEndPoint(endPoint); + } catch (Throwable t) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); + } + } + } + + private boolean validate(final Object target, final Object[] args) { + if (args == null || args.length < 2 || args[1] == null) { + if (isDebug) { + logger.debug("Invalid arguments. Null or not found args({}).", args); + } + return false; + } + + if (!(target instanceof EndPointAccessor)) { + if (isDebug) { + logger.debug("Invalid target object. Need field accessor({}).", EndPointAccessor.class.getName()); + } + return false; + } + + if (!(args[1] instanceof RedisURI)) { + if (isDebug) { + logger.debug("Invalid args[1] object. args[1]={}", args[1]); + } + return false; + } + return true; + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + } +} \ No newline at end of file diff --git a/plugins/redis/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/redis/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin index e442fa5f2f39..931fb50a4932 100644 --- a/plugins/redis/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin +++ b/plugins/redis/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -1 +1,2 @@ -com.navercorp.pinpoint.plugin.redis.RedisPlugin \ No newline at end of file +com.navercorp.pinpoint.plugin.redis.jedis.RedisPlugin +com.navercorp.pinpoint.plugin.redis.lettuce.LettucePlugin \ No newline at end of file diff --git a/plugins/redis/src/test/java/com/navercorp/pinpoint/plugin/redis/RedisPluginTest.java b/plugins/redis/src/test/java/com/navercorp/pinpoint/plugin/redis/RedisPluginTest.java index 773a48053562..e8b2bba8d3fa 100644 --- a/plugins/redis/src/test/java/com/navercorp/pinpoint/plugin/redis/RedisPluginTest.java +++ b/plugins/redis/src/test/java/com/navercorp/pinpoint/plugin/redis/RedisPluginTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.plugin.redis; import static org.junit.Assert.*; @@ -6,13 +22,13 @@ import java.util.List; +import com.navercorp.pinpoint.profiler.context.SpanEvent; import org.junit.Test; import redis.clients.jedis.Client; import redis.clients.jedis.Jedis; import redis.clients.jedis.Pipeline; -import com.navercorp.pinpoint.common.server.bo.SpanEventBo; import com.navercorp.pinpoint.test.junit4.BasePinpointTest; public class RedisPluginTest extends BasePinpointTest { @@ -26,33 +42,35 @@ public void jedis() { try { jedis.get("foo"); } finally { - if(jedis != null) { - jedis.close(); - } + close(jedis); } - final List events = getCurrentSpanEvents(); + final List events = getCurrentSpanEvents(); assertEquals(1, events.size()); - final SpanEventBo eventBo = events.get(0); + final SpanEvent eventBo = events.get(0); assertEquals(HOST + ":" + PORT, eventBo.getEndPoint()); assertEquals("REDIS", eventBo.getDestinationId()); } - + + public void close(Jedis jedis) { + if (jedis != null) { + jedis.close(); + } + } + @Test public void binaryJedis() { JedisMock jedis = new JedisMock("localhost", 6379); try { jedis.get("foo".getBytes()); } finally { - if(jedis != null) { - jedis.close(); - } + close(jedis); } - final List events = getCurrentSpanEvents(); + final List events = getCurrentSpanEvents(); assertEquals(1, events.size()); - final SpanEventBo eventBo = events.get(0); + final SpanEvent eventBo = events.get(0); assertEquals(HOST + ":" + PORT, eventBo.getEndPoint()); assertEquals("REDIS", eventBo.getDestinationId()); } @@ -65,12 +83,10 @@ public void pipeline() { Pipeline pipeline = jedis.pipelined(); pipeline.get("foo"); } finally { - if(jedis != null) { - jedis.close(); - } + close(jedis); } - final List events = getCurrentSpanEvents(); + final List events = getCurrentSpanEvents(); assertEquals(1, events.size()); } diff --git a/plugins/resin/clover.license b/plugins/resin/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/resin/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 @@ -6,7 +22,7 @@ com.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-resin-plugin @@ -30,6 +46,70 @@ 3.0.9 provided + + + com.navercorp.pinpoint + pinpoint-common-servlet + ${project.version} + compile + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.10 + + + generate-sources + + add-source + + + + src/main/java-resin + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + com/navercorp/**/* + META-INF/**/* + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${plugin.shade.version} + + + package + + shade + + + + + com.navercorp.pinpoint.plugin.common.servlet + com.navercorp.pinpoint.plugin.resin.common.servlet + + + + ${project.build.directory}/dependency-reduced-pom.xml + + + + + + + diff --git a/plugins/resin/src/main/java-resin/com/caucho/server/http/HttpServletRequestImpl.java b/plugins/resin/src/main/java-resin/com/caucho/server/http/HttpServletRequestImpl.java new file mode 100644 index 000000000000..f46fad3f040a --- /dev/null +++ b/plugins/resin/src/main/java-resin/com/caucho/server/http/HttpServletRequestImpl.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.caucho.server.http; +/** + * @author jaehong.kim + */ +public class HttpServletRequestImpl { + // Dummy + public HttpServletResponseImpl getResponse() { + return null; + } +} \ No newline at end of file diff --git a/plugins/resin/src/main/java-resin/com/caucho/server/http/HttpServletResponseImpl.java b/plugins/resin/src/main/java-resin/com/caucho/server/http/HttpServletResponseImpl.java new file mode 100644 index 000000000000..45c2c2101522 --- /dev/null +++ b/plugins/resin/src/main/java-resin/com/caucho/server/http/HttpServletResponseImpl.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.caucho.server.http; + +/** + * @author jaehong.kim + */ +public class HttpServletResponseImpl { + // Dummy + public int getStatus() { + return 0; + } +} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/AsyncAccessor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/AsyncAccessor.java deleted file mode 100644 index b2f4ef01b40b..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/AsyncAccessor.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.navercorp.pinpoint.plugin.resin; - -public interface AsyncAccessor { - void _$PINPOINT$_setAsync(boolean async); - - boolean _$PINPOINT$_isAsync(); -} diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/HttpServletRequestGetter.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/HttpServletRequestGetter.java deleted file mode 100644 index 26f1ae0d3876..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/HttpServletRequestGetter.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.navercorp.pinpoint.plugin.resin; - -import javax.servlet.http.HttpServletRequest; - -public interface HttpServletRequestGetter { - HttpServletRequest _$PINPOINT$_getRequest(); -} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinAsyncListener.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinAsyncListener.java new file mode 100644 index 000000000000..99f9a5276c32 --- /dev/null +++ b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinAsyncListener.java @@ -0,0 +1,122 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.resin; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.AsyncListenerInterceptorHelper; + +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author jaehong.kim + */ +public class ResinAsyncListener implements AsyncListener { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private final AsyncListenerInterceptorHelper asyncListenerInterceptorHelper; + + public ResinAsyncListener(final TraceContext traceContext, final AsyncContext asyncContext) { + this.asyncListenerInterceptorHelper = new AsyncListenerInterceptorHelper(traceContext, asyncContext); + } + + @Override + public void onComplete(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Complete asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + final int statusCode = getStatusCode(asyncEvent); + this.asyncListenerInterceptorHelper.complete(asyncEvent.getThrowable(), statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + } + + @Override + public void onTimeout(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Timeout asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.timeout(asyncEvent.getThrowable()); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onError(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Error asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.error(asyncEvent.getThrowable()); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + } + + @Override + public void onStartAsync(AsyncEvent asyncEvent) throws IOException { + } + + private int getStatusCode(final AsyncEvent asyncEvent) { + try { + if (asyncEvent.getSuppliedResponse() instanceof HttpServletResponse) { + return ((HttpServletResponse) asyncEvent.getSuppliedResponse()).getStatus(); + } + } catch (Exception ignored) { + } + return 0; + } +} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinConfig.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinConfig.java index d8ff702ce1c4..c9f3329747c0 100644 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinConfig.java +++ b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinConfig.java @@ -1,39 +1,31 @@ package com.navercorp.pinpoint.plugin.resin; -import com.navercorp.pinpoint.bootstrap.config.DumpType; import com.navercorp.pinpoint.bootstrap.config.ExcludeMethodFilter; import com.navercorp.pinpoint.bootstrap.config.ExcludePathFilter; import com.navercorp.pinpoint.bootstrap.config.Filter; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; /** - * * @author huangpengjie@fang.com - * */ public class ResinConfig { - private final boolean resinEnable; + private final boolean enable; - private final String resinBootstrapMains; + private final String bootstrapMains; - private final boolean resinHidePinpointHeader; + private final boolean hidePinpointHeader; - private final boolean resinTraceRequestParam; + private final boolean traceRequestParam; - private final Filter resinExcludeUrlFilter; + private final Filter excludeUrlFilter; - private final String resinRealIpHeader; + private final String realIpHeader; - private final String resinRealIpEmptyValue; + private final String realIpEmptyValue; - private final Filter resinExcludeProfileMethodFilter; + private final Filter excludeProfileMethodFilter; - private final boolean isTraceCookies; - - private final int cookieSamplingRate; - - private final DumpType cookieDumpType; public ResinConfig(ProfilerConfig config) { @@ -42,74 +34,73 @@ public ResinConfig(ProfilerConfig config) { } // plugin - this.resinEnable = config.readBoolean("profiler.resin.enable", true); - this.resinBootstrapMains = config.readString("profiler.resin.bootstrap.main", ""); + this.enable = config.readBoolean("profiler.resin.enable", true); + this.bootstrapMains = config.readString("profiler.resin.bootstrap.main", ""); // runtime - this.resinTraceRequestParam = config.readBoolean("profiler.resin.tracerequestparam", true); + this.traceRequestParam = config.readBoolean("profiler.resin.tracerequestparam", true); final String resinExcludeURL = config.readString("profiler.resin.excludeurl", ""); if (!resinExcludeURL.isEmpty()) { - this.resinExcludeUrlFilter = new ExcludePathFilter(resinExcludeURL); + this.excludeUrlFilter = new ExcludePathFilter(resinExcludeURL); } else { - this.resinExcludeUrlFilter = new ExcludePathFilter(""); + this.excludeUrlFilter = new ExcludePathFilter(""); } - this.resinRealIpHeader = config.readString("profiler.resin.realipheader", null); - this.resinRealIpEmptyValue = config.readString("profiler.resin.realipemptyvalue", null); + this.realIpHeader = config.readString("profiler.resin.realipheader", null); + this.realIpEmptyValue = config.readString("profiler.resin.realipemptyvalue", null); final String resinExcludeProfileMethod = config.readString("profiler.resin.excludemethod", ""); if (!resinExcludeProfileMethod.isEmpty()) { - this.resinExcludeProfileMethodFilter = new ExcludeMethodFilter(resinExcludeProfileMethod); + this.excludeProfileMethodFilter = new ExcludeMethodFilter(resinExcludeProfileMethod); } else { - this.resinExcludeProfileMethodFilter = new ExcludeMethodFilter(""); + this.excludeProfileMethodFilter = new ExcludeMethodFilter(""); } - this.resinHidePinpointHeader = config.readBoolean("profiler.resin.hidepinpointheader", true); - this.isTraceCookies = config.readBoolean("profiler.resin.tracecookies", true); - this.cookieSamplingRate = config.readInt("profiler.resin.cookie.sampling.rate", 10); - this.cookieDumpType = config.readDumpType("profiler.resin.cookie.dumptype", DumpType.ALWAYS); - } - - public boolean isResinEnable() { - return resinEnable; + this.hidePinpointHeader = config.readBoolean("profiler.resin.hidepinpointheader", true); } - public String getResinBootstrapMains() { - return resinBootstrapMains; + public boolean isEnable() { + return enable; } - public boolean isResinTraceRequestParam() { - return resinTraceRequestParam; + public String getBootstrapMains() { + return bootstrapMains; } - public Filter getResinExcludeUrlFilter() { - return resinExcludeUrlFilter; + public boolean isTraceRequestParam() { + return traceRequestParam; } - public String getResinRealIpHeader() { - return resinRealIpHeader; + public Filter getExcludeUrlFilter() { + return excludeUrlFilter; } - public String getResinRealIpEmptyValue() { - return resinRealIpEmptyValue; + public String getRealIpHeader() { + return realIpHeader; } - public Filter getResinExcludeProfileMethodFilter() { - return resinExcludeProfileMethodFilter; + public String getRealIpEmptyValue() { + return realIpEmptyValue; } - public boolean isResinHidePinpointHeader() { - return resinHidePinpointHeader; + public Filter getExcludeProfileMethodFilter() { + return excludeProfileMethodFilter; } - public boolean isTraceCookies() { - return isTraceCookies; + public boolean isHidePinpointHeader() { + return hidePinpointHeader; } - public int getCookieSamplingRate() { - return cookieSamplingRate; + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ResinConfig{"); + sb.append("enable=").append(enable); + sb.append(", bootstrapMains='").append(bootstrapMains).append('\''); + sb.append(", hidePinpointHeader=").append(hidePinpointHeader); + sb.append(", traceRequestParam=").append(traceRequestParam); + sb.append(", excludeUrlFilter=").append(excludeUrlFilter); + sb.append(", realIpHeader='").append(realIpHeader).append('\''); + sb.append(", realIpEmptyValue='").append(realIpEmptyValue).append('\''); + sb.append(", excludeProfileMethodFilter=").append(excludeProfileMethodFilter); + sb.append('}'); + return sb.toString(); } - - public DumpType getCookieDumpType() { - return cookieDumpType; - } - } diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinConstants.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinConstants.java index 6c7060f68c90..9bbf1ebcc912 100644 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinConstants.java +++ b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinConstants.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.plugin.resin; import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; @@ -10,18 +26,10 @@ * @author huangpengjie@fang.com * */ -public interface ResinConstants { +public final class ResinConstants { + private ResinConstants() { + } public static final ServiceType RESIN = ServiceTypeFactory.of(1200, "RESIN", RECORD_STATISTICS); public static final ServiceType RESIN_METHOD = ServiceTypeFactory.of(1201, "RESIN_METHOD"); - - public static final String RESIN_SERVLET_SCOPE = "ResinServletScope"; - - public static final String RESIN_SERVLET_ASYNC_SCOPE = "ResinServletAsyncScope"; - - public static final String ASYNC_ACCESSOR = "com.navercorp.pinpoint.plugin.resin.AsyncAccessor"; - public static final String TRACE_ACCESSOR = "com.navercorp.pinpoint.plugin.resin.TraceAccessor"; - - public static final String VERSION_ACCESSOR = "com.navercorp.pinpoint.plugin.resin.VersionAccessor"; - } diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinPlugin.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinPlugin.java index b0642186b901..4f3ebb99b58d 100644 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinPlugin.java +++ b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ResinPlugin.java @@ -1,27 +1,23 @@ package com.navercorp.pinpoint.plugin.resin; -import java.security.ProtectionDomain; - -import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; -import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExecutionPolicy; -import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import java.security.ProtectionDomain; + /** - * * @author huangpengjie@fang.com - * + * @author jaehong.kim */ public class ResinPlugin implements ProfilerPlugin, TransformTemplateAware { @@ -32,65 +28,26 @@ public class ResinPlugin implements ProfilerPlugin, TransformTemplateAware { @Override public void setup(ProfilerPluginSetupContext context) { final ResinConfig config = new ResinConfig(context.getConfig()); - if (logger.isInfoEnabled()) { - logger.info("ResinPlugin config:{}", config); - } - if (!config.isResinEnable()) { + if (!config.isEnable()) { logger.info("ResinPlugin disabled"); return; } + logger.info("ResinPlugin config:{}", config); - ResinDetector resinDetector = new ResinDetector(config.getResinBootstrapMains()); + final ResinDetector resinDetector = new ResinDetector(config.getBootstrapMains()); context.addApplicationTypeDetector(resinDetector); logger.info("Adding Resin transformers"); addTransformers(config); } - private void addTransformers(ResinConfig config) { + private void addTransformers(final ResinConfig config) { + // Dispatch library & Add servlet request listener. Servlet 2.4 addWebApp(); + // Add async listener. Servlet 3.0 + addHttpServletRequestImpl(config); + // Record HTTP status code & Close trace addServletInvocation(); - - // handle async request - addHttpServletRequestImpl(); - addAsyncContextImpl(); - addCauchoRequestWrapper(); - - addErrorPageManager(); - } - - private void addCauchoRequestWrapper() { - transformTemplate.transform("com.caucho.server.http.CauchoRequestWrapper", new TransformCallback() { - - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - - target.addGetter("com.navercorp.pinpoint.plugin.resin.HttpServletRequestGetter", "_request"); - return target.toBytecode(); - } - }); - } - - @Override - public void setTransformTemplate(TransformTemplate transformTemplate) { - this.transformTemplate = transformTemplate; - } - - private void addErrorPageManager() { - transformTemplate.transform("com.caucho.server.webapp.ErrorPageManager", new TransformCallback() { - - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - - InstrumentMethod sendServletErrorMethodEditorBuilder = target.getDeclaredMethod("sendServletError", "java.lang.Throwable", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); - if (sendServletErrorMethodEditorBuilder != null) { - sendServletErrorMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.resin.interceptor.ErrorPageManagerInterceptor"); - } - return target.toBytecode(); - } - }); } private void addWebApp() { @@ -98,83 +55,54 @@ private void addWebApp() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - - InstrumentMethod initMethodEditorBuilder = target.getDeclaredMethod("init"); + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Dispatch library & Add servlet request listener. Servlet 2.4 + final InstrumentMethod initMethodEditorBuilder = target.getDeclaredMethod("init"); if (initMethodEditorBuilder != null) { initMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.resin.interceptor.WebAppInterceptor"); } - return target.toBytecode(); } }); } - private void addServletInvocation() { - transformTemplate.transform("com.caucho.server.dispatch.ServletInvocation", new TransformCallback() { - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - - InterceptorScope scope = instrumentor.getInterceptorScope(ResinConstants.RESIN_SERVLET_SCOPE); - - // trace request. - InstrumentMethod serviceMethodEditorBuilder = target.getDeclaredMethod("service", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); - if (serviceMethodEditorBuilder != null) { - serviceMethodEditorBuilder.addScopedInterceptor("com.navercorp.pinpoint.plugin.resin.interceptor.ServletInvocationInterceptor", scope, ExecutionPolicy.BOUNDARY); - } - - // resin4 isAsyncSupported - InstrumentMethod isAsyncSupportedMethodEditorBuilder = target.getDeclaredMethod("isAsyncSupported"); - if (isAsyncSupportedMethodEditorBuilder != null) { - target.addField(ResinConstants.VERSION_ACCESSOR); - } - - return target.toBytecode(); - } - }); - } - - private void addHttpServletRequestImpl() { + private void addHttpServletRequestImpl(final ResinConfig config) { transformTemplate.transform("com.caucho.server.http.HttpServletRequestImpl", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - - // trace asynchronous process. - InstrumentMethod startAsyncMethodEditor = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + if (config.isHidePinpointHeader()) { + // Hide pinpoint headers + target.weave("com.navercorp.pinpoint.plugin.resin.aspect.HttpServletRequestImplAspect"); + } + // Add async listener. Servlet 3.0 + final InstrumentMethod startAsyncMethodEditor = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); if (startAsyncMethodEditor != null) { - target.addField(ResinConstants.TRACE_ACCESSOR); - target.addField(ResinConstants.ASYNC_ACCESSOR); startAsyncMethodEditor.addInterceptor("com.navercorp.pinpoint.plugin.resin.interceptor.HttpServletRequestImplInterceptor"); } - - // clear request. 4.x - InstrumentMethod finishRequestInvocationMethodEditor = target.getDeclaredMethod("finishRequest"); - if (finishRequestInvocationMethodEditor != null) { - finishRequestInvocationMethodEditor.addInterceptor("com.navercorp.pinpoint.plugin.resin.interceptor.HttpRequestInterceptor"); - } - return target.toBytecode(); } }); } - private void addAsyncContextImpl() { - transformTemplate.transform("com.caucho.server.http.AsyncContextImpl", new TransformCallback() { - + private void addServletInvocation() { + transformTemplate.transform("com.caucho.server.dispatch.ServletInvocation", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - target.addField(AsyncContextAccessor.class.getName()); - for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("dispatch"))) { - method.addScopedInterceptor("com.navercorp.pinpoint.plugin.resin.interceptor.AsyncContextImplDispatchMethodInterceptor", ResinConstants.RESIN_SERVLET_ASYNC_SCOPE); + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Record HTTP status code & Close trace + final InstrumentMethod serviceMethodEditorBuilder = target.getDeclaredMethod("service", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); + if (serviceMethodEditorBuilder != null) { + serviceMethodEditorBuilder.addScopedInterceptor("com.navercorp.pinpoint.plugin.resin.interceptor.ServletInvocationServiceInterceptor", "RESIN_REQUEST", ExecutionPolicy.BOUNDARY); } - return target.toBytecode(); } }); } -} + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } +} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ServletAsyncMethodDescriptor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ServletAsyncMethodDescriptor.java deleted file mode 100644 index a4cfb35ac53e..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ServletAsyncMethodDescriptor.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.resin; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.common.trace.MethodType; - -/** - * - * @author jaehong.kim - * - */ -public class ServletAsyncMethodDescriptor implements MethodDescriptor { - private int apiId = 0; - private int type = MethodType.WEB_REQUEST; - - @Override - public String getMethodName() { - return ""; - } - - @Override - public String getClassName() { - return ""; - } - - @Override - public String[] getParameterTypes() { - return null; - } - - @Override - public String[] getParameterVariableName() { - return null; - } - - @Override - public String getParameterDescriptor() { - return "()"; - } - - @Override - public int getLineNumber() { - return -1; - } - - @Override - public String getFullName() { - return ServletAsyncMethodDescriptor.class.getName(); - } - - @Override - public void setApiId(int apiId) { - this.apiId = apiId; - } - - @Override - public int getApiId() { - return apiId; - } - - @Override - public String getApiDescriptor() { - return "Resin Servlet Asynchronous Process"; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } -} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ServletSyncMethodDescriptor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ServletSyncMethodDescriptor.java deleted file mode 100644 index 75b053df5365..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/ServletSyncMethodDescriptor.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.resin; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.common.trace.MethodType; - -/** - * - * @author jaehong.kim - * - */ -public class ServletSyncMethodDescriptor implements MethodDescriptor { - private int apiId = 0; - private int type = MethodType.WEB_REQUEST; - - @Override - public String getMethodName() { - return ""; - } - - @Override - public String getClassName() { - return ""; - } - - @Override - public String[] getParameterTypes() { - return null; - } - - @Override - public String[] getParameterVariableName() { - return null; - } - - @Override - public String getParameterDescriptor() { - return "()"; - } - - @Override - public int getLineNumber() { - return -1; - } - - @Override - public String getFullName() { - return ServletSyncMethodDescriptor.class.getName(); - } - - @Override - public void setApiId(int apiId) { - this.apiId = apiId; - } - - @Override - public int getApiId() { - return apiId; - } - - @Override - public String getApiDescriptor() { - return "Resin Servlet Process"; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } -} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/TraceAccessor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/TraceAccessor.java deleted file mode 100644 index 811c9c0eeb75..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/TraceAccessor.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.navercorp.pinpoint.plugin.resin; - -import com.navercorp.pinpoint.bootstrap.context.Trace; - -public interface TraceAccessor { - void _$PINPOINT$_setTrace(Trace trace); - - Trace _$PINPOINT$_getTrace(); -} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/VersionAccessor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/VersionAccessor.java deleted file mode 100644 index 1e7b583725e0..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/VersionAccessor.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.navercorp.pinpoint.plugin.resin; - -public interface VersionAccessor { - void _$PINPOINT$_setVersion(String version); - - String _$PINPOINT$_getVersion(); -} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/aspect/HttpServletRequestImplAspect.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/aspect/HttpServletRequestImplAspect.java new file mode 100644 index 000000000000..62bda7d5918e --- /dev/null +++ b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/aspect/HttpServletRequestImplAspect.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.resin.aspect; + +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; +import com.navercorp.pinpoint.common.util.DelegateEnumeration; + +import java.util.Enumeration; + +/** + * @author jaehong.kim + */ +@Aspect +public abstract class HttpServletRequestImplAspect { + @PointCut + public Enumeration getHeaderNames() { + return new DelegateEnumeration(__getHeaderNames(), Header.FILTER); + } + + @JointPoint + abstract Enumeration __getHeaderNames(); +} diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/AsyncContextImplDispatchMethodInterceptor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/AsyncContextImplDispatchMethodInterceptor.java deleted file mode 100644 index 9c45b3bfc328..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/AsyncContextImplDispatchMethodInterceptor.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.resin.interceptor; - -import com.navercorp.pinpoint.bootstrap.context.AsyncContext; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.interceptor.AsyncContextSpanEventSimpleAroundInterceptor; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.plugin.resin.ResinConstants; - -/** - * - * @author jaehong.kim - * - */ -public class AsyncContextImplDispatchMethodInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor { - - public AsyncContextImplDispatchMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { - super(traceContext, methodDescriptor); - } - - @Override - protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { - recorder.recordServiceType(ResinConstants.RESIN_METHOD); - recorder.recordTime(isDebug); - } - - @Override - protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { - recorder.recordApi(methodDescriptor); - recorder.recordException(throwable); - if (throwable != null) { - if (throwable instanceof IllegalStateException) { - recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, 503); - } else { - recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, 500); - } - } - } -} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/ErrorPageManagerInterceptor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/ErrorPageManagerInterceptor.java deleted file mode 100644 index 75282afcff13..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/ErrorPageManagerInterceptor.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.navercorp.pinpoint.plugin.resin.interceptor; - -import javax.servlet.DispatcherType; -import javax.servlet.http.HttpServletRequest; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.Trace; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; -import com.navercorp.pinpoint.bootstrap.logging.PLogger; -import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.resin.TraceAccessor; - -/** - * - * @author huangpengjie@fang.com - * - */ -public class ErrorPageManagerInterceptor implements AroundInterceptor { - - private PLogger logger = PLoggerFactory.getLogger(this.getClass()); - private boolean isDebug = logger.isDebugEnabled(); - - private TraceContext traceContext; - private MethodDescriptor methodDescriptor; - - public ErrorPageManagerInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { - super(); - this.traceContext = traceContext; - this.methodDescriptor = methodDescriptor; - } - - @Override - public void before(Object target, Object[] args) { - - } - - @Override - public void after(Object target, Object[] args, Object result, Throwable throwable) { - if (isDebug) { - logger.afterInterceptor(target, args, result, throwable); - } - - final Trace trace = traceContext.currentRawTraceObject(); - if (trace == null) { - return; - } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - traceContext.removeTraceObject(); - return; - } - final Exception exception = (Exception) args[0]; - try { - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - - recorder.recordApi(methodDescriptor); - recorder.recordException(exception); - } catch (Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("AFTER. Caused:{}", th.getMessage(), th); - } - } finally { - traceContext.removeTraceObject(); - deleteTrace(trace, target, args, result, throwable); - } - } - - private void deleteTrace(Trace trace, Object target, Object[] args, Object result, Throwable throwable) { - trace.traceBlockEnd(); - - final HttpServletRequest request = (HttpServletRequest) args[1]; - if (!isAsynchronousProcess(request)) { - trace.close(); - // reset - setTraceMetadata(request, null); - } - } - - private boolean isAsynchronousProcess(final HttpServletRequest request) { - return request.getDispatcherType() == DispatcherType.ASYNC; - } - - private void setTraceMetadata(final HttpServletRequest request, final Trace trace) { - if (request instanceof TraceAccessor) { - ((TraceAccessor) request)._$PINPOINT$_setTrace(trace); - } - } -} diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/HttpRequestInterceptor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/HttpRequestInterceptor.java deleted file mode 100644 index 92184213d755..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/HttpRequestInterceptor.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.resin.interceptor; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.Trace; -import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; -import com.navercorp.pinpoint.bootstrap.logging.PLogger; -import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.resin.AsyncAccessor; -import com.navercorp.pinpoint.plugin.resin.TraceAccessor; - -/** - * - * @author huangpengjie@fang.com - * - */ -public class HttpRequestInterceptor implements AroundInterceptor { - - private PLogger logger = PLoggerFactory.getLogger(this.getClass()); - - private MethodDescriptor methodDescriptor; - - public HttpRequestInterceptor(MethodDescriptor methodDescriptor) { - this.methodDescriptor = methodDescriptor; - } - - @Override - public void before(Object target, Object[] args) { - if (logger.isDebugEnabled()) { - logger.beforeInterceptor(target, methodDescriptor.getClassName(), methodDescriptor.getMethodName(), "", args); - } - try { - if (target != null) { - if (target instanceof AsyncAccessor) { - // reset - ((AsyncAccessor) target)._$PINPOINT$_setAsync(Boolean.FALSE); - } - - if (target instanceof TraceAccessor) { - final Trace trace = ((TraceAccessor) target)._$PINPOINT$_getTrace(); - if (trace != null && trace.canSampled()) { - // end of root span - trace.close(); - } - // reset - ((TraceAccessor) target)._$PINPOINT$_setTrace(null); - } - } - } catch (Throwable t) { - logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); - } - } - - @Override - public void after(Object target, Object[] args, Object result, Throwable throwable) { - } -} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/HttpServletRequestImplInterceptor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/HttpServletRequestImplInterceptor.java index f77d1a65c6e8..af611c563f7c 100644 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/HttpServletRequestImplInterceptor.java +++ b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/HttpServletRequestImplInterceptor.java @@ -1,7 +1,5 @@ package com.navercorp.pinpoint.plugin.resin.interceptor; -import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; -import com.navercorp.pinpoint.bootstrap.context.AsyncContext; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -9,16 +7,18 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.resin.AsyncAccessor; +import com.navercorp.pinpoint.plugin.resin.ResinAsyncListener; import com.navercorp.pinpoint.plugin.resin.ResinConstants; +import javax.servlet.AsyncContext; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletRequest; + /** - * * @author huangpengjie@fang.com - * + * @author jaehong.kim */ public class HttpServletRequestImplInterceptor implements AroundInterceptor { - private PLogger logger = PLoggerFactory.getLogger(this.getClass()); private boolean isDebug = logger.isDebugEnabled(); @@ -33,7 +33,7 @@ public HttpServletRequestImplInterceptor(TraceContext context, MethodDescriptor @Override public void before(Object target, Object[] args) { if (isDebug) { - logger.beforeInterceptor(target, "", descriptor.getMethodName(), "", args); + logger.beforeInterceptor(target, args); } final Trace trace = traceContext.currentTraceObject(); @@ -46,7 +46,7 @@ public void before(Object target, Object[] args) { @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { - logger.afterInterceptor(target, "", descriptor.getMethodName(), "", args); + logger.afterInterceptor(target, args, result, throwable); } final Trace trace = traceContext.currentTraceObject(); @@ -55,19 +55,15 @@ public void after(Object target, Object[] args, Object result, Throwable throwab } try { - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); if (validate(target, result, throwable)) { - ((AsyncAccessor) target)._$PINPOINT$_setAsync(Boolean.TRUE); - - // make asynchronous trace-id - final AsyncContext asyncContext = recorder.recordNextAsyncContext(); - // result is BasicFuture type check validate() - ((AsyncContextAccessor) result)._$PINPOINT$_setAsyncContext(asyncContext); + final AsyncContext asyncContext = (AsyncContext) result; + final AsyncListener asyncListener = new ResinAsyncListener(this.traceContext, recorder.recordNextAsyncContext(true)); + asyncContext.addListener(asyncListener); if (isDebug) { - logger.debug("Set AsyncContext {}", asyncContext); + logger.debug("Add async listener {}", asyncListener); } } - recorder.recordServiceType(ResinConstants.RESIN_METHOD); recorder.recordApi(descriptor); recorder.recordException(throwable); @@ -83,17 +79,19 @@ private boolean validate(final Object target, final Object result, final Throwab return false; } - if (!(target instanceof AsyncAccessor)) { - logger.debug("Invalid target object. Need field accessor({}).", AsyncAccessor.class.getName()); + if (!(target instanceof HttpServletRequest)) { + if (isDebug) { + logger.debug("Invalid target object, The javax.servlet.http.HttpServletRequest interface is not implemented. target={}", target); + } return false; } - if (!(result instanceof AsyncContextAccessor)) { - logger.debug("Invalid target object. Need metadata accessor({}).", AsyncContextAccessor.class.getName()); + if (!(result instanceof AsyncContext)) { + if (isDebug) { + logger.debug("Invalid result object, The javax.servlet.AsyncContext interface is not implemented. result={}.", result); + } return false; } - return true; } - -} +} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/ServletInvocationInterceptor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/ServletInvocationInterceptor.java deleted file mode 100644 index 292a3af6da7e..000000000000 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/ServletInvocationInterceptor.java +++ /dev/null @@ -1,490 +0,0 @@ -package com.navercorp.pinpoint.plugin.resin.interceptor; - -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.navercorp.pinpoint.bootstrap.config.DumpType; -import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.context.Header; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.RemoteAddressResolver; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.SpanId; -import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; -import com.navercorp.pinpoint.bootstrap.context.Trace; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; -import com.navercorp.pinpoint.bootstrap.logging.PLogger; -import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderHandler; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderRecorder; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; -import com.navercorp.pinpoint.bootstrap.util.NumberUtils; -import com.navercorp.pinpoint.bootstrap.util.SimpleSampler; -import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.ArrayUtils; - -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.plugin.resin.AsyncAccessor; -import com.navercorp.pinpoint.plugin.resin.HttpServletRequestGetter; -import com.navercorp.pinpoint.plugin.resin.ResinConfig; -import com.navercorp.pinpoint.plugin.resin.ResinConstants; -import com.navercorp.pinpoint.plugin.resin.ServletAsyncMethodDescriptor; -import com.navercorp.pinpoint.plugin.resin.ServletSyncMethodDescriptor; -import com.navercorp.pinpoint.plugin.resin.TraceAccessor; -import com.navercorp.pinpoint.plugin.resin.VersionAccessor; - -/** - * @author huangpengjie@fang.com - */ -public class ServletInvocationInterceptor implements AroundInterceptor { - - public static final String SERVLET_INVOCATION_CLASS_NAME = "com.caucho.server.dispatch.ServletInvocation"; - - public static final ServletSyncMethodDescriptor SERVLET_SYNCHRONOUS_API_TAG = new ServletSyncMethodDescriptor(); - public static final ServletAsyncMethodDescriptor SERVLET_ASYNCHRONOUS_API_TAG = new ServletAsyncMethodDescriptor(); - - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - - private final boolean isTraceRequestParam; - private final Filter excludeUrlFilter; - private final Filter excludeProfileMethodFilter; - private final RemoteAddressResolver remoteAddressResolver; - - private final MethodDescriptor methodDescriptor; - private final TraceContext traceContext; - - private final boolean isTraceCookies; - - private final SimpleSampler cookieSampler; - - private final DumpType cookieDumpType; - private final ProxyHttpHeaderRecorder proxyHttpHeaderRecorder; - - public ServletInvocationInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { - this.traceContext = traceContext; - this.methodDescriptor = descriptor; - - ResinConfig resinConfig = new ResinConfig(traceContext.getProfilerConfig()); - this.excludeUrlFilter = resinConfig.getResinExcludeUrlFilter(); - final String proxyIpHeader = resinConfig.getResinRealIpHeader(); - if (StringUtils.isEmpty(proxyIpHeader)) { - this.remoteAddressResolver = new Bypass(); - } else { - final String tomcatRealIpEmptyValue = resinConfig.getResinRealIpEmptyValue(); - this.remoteAddressResolver = new RealIpHeaderResolver(proxyIpHeader, tomcatRealIpEmptyValue); - } - this.isTraceRequestParam = resinConfig.isResinTraceRequestParam(); - this.excludeProfileMethodFilter = resinConfig.getResinExcludeProfileMethodFilter(); - this.isTraceCookies = resinConfig.isTraceCookies(); - this.cookieSampler = SimpleSamplerFactory.createSampler(isTraceCookies, resinConfig.getCookieSamplingRate()); - this.cookieDumpType = resinConfig.getCookieDumpType(); - this.proxyHttpHeaderRecorder = new ProxyHttpHeaderRecorder(traceContext.getProfilerConfig().isProxyHttpHeaderEnable()); - - traceContext.cacheApi(SERVLET_ASYNCHRONOUS_API_TAG); - traceContext.cacheApi(SERVLET_SYNCHRONOUS_API_TAG); - } - - @Override - public void before(Object target, Object[] args) { - if (isDebug) { - logger.beforeInterceptor(target, args); - } - try { - final Trace trace = createTrace(target, args); - if (trace == null) { - return; - } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - return; - } - // ------------------------------------------------------ - SpanEventRecorder recorder = trace.traceBlockBegin(); - recorder.recordServiceType(ResinConstants.RESIN_METHOD); - } catch (Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("BEFORE. Caused:{}", th.getMessage(), th); - } - } - } - - @Override - public void after(Object target, Object[] args, Object result, Throwable throwable) { - if (isDebug) { - logger.afterInterceptor(target, args, result, throwable); - } - final Trace trace = traceContext.currentRawTraceObject(); - if (trace == null) { - return; - } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - traceContext.removeTraceObject(); - return; - } - // ------------------------------------------------------ - try { - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - - if (this.isTraceRequestParam) { - final HttpServletRequest request = (HttpServletRequest) args[0]; - if (!excludeProfileMethodFilter.filter(request.getMethod())) { - final String parameters = getRequestParameter(request, 64, 512); - if (StringUtils.hasLength(parameters)) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM, parameters); - } - } - recordRequest(trace, request, throwable); - } - final HttpServletResponse response = (HttpServletResponse) args[1]; - if (throwable != null) { - recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, 500); - recorder.recordException(throwable); - } else { - if (isResinVersion4(target)) { - recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, response.getStatus()); - } - } - recorder.recordApi(methodDescriptor); - } catch (Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("AFTER. Caused:{}", th.getMessage(), th); - } - } finally { - traceContext.removeTraceObject(); - deleteTrace(trace, target, args, result, throwable); - } - - } - - private String getRequestParameter(HttpServletRequest request, int eachLimit, int totalLimit) { - Enumeration attrs = request.getParameterNames(); - final StringBuilder params = new StringBuilder(64); - - while (attrs.hasMoreElements()) { - if (params.length() != 0) { - params.append('&'); - } - // skip appending parameters if parameter size is bigger than totalLimit - if (params.length() > totalLimit) { - params.append("..."); - return params.toString(); - } - String key = attrs.nextElement().toString(); - params.append(StringUtils.abbreviate(key, eachLimit)); - params.append('='); - Object value = request.getParameter(key); - if (value != null) { - params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); - } - } - return params.toString(); - } - - private void deleteTrace(Trace trace, Object target, Object[] args, Object result, Throwable throwable) { - trace.traceBlockEnd(); - - final HttpServletRequest request = (HttpServletRequest) args[0]; - if (!isAsynchronousProcess(request)) { - trace.close(); - // reset - setTraceMetadata(request, null); - } - } - - private Trace createTrace(Object target, Object[] args) { - final HttpServletRequest request = (HttpServletRequest) args[0]; - - if (isAsynchronousProcess(request)) { - // servlet 3.0 - final Trace trace = getTraceMetadata(request); - if (trace != null) { - // change api - SpanRecorder recorder = trace.getSpanRecorder(); - recorder.recordApi(SERVLET_ASYNCHRONOUS_API_TAG); - // attach current thread local. - traceContext.continueTraceObject(trace); - return trace; - } - } - - final Trace currentRawTraceObject = traceContext.currentRawTraceObject(); - if (currentRawTraceObject != null) { - return currentRawTraceObject; - } - final String requestURI = request.getRequestURI(); - if (excludeUrlFilter.filter(requestURI)) { - if (isDebug) { - logger.debug("filter requestURI:{}", requestURI); - } - return null; - } - - // check sampling flag from client. If the flag is false, do not sample this request. - final boolean sampling = samplingEnable(request); - if (!sampling) { - // Even if this transaction is not a sampling target, we have to create Trace object to mark 'not sampling'. - // For example, if this transaction invokes rpc call, we can add parameter to tell remote node 'don't sample this transaction' - final Trace trace = traceContext.disableSampling(); - if (isDebug) { - logger.debug("remotecall sampling flag found. skip trace requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - return trace; - } - - final TraceId traceId = populateTraceIdFromRequest(request); - if (traceId != null) { - // TODO Maybe we should decide to trace or not even if the sampling flag is true to prevent too many requests are traced. - final Trace trace = traceContext.continueTraceObject(traceId); - if (trace.canSampled()) { - SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - setTraceMetadata(request, trace); - if (isDebug) { - logger.debug("TraceID exist. continue trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), request.getRemoteAddr()); - } - } else { - if (isDebug) { - logger.debug("TraceID exist. camSampled is false. skip trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), request.getRemoteAddr()); - } - } - return trace; - } else { - final Trace trace = traceContext.newTraceObject(); - if (trace.canSampled()) { - SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - setTraceMetadata(request, trace); - if (isDebug) { - logger.debug("TraceID not exist. start new trace. requestUrl:{}, remoteAddr:{} , traceId:{}", request.getRequestURI(), request.getRemoteAddr(), trace.getTraceId()); - } - } else { - if (isDebug) { - logger.debug("TraceID not exist. camSampled is false. skip trace. requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - } - return trace; - } - } - - private void setTraceMetadata(final HttpServletRequest request, final Trace trace) { - if (request instanceof TraceAccessor) { - ((TraceAccessor) request)._$PINPOINT$_setTrace(trace); - } - } - - private Trace getTraceMetadata(HttpServletRequest request) { - if (request instanceof HttpServletRequestGetter) { - request = ((HttpServletRequestGetter) request)._$PINPOINT$_getRequest(); - } - if (!(request instanceof TraceAccessor)) { - return null; - } - return ((TraceAccessor) request)._$PINPOINT$_getTrace(); - } - - private boolean getAsyncMetadata(HttpServletRequest request) { - // AsyncRequest - if (request instanceof HttpServletRequestGetter) { - request = ((HttpServletRequestGetter) request)._$PINPOINT$_getRequest(); - } - if (!(request instanceof AsyncAccessor)) { - return false; - } - - return ((AsyncAccessor) request)._$PINPOINT$_isAsync(); - } - - private boolean isAsynchronousProcess(HttpServletRequest request) { - if (getTraceMetadata(request) == null) { - return false; - } - return getAsyncMetadata(request); - } - - private void recordRootSpan(final SpanRecorder recorder, final HttpServletRequest request) { - // root - recorder.recordServiceType(ResinConstants.RESIN); - - final String requestURL = request.getRequestURI(); - recorder.recordRpcName(requestURL); - - final int port = request.getServerPort(); - final String endPoint = HostAndPort.toHostAndPortString(request.getServerName(), port); - recorder.recordEndPoint(endPoint); - - final String remoteAddr = remoteAddressResolver.resolve(request); - recorder.recordRemoteAddress(remoteAddr); - - if (!recorder.isRoot()) { - recordParentInfo(recorder, request); - } - recorder.recordApi(SERVLET_SYNCHRONOUS_API_TAG); - - // record proxy HTTP headers. - this.proxyHttpHeaderRecorder.record(recorder, new ProxyHttpHeaderHandler() { - @Override - public String read(String name) { - return request.getHeader(name); - } - }); - } - - private void recordParentInfo(SpanRecorder recorder, HttpServletRequest request) { - String parentApplicationName = request.getHeader(Header.HTTP_PARENT_APPLICATION_NAME.toString()); - if (parentApplicationName != null) { - final String host = request.getHeader(Header.HTTP_HOST.toString()); - if (host != null) { - recorder.recordAcceptorHost(host); - } else { - recorder.recordAcceptorHost(NetworkUtils.getHostFromURL(request.getRequestURL().toString())); - } - final String type = request.getHeader(Header.HTTP_PARENT_APPLICATION_TYPE.toString()); - final short parentApplicationType = NumberUtils.parseShort(type, ServiceType.UNDEFINED.getCode()); - recorder.recordParentApplication(parentApplicationName, parentApplicationType); - } - } - - /** - * Populate source trace from HTTP Header. - * - * @param request - * @return TraceId when it is possible to get a transactionId from Http header. if not possible return null - */ - private TraceId populateTraceIdFromRequest(HttpServletRequest request) { - - String transactionId = request.getHeader(Header.HTTP_TRACE_ID.toString()); - if (transactionId != null) { - - long parentSpanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_PARENT_SPAN_ID.toString()), SpanId.NULL); - long spanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_SPAN_ID.toString()), SpanId.NULL); - short flags = NumberUtils.parseShort(request.getHeader(Header.HTTP_FLAGS.toString()), (short) 0); - - final TraceId id = traceContext.createTraceId(transactionId, parentSpanID, spanID, flags); - if (isDebug) { - logger.debug("TraceID exist. continue trace. {}", id); - } - return id; - } else { - return null; - } - } - - private boolean samplingEnable(HttpServletRequest request) { - // optional value - final String samplingFlag = request.getHeader(Header.HTTP_SAMPLED.toString()); - if (isDebug) { - logger.debug("SamplingFlag:{}", samplingFlag); - } - return SamplingFlagUtils.isSamplingFlag(samplingFlag); - } - - private static class Bypass implements RemoteAddressResolver { - - @Override - public String resolve(T servletRequest) { - return servletRequest.getRemoteAddr(); - } - } - - private static class RealIpHeaderResolver implements RemoteAddressResolver { - - public static final String X_FORWARDED_FOR = "x-forwarded-for"; - @SuppressWarnings("unused") - public static final String X_REAL_IP = "x-real-ip"; - public static final String UNKNOWN = "unknown"; - - private final String realIpHeaderName; - private final String emptyHeaderValue; - - @SuppressWarnings("unused") - public RealIpHeaderResolver() { - this(X_FORWARDED_FOR, UNKNOWN); - } - - public RealIpHeaderResolver(String realIpHeaderName, String emptyHeaderValue) { - if (realIpHeaderName == null) { - throw new NullPointerException("realIpHeaderName must not be null"); - } - this.realIpHeaderName = realIpHeaderName; - this.emptyHeaderValue = emptyHeaderValue; - } - - @Override - public String resolve(T httpServletRequest) { - final String realIp = httpServletRequest.getHeader(this.realIpHeaderName); - - if (StringUtils.isEmpty(realIp)) { - return httpServletRequest.getRemoteAddr(); - } - - if (emptyHeaderValue != null && emptyHeaderValue.equalsIgnoreCase(realIp)) { - return httpServletRequest.getRemoteAddr(); - } - - final int firstIndex = realIp.indexOf(','); - if (firstIndex == -1) { - return realIp; - } else { - return realIp.substring(0, firstIndex); - } - } - } - - public boolean isResinVersion4(Object target) { - if (!(target instanceof VersionAccessor)) { - logger.debug(" resin version 3 "); - return false; - } else { - logger.debug(" resin version 4 "); - return true; - } - - } - - private void recordRequest(Trace trace, HttpServletRequest request, Throwable throwable) { - final boolean isException = InterceptorUtils.isThrowable(throwable); - if (isTraceCookies) { - if (DumpType.ALWAYS == cookieDumpType) { - recordCookie(request, trace); - } else if (DumpType.EXCEPTION == cookieDumpType && isException) { - recordCookie(request, trace); - } - } - } - - private void recordCookie(HttpServletRequest request, Trace trace) { - if (cookieSampler.isSampling()) { - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - Map cookies = readCookieMap(request); - recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, cookies); - } - } - - public Map readCookieMap(HttpServletRequest request) { - Map params = new HashMap(); - try { - Cookie[] cookies = request.getCookies(); - if (ArrayUtils.hasLength(cookies)) { - for (Cookie cookie : cookies) { - params.put(cookie.getName(), cookie.getValue()); - } - } - } catch (NullPointerException e) { - logger.info(" resin without ROOT project "); - } - return params; - } -} diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/ServletInvocationServiceInterceptor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/ServletInvocationServiceInterceptor.java new file mode 100644 index 000000000000..39aa60ea0e70 --- /dev/null +++ b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/ServletInvocationServiceInterceptor.java @@ -0,0 +1,126 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.resin.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServletRequestListenerInterceptorHelper; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.RemoteAddressResolverFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.ArgumentValidator; +import com.navercorp.pinpoint.plugin.common.servlet.util.HttpServletRequestAdaptor; +import com.navercorp.pinpoint.plugin.common.servlet.util.ParameterRecorderFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.ServletArgumentValidator; +import com.navercorp.pinpoint.plugin.resin.ResinConfig; +import com.navercorp.pinpoint.plugin.resin.ResinConstants; + +import javax.servlet.DispatcherType; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author jaehong.kim + */ +public class ServletInvocationServiceInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private final MethodDescriptor methodDescriptor; + private final ArgumentValidator argumentValidator; + private final ServletRequestListenerInterceptorHelper servletRequestListenerInterceptorHelper; + + public ServletInvocationServiceInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + this.methodDescriptor = methodDescriptor; + this.argumentValidator = new ServletArgumentValidator(logger, 0, HttpServletRequest.class, 1, HttpServletResponse.class); + final ResinConfig config = new ResinConfig(traceContext.getProfilerConfig()); + + RequestAdaptor requestAdaptor = new HttpServletRequestAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, config.getRealIpHeader(), config.getRealIpEmptyValue()); + ParameterRecorder parameterRecorder = ParameterRecorderFactory.newParameterRecorderFactory(config.getExcludeProfileMethodFilter(), config.isTraceRequestParam()); + this.servletRequestListenerInterceptorHelper = new ServletRequestListenerInterceptorHelper(ResinConstants.RESIN, traceContext, requestAdaptor, config.getExcludeUrlFilter(), parameterRecorder); + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (!argumentValidator.validate(args)) { + return; + } + + try { + final HttpServletRequest request = (HttpServletRequest) args[0]; + if (request.getDispatcherType() == DispatcherType.ASYNC) { + if (isDebug) { + logger.debug("Skip async servlet Request. isAsyncStarted={}, dispatcherType={}", request.isAsyncStarted(), request.getDispatcherType()); + } + return; + } + + this.servletRequestListenerInterceptorHelper.initialized(request, ResinConstants.RESIN_METHOD, this.methodDescriptor); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); + } + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + if (!argumentValidator.validate(args)) { + return; + } + + try { + final HttpServletRequest request = (HttpServletRequest) args[0]; + final HttpServletResponse response = (HttpServletResponse) args[1]; + if (request.getDispatcherType() == DispatcherType.ASYNC) { + if (isDebug) { + logger.debug("Skip async servlet Request. isAsyncStarted={}, dispatcherType={}", request.isAsyncStarted(), request.getDispatcherType()); + } + return; + } + + int statusCode = getStatusCode(response); + this.servletRequestListenerInterceptorHelper.destroyed(request, throwable, statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); + } + } + } + + + private int getStatusCode(final HttpServletResponse response) { + try { + return response.getStatus(); + } catch (Exception ignored) { + } + return 0; + } +} \ No newline at end of file diff --git a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/WebAppInterceptor.java b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/WebAppInterceptor.java index e093082d167b..d60c98a3b285 100644 --- a/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/WebAppInterceptor.java +++ b/plugins/resin/src/main/java/com/navercorp/pinpoint/plugin/resin/interceptor/WebAppInterceptor.java @@ -9,6 +9,7 @@ import java.util.Collections; import java.util.List; import javax.servlet.ServletContext; + import com.navercorp.pinpoint.bootstrap.context.ServerMetaDataHolder; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; @@ -17,9 +18,7 @@ import com.navercorp.pinpoint.common.util.StringUtils; /** - * * @author huangpengjie@fang.com - * */ public class WebAppInterceptor implements AroundInterceptor { @@ -29,7 +28,6 @@ public class WebAppInterceptor implements AroundInterceptor { private final TraceContext traceContext; public WebAppInterceptor(TraceContext traceContext) { - super(); this.traceContext = traceContext; } @@ -40,25 +38,24 @@ public void before(Object target, Object[] args) { @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { - if (isDebug) { logger.afterInterceptor(target, args, result, throwable); } - if (target instanceof ServletContext) { - ServletContext servletContext = (ServletContext) target; - try { - String contextKey = extractContextKey(servletContext); - List loadedJarNames = extractLibJars(servletContext); + try { + if (target instanceof ServletContext) { + final ServletContext servletContext = (ServletContext) target; + final String contextKey = extractContextKey(servletContext); + final List loadedJarNames = extractLibJars(servletContext); if (isDebug) { logger.debug("{} jars : {}", contextKey, Arrays.toString(loadedJarNames.toArray())); } dispatchLibJars(contextKey, loadedJarNames, servletContext); - } catch (Exception e) { - logger.warn(e.getMessage(), e); + } else { + logger.warn("Webapp loader is not an instance of javax.servlet.ServletContext , target={}", target); } - } else { - logger.warn("Webapp loader is not an instance of javax.servlet.ServletContext , Found [{}]", target.getClass().toString()); + } catch (Exception e) { + logger.warn("Failed to dispatch lib jars", e); } } @@ -123,5 +120,4 @@ private List extractLibJars(ServletContext webapp) { return Collections.emptyList(); } } - -} +} \ No newline at end of file diff --git a/plugins/resttemplate/clover.license b/plugins/resttemplate/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/resttemplate/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-resttemplate-plugin diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/RestTemplateConstants.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/RestTemplateConstants.java index a9d7c682e49c..b21f9cf52a74 100644 --- a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/RestTemplateConstants.java +++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/RestTemplateConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -24,6 +24,9 @@ */ public final class RestTemplateConstants { + private RestTemplateConstants() { + } + public static final String SCOPE = "REST_TEMPLATE_SCOPE"; public static final ServiceType SERVICE_TYPE = ServiceTypeFactory.of(9140, "REST_TEMPLATE"); diff --git a/plugins/rxjava/clover.license b/plugins/rxjava/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/rxjava/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-rxjava-plugin pinpoint-rxjava-plugin jar + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint diff --git a/plugins/rxjava/src/main/java/com/navercorp/pinpoint/plugin/rxjava/RxJavaPluginConstants.java b/plugins/rxjava/src/main/java/com/navercorp/pinpoint/plugin/rxjava/RxJavaPluginConstants.java index 6fbc380146a4..d7e94ab08367 100644 --- a/plugins/rxjava/src/main/java/com/navercorp/pinpoint/plugin/rxjava/RxJavaPluginConstants.java +++ b/plugins/rxjava/src/main/java/com/navercorp/pinpoint/plugin/rxjava/RxJavaPluginConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -22,11 +22,13 @@ /** * @author HyunGil Jeong */ -public interface RxJavaPluginConstants { +public final class RxJavaPluginConstants { + private RxJavaPluginConstants() { + } - ServiceType RX_JAVA = ServiceTypeFactory.of(6500, "RX_JAVA"); - ServiceType RX_JAVA_INTERNAL = ServiceTypeFactory.of(6501, "RX_JAVA_INTERNAL", "RX_JAVA"); + public static final ServiceType RX_JAVA = ServiceTypeFactory.of(6500, "RX_JAVA"); + public static final ServiceType RX_JAVA_INTERNAL = ServiceTypeFactory.of(6501, "RX_JAVA_INTERNAL", "RX_JAVA"); - String RX_JAVA_SUBSCRIBE_SCOPE = "RxJavaObservableSubscribeScope"; - String RX_JAVA_OBSERVABLE_SCOPE = "RxJavaObservableScope"; + public static final String RX_JAVA_SUBSCRIBE_SCOPE = "RxJavaObservableSubscribeScope"; + public static final String RX_JAVA_OBSERVABLE_SCOPE = "RxJavaObservableScope"; } diff --git a/plugins/spring-boot/clover.license b/plugins/spring-boot/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/spring-boot/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-spring-boot-plugin diff --git a/plugins/spring/clover.license b/plugins/spring/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/spring/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-spring-plugin diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncConfig.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncConfig.java new file mode 100644 index 000000000000..4f4cd1a4724c --- /dev/null +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncConfig.java @@ -0,0 +1,71 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.spring.async; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author jaehong.kim + */ +public class SpringAsyncConfig { + private static final String[] DEFAULT_ASYNC_TASK_EXECUTOR = { + "org.springframework.scheduling.concurrent.ConcurrentTaskExecutor", + "org.springframework.core.task.SimpleAsyncTaskExecutor", + "org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor", + "org.springframework.core.task.support.TaskExecutorAdapter", + "org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor", + "org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler", + "org.springframework.jca.work.WorkManagerTaskExecutor", + "org.springframework.scheduling.commonj.WorkManagerTaskExecutor" + }; + + private final List asyncTaskExecutorClassNameList = new ArrayList(Arrays.asList(DEFAULT_ASYNC_TASK_EXECUTOR)); + private final boolean enable; + + public SpringAsyncConfig(ProfilerConfig config) { + this.enable = config.readBoolean("profiler.spring.async.enable", true); + final List list = config.readList("profiler.spring.async.executor.class.names"); + if (!list.isEmpty()) { + for (String className : list) { + if (!this.asyncTaskExecutorClassNameList.contains(className)) { + this.asyncTaskExecutorClassNameList.add(className); + } + } + } + } + + public List getAsyncTaskExecutorClassNameList() { + return asyncTaskExecutorClassNameList; + } + + public boolean isEnable() { + return enable; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("SpringAsyncConfig{"); + sb.append("asyncTaskExecutorClassNameList=").append(asyncTaskExecutorClassNameList); + sb.append(", enable=").append(enable); + sb.append('}'); + return sb.toString(); + } +} diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncConstants.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncConstants.java new file mode 100644 index 000000000000..30639a9e2982 --- /dev/null +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncConstants.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.spring.async; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +/** + * @author jaehong.kim + */ +public class SpringAsyncConstants { + + public static final ServiceType SPRING_ASYNC = ServiceTypeFactory.of(5052, "SPRING_ASYNC", "SPRING_ASYNC"); + public static final String ASYNC_TASK_EXECUTOR_SCOPE = "AsyncTaskExecutorScope"; + +} diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncPlugin.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncPlugin.java new file mode 100644 index 000000000000..0878e1719cdc --- /dev/null +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncPlugin.java @@ -0,0 +1,100 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.spring.async; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.matcher.Matcher; +import com.navercorp.pinpoint.bootstrap.instrument.matcher.Matchers; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.MatchableTransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.MatchableTransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import com.navercorp.pinpoint.common.util.StringUtils; + +import java.security.ProtectionDomain; +import java.util.List; + +public class SpringAsyncPlugin implements ProfilerPlugin, MatchableTransformTemplateAware { + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + private MatchableTransformTemplate transformTemplate; + + @Override + public void setup(ProfilerPluginSetupContext context) { + final SpringAsyncConfig config = new SpringAsyncConfig(context.getConfig()); + if (!config.isEnable()) { + logger.info("Disable SpringAsyncPlugin"); + return; + } + logger.info("SpringAsyncPlugin config={}", config); + + // Add task class + addAsyncExecutionInterceptorTask(Matchers.newClassNameMatcher("org.springframework.aop.interceptor.AsyncExecutionInterceptor$1")); + // Apply to spring framework 5.0 or later. + addAsyncExecutionInterceptorTask(Matchers.newPackageBasedMatcher("org.springframework.aop.interceptor.AsyncExecutionInterceptor$$Lambda$")); + // Add AsyncTaskExecutor classes + final List asyncTaskExecutorClassNameList = config.getAsyncTaskExecutorClassNameList(); + for (String className : asyncTaskExecutorClassNameList) { + if (!StringUtils.isEmpty(className)) { + addAsyncTaskExecutor(className); + } + } + } + + private void addAsyncExecutionInterceptorTask(final Matcher matcher) { + transformTemplate.transform(matcher, new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + target.addField(AsyncContextAccessor.class.getName()); + final InstrumentMethod callMethod = target.getDeclaredMethod("call"); + if (callMethod != null) { + callMethod.addInterceptor("com.navercorp.pinpoint.plugin.spring.async.interceptor.TaskCallInterceptor"); + } + + return target.toBytecode(); + } + }); + } + + private void addAsyncTaskExecutor(final String className) { + transformTemplate.transform(className, new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + final InstrumentMethod submitMethod = target.getDeclaredMethod("submit", "java.util.concurrent.Callable"); + if (submitMethod != null) { + submitMethod.addScopedInterceptor("com.navercorp.pinpoint.plugin.spring.async.interceptor.AsyncTaskExecutorSubmitInterceptor", SpringAsyncConstants.ASYNC_TASK_EXECUTOR_SCOPE); + } + + return target.toBytecode(); + } + }); + } + + @Override + public void setTransformTemplate(MatchableTransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } +} \ No newline at end of file diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncTraceMetadataProvider.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncTraceMetadataProvider.java new file mode 100644 index 000000000000..ae77be8c2509 --- /dev/null +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/SpringAsyncTraceMetadataProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.spring.async; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * @author jaehong.kim + */ +public class SpringAsyncTraceMetadataProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(SpringAsyncConstants.SPRING_ASYNC); + } + +} diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/interceptor/AsyncTaskExecutorSubmitInterceptor.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/interceptor/AsyncTaskExecutorSubmitInterceptor.java new file mode 100644 index 000000000000..7dc0e422c460 --- /dev/null +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/interceptor/AsyncTaskExecutorSubmitInterceptor.java @@ -0,0 +1,105 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.spring.async.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.spring.async.SpringAsyncConstants; + +/** + * @author jaehong.kim + */ +public class AsyncTaskExecutorSubmitInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor descriptor; + + public AsyncTaskExecutorSubmitInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.traceContext = traceContext; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + final SpanEventRecorder recorder = trace.traceBlockBegin(); + if (validate(args)) { + // make asynchronous trace-id + final AsyncContext asyncContext = recorder.recordNextAsyncContext(); + ((AsyncContextAccessor) args[0])._$PINPOINT$_setAsyncContext(asyncContext); + if (isDebug) { + logger.debug("Set asyncContext {}", asyncContext); + } + } + } + + private boolean validate(final Object[] args) { + if (args == null || args.length < 1) { + if (isDebug) { + logger.debug("Invalid args object. args={}.", args); + } + return false; + } + + if (!(args[0] instanceof AsyncContextAccessor)) { + if (isDebug) { + logger.debug("Invalid args[0] object. Need metadata accessor({}).", AsyncContextAccessor.class.getName()); + } + return false; + } + + return true; + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + recorder.recordApi(this.descriptor); + recorder.recordServiceType(SpringAsyncConstants.SPRING_ASYNC); + recorder.recordException(throwable); + } finally { + trace.traceBlockEnd(); + } + } +} \ No newline at end of file diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/interceptor/TaskCallInterceptor.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/interceptor/TaskCallInterceptor.java new file mode 100644 index 000000000000..f0581500071a --- /dev/null +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/async/interceptor/TaskCallInterceptor.java @@ -0,0 +1,28 @@ +package com.navercorp.pinpoint.plugin.spring.async.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AsyncContextSpanEventSimpleAroundInterceptor; +import com.navercorp.pinpoint.plugin.spring.async.SpringAsyncConstants; + +/** + * @author jaehong.kim + */ +public class TaskCallInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor { + public TaskCallInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + super(traceContext, methodDescriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + } + + @Override + protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(SpringAsyncConstants.SPRING_ASYNC); + recorder.recordException(throwable); + } +} diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/beans/SpringBeansPlugin.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/beans/SpringBeansPlugin.java index 1c21dad96b53..c8766352e618 100644 --- a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/beans/SpringBeansPlugin.java +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/beans/SpringBeansPlugin.java @@ -100,7 +100,7 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); final BeanMethodTransformer beanTransformer = new BeanMethodTransformer(errorMark); - final ObjectFactory beanFilterFactory = ObjectFactory.byStaticFactory("com.navercorp.pinpoint.plugin.spring.beans.interceptor.TargetBeanFilter", "of", context.getConfig()); + final ObjectFactory beanFilterFactory = ObjectFactory.byStaticFactory("com.navercorp.pinpoint.plugin.spring.beans.interceptor.TargetBeanFilter", "of", config); final InstrumentMethod method = target.getDeclaredMethod("doScan", "java.lang.String[]"); method.addInterceptor("com.navercorp.pinpoint.plugin.spring.beans.interceptor.ClassPathDefinitionScannerDoScanInterceptor", va(loader, beanTransformer, beanFilterFactory)); diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcConstants.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcConstants.java new file mode 100644 index 000000000000..26c8e6427fff --- /dev/null +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcConstants.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.spring.web; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class SpringWebMvcConstants { + private SpringWebMvcConstants() { + } + + public static final ServiceType SPRING_MVC = ServiceTypeFactory.of(5051, "SPRING_MVC", "SPRING"); +} diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcPlugin.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcPlugin.java index 0b4cb76308ff..d4a849557c7e 100644 --- a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcPlugin.java +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcPlugin.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,6 +21,7 @@ import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; @@ -27,15 +29,13 @@ import com.navercorp.pinpoint.bootstrap.interceptor.BasicMethodInterceptor; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + /** * @author Jongho Moon * */ public class SpringWebMvcPlugin implements ProfilerPlugin, TransformTemplateAware { - public static final ServiceType SPRING_MVC = ServiceTypeFactory.of(5051, "SPRING_MVC", "SPRING"); private TransformTemplate transformTemplate; @@ -46,9 +46,12 @@ public void setup(ProfilerPluginSetupContext context) { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - - target.getDeclaredMethod("doGet", "javax.servlet.http.HttpServletRequest", "javax.servlet.http.HttpServletResponse").addInterceptor(BasicMethodInterceptor.class.getName(), va(SPRING_MVC)); - target.getDeclaredMethod("doPost", "javax.servlet.http.HttpServletRequest", "javax.servlet.http.HttpServletResponse").addInterceptor(BasicMethodInterceptor.class.getName(), va(SPRING_MVC)); + + InstrumentMethod doGet = target.getDeclaredMethod("doGet", "javax.servlet.http.HttpServletRequest", "javax.servlet.http.HttpServletResponse"); + doGet.addInterceptor(BasicMethodInterceptor.class.getName(), va(SpringWebMvcConstants.SPRING_MVC)); + + InstrumentMethod doPost = target.getDeclaredMethod("doPost", "javax.servlet.http.HttpServletRequest", "javax.servlet.http.HttpServletResponse"); + doPost.addInterceptor(BasicMethodInterceptor.class.getName(), va(SpringWebMvcConstants.SPRING_MVC)); return target.toBytecode(); } diff --git a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcTraceMetadataProvider.java b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcTraceMetadataProvider.java index 3cb193fac1b0..f236123475db 100644 --- a/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcTraceMetadataProvider.java +++ b/plugins/spring/src/main/java/com/navercorp/pinpoint/plugin/spring/web/SpringWebMvcTraceMetadataProvider.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,7 +29,7 @@ public class SpringWebMvcTraceMetadataProvider implements TraceMetadataProvider */ @Override public void setup(TraceMetadataSetupContext context) { - context.addServiceType(SpringWebMvcPlugin.SPRING_MVC); + context.addServiceType(SpringWebMvcConstants.SPRING_MVC); } } diff --git a/plugins/spring/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/spring/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin index ccd3783a6e15..1b8abbed2377 100644 --- a/plugins/spring/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin +++ b/plugins/spring/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -1,2 +1,3 @@ com.navercorp.pinpoint.plugin.spring.beans.SpringBeansPlugin com.navercorp.pinpoint.plugin.spring.web.SpringWebMvcPlugin +com.navercorp.pinpoint.plugin.spring.async.SpringAsyncPlugin diff --git a/plugins/spring/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/spring/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider index 4d3a8258c924..8ee7d232b783 100644 --- a/plugins/spring/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider +++ b/plugins/spring/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -1,2 +1,3 @@ com.navercorp.pinpoint.plugin.spring.beans.SpringBeansTraceMetadataProvider -com.navercorp.pinpoint.plugin.spring.web.SpringWebMvcTraceMetadataProvider \ No newline at end of file +com.navercorp.pinpoint.plugin.spring.web.SpringWebMvcTraceMetadataProvider +com.navercorp.pinpoint.plugin.spring.async.SpringAsyncTraceMetadataProvider \ No newline at end of file diff --git a/plugins/thrift/clover.license b/plugins/thrift/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/plugins/thrift/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-thrift-plugin diff --git a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftClientCallContext.java b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftClientCallContext.java index 482a87550770..2a3217372795 100644 --- a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftClientCallContext.java +++ b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftClientCallContext.java @@ -25,6 +25,8 @@ public class ThriftClientCallContext { public static final ThriftHeader NONE = null; private final String methodName; + + private boolean isEntryPoint; private ThriftHeader traceHeaderToBeRead; @@ -37,7 +39,15 @@ public ThriftClientCallContext(String methodName) { public String getMethodName() { return methodName; } - + + public boolean isEntryPoint() { + return isEntryPoint; + } + + public void setEntryPoint(boolean entryPoint) { + isEntryPoint = entryPoint; + } + public ThriftHeader getTraceHeaderToBeRead() { return traceHeaderToBeRead; } @@ -56,14 +66,12 @@ public void setTraceHeader(ThriftRequestProperty traceHeader) { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("ThriftClientCallContext={methodName=").append(this.methodName); - sb.append(", traceHeaderToBeRead=").append(this.traceHeaderToBeRead.name()); - sb.append(", traceHeader=").append(this.traceHeader.toString()); - sb.append("}"); + final StringBuilder sb = new StringBuilder("ThriftClientCallContext{"); + sb.append("methodName='").append(methodName).append('\''); + sb.append(", isEntryPoint=").append(isEntryPoint); + sb.append(", traceHeaderToBeRead=").append(traceHeaderToBeRead); + sb.append(", traceHeader=").append(traceHeader); + sb.append('}'); return sb.toString(); } - - - } diff --git a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftConstants.java b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftConstants.java index ca70c0df91b0..d52d92d1c708 100644 --- a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftConstants.java +++ b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftConstants.java @@ -55,6 +55,7 @@ private ThriftConstants() { public static final String T_ASYNC_METHOD_CALL_FIELD_TRANSPORT = "transport"; public static final String FRAME_BUFFER_FIELD_TRANS_ = "trans_"; public static final String FRAME_BUFFER_FIELD_IN_TRANS_ = "inTrans_"; + public static final String T_HTTP_CLIENT_FIELD_URL_ = "url_"; // custom field injector (accessor) FQCN private static final String FIELD_ACCESSOR_BASE = "com.navercorp.pinpoint.plugin.thrift.field.accessor."; @@ -68,4 +69,5 @@ private ThriftConstants() { public static final String FIELD_GETTER_T_NON_BLOCKING_TRANSPORT = FIELD_GETTER_BASE + "TNonblockingTransportFieldGetter"; public static final String FIELD_GETTER_T_TRANSPORT = FIELD_GETTER_BASE + "TTransportFieldGetter"; public static final String FIELD_GETTER_T_PROTOCOL = FIELD_GETTER_BASE + "TProtocolFieldGetter"; + public static final String FIELD_GETTER_URL = FIELD_GETTER_BASE + "UrlFieldGetter"; } diff --git a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftPlugin.java b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftPlugin.java index 6260d49bdbfd..c310113801f6 100644 --- a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftPlugin.java +++ b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftPlugin.java @@ -54,6 +54,7 @@ public void setup(ProfilerPluginSetupContext context) { if (traceClient) { addInterceptorsForSynchronousClients(config); + addTHttpClientEditor(); if (traceClientAsync) { addInterceptorsForAsynchronousClients(); } @@ -274,6 +275,19 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin }); } + // THttpClient + + private void addTHttpClientEditor() { + transformTemplate.transform("org.apache.thrift.transport.THttpClient", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + target.addGetter(ThriftConstants.FIELD_GETTER_URL, ThriftConstants.T_HTTP_CLIENT_FIELD_URL_); + return target.toBytecode(); + } + }); + } + // Common private void addInterceptorsForRetrievingSocketAddresses() { diff --git a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftTypeProvider.java b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftTypeProvider.java index 96ba3d159592..c61e2ba68f0e 100644 --- a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftTypeProvider.java +++ b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftTypeProvider.java @@ -29,8 +29,8 @@ public class ThriftTypeProvider implements TraceMetadataProvider { public void setup(TraceMetadataSetupContext context) { context.addServiceType(ThriftConstants.THRIFT_SERVER); context.addServiceType(ThriftConstants.THRIFT_CLIENT, AnnotationKeyMatchers.exact(ThriftConstants.THRIFT_URL)); - context.addServiceType(ThriftConstants.THRIFT_SERVER_INTERNAL, AnnotationKeyMatchers.ARGS_MATCHER); - context.addServiceType(ThriftConstants.THRIFT_CLIENT_INTERNAL, AnnotationKeyMatchers.ARGS_MATCHER); + context.addServiceType(ThriftConstants.THRIFT_SERVER_INTERNAL, AnnotationKeyMatchers.exact(ThriftConstants.THRIFT_URL)); + context.addServiceType(ThriftConstants.THRIFT_CLIENT_INTERNAL, AnnotationKeyMatchers.exact(ThriftConstants.THRIFT_URL)); context.addAnnotationKey(ThriftConstants.THRIFT_URL); context.addAnnotationKey(ThriftConstants.THRIFT_ARGS); context.addAnnotationKey(ThriftConstants.THRIFT_RESULT); diff --git a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftUtils.java b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftUtils.java index 08a9a8b5828e..1a6afb7bd2e3 100644 --- a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftUtils.java +++ b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftUtils.java @@ -16,16 +16,17 @@ package com.navercorp.pinpoint.plugin.thrift; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.regex.Pattern; - +import com.navercorp.pinpoint.bootstrap.plugin.util.SocketAddressUtils; import com.navercorp.pinpoint.common.plugin.util.HostAndPort; import org.apache.thrift.TBaseAsyncProcessor; import org.apache.thrift.TBaseProcessor; import org.apache.thrift.TServiceClient; import org.apache.thrift.async.TAsyncMethodCall; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.regex.Pattern; + /** * @author HyunGil Jeong */ @@ -75,7 +76,14 @@ public static String getClientServiceName(TServiceClient client) { */ public static String getAsyncMethodCallName(TAsyncMethodCall asyncMethodCall) { String asyncMethodCallClassName = asyncMethodCall.getClass().getName(); - return convertDotPathToUriPath(ThriftConstants.ASYNC_METHOD_CALL_PATTERN.matcher(asyncMethodCallClassName).replaceAll(".")); + String convertedMethodCallName = convertDotPathToUriPath(ThriftConstants.ASYNC_METHOD_CALL_PATTERN.matcher(asyncMethodCallClassName).replaceAll(".")); + // thrift java generator appends "_call" to the method name when naming the function class + // https://github.com/apache/thrift/blob/master/compiler/cpp/src/thrift/generate/t_java_generator.cc#L3151 + final String callSuffix = "_call"; + if (convertedMethodCallName.endsWith(callSuffix)) { + return convertedMethodCallName.substring(0, convertedMethodCallName.length() - callSuffix.length()); + } + return convertedMethodCallName; } /** @@ -85,16 +93,12 @@ public static String getAsyncMethodCallName(TAsyncMethodCall asyncMethodCall) * @return the ip address retrieved from the given socketAddress, * or {@literal ThriftConstants.UNKNOWN_ADDRESS} if it cannot be retrieved */ - // TODO should probably be pulled up as a common API public static String getIp(SocketAddress socketAddress) { - if (socketAddress == null) { - return ThriftConstants.UNKNOWN_ADDRESS; - } if (socketAddress instanceof InetSocketAddress) { - InetSocketAddress addr = (InetSocketAddress)socketAddress; - return addr.getAddress().getHostAddress(); + InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; + return SocketAddressUtils.getAddressFirst(inetSocketAddress, ThriftConstants.UNKNOWN_ADDRESS); } - return getSocketAddress(socketAddress); + return ThriftConstants.UNKNOWN_ADDRESS; } /** @@ -104,16 +108,16 @@ public static String getIp(SocketAddress socketAddress) { * @return the ip/port retrieved from the given socketAddress, * or {@literal ThriftConstants.UNKNOWN_ADDRESS} if it cannot be retrieved */ - // TODO should probably be pulled up as a common API public static String getIpPort(SocketAddress socketAddress) { - if (socketAddress == null) { - return ThriftConstants.UNKNOWN_ADDRESS; - } if (socketAddress instanceof InetSocketAddress) { - InetSocketAddress addr = (InetSocketAddress)socketAddress; - return HostAndPort.toHostAndPortString(addr.getAddress().getHostAddress(), addr.getPort()); + InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; + String address = SocketAddressUtils.getAddressFirst(inetSocketAddress); + if (address == null) { + return ThriftConstants.UNKNOWN_ADDRESS; + } + return HostAndPort.toHostAndPortString(address, inetSocketAddress.getPort()); } - return getSocketAddress(socketAddress); + return ThriftConstants.UNKNOWN_ADDRESS; } /** @@ -123,16 +127,12 @@ public static String getIpPort(SocketAddress socketAddress) { * @return the host retrieved from the given socketAddress, * or {@literal ThriftConstants.UNKNOWN_ADDRESS} if it cannot be retrieved */ - // TODO should probably be pulled up as a common API public static String getHost(SocketAddress socketAddress) { - if (socketAddress == null) { - return ThriftConstants.UNKNOWN_ADDRESS; - } if (socketAddress instanceof InetSocketAddress) { - InetSocketAddress addr = (InetSocketAddress)socketAddress; - return addr.getHostName(); + InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; + return SocketAddressUtils.getHostNameFirst(inetSocketAddress, ThriftConstants.UNKNOWN_ADDRESS); } - return getSocketAddress(socketAddress); + return ThriftConstants.UNKNOWN_ADDRESS; } /** @@ -142,32 +142,15 @@ public static String getHost(SocketAddress socketAddress) { * @return the host/port retrieved from the given socketAddress, * or {@literal ThriftConstants.UNKNOWN_ADDRESS} if it cannot be retrieved */ - // TODO should probably be pulled up as a common API public static String getHostPort(SocketAddress socketAddress) { - if (socketAddress == null) { - return ThriftConstants.UNKNOWN_ADDRESS; - } if (socketAddress instanceof InetSocketAddress) { - InetSocketAddress addr = (InetSocketAddress)socketAddress; - return HostAndPort.toHostAndPortString(addr.getHostName(), addr.getPort()); - } - return getSocketAddress(socketAddress); - } - - private static String getSocketAddress(SocketAddress socketAddress) { - String address = socketAddress.toString(); - int addressLength = address.length(); - - if (addressLength > 0) { - if (address.startsWith("/")) { - return address.substring(1); - } else { - final int delimeterIndex = address.indexOf('/'); - if (delimeterIndex != -1 && delimeterIndex < addressLength) { - return address.substring(address.indexOf('/') + 1); - } + InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; + String hostName = SocketAddressUtils.getHostNameFirst(inetSocketAddress); + if (hostName == null) { + return ThriftConstants.UNKNOWN_ADDRESS; } + return HostAndPort.toHostAndPortString(hostName, inetSocketAddress.getPort()); } - return address; + return ThriftConstants.UNKNOWN_ADDRESS; } } diff --git a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/field/getter/UrlFieldGetter.java b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/field/getter/UrlFieldGetter.java new file mode 100644 index 000000000000..5109fb7fe843 --- /dev/null +++ b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/field/getter/UrlFieldGetter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.thrift.field.getter; + +import java.net.URL; + +/** + * @author HyunGil Jeong + */ +public interface UrlFieldGetter { + URL _$PINPOINT$_getUrl(); +} diff --git a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/client/TServiceClientSendBaseInterceptor.java b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/client/TServiceClientSendBaseInterceptor.java index a421db1c6546..61370df0384e 100644 --- a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/client/TServiceClientSendBaseInterceptor.java +++ b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/client/TServiceClientSendBaseInterceptor.java @@ -17,12 +17,16 @@ package com.navercorp.pinpoint.plugin.thrift.interceptor.client; import java.net.Socket; +import java.net.URL; import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.plugin.thrift.field.getter.UrlFieldGetter; import org.apache.thrift.TBase; import org.apache.thrift.TServiceClient; import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.transport.THttpClient; import org.apache.thrift.transport.TTransport; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; @@ -84,43 +88,39 @@ public void before(Object target, Object[] args) { if (trace == null) { return; } - ThriftRequestProperty parentTraceInfo = new ThriftRequestProperty(); + final boolean shouldSample = trace.canSampled(); if (!shouldSample) { + if (transport instanceof THttpClient) { + return; + } + ThriftRequestProperty parentTraceInfo = new ThriftRequestProperty(); if (isDebug) { logger.debug("set Sampling flag=false"); } - parentTraceInfo.setShouldSample(shouldSample); + parentTraceInfo.setShouldSample(false); + InterceptorScopeInvocation currentTransaction = this.scope.getCurrentInvocation(); + currentTransaction.setAttachment(parentTraceInfo); + return; + } + + SpanEventRecorder recorder = trace.traceBlockBegin(); + String remoteAddress = ThriftConstants.UNKNOWN_ADDRESS; + + // If we're writing to THttpClient, http client plugin will handle trace propagation. + // We simply record as basic method. + if (transport instanceof THttpClient) { + recorder.recordServiceType(ThriftConstants.THRIFT_CLIENT_INTERNAL); + remoteAddress = getRemoteAddressForTHttpClient((THttpClient) transport); } else { - SpanEventRecorder recorder = trace.traceBlockBegin(); recorder.recordServiceType(ThriftConstants.THRIFT_CLIENT); - - // retrieve connection information - String remoteAddress = ThriftConstants.UNKNOWN_ADDRESS; - if (transport instanceof SocketFieldAccessor) { - Socket socket = ((SocketFieldAccessor)transport)._$PINPOINT$_getSocket(); - if (socket != null) { - remoteAddress = ThriftUtils.getHostPort(socket.getRemoteSocketAddress()); - } - } else { - if (isDebug) { - logger.debug("Invalid target object. Need field accessor({}).", SocketFieldAccessor.class.getName()); - } - } + remoteAddress = getRemoteAddress(transport); recorder.recordDestinationId(remoteAddress); - String methodName = ThriftConstants.UNKNOWN_METHOD_NAME; - if (args[0] instanceof String) { - methodName = (String)args[0]; - } - String serviceName = ThriftUtils.getClientServiceName(client); - - String thriftUrl = getServiceUrl(remoteAddress, serviceName, methodName); - recorder.recordAttribute(ThriftConstants.THRIFT_URL, thriftUrl); - TraceId nextId = trace.getTraceId().getNextTraceId(); recorder.recordNextSpanId(nextId.getSpanId()); + ThriftRequestProperty parentTraceInfo = new ThriftRequestProperty(); parentTraceInfo.setTraceId(nextId.getTransactionId()); parentTraceInfo.setSpanId(nextId.getSpanId()); parentTraceInfo.setParentSpanId(nextId.getParentSpanId()); @@ -129,10 +129,49 @@ public void before(Object target, Object[] args) { parentTraceInfo.setParentApplicationName(traceContext.getApplicationName()); parentTraceInfo.setParentApplicationType(traceContext.getServerTypeCode()); parentTraceInfo.setAcceptorHost(remoteAddress); + + InterceptorScopeInvocation currentTransaction = this.scope.getCurrentInvocation(); + currentTransaction.setAttachment(parentTraceInfo); + + } + + String methodName = ThriftConstants.UNKNOWN_METHOD_NAME; + if (args[0] instanceof String) { + methodName = (String)args[0]; + } + String serviceName = ThriftUtils.getClientServiceName(client); + String thriftUrl = getServiceUrl(remoteAddress, serviceName, methodName); + recorder.recordAttribute(ThriftConstants.THRIFT_URL, thriftUrl); + } + } + + private String getRemoteAddressForTHttpClient(THttpClient tHttpClient) { + if (tHttpClient instanceof UrlFieldGetter) { + URL url = ((UrlFieldGetter) tHttpClient)._$PINPOINT$_getUrl(); + if (url == null) { + return ThriftConstants.UNKNOWN_ADDRESS; + } + return HostAndPort.toHostAndPortString(url.getHost(), url.getPort()); + } + if (isDebug) { + logger.debug("Invalid oprot transport object. Need field getter({}).", UrlFieldGetter.class.getName()); + } + return ThriftConstants.UNKNOWN_ADDRESS; + } + + private String getRemoteAddress(TTransport transport) { + if (transport instanceof SocketFieldAccessor) { + Socket socket = ((SocketFieldAccessor)transport)._$PINPOINT$_getSocket(); + if (socket == null) { + return ThriftConstants.UNKNOWN_ADDRESS; + } + return ThriftUtils.getHostPort(socket.getRemoteSocketAddress()); + } else { + if (isDebug) { + logger.debug("Invalid oprot transport object. Need field accessor({}).", SocketFieldAccessor.class.getName()); } - InterceptorScopeInvocation currentTransaction = this.scope.getCurrentInvocation(); - currentTransaction.setAttachment(parentTraceInfo); } + return ThriftConstants.UNKNOWN_ADDRESS; } private String getServiceUrl(String url, String serviceName, String methodName) { diff --git a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/server/TBaseProcessorProcessInterceptor.java b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/server/TBaseProcessorProcessInterceptor.java index f09b89ac78ed..634b51683f83 100644 --- a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/server/TBaseProcessorProcessInterceptor.java +++ b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/server/TBaseProcessorProcessInterceptor.java @@ -16,12 +16,9 @@ package com.navercorp.pinpoint.plugin.thrift.interceptor.server; -import java.net.Socket; import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; import org.apache.thrift.TBaseProcessor; -import org.apache.thrift.protocol.TProtocol; -import org.apache.thrift.transport.TTransport; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; @@ -35,7 +32,6 @@ import com.navercorp.pinpoint.plugin.thrift.ThriftClientCallContext; import com.navercorp.pinpoint.plugin.thrift.ThriftConstants; import com.navercorp.pinpoint.plugin.thrift.ThriftUtils; -import com.navercorp.pinpoint.plugin.thrift.field.accessor.SocketFieldAccessor; /** * Entry/exit point for tracing synchronous processors for Thrift services. @@ -98,65 +94,61 @@ public void after(Object target, Object[] args, Object result, Throwable throwab if (trace == null) { return; } + + InterceptorScopeInvocation currentTransaction = this.scope.getCurrentInvocation(); + Object attachment = currentTransaction.getAttachment(); + if (!(attachment instanceof ThriftClientCallContext)) { + return; + } + // logging here as some Thrift servers depend on TTransportException being thrown for normal operations. // log only when current transaction is being traced. if (isDebug) { logger.afterInterceptor(target, args, result, throwable); } - this.traceContext.removeTraceObject(); + + ThriftClientCallContext clientCallContext = (ThriftClientCallContext) attachment; + if (clientCallContext.isEntryPoint()) { + traceContext.removeTraceObject(); + } + if (trace.canSampled()) { - try { - processTraceObject(trace, target, args, throwable); - } catch (Throwable t) { - logger.warn("Error processing trace object. Cause:{}", t.getMessage(), t); - } finally { - trace.close(); + String methodUri = getMethodUri(target); + if (clientCallContext.isEntryPoint()) { + finalizeSpan(trace, methodUri, throwable); + } else { + finalizeSpanEvent(trace, methodUri, throwable); } } } - private void processTraceObject(final Trace trace, Object target, Object[] args, Throwable throwable) { - // end spanEvent + private void finalizeSpan(final Trace trace, String methodUri, Throwable throwable) { + try { + finalizeSpanEvent(trace, null, throwable); + SpanRecorder recorder = trace.getSpanRecorder(); + recorder.recordRpcName(methodUri); + } catch (Throwable t) { + logger.warn("Error processing trace object. Cause:{}", t.getMessage(), t); + } finally { + trace.close(); + } + } + + private void finalizeSpanEvent(final Trace trace, String methodUri, Throwable throwable) { try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); // TODO Might need a way to collect and record method arguments // trace.recordAttribute(...); recorder.recordException(throwable); recorder.recordApi(this.descriptor); + if (methodUri != null) { + recorder.recordAttribute(ThriftConstants.THRIFT_URL, methodUri); + } } catch (Throwable t) { logger.warn("Error processing trace object. Cause:{}", t.getMessage(), t); } finally { trace.traceBlockEnd(); } - - // end root span - SpanRecorder recorder = trace.getSpanRecorder(); - String methodUri = getMethodUri(target); - recorder.recordRpcName(methodUri); - // retrieve connection information - String localIpPort = ThriftConstants.UNKNOWN_ADDRESS; - String remoteAddress = ThriftConstants.UNKNOWN_ADDRESS; - if (args.length == 2 && args[0] instanceof TProtocol) { - TProtocol inputProtocol = (TProtocol)args[0]; - TTransport inputTransport = inputProtocol.getTransport(); - if (inputTransport instanceof SocketFieldAccessor) { - Socket socket = ((SocketFieldAccessor)inputTransport)._$PINPOINT$_getSocket(); - if (socket != null) { - localIpPort = ThriftUtils.getHostPort(socket.getLocalSocketAddress()); - remoteAddress = ThriftUtils.getHost(socket.getRemoteSocketAddress()); - } - } else { - if (isDebug) { - logger.debug("Invalid target object. Need field accessor({}).", SocketFieldAccessor.class.getName()); - } - } - } - if (localIpPort != ThriftConstants.UNKNOWN_ADDRESS) { - recorder.recordEndPoint(localIpPort); - } - if (remoteAddress != ThriftConstants.UNKNOWN_ADDRESS) { - recorder.recordRemoteAddress(remoteAddress); - } } private String getMethodUri(Object target) { diff --git a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/tprotocol/server/TProtocolReadMessageEndInterceptor.java b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/tprotocol/server/TProtocolReadMessageEndInterceptor.java index ebef5c275507..54a3148beae6 100644 --- a/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/tprotocol/server/TProtocolReadMessageEndInterceptor.java +++ b/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/interceptor/tprotocol/server/TProtocolReadMessageEndInterceptor.java @@ -99,12 +99,9 @@ public void after(Object target, Object[] args, Object result, Throwable throwab InterceptorScopeInvocation currentTransaction = this.scope.getCurrentInvocation(); Object attachment = currentTransaction.getAttachment(); if (attachment instanceof ThriftClientCallContext) { - ThriftClientCallContext clientCallContext = (ThriftClientCallContext)attachment; - String methodName = clientCallContext.getMethodName(); - ThriftRequestProperty parentTraceInfo = clientCallContext.getTraceHeader(); + ThriftClientCallContext clientCallContext = (ThriftClientCallContext) attachment; try { - this.logger.debug("parentTraceInfo : {}", parentTraceInfo); - recordTrace(target, parentTraceInfo, methodName); + recordTrace(target, clientCallContext); } catch (Throwable t) { logger.warn("Error creating trace object. Cause:{}", t.getMessage(), t); } @@ -132,8 +129,17 @@ private boolean validate(Object target) { return true; } - private void recordTrace(Object target, ThriftRequestProperty parentTraceInfo, String methodName) { - final Trace trace = createTrace(target, parentTraceInfo, methodName); + private void recordTrace(Object target, ThriftClientCallContext clientCallContext) { + String methodName = clientCallContext.getMethodName(); + // Check if there is an active trace first for cases such as TServlet, which one of the WAS plugins would + // have created one already. + Trace trace = traceContext.currentRawTraceObject(); + if (trace == null) { + ThriftRequestProperty parentTraceInfo = clientCallContext.getTraceHeader(); + this.logger.debug("parentTraceInfo : {}", parentTraceInfo); + trace = createTrace(target, parentTraceInfo, methodName); + clientCallContext.setEntryPoint(true); + } if (trace == null) { return; } @@ -250,10 +256,10 @@ private void recordConnection(SpanRecorder recorder, TTransport transport) { // retrieve connection information String localIpPort = ThriftConstants.UNKNOWN_ADDRESS; String remoteAddress = ThriftConstants.UNKNOWN_ADDRESS; - Socket socket = ((SocketFieldAccessor)transport)._$PINPOINT$_getSocket(); + Socket socket = ((SocketFieldAccessor) transport)._$PINPOINT$_getSocket(); if (socket != null) { - localIpPort = ThriftUtils.getHostPort(socket.getLocalSocketAddress()); - remoteAddress = ThriftUtils.getHost(socket.getRemoteSocketAddress()); + localIpPort = ThriftUtils.getIpPort(socket.getLocalSocketAddress()); + remoteAddress = ThriftUtils.getIp(socket.getRemoteSocketAddress()); } if (localIpPort != ThriftConstants.UNKNOWN_ADDRESS) { recorder.recordEndPoint(localIpPort); diff --git a/plugins/tomcat/clover.license b/plugins/tomcat/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/tomcat/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 @@ -5,7 +21,7 @@ com.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-tomcat-plugin @@ -16,6 +32,18 @@ ${env.JAVA_7_HOME} + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + com.navercorp.pinpoint @@ -44,6 +72,18 @@ test + + com.navercorp.pinpoint + pinpoint-common-servlet + ${project.version} + compile + + + + javax.servlet + javax.servlet-api + provided + org.apache.tomcat @@ -60,5 +100,35 @@ coyote test + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${plugin.shade.version} + + + package + + shade + + + + + com.navercorp.pinpoint.plugin.common.servlet + com.navercorp.pinpoint.plugin.tomcat.common.servlet + + + + ${project.build.directory}/dependency-reduced-pom.xml + + + + + + + diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/AsyncAccessor.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/AsyncAccessor.java deleted file mode 100644 index 18ebbb0e3318..000000000000 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/AsyncAccessor.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.navercorp.pinpoint.plugin.tomcat; - -public interface AsyncAccessor { - void _$PINPOINT$_setAsync(boolean async); - boolean _$PINPOINT$_isAsync(); -} diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/ServletAsyncMethodDescriptor.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/ServletAsyncMethodDescriptor.java deleted file mode 100644 index 537636a109a8..000000000000 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/ServletAsyncMethodDescriptor.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.tomcat; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.common.trace.MethodType; - -/** - * - * @author jaehong.kim - * - */ -public class ServletAsyncMethodDescriptor implements MethodDescriptor { - private int apiId = 0; - private int type = MethodType.WEB_REQUEST; - - @Override - public String getMethodName() { - return ""; - } - - @Override - public String getClassName() { - return ""; - } - - @Override - public String[] getParameterTypes() { - return null; - } - - @Override - public String[] getParameterVariableName() { - return null; - } - - @Override - public String getParameterDescriptor() { - return "()"; - } - - @Override - public int getLineNumber() { - return -1; - } - - @Override - public String getFullName() { - return ServletAsyncMethodDescriptor.class.getName(); - } - - @Override - public void setApiId(int apiId) { - this.apiId = apiId; - } - - @Override - public int getApiId() { - return apiId; - } - - @Override - public String getApiDescriptor() { - return "Tomcat Servlet Asynchronous Process"; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } -} \ No newline at end of file diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/ServletSyncMethodDescriptor.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/ServletSyncMethodDescriptor.java deleted file mode 100644 index 4f25de55f7a8..000000000000 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/ServletSyncMethodDescriptor.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.tomcat; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.common.trace.MethodType; - -/** - * - * @author jaehong.kim - * - */ -public class ServletSyncMethodDescriptor implements MethodDescriptor { - private int apiId = 0; - private int type = MethodType.WEB_REQUEST; - - @Override - public String getMethodName() { - return ""; - } - - @Override - public String getClassName() { - return ""; - } - - @Override - public String[] getParameterTypes() { - return null; - } - - @Override - public String[] getParameterVariableName() { - return null; - } - - @Override - public String getParameterDescriptor() { - return "()"; - } - - @Override - public int getLineNumber() { - return -1; - } - - @Override - public String getFullName() { - return ServletSyncMethodDescriptor.class.getName(); - } - - @Override - public void setApiId(int apiId) { - this.apiId = apiId; - } - - @Override - public int getApiId() { - return apiId; - } - - @Override - public String getApiDescriptor() { - return "Tomcat Servlet Process"; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } -} \ No newline at end of file diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatAsyncListener.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatAsyncListener.java new file mode 100644 index 000000000000..9ad6277e929e --- /dev/null +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatAsyncListener.java @@ -0,0 +1,122 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.tomcat; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.AsyncListenerInterceptorHelper; + +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author jaehong.kim + */ +public class TomcatAsyncListener implements AsyncListener { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private final AsyncListenerInterceptorHelper asyncListenerInterceptorHelper; + + public TomcatAsyncListener(final TraceContext traceContext, final AsyncContext asyncContext) { + this.asyncListenerInterceptorHelper = new AsyncListenerInterceptorHelper(traceContext, asyncContext); + } + + @Override + public void onComplete(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Complete asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + final int statusCode = getStatusCode(asyncEvent); + this.asyncListenerInterceptorHelper.complete(asyncEvent.getThrowable(), statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + } + + @Override + public void onTimeout(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Timeout asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.timeout(asyncEvent.getThrowable()); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onError(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Error asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.error(asyncEvent.getThrowable()); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + } + + @Override + public void onStartAsync(AsyncEvent asyncEvent) throws IOException { + } + + private int getStatusCode(final AsyncEvent asyncEvent) { + try { + if (asyncEvent.getSuppliedResponse() instanceof HttpServletResponse) { + return ((HttpServletResponse) asyncEvent.getSuppliedResponse()).getStatus(); + } + } catch (Exception ignored) { + } + return 0; + } +} \ No newline at end of file diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatConfig.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatConfig.java index 3b2a4d6f5586..8886cbe1dd28 100644 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatConfig.java +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatConfig.java @@ -30,16 +30,16 @@ */ public class TomcatConfig { - private final boolean tomcatEnable; - private final List tomcatBootstrapMains; - private final boolean tomcatConditionalTransformEnable; - private final boolean tomcatHidePinpointHeader; + private final boolean enable; + private final List bootstrapMains; + private final boolean conditionalTransformEnable; + private final boolean hidePinpointHeader; - private final boolean tomcatTraceRequestParam; - private final Filter tomcatExcludeUrlFilter; - private final String tomcatRealIpHeader; - private final String tomcatRealIpEmptyValue; - private final Filter tomcatExcludeProfileMethodFilter; + private final boolean traceRequestParam; + private final Filter excludeUrlFilter; + private final String realIpHeader; + private final String realIpEmptyValue; + private final Filter excludeProfileMethodFilter; // for transform conditional check private final List springBootBootstrapMains; @@ -50,66 +50,66 @@ public TomcatConfig(ProfilerConfig config) { } // plugin - this.tomcatEnable = config.readBoolean("profiler.tomcat.enable", true); - this.tomcatBootstrapMains = config.readList("profiler.tomcat.bootstrap.main"); - this.tomcatConditionalTransformEnable = config.readBoolean("profiler.tomcat.conditional.transform", true); - this.tomcatHidePinpointHeader = config.readBoolean("profiler.tomcat.hidepinpointheader", true); + this.enable = config.readBoolean("profiler.tomcat.enable", true); + this.bootstrapMains = config.readList("profiler.tomcat.bootstrap.main"); + this.conditionalTransformEnable = config.readBoolean("profiler.tomcat.conditional.transform", true); + this.hidePinpointHeader = config.readBoolean("profiler.tomcat.hidepinpointheader", true); // runtime - this.tomcatTraceRequestParam = config.readBoolean("profiler.tomcat.tracerequestparam", true); + this.traceRequestParam = config.readBoolean("profiler.tomcat.tracerequestparam", true); final String tomcatExcludeURL = config.readString("profiler.tomcat.excludeurl", ""); if (!tomcatExcludeURL.isEmpty()) { - this.tomcatExcludeUrlFilter = new ExcludePathFilter(tomcatExcludeURL); + this.excludeUrlFilter = new ExcludePathFilter(tomcatExcludeURL); } else { - this.tomcatExcludeUrlFilter = new SkipFilter(); + this.excludeUrlFilter = new SkipFilter(); } - this.tomcatRealIpHeader = config.readString("profiler.tomcat.realipheader", null); - this.tomcatRealIpEmptyValue = config.readString("profiler.tomcat.realipemptyvalue", null); + this.realIpHeader = config.readString("profiler.tomcat.realipheader", null); + this.realIpEmptyValue = config.readString("profiler.tomcat.realipemptyvalue", null); final String tomcatExcludeProfileMethod = config.readString("profiler.tomcat.excludemethod", ""); if (!tomcatExcludeProfileMethod.isEmpty()) { - this.tomcatExcludeProfileMethodFilter = new ExcludeMethodFilter(tomcatExcludeProfileMethod); + this.excludeProfileMethodFilter = new ExcludeMethodFilter(tomcatExcludeProfileMethod); } else { - this.tomcatExcludeProfileMethodFilter = new SkipFilter(); + this.excludeProfileMethodFilter = new SkipFilter(); } this.springBootBootstrapMains = config.readList("profiler.springboot.bootstrap.main"); } - public boolean isTomcatEnable() { - return tomcatEnable; + public boolean isEnable() { + return enable; } - public List getTomcatBootstrapMains() { - return tomcatBootstrapMains; + public List getBootstrapMains() { + return bootstrapMains; } - public boolean isTomcatConditionalTransformEnable() { - return tomcatConditionalTransformEnable; + public boolean isConditionalTransformEnable() { + return conditionalTransformEnable; } - public boolean isTomcatHidePinpointHeader() { - return tomcatHidePinpointHeader; + public boolean isHidePinpointHeader() { + return hidePinpointHeader; } - public boolean isTomcatTraceRequestParam() { - return tomcatTraceRequestParam; + public boolean isTraceRequestParam() { + return traceRequestParam; } - public Filter getTomcatExcludeUrlFilter() { - return tomcatExcludeUrlFilter; + public Filter getExcludeUrlFilter() { + return excludeUrlFilter; } - public String getTomcatRealIpHeader() { - return tomcatRealIpHeader; + public String getRealIpHeader() { + return realIpHeader; } - public String getTomcatRealIpEmptyValue() { - return tomcatRealIpEmptyValue; + public String getRealIpEmptyValue() { + return realIpEmptyValue; } - public Filter getTomcatExcludeProfileMethodFilter() { - return tomcatExcludeProfileMethodFilter; + public Filter getExcludeProfileMethodFilter() { + return excludeProfileMethodFilter; } public List getSpringBootBootstrapMains() { @@ -119,15 +119,15 @@ public List getSpringBootBootstrapMains() { @Override public String toString() { final StringBuilder sb = new StringBuilder("TomcatConfig{"); - sb.append("tomcatEnable=").append(tomcatEnable); - sb.append(", tomcatBootstrapMains=").append(tomcatBootstrapMains); - sb.append(", tomcatConditionalTransformEnable=").append(tomcatConditionalTransformEnable); - sb.append(", tomcatHidePinpointHeader=").append(tomcatHidePinpointHeader); - sb.append(", tomcatTraceRequestParam=").append(tomcatTraceRequestParam); - sb.append(", tomcatExcludeUrlFilter=").append(tomcatExcludeUrlFilter); - sb.append(", tomcatRealIpHeader='").append(tomcatRealIpHeader).append('\''); - sb.append(", tomcatRealIpEmptyValue='").append(tomcatRealIpEmptyValue).append('\''); - sb.append(", tomcatExcludeProfileMethodFilter=").append(tomcatExcludeProfileMethodFilter); + sb.append("enable=").append(enable); + sb.append(", bootstrapMains=").append(bootstrapMains); + sb.append(", conditionalTransformEnable=").append(conditionalTransformEnable); + sb.append(", hidePinpointHeader=").append(hidePinpointHeader); + sb.append(", traceRequestParam=").append(traceRequestParam); + sb.append(", excludeUrlFilter=").append(excludeUrlFilter); + sb.append(", realIpHeader='").append(realIpHeader).append('\''); + sb.append(", realIpEmptyValue='").append(realIpEmptyValue).append('\''); + sb.append(", excludeProfileMethodFilter=").append(excludeProfileMethodFilter); sb.append(", springBootBootstrapMains=").append(springBootBootstrapMains); sb.append('}'); return sb.toString(); diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatConstants.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatConstants.java index 60538acd1094..22bdeeb74b65 100644 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatConstants.java +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatConstants.java @@ -32,8 +32,5 @@ private TomcatConstants() { public static final ServiceType TOMCAT_METHOD = ServiceTypeFactory.of(1011, "TOMCAT_METHOD"); public static final String TOMCAT_SERVLET_ASYNC_SCOPE = "TomcatServletAsyncScope"; - - public static final String ASYNC_ACCESSOR = "com.navercorp.pinpoint.plugin.tomcat.AsyncAccessor"; - public static final String TRACE_ACCESSOR = "com.navercorp.pinpoint.plugin.tomcat.TraceAccessor"; - + public static final String TOMCAT_SERVLET_REQUEST_TRACE = "com.navercorp.pinpoint.trace"; } \ No newline at end of file diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatPlugin.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatPlugin.java index a4c328d56b39..a11c68933f42 100644 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatPlugin.java +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TomcatPlugin.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,11 +16,9 @@ import java.security.ProtectionDomain; -import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; -import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; @@ -41,24 +39,19 @@ public class TomcatPlugin implements ProfilerPlugin, TransformTemplateAware { private TransformTemplate transformTemplate; - /* - * (non-Javadoc) - * - * @see com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin#setUp(com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext) - */ @Override public void setup(ProfilerPluginSetupContext context) { - final TomcatConfig config = new TomcatConfig(context.getConfig()); - if (logger.isInfoEnabled()) { - logger.info("TomcatPlugin config:{}", config); - } - if (!config.isTomcatEnable()) { + if (!config.isEnable()) { logger.info("TomcatPlugin disabled"); return; } - TomcatDetector tomcatDetector = new TomcatDetector(config.getTomcatBootstrapMains()); + if (logger.isInfoEnabled()) { + logger.info("TomcatPlugin config:{}", config); + } + + final TomcatDetector tomcatDetector = new TomcatDetector(config.getBootstrapMains()); context.addApplicationTypeDetector(tomcatDetector); if (shouldAddTransformers(config)) { @@ -71,144 +64,84 @@ public void setup(ProfilerPluginSetupContext context) { private boolean shouldAddTransformers(TomcatConfig config) { // Transform if conditional check is disabled - if (!config.isTomcatConditionalTransformEnable()) { + if (!config.isConditionalTransformEnable()) { return true; } // Only transform if it's a Tomcat application or SpringBoot application - ConditionProvider conditionProvider = ConditionProvider.DEFAULT_CONDITION_PROVIDER; - boolean isTomcatApplication = conditionProvider.checkMainClass(config.getTomcatBootstrapMains()); - boolean isSpringBootApplication = conditionProvider.checkMainClass(config.getSpringBootBootstrapMains()); + final ConditionProvider conditionProvider = ConditionProvider.DEFAULT_CONDITION_PROVIDER; + final boolean isTomcatApplication = conditionProvider.checkMainClass(config.getBootstrapMains()); + final boolean isSpringBootApplication = conditionProvider.checkMainClass(config.getSpringBootBootstrapMains()); return isTomcatApplication || isSpringBootApplication; } private void addTransformers(TomcatConfig config) { - if (config.isTomcatHidePinpointHeader()) { - addRequestFacadeEditor(); - } - - addRequestEditor(); - addStandardHostValveEditor(); - addStandardServiceEditor(); - addTomcatConnectorEditor(); - addWebappLoaderEditor(); - - addAsyncContextImpl(); - } - - private void addRequestEditor() { - transformTemplate.transform("org.apache.catalina.connector.Request", new TransformCallback() { - - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - target.addField(TomcatConstants.TRACE_ACCESSOR); - target.addField(TomcatConstants.ASYNC_ACCESSOR); - - // clear request. - InstrumentMethod recycleMethodEditorBuilder = target.getDeclaredMethod("recycle"); - if (recycleMethodEditorBuilder != null) { - recycleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.RequestRecycleInterceptor"); - } - - // trace asynchronous process. - InstrumentMethod startAsyncMethodEditor = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); - if (startAsyncMethodEditor != null) { - startAsyncMethodEditor.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.RequestStartAsyncInterceptor"); - } - - return target.toBytecode(); - } - }); - } - - private void addRequestFacadeEditor() { - transformTemplate.transform("org.apache.catalina.connector.RequestFacade", new TransformCallback() { - - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - if (target != null) { - target.weave("com.navercorp.pinpoint.plugin.tomcat.aspect.RequestFacadeAspect"); - return target.toBytecode(); - } - - return null; - } - }); + // Add server metadata + addStandardService(); + addTomcatConnector(); + addWebappLoader(); + + // Add async listener. Servlet 3.0 + addRequest(); + // Hide pinpoint headers & Trace HTTP response status code + addRequestFacade(config); + // Entry Point + addStandardHostValve(); } - private void addStandardHostValveEditor() { - transformTemplate.transform("org.apache.catalina.core.StandardHostValve", new TransformCallback() { - - @Override - public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - - InstrumentMethod method = target.getDeclaredMethod("invoke", "org.apache.catalina.connector.Request", "org.apache.catalina.connector.Response"); - if (method != null) { - method.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.StandardHostValveInvokeInterceptor"); - } - - return target.toBytecode(); - } - }); - } - private void addStandardServiceEditor() { + private void addStandardService() { transformTemplate.transform("org.apache.catalina.core.StandardService", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Add server metadata // Tomcat 6 - InstrumentMethod startEditor = target.getDeclaredMethod("start"); + final InstrumentMethod startEditor = target.getDeclaredMethod("start"); if (startEditor != null) { startEditor.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.StandardServiceStartInterceptor"); } // Tomcat 7 - InstrumentMethod startInternalEditor = target.getDeclaredMethod("startInternal"); + final InstrumentMethod startInternalEditor = target.getDeclaredMethod("startInternal"); if (startInternalEditor != null) { startInternalEditor.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.StandardServiceStartInterceptor"); } - return target.toBytecode(); } }); } - private void addTomcatConnectorEditor() { + private void addTomcatConnector() { transformTemplate.transform("org.apache.catalina.connector.Connector", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Add server metadata // Tomcat 6 - InstrumentMethod initializeEditor = target.getDeclaredMethod("initialize"); + final InstrumentMethod initializeEditor = target.getDeclaredMethod("initialize"); if (initializeEditor != null) { initializeEditor.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.ConnectorInitializeInterceptor"); } // Tomcat 7 - InstrumentMethod initInternalEditor = target.getDeclaredMethod("initInternal"); + final InstrumentMethod initInternalEditor = target.getDeclaredMethod("initInternal"); if (initInternalEditor != null) { initInternalEditor.addScopedInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.ConnectorInitializeInterceptor", TomcatConstants.TOMCAT_SERVLET_ASYNC_SCOPE); } - return target.toBytecode(); } }); } - private void addWebappLoaderEditor() { + private void addWebappLoader() { transformTemplate.transform("org.apache.catalina.loader.WebappLoader", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Add servlet information InstrumentMethod startMethod = null; if (target.hasDeclaredMethod("start")) { // Tomcat 6 - org.apache.catalina.loader.WebappLoader.start() @@ -221,30 +154,61 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, if (startMethod != null) { startMethod.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.WebappLoaderStartInterceptor"); } + return target.toBytecode(); + } + }); + } + + private void addRequest() { + transformTemplate.transform("org.apache.catalina.connector.Request", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Add async listener. Servlet 3.0 + final InstrumentMethod startAsyncMethodEditor = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); + if (startAsyncMethodEditor != null) { + startAsyncMethodEditor.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.RequestStartAsyncInterceptor"); + } return target.toBytecode(); } }); } - private void addAsyncContextImpl() { - transformTemplate.transform("org.apache.catalina.core.AsyncContextImpl", new TransformCallback() { + private void addRequestFacade(final TomcatConfig config) { + transformTemplate.transform("org.apache.catalina.connector.RequestFacade", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - target.addField(AsyncContextAccessor.class.getName()); - for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("dispatch"))) { - method.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.AsyncContextImplDispatchMethodInterceptor"); + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + if (config.isHidePinpointHeader()) { + // Hide pinpoint headers + target.weave("com.navercorp.pinpoint.plugin.tomcat.aspect.RequestFacadeAspect"); } + return target.toBytecode(); + } + }); + } + private void addStandardHostValve() { + transformTemplate.transform("org.apache.catalina.core.StandardHostValve", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Remove bind trace + final InstrumentMethod method = target.getDeclaredMethod("invoke", "org.apache.catalina.connector.Request", "org.apache.catalina.connector.Response"); + if (method != null) { + method.addInterceptor("com.navercorp.pinpoint.plugin.tomcat.interceptor.StandardHostValveInvokeInterceptor"); + } return target.toBytecode(); } }); } + @Override public void setTransformTemplate(TransformTemplate transformTemplate) { this.transformTemplate = transformTemplate; } -} +} \ No newline at end of file diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TraceAccessor.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TraceAccessor.java deleted file mode 100644 index 10a43310b3c3..000000000000 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/TraceAccessor.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.navercorp.pinpoint.plugin.tomcat; - -import com.navercorp.pinpoint.bootstrap.context.Trace; - -public interface TraceAccessor { - void _$PINPOINT$_setTrace(Trace trace); - Trace _$PINPOINT$_getTrace(); -} \ No newline at end of file diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/aspect/RequestFacadeAspect.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/aspect/RequestFacadeAspect.java index 1438b2b54f89..444cd3856dc1 100644 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/aspect/RequestFacadeAspect.java +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/aspect/RequestFacadeAspect.java @@ -21,40 +21,17 @@ import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; import com.navercorp.pinpoint.common.util.DelegateEnumeration; -import com.navercorp.pinpoint.common.util.EmptyEnumeration; import java.util.Enumeration; /** - * filtering pinpoint header + * Filtering pinpoint header * * @author emeroad + * @author jaehong.kim */ @Aspect public abstract class RequestFacadeAspect { - - @PointCut - public String getHeader(String name) { - if (Header.startWithPinpointHeader(name)) { - return null; - } - return __getHeader(name); - } - - @JointPoint - abstract String __getHeader(String name); - - @PointCut - public Enumeration getHeaders(String name) { - if (Header.startWithPinpointHeader(name)) { - return new EmptyEnumeration(); - } - return __getHeaders(name); - } - - @JointPoint - abstract Enumeration __getHeaders(String name); - @PointCut public Enumeration getHeaderNames() { return new DelegateEnumeration(__getHeaderNames(), Header.FILTER); diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/AsyncContextImplDispatchMethodInterceptor.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/AsyncContextImplDispatchMethodInterceptor.java deleted file mode 100644 index 53c585cb2e30..000000000000 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/AsyncContextImplDispatchMethodInterceptor.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.tomcat.interceptor; - -import com.navercorp.pinpoint.bootstrap.context.AsyncContext; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.interceptor.AsyncContextSpanEventSimpleAroundInterceptor; -import com.navercorp.pinpoint.plugin.tomcat.TomcatConstants; - -/** - * - * @author jaehong.kim - * - */ -public class AsyncContextImplDispatchMethodInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor { - - public AsyncContextImplDispatchMethodInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { - super(traceContext, methodDescriptor); - } - - @Override - protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { - recorder.recordServiceType(TomcatConstants.TOMCAT_METHOD); - } - - @Override - protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { - recorder.recordApi(methodDescriptor); - recorder.recordException(throwable); - } -} \ No newline at end of file diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RequestRecycleInterceptor.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RequestRecycleInterceptor.java deleted file mode 100644 index 8582899f8f08..000000000000 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RequestRecycleInterceptor.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.tomcat.interceptor; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.Trace; -import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; -import com.navercorp.pinpoint.bootstrap.logging.PLogger; -import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.tomcat.AsyncAccessor; -import com.navercorp.pinpoint.plugin.tomcat.TraceAccessor; - -/** - * - * @author jaehong.kim - * - */ -public class RequestRecycleInterceptor implements AroundInterceptor { - - private PLogger logger = PLoggerFactory.getLogger(this.getClass()); - - private final MethodDescriptor methodDescriptor; - - public RequestRecycleInterceptor(MethodDescriptor methodDescriptor) { - this.methodDescriptor = methodDescriptor; - } - - @Override - public void before(Object target, Object[] args) { - if (logger.isDebugEnabled()) { - logger.beforeInterceptor(target, methodDescriptor.getClassName(), methodDescriptor.getMethodName(), "", args); - } - try { - if (target instanceof AsyncAccessor) { - // reset - ((AsyncAccessor) target)._$PINPOINT$_setAsync(Boolean.FALSE); - } - - if (target instanceof TraceAccessor) { - final Trace trace = ((TraceAccessor) target)._$PINPOINT$_getTrace(); - if (trace != null && trace.canSampled()) { - // end of root span - trace.close(); - } - // reset - ((TraceAccessor) target)._$PINPOINT$_setTrace(null); - } - } catch (Throwable t) { - logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); - } - } - - @Override - public void after(Object target, Object[] args, Object result, Throwable throwable) { - } -} \ No newline at end of file diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RequestStartAsyncInterceptor.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RequestStartAsyncInterceptor.java index c116b70f09de..8ba9fb358570 100644 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RequestStartAsyncInterceptor.java +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RequestStartAsyncInterceptor.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,8 +14,6 @@ */ package com.navercorp.pinpoint.plugin.tomcat.interceptor; -import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; -import com.navercorp.pinpoint.bootstrap.context.AsyncContext; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; @@ -23,16 +21,17 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.tomcat.AsyncAccessor; +import com.navercorp.pinpoint.plugin.tomcat.TomcatAsyncListener; import com.navercorp.pinpoint.plugin.tomcat.TomcatConstants; +import javax.servlet.AsyncContext; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletRequest; + /** - * * @author jaehong.kim - * */ public class RequestStartAsyncInterceptor implements AroundInterceptor { - private PLogger logger = PLoggerFactory.getLogger(this.getClass()); private boolean isDebug = logger.isDebugEnabled(); @@ -47,7 +46,7 @@ public RequestStartAsyncInterceptor(TraceContext context, MethodDescriptor descr @Override public void before(Object target, Object[] args) { if (isDebug) { - logger.beforeInterceptor(target, "", descriptor.getMethodName(), "", args); + logger.beforeInterceptor(target, args); } final Trace trace = traceContext.currentTraceObject(); @@ -60,7 +59,7 @@ public void before(Object target, Object[] args) { @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { - logger.afterInterceptor(target, "", descriptor.getMethodName(), "", args); + logger.afterInterceptor(target, args, result, throwable); } final Trace trace = traceContext.currentTraceObject(); @@ -69,21 +68,21 @@ public void after(Object target, Object[] args, Object result, Throwable throwab } try { - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); if (validate(target, result, throwable)) { - ((AsyncAccessor)target)._$PINPOINT$_setAsync(Boolean.TRUE); - - // make asynchronous trace-id - final AsyncContext asyncContext = recorder.recordNextAsyncContext(); + final HttpServletRequest request = (HttpServletRequest) target; + request.setAttribute(TomcatConstants.TOMCAT_SERVLET_REQUEST_TRACE, trace); + if (isDebug) { + logger.debug("Set request attribute {}={}", TomcatConstants.TOMCAT_SERVLET_REQUEST_TRACE, trace); + } - // result is BasicFuture - // type check validate() - ((AsyncContextAccessor)result)._$PINPOINT$_setAsyncContext(asyncContext); + final AsyncContext asyncContext = (AsyncContext) result; + final AsyncListener asyncListener = new TomcatAsyncListener(this.traceContext, recorder.recordNextAsyncContext(true)); + asyncContext.addListener(asyncListener); if (isDebug) { - logger.debug("Set AsyncContext {}", asyncContext); + logger.debug("Add async listener {}", asyncListener); } } - recorder.recordServiceType(TomcatConstants.TOMCAT_METHOD); recorder.recordApi(descriptor); recorder.recordException(throwable); @@ -99,16 +98,18 @@ private boolean validate(final Object target, final Object result, final Throwab return false; } - if (!(target instanceof AsyncAccessor)) { - logger.debug("Invalid target object. Need field accessor({}).", AsyncAccessor.class.getName()); + if (!(target instanceof HttpServletRequest)) { + if (isDebug) { + logger.debug("Invalid target object, The javax.servlet.http.HttpServletRequest interface is not implemented. target={}", target); + } return false; } - - if (!(result instanceof AsyncContextAccessor)) { - logger.debug("Invalid target object. Need metadata accessor({}).", AsyncContextAccessor.class.getName()); + if (!(result instanceof AsyncContext)) { + if (isDebug) { + logger.debug("Invalid result object, The javax.servlet.AsyncContext interface is not implemented. result={}.", result); + } return false; } - return true; } } \ No newline at end of file diff --git a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/StandardHostValveInvokeInterceptor.java b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/StandardHostValveInvokeInterceptor.java index 9a2672b7864e..09b8f8c615a3 100644 --- a/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/StandardHostValveInvokeInterceptor.java +++ b/plugins/tomcat/src/main/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/StandardHostValveInvokeInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,78 +16,49 @@ package com.navercorp.pinpoint.plugin.tomcat.interceptor; -import java.util.Enumeration; - -import javax.servlet.http.HttpServletRequest; - import com.navercorp.pinpoint.bootstrap.context.*; - -import com.navercorp.pinpoint.bootstrap.config.Filter; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.plugin.http.HttpStatusCodeRecorder; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderHandler; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderRecorder; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; -import com.navercorp.pinpoint.bootstrap.util.NumberUtils; -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.plugin.tomcat.AsyncAccessor; -import com.navercorp.pinpoint.plugin.tomcat.ServletAsyncMethodDescriptor; -import com.navercorp.pinpoint.plugin.tomcat.ServletSyncMethodDescriptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServletRequestListenerInterceptorHelper; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.RemoteAddressResolverFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.ArgumentValidator; +import com.navercorp.pinpoint.plugin.common.servlet.util.HttpServletRequestAdaptor; +import com.navercorp.pinpoint.plugin.common.servlet.util.ParameterRecorderFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.ServletArgumentValidator; import com.navercorp.pinpoint.plugin.tomcat.TomcatConfig; import com.navercorp.pinpoint.plugin.tomcat.TomcatConstants; -import com.navercorp.pinpoint.plugin.tomcat.TraceAccessor; import org.apache.catalina.connector.Response; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + /** * @author emeroad * @author jaehong.kim */ public class StandardHostValveInvokeInterceptor implements AroundInterceptor { - public static final ServletSyncMethodDescriptor SERVLET_SYNCHRONOUS_API_TAG = new ServletSyncMethodDescriptor(); - public static final ServletAsyncMethodDescriptor SERVLET_ASYNCHRONOUS_API_TAG = new ServletAsyncMethodDescriptor(); - - private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private final boolean isTrace = logger.isTraceEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private final MethodDescriptor methodDescriptor; + private final ArgumentValidator argumentValidator; - private final boolean isTraceRequestParam; - private final Filter excludeUrlFilter; - private final Filter excludeProfileMethodFilter; - private final RemoteAddressResolver remoteAddressResolver; - private final ProxyHttpHeaderRecorder proxyHttpHeaderRecorder; - private final HttpStatusCodeRecorder httpStatusCodeRecorder; + private final ServletRequestListenerInterceptorHelper servletRequestListenerInterceptorHelper; - private MethodDescriptor methodDescriptor; - private TraceContext traceContext; public StandardHostValveInvokeInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { - this.traceContext = traceContext; this.methodDescriptor = descriptor; - - TomcatConfig tomcatConfig = new TomcatConfig(traceContext.getProfilerConfig()); - this.excludeUrlFilter = tomcatConfig.getTomcatExcludeUrlFilter(); - - final String proxyIpHeader = tomcatConfig.getTomcatRealIpHeader(); - if (StringUtils.isEmpty(proxyIpHeader)) { - this.remoteAddressResolver = new Bypass(); - } else { - final String tomcatRealIpEmptyValue = tomcatConfig.getTomcatRealIpEmptyValue(); - this.remoteAddressResolver = new RealIpHeaderResolver(proxyIpHeader, tomcatRealIpEmptyValue); - } - this.isTraceRequestParam = tomcatConfig.isTomcatTraceRequestParam(); - this.excludeProfileMethodFilter = tomcatConfig.getTomcatExcludeProfileMethodFilter(); - this.proxyHttpHeaderRecorder = new ProxyHttpHeaderRecorder(traceContext.getProfilerConfig().isProxyHttpHeaderEnable()); - this.httpStatusCodeRecorder = new HttpStatusCodeRecorder(traceContext.getProfilerConfig().getHttpStatusCodeErrors()); - - traceContext.cacheApi(SERVLET_ASYNCHRONOUS_API_TAG); - traceContext.cacheApi(SERVLET_SYNCHRONOUS_API_TAG); + this.argumentValidator = new ServletArgumentValidator(logger, 0, HttpServletRequest.class, 1, HttpServletResponse.class); + final TomcatConfig config = new TomcatConfig(traceContext.getProfilerConfig()); + RequestAdaptor requestAdaptor = new HttpServletRequestAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, config.getRealIpHeader(), config.getRealIpEmptyValue()); + ParameterRecorder parameterRecorder = ParameterRecorderFactory.newParameterRecorderFactory(config.getExcludeProfileMethodFilter(), config.isTraceRequestParam()); + this.servletRequestListenerInterceptorHelper = new ServletRequestListenerInterceptorHelper(TomcatConstants.TOMCAT, traceContext, requestAdaptor, config.getExcludeUrlFilter(), parameterRecorder); } @Override @@ -96,226 +67,25 @@ public void before(Object target, Object[] args) { logger.beforeInterceptor(target, args); } - try { - final Trace trace = createTrace(target, args); - if (trace == null) { - return; - } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - return; - } - // ------------------------------------------------------ - SpanEventRecorder recorder = trace.traceBlockBegin(); - recorder.recordServiceType(TomcatConstants.TOMCAT_METHOD); - } catch (Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("BEFORE. Caused:{}", th.getMessage(), th); - } - } - } - - public static class Bypass implements RemoteAddressResolver { - - @Override - public String resolve(T servletRequest) { - return servletRequest.getRemoteAddr(); - } - } - - public static class RealIpHeaderResolver implements RemoteAddressResolver { - - public static final String X_FORWARDED_FOR = "x-forwarded-for"; - public static final String X_REAL_IP = "x-real-ip"; - public static final String UNKNOWN = "unknown"; - - private final String realIpHeaderName; - private final String emptyHeaderValue; - - public RealIpHeaderResolver() { - this(X_FORWARDED_FOR, UNKNOWN); - } - - public RealIpHeaderResolver(String realIpHeaderName, String emptyHeaderValue) { - if (realIpHeaderName == null) { - throw new NullPointerException("realIpHeaderName must not be null"); - } - this.realIpHeaderName = realIpHeaderName; - this.emptyHeaderValue = emptyHeaderValue; - } - - @Override - public String resolve(T httpServletRequest) { - final String realIp = httpServletRequest.getHeader(this.realIpHeaderName); - - if (StringUtils.isEmpty(realIp)) { - return httpServletRequest.getRemoteAddr(); - } - - if (emptyHeaderValue != null && emptyHeaderValue.equalsIgnoreCase(realIp)) { - return httpServletRequest.getRemoteAddr(); - } - - final int firstIndex = realIp.indexOf(','); - if (firstIndex == -1) { - return realIp; - } else { - return realIp.substring(0, firstIndex); - } - } - } - - private Trace createTrace(Object target, Object[] args) { - final HttpServletRequest request = (HttpServletRequest) args[0]; - - if (isAsynchronousProcess(request)) { - // servlet 3.0 - final Trace trace = getTraceMetadata(request); - if (trace != null) { - // change api - SpanRecorder recorder = trace.getSpanRecorder(); - recorder.recordApi(SERVLET_ASYNCHRONOUS_API_TAG); - // unmarked async flag. - setAsyncMetadata(request, false); - - // attach current thread local. - traceContext.continueTraceObject(trace); - - return trace; - } - } - - final String requestURI = request.getRequestURI(); - if (excludeUrlFilter.filter(requestURI)) { - if (isTrace) { - logger.trace("filter requestURI:{}", requestURI); - } - return null; - } - - // check sampling flag from client. If the flag is false, do not sample this request. - final boolean sampling = samplingEnable(request); - if (!sampling) { - // Even if this transaction is not a sampling target, we have to create Trace object to mark 'not sampling'. - // For example, if this transaction invokes rpc call, we can add parameter to tell remote node 'don't sample this transaction' - final Trace trace = traceContext.disableSampling(); - if (isDebug) { - logger.debug("remotecall sampling flag found. skip trace requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - return trace; + if (!argumentValidator.validate(args)) { + return; } - final TraceId traceId = populateTraceIdFromRequest(request); - if (traceId != null) { - // TODO Maybe we should decide to trace or not even if the sampling flag is true to prevent too many requests are traced. - final Trace trace = traceContext.continueTraceObject(traceId); - if (trace.canSampled()) { - SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - setTraceMetadata(request, trace); - if (isDebug) { - logger.debug("TraceID exist. continue trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), request.getRemoteAddr()); - } - } else { - if (isDebug) { - logger.debug("TraceID exist. camSampled is false. skip trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), request.getRemoteAddr()); - } - } - return trace; - } else { - final Trace trace = traceContext.newTraceObject(); - if (trace.canSampled()) { - SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - setTraceMetadata(request, trace); - if (isDebug) { - logger.debug("TraceID not exist. start new trace. requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - } else { + try { + final HttpServletRequest request = (HttpServletRequest) args[0]; + final Trace asyncTrace = (Trace) request.getAttribute(TomcatConstants.TOMCAT_SERVLET_REQUEST_TRACE); + if (asyncTrace != null) { if (isDebug) { - logger.debug("TraceID not exist. camSampled is false. skip trace. requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); + logger.debug("Skip async servlet request event."); } + // skip + return; } - return trace; - } - } - - private void setTraceMetadata(final HttpServletRequest request, final Trace trace) { - if (request instanceof TraceAccessor) { - ((TraceAccessor) request)._$PINPOINT$_setTrace(trace); - } - } - - private Trace getTraceMetadata(final HttpServletRequest request) { - if (!(request instanceof TraceAccessor)) { - return null; - } - - return ((TraceAccessor) request)._$PINPOINT$_getTrace(); - } - - private void setAsyncMetadata(final HttpServletRequest request, final boolean async) { - if (request instanceof AsyncAccessor) { - ((AsyncAccessor) request)._$PINPOINT$_setAsync(async); - } - } - - private boolean getAsyncMetadata(final HttpServletRequest request) { - if (!(request instanceof AsyncAccessor)) { - return false; - } - - return ((AsyncAccessor) request)._$PINPOINT$_isAsync(); - } - - private boolean isAsynchronousProcess(final HttpServletRequest request) { - if (getTraceMetadata(request) == null) { - return false; - } - - return getAsyncMetadata(request); - } - - private void recordRootSpan(final SpanRecorder recorder, final HttpServletRequest request) { - // root - recorder.recordServiceType(TomcatConstants.TOMCAT); - - final String requestURL = request.getRequestURI(); - recorder.recordRpcName(requestURL); - - final int port = request.getServerPort(); - final String endPoint = HostAndPort.toHostAndPortString(request.getServerName(), port); - recorder.recordEndPoint(endPoint); - - final String remoteAddr = remoteAddressResolver.resolve(request); - recorder.recordRemoteAddress(remoteAddr); - - if (!recorder.isRoot()) { - recordParentInfo(recorder, request); - } - recorder.recordApi(SERVLET_SYNCHRONOUS_API_TAG); - - // record proxy HTTP header. - this.proxyHttpHeaderRecorder.record(recorder, new ProxyHttpHeaderHandler() { - @Override - public String read(String name) { - return request.getHeader(name); - } - }); - } - - private void recordParentInfo(SpanRecorder recorder, HttpServletRequest request) { - String parentApplicationName = request.getHeader(Header.HTTP_PARENT_APPLICATION_NAME.toString()); - if (parentApplicationName != null) { - final String host = request.getHeader(Header.HTTP_HOST.toString()); - if (host != null) { - recorder.recordAcceptorHost(host); - } else { - recorder.recordAcceptorHost(NetworkUtils.getHostFromURL(request.getRequestURL().toString())); + this.servletRequestListenerInterceptorHelper.initialized(request, TomcatConstants.TOMCAT_METHOD, this.methodDescriptor); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); } - final String type = request.getHeader(Header.HTTP_PARENT_APPLICATION_TYPE.toString()); - final short parentApplicationType = NumberUtils.parseShort(type, ServiceType.UNDEFINED.getCode()); - recorder.recordParentApplication(parentApplicationName, parentApplicationType); } } @@ -325,113 +95,33 @@ public void after(Object target, Object[] args, Object result, Throwable throwab logger.afterInterceptor(target, args, result, throwable); } - final Trace trace = traceContext.currentRawTraceObject(); - if (trace == null) { + if (!argumentValidator.validate(args)) { return; } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - traceContext.removeTraceObject(); - return; - } - // ------------------------------------------------------ try { - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - - if (this.isTraceRequestParam) { - final HttpServletRequest request = (HttpServletRequest) args[0]; - if (!excludeProfileMethodFilter.filter(request.getMethod())) { - final String parameters = getRequestParameter(request, 64, 512); - if (StringUtils.hasLength(parameters)) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM, parameters); - } - } - } - recorder.recordApi(methodDescriptor); - recorder.recordException(throwable); - } catch (Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("AFTER. Caused:{}", th.getMessage(), th); - } - } finally { - traceContext.removeTraceObject(); - deleteTrace(trace, target, args, result, throwable); - } - } - - /** - * Populate source trace from HTTP Header. - * - * @param request - * @return TraceId when it is possible to get a transactionId from Http header. if not possible return null - */ - private TraceId populateTraceIdFromRequest(HttpServletRequest request) { - - String transactionId = request.getHeader(Header.HTTP_TRACE_ID.toString()); - if (transactionId != null) { - - long parentSpanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_PARENT_SPAN_ID.toString()), SpanId.NULL); - long spanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_SPAN_ID.toString()), SpanId.NULL); - short flags = NumberUtils.parseShort(request.getHeader(Header.HTTP_FLAGS.toString()), (short) 0); - - final TraceId id = traceContext.createTraceId(transactionId, parentSpanID, spanID, flags); - if (isDebug) { - logger.debug("TraceID exist. continue trace. {}", id); + final HttpServletRequest request = (HttpServletRequest) args[0]; + final HttpServletResponse response = (HttpServletResponse) args[1]; + int statusCode = getStatusCode(response); + this.servletRequestListenerInterceptorHelper.destroyed(request, throwable, statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); } - return id; - } else { - return null; - } - } - - private boolean samplingEnable(HttpServletRequest request) { - // optional value - final String samplingFlag = request.getHeader(Header.HTTP_SAMPLED.toString()); - if (isDebug) { - logger.debug("SamplingFlag:{}", samplingFlag); } - return SamplingFlagUtils.isSamplingFlag(samplingFlag); } - private String getRequestParameter(HttpServletRequest request, int eachLimit, int totalLimit) { - Enumeration attrs = request.getParameterNames(); - final StringBuilder params = new StringBuilder(64); - - while (attrs.hasMoreElements()) { - if (params.length() != 0) { - params.append('&'); - } - // skip appending parameters if parameter size is bigger than totalLimit - if (params.length() > totalLimit) { - params.append("..."); - return params.toString(); - } - String key = attrs.nextElement().toString(); - params.append(StringUtils.abbreviate(key, eachLimit)); - params.append('='); - Object value = request.getParameter(key); - if (value != null) { - params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); - } - } - return params.toString(); - } - - private void deleteTrace(Trace trace, Object target, Object[] args, Object result, Throwable throwable) { - trace.traceBlockEnd(); - - final HttpServletRequest request = (HttpServletRequest) args[0]; - if (!isAsynchronousProcess(request)) { - if (args[1] instanceof Response) { - // record response status. - final Response response = (Response) args[1]; - final SpanRecorder spanRecorder = trace.getSpanRecorder(); - this.httpStatusCodeRecorder.record(spanRecorder, response.getStatus()); + private int getStatusCode(final HttpServletResponse response) { + try { + // Tomcat 6 + if (response instanceof Response) { + final Response r = (Response) response; + return r.getStatus(); + } else { + response.getStatus(); } - trace.close(); - // reset - setTraceMetadata(request, null); + } catch (Exception ignored) { } + return 0; } -} +} \ No newline at end of file diff --git a/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/InvokeMethodInterceptorTest.java b/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/InvokeMethodInterceptorTest.java deleted file mode 100644 index 560d44864824..000000000000 --- a/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/InvokeMethodInterceptorTest.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.navercorp.pinpoint.plugin.tomcat; -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - -import static org.mockito.Mockito.*; - -import java.util.Enumeration; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; -import com.navercorp.pinpoint.profiler.context.module.ApplicationContext; -import com.navercorp.pinpoint.test.MockTraceContextFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import com.navercorp.pinpoint.bootstrap.context.Header; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.plugin.tomcat.interceptor.StandardHostValveInvokeInterceptor; -import com.navercorp.pinpoint.profiler.context.DefaultMethodDescriptor; -import com.navercorp.pinpoint.profiler.logging.Slf4jLoggerBinder; - -/** - * @author emeroad - */ -public class InvokeMethodInterceptorTest { - - @Mock - private HttpServletRequest request; - - @Mock - private HttpServletResponse response; - - private final MethodDescriptor descriptor = new DefaultMethodDescriptor("org.apache.catalina.core.StandardHostValve", "invoke", new String[] {"org.apache.catalina.connector.Request", "org.apache.catalina.connector.Response"}, new String[] {"request", "response"}); - - private ApplicationContext applicationContext; - - @BeforeClass - public static void before() { - PLoggerFactory.initialize(new Slf4jLoggerBinder()); - } - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - - ProfilerConfig profilerConfig = new DefaultProfilerConfig(); - applicationContext = MockTraceContextFactory.newMockApplicationContext(profilerConfig); - } - - @After - public void tearDown() throws Exception { - if (applicationContext != null) { - applicationContext.close(); - } - } - - private TraceContext spyTraceContext() { - TraceContext traceContext = applicationContext.getTraceContext(); - return spy(traceContext); - } - - @Test - public void testHeaderNOTExists() { - - when(request.getRequestURI()).thenReturn("/hellotest.nhn"); - when(request.getRemoteAddr()).thenReturn("10.0.0.1"); - when(request.getHeader(Header.HTTP_TRACE_ID.toString())).thenReturn(null); - when(request.getHeader(Header.HTTP_PARENT_SPAN_ID.toString())).thenReturn(null); - when(request.getHeader(Header.HTTP_SPAN_ID.toString())).thenReturn(null); - when(request.getHeader(Header.HTTP_SAMPLED.toString())).thenReturn(null); - when(request.getHeader(Header.HTTP_FLAGS.toString())).thenReturn(null); - Enumeration enumeration = mock(Enumeration.class); - when(request.getParameterNames()).thenReturn(enumeration); - - TraceContext traceContext = spyTraceContext(); - StandardHostValveInvokeInterceptor interceptor = new StandardHostValveInvokeInterceptor(traceContext, descriptor); - - interceptor.before("target", new Object[]{request, response}); - interceptor.after("target", new Object[]{request, response}, new Object(), null); - - verify(traceContext, times(1)).newTraceObject(); - - interceptor.before("target", new Object[]{request, response}); - interceptor.after("target", new Object[]{request, response}, new Object(), null); - - verify(traceContext, times(2)).newTraceObject(); - } - - @Test - public void testInvalidHeaderExists() { - - when(request.getRequestURI()).thenReturn("/hellotest.nhn"); - when(request.getRemoteAddr()).thenReturn("10.0.0.1"); - when(request.getHeader(Header.HTTP_TRACE_ID.toString())).thenReturn("TRACEID"); - when(request.getHeader(Header.HTTP_PARENT_SPAN_ID.toString())).thenReturn("PARENTSPANID"); - when(request.getHeader(Header.HTTP_SPAN_ID.toString())).thenReturn("SPANID"); - when(request.getHeader(Header.HTTP_SAMPLED.toString())).thenReturn("false"); - when(request.getHeader(Header.HTTP_FLAGS.toString())).thenReturn("0"); - Enumeration enumeration = mock(Enumeration.class); - when(request.getParameterNames()).thenReturn(enumeration); - - TraceContext traceContext = spyTraceContext(); - StandardHostValveInvokeInterceptor interceptor = new StandardHostValveInvokeInterceptor(traceContext, descriptor); - interceptor.before("target", new Object[]{request, response}); - interceptor.after("target", new Object[]{request, response}, new Object(), null); - - verify(traceContext, never()).newTraceObject(); - verify(traceContext, never()).disableSampling(); - verify(traceContext, never()).continueTraceObject(any(TraceId.class)); - - - interceptor.before("target", new Object[]{request, response}); - interceptor.after("target", new Object[]{request, response}, new Object(), null); - - verify(traceContext, never()).newTraceObject(); - verify(traceContext, never()).disableSampling(); - verify(traceContext, never()).continueTraceObject(any(TraceId.class)); - } - - @Test - public void testValidHeaderExists() { - - when(request.getRequestURI()).thenReturn("/hellotest.nhn"); - when(request.getRemoteAddr()).thenReturn("10.0.0.1"); - - TraceId traceId = new DefaultTraceId("agentTest", System.currentTimeMillis(), 1); - when(request.getHeader(Header.HTTP_TRACE_ID.toString())).thenReturn(traceId.getTransactionId()); - when(request.getHeader(Header.HTTP_PARENT_SPAN_ID.toString())).thenReturn("PARENTSPANID"); - when(request.getHeader(Header.HTTP_SPAN_ID.toString())).thenReturn("SPANID"); - when(request.getHeader(Header.HTTP_SAMPLED.toString())).thenReturn("false"); - when(request.getHeader(Header.HTTP_FLAGS.toString())).thenReturn("0"); - Enumeration enumeration = mock(Enumeration.class); - when(request.getParameterNames()).thenReturn(enumeration); - - TraceContext traceContext = spyTraceContext(); - StandardHostValveInvokeInterceptor interceptor = new StandardHostValveInvokeInterceptor(traceContext, descriptor); - - interceptor.before("target", new Object[]{request, response}); - interceptor.after("target", new Object[]{request, response}, new Object(), null); - - verify(traceContext, times(1)).continueTraceObject(any(TraceId.class)); - - interceptor.before("target", new Object[]{request, response}); - interceptor.after("target", new Object[]{request, response}, new Object(), null); - - verify(traceContext, times(2)).continueTraceObject(any(TraceId.class)); - } -} diff --git a/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/StandardHostValveInvokeModifierTest.java b/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/StandardHostValveInvokeModifierTest.java deleted file mode 100644 index af474fcf364b..000000000000 --- a/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/StandardHostValveInvokeModifierTest.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.navercorp.pinpoint.plugin.tomcat; -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import java.util.Enumeration; -import java.util.List; - -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.core.StandardHost; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import com.navercorp.pinpoint.bootstrap.context.Header; -import com.navercorp.pinpoint.common.server.bo.SpanBo; -import com.navercorp.pinpoint.common.server.bo.SpanEventBo; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.TransactionIdUtils; -import com.navercorp.pinpoint.test.junit4.BasePinpointTest; -import com.navercorp.pinpoint.test.junit4.IsRootSpan; - -/** - * @author hyungil.jeong - */ -public class StandardHostValveInvokeModifierTest extends BasePinpointTest { - - private static final ServiceType SERVICE_TYPE = TomcatConstants.TOMCAT; - private static final String REQUEST_URI = "testRequestUri"; - private static final String SERVER_NAME = "serverForTest"; - private static final int SERVER_PORT = 19999; - private static final String REMOTE_ADDRESS = "1.1.1.1"; - private static final Enumeration EMPTY_PARAM_KEYS = new Enumeration() { - @Override - public boolean hasMoreElements() { - return false; - } - - @Override - public String nextElement() { - return null; - } - }; - - private StandardHost host; - - @Mock - private Request mockRequest; - @Mock - private Response mockResponse; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - initMockRequest(); - // StandardHost's default constructor sets StandardHostValve as the first item in the pipeline. - host = new StandardHost(); - } - - private void initMockRequest() { - when(mockRequest.getRequestURI()).thenReturn(REQUEST_URI); - when(mockRequest.getServerName()).thenReturn(SERVER_NAME); - when(mockRequest.getServerPort()).thenReturn(SERVER_PORT); - when(mockRequest.getRemoteAddr()).thenReturn(REMOTE_ADDRESS); - when(mockRequest.getParameterNames()).thenReturn(EMPTY_PARAM_KEYS); - } - - @Test - @IsRootSpan - public void invokeShouldBeTraced() throws Exception { - // Given - // When - host.invoke(mockRequest, mockResponse); - // Then - final List rootSpans = getCurrentRootSpans(); - assertEquals(rootSpans.size(), 1); - - final SpanBo rootSpan = rootSpans.get(0); - assertEquals(rootSpan.getParentSpanId(), -1); - assertEquals(rootSpan.getServiceType(), SERVICE_TYPE.getCode()); - assertEquals(rootSpan.getRpc(), REQUEST_URI); - assertEquals(rootSpan.getEndPoint(), SERVER_NAME + ":" + SERVER_PORT); - assertEquals(rootSpan.getRemoteAddr(), REMOTE_ADDRESS); - } - - @Test - @IsRootSpan - public void invokeShouldTraceExceptions() throws Exception { - // Given - when(mockRequest.getContext()).thenThrow(new RuntimeException("expected exception.")); - // When - try { - host.invoke(mockRequest, mockResponse); - assertTrue(false); - } catch (RuntimeException e) { - // Then - final List rootSpans = getCurrentRootSpans(); - assertEquals(rootSpans.size(), 1); - - final SpanBo rootSpan = rootSpans.get(0); - assertEquals(rootSpan.getParentSpanId(), -1); - assertEquals(rootSpan.getServiceType(), SERVICE_TYPE.getCode()); - - final List spanEvents = getCurrentSpanEvents(); - final SpanEventBo spanEvent = spanEvents.get(0); - - assertTrue(spanEvent.hasException()); - } - } - - @Test - @IsRootSpan - public void invokeShouldContinueTracingFromRequest() throws Exception { - // Given - // Set Transaction ID from remote source. - final String sourceAgentId = "agentId"; - final long sourceAgentStartTime = 1234567890123L; - final long sourceTransactionSequence = 12345678L; - final String sourceTransactionId = TransactionIdUtils.formatString(sourceAgentId, sourceAgentStartTime, sourceTransactionSequence); - when(mockRequest.getHeader(Header.HTTP_TRACE_ID.toString())).thenReturn(sourceTransactionId); - // Set parent Span ID from remote source. - final long sourceParentId = 99999; - when(mockRequest.getHeader(Header.HTTP_PARENT_SPAN_ID.toString())).thenReturn(String.valueOf(sourceParentId)); - // When - host.invoke(mockRequest, mockResponse); - // Then - final List rootSpans = getCurrentRootSpans(); - assertEquals(rootSpans.size(), 1); - - final SpanBo rootSpan = rootSpans.get(0); - // Check Transaction ID from remote source. - assertEquals(TransactionIdUtils.formatString(rootSpan.getTransactionId()), sourceTransactionId); - assertEquals(rootSpan.getTransactionId().getAgentId(), sourceAgentId); - assertEquals(rootSpan.getTransactionId().getAgentStartTime(), sourceAgentStartTime); - assertEquals(rootSpan.getTransactionId().getTransactionSequence(), sourceTransactionSequence); - // Check parent Span ID from remote source. - assertEquals(rootSpan.getParentSpanId(), sourceParentId); - } - -} diff --git a/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/aspect/RequestFacadeAspectTest.java b/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/aspect/RequestFacadeAspectTest.java index ace826c4e441..8daf9c9a9f5c 100644 --- a/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/aspect/RequestFacadeAspectTest.java +++ b/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/aspect/RequestFacadeAspectTest.java @@ -27,25 +27,14 @@ import com.navercorp.pinpoint.bootstrap.context.Header; import com.navercorp.pinpoint.plugin.tomcat.aspect.RequestFacadeAspect; - +/** + * @author jaehong.kim + */ public class RequestFacadeAspectTest { public static class RequestFacadeAspectMock extends RequestFacadeAspect { - @Override - String __getHeader(String name) { - return "header"; - } - - @Override - Enumeration __getHeaders(String name) { - Hashtable hashtable = new Hashtable(); - hashtable.put("a", "aa"); - hashtable.put("b", "bb"); - return hashtable.elements(); - } - @Override Enumeration __getHeaderNames() { - Hashtable hashtable = new Hashtable (); + Hashtable hashtable = new Hashtable(); hashtable.put("b", "bb"); hashtable.put("c", "cc"); hashtable.put("d", Header.HTTP_SPAN_ID.toString()); @@ -53,32 +42,6 @@ Enumeration __getHeaderNames() { } } - @Test - public void getHeader() { - RequestFacadeAspect mock = new RequestFacadeAspectMock(); - - String isNull = mock.getHeader(Header.HTTP_SPAN_ID.toString()); - Assert.assertNull(isNull); - - String header = mock.getHeader("test"); - Assert.assertEquals(header, "header"); - } - - - @Test - public void getHeaders() { - RequestFacadeAspect mock = new RequestFacadeAspectMock(); - Enumeration isNull = mock.getHeaders(Header.HTTP_SPAN_ID.toString()); - - ArrayList list = Collections.list(isNull); - Assert.assertEquals(list.size(), 0); - - Enumeration header = mock.getHeaders("test"); - Assert.assertEquals(Collections.list(header).size(), 2); - } - - - @Test public void getHeaderNames() { RequestFacadeAspect mock = new RequestFacadeAspectMock(); diff --git a/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RealIpHeaderResolverTest.java b/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RealIpHeaderResolverTest.java deleted file mode 100644 index 7fa173e52af6..000000000000 --- a/plugins/tomcat/src/test/java/com/navercorp/pinpoint/plugin/tomcat/interceptor/RealIpHeaderResolverTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.plugin.tomcat.interceptor; - -import org.junit.Assert; -import org.junit.Test; - -import javax.servlet.http.HttpServletRequest; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author emeroad - */ -public class RealIpHeaderResolverTest { - - private final String xForwardedFor = StandardHostValveInvokeInterceptor.RealIpHeaderResolver.X_FORWARDED_FOR; - - @Test - public void testProxyHeader() { - - HttpServletRequest mock = mock(HttpServletRequest.class); - when(mock.getHeader(xForwardedFor)).thenReturn("127.0.0.1"); - when(mock.getRemoteAddr()).thenReturn("127.0.0.2"); - - - StandardHostValveInvokeInterceptor.RealIpHeaderResolver realIpHeaderResolver = new StandardHostValveInvokeInterceptor.RealIpHeaderResolver(); - String resolve = realIpHeaderResolver.resolve(mock); - Assert.assertEquals(resolve, "127.0.0.1"); - - - } - - @Test - public void testProxyHeader_proxy1() { - - HttpServletRequest mock = mock(HttpServletRequest.class); - when(mock.getHeader(xForwardedFor)).thenReturn("127.0.0.1, proxy1, proxy2"); - when(mock.getRemoteAddr()).thenReturn("127.0.0.2"); - - StandardHostValveInvokeInterceptor.RealIpHeaderResolver realIpHeaderResolver = new StandardHostValveInvokeInterceptor.RealIpHeaderResolver(); - String resolve = realIpHeaderResolver.resolve(mock); - Assert.assertEquals(resolve, "127.0.0.1"); - - } - - @Test - public void testProxyHeader_proxy2() { - - HttpServletRequest mock = mock(HttpServletRequest.class); - when(mock.getHeader(xForwardedFor)).thenReturn("127.0.0.1,"); - when(mock.getRemoteAddr()).thenReturn("127.0.0.2"); - - StandardHostValveInvokeInterceptor.RealIpHeaderResolver realIpHeaderResolver = new StandardHostValveInvokeInterceptor.RealIpHeaderResolver(); - String resolve = realIpHeaderResolver.resolve(mock); - Assert.assertEquals(resolve, "127.0.0.1"); - } - - @Test - public void testProxyHeader_header_not_exist() { - - HttpServletRequest mock = mock(HttpServletRequest.class); - when(mock.getRemoteAddr()).thenReturn("127.0.0.2"); - - - StandardHostValveInvokeInterceptor.RealIpHeaderResolver realIpHeaderResolver = new StandardHostValveInvokeInterceptor.RealIpHeaderResolver(); - String resolve = realIpHeaderResolver.resolve(mock); - Assert.assertEquals(resolve, "127.0.0.2"); - - } - -} diff --git a/plugins/undertow/.gitignore b/plugins/undertow/.gitignore new file mode 100644 index 000000000000..8c2d47305b59 --- /dev/null +++ b/plugins/undertow/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml diff --git a/plugins/undertow/pom.xml b/plugins/undertow/pom.xml new file mode 100644 index 000000000000..790be86f713b --- /dev/null +++ b/plugins/undertow/pom.xml @@ -0,0 +1,104 @@ + + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-undertow-plugin + pinpoint-undertow-plugin + jar + + + 1.6 + ${env.JAVA_7_HOME} + java17 + + + + + + com.navercorp.pinpoint + pinpoint-plugin-bom + ${project.version} + pom + import + + + + + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + + com.navercorp.pinpoint + pinpoint-common-servlet + ${project.version} + compile + + + + javax.servlet + javax.servlet-api + provided + + + + io.undertow + undertow-core + provided + + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${plugin.shade.version} + + + package + + shade + + + + + com.navercorp.pinpoint.plugin.common.servlet + com.navercorp.pinpoint.plugin.undertow.common.servlet + + + + ${project.build.directory}/dependency-reduced-pom.xml + + + + + + + + diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/HttpServerExchangeParameterExtractor.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/HttpServerExchangeParameterExtractor.java new file mode 100644 index 000000000000..f70c9944945b --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/HttpServerExchangeParameterExtractor.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.undertow; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.common.util.StringUtils; +import io.undertow.server.HttpServerExchange; + +import java.util.Deque; +import java.util.Map; + +/** + * @author jaehong.kim + */ +public class HttpServerExchangeParameterExtractor implements ParameterExtractor { + private int eachLimit; + private int totalLimit; + + public HttpServerExchangeParameterExtractor(int eachLimit, int totalLimit) { + this.eachLimit = eachLimit; + this.totalLimit = totalLimit; + } + + @Override + public String extractParameter(HttpServerExchange request) { + final Map> parameterMap = request.getQueryParameters(); + final StringBuilder params = new StringBuilder(64); + for (Map.Entry> entry : parameterMap.entrySet()) { + if (params.length() != 0) { + params.append('&'); + } + // skip appending parameters if parameter size is bigger than totalLimit + if (params.length() > totalLimit) { + params.append("..."); + return params.toString(); + } + final String key = entry.getKey(); + if (!StringUtils.hasLength(key)) { + // skip empty or null header name + continue; + } + // append key + params.append(StringUtils.abbreviate(key, eachLimit)); + params.append('='); + // append value + Deque values = entry.getValue(); + if (CollectionUtils.isEmpty(values)) { + // skip empty or null header value + continue; + } + for (String value : values) { + if (value != null) { + params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); + } + } + } + return params.toString(); + } +} \ No newline at end of file diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/MethodFilterExtractor.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/MethodFilterExtractor.java new file mode 100644 index 000000000000..f3e11d6c80f0 --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/MethodFilterExtractor.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.undertow; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import io.undertow.server.HttpServerExchange; + +/** + * @author jaehong.kim + */ +public class MethodFilterExtractor implements ParameterExtractor { + + private final Filter excludeProfileMethodFilter; + + private final ParameterExtractor delegate; + + public MethodFilterExtractor(Filter excludeProfileMethodFilter, ParameterExtractor delegate) { + this.excludeProfileMethodFilter = excludeProfileMethodFilter; + this.delegate = delegate; + } + + @Override + public String extractParameter(HttpServerExchange request) { + if (excludeProfileMethodFilter.filter(request.getRequestMethod().toString())) { + return null; + } + return delegate.extractParameter(request); + } +} diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/ParameterRecorderFactory.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/ParameterRecorderFactory.java new file mode 100644 index 000000000000..1d17794ab2d5 --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/ParameterRecorderFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.undertow; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.DisableParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.HttpParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import io.undertow.server.HttpServerExchange; + +/** + * @author jaehong.kim + */ +public class ParameterRecorderFactory { + public static ParameterRecorder newParameterRecorderFactory(Filter excludeProfileMethodFilter, boolean traceRequestParam) { + if (!traceRequestParam) { + return new DisableParameterRecorder(); + } + ParameterExtractor parameterExtractor = new HttpServerExchangeParameterExtractor(64, 512); + ParameterExtractor methodFilterExtractor = new MethodFilterExtractor(excludeProfileMethodFilter, parameterExtractor); + return new HttpParameterRecorder(methodFilterExtractor); + } +} diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowAsyncListener.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowAsyncListener.java new file mode 100644 index 000000000000..6127651622c4 --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowAsyncListener.java @@ -0,0 +1,122 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.undertow; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.AsyncListenerInterceptorHelper; + +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author jaehong.kim + */ +public class UndertowAsyncListener implements AsyncListener { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private final AsyncListenerInterceptorHelper asyncListenerInterceptorHelper; + + public UndertowAsyncListener(final TraceContext traceContext, final AsyncContext asyncContext) { + this.asyncListenerInterceptorHelper = new AsyncListenerInterceptorHelper(traceContext, asyncContext); + } + + @Override + public void onComplete(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Complete asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + final int statusCode = getStatusCode(asyncEvent); + this.asyncListenerInterceptorHelper.complete(asyncEvent.getThrowable(), statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + } + + @Override + public void onTimeout(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Timeout asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.timeout(asyncEvent.getThrowable()); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onError(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Error asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.error(asyncEvent.getThrowable()); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + } + + @Override + public void onStartAsync(AsyncEvent asyncEvent) throws IOException { + } + + private int getStatusCode(final AsyncEvent asyncEvent) { + try { + if (asyncEvent.getSuppliedResponse() instanceof HttpServletResponse) { + return ((HttpServletResponse) asyncEvent.getSuppliedResponse()).getStatus(); + } + } catch (Exception ignored) { + } + return 0; + } +} \ No newline at end of file diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowConfig.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowConfig.java new file mode 100644 index 000000000000..51a9e3f0beeb --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowConfig.java @@ -0,0 +1,117 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.undertow; + +import com.navercorp.pinpoint.bootstrap.config.ExcludeMethodFilter; +import com.navercorp.pinpoint.bootstrap.config.ExcludePathFilter; +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.bootstrap.config.SkipFilter; + +import java.util.List; + +/** + * @author jaehong.kim + */ +public class UndertowConfig { + + private final boolean enable; + private final List bootstrapMains; + private final boolean hidePinpointHeader; + + private final boolean traceRequestParam; + private final Filter excludeUrlFilter; + private final String realIpHeader; + private final String realIpEmptyValue; + private final Filter excludeProfileMethodFilter; + + public UndertowConfig(ProfilerConfig config) { + if (config == null) { + throw new NullPointerException("config must not be null"); + } + + // plugin + this.enable = config.readBoolean("profiler.undertow.enable", true); + this.bootstrapMains = config.readList("profiler.undertow.bootstrap.main"); + this.hidePinpointHeader = config.readBoolean("profiler.undertow.hidepinpointheader", true); + + // runtime + this.traceRequestParam = config.readBoolean("profiler.undertow.tracerequestparam", true); + final String tomcatExcludeURL = config.readString("profiler.undertow.excludeurl", ""); + if (!tomcatExcludeURL.isEmpty()) { + this.excludeUrlFilter = new ExcludePathFilter(tomcatExcludeURL); + } else { + this.excludeUrlFilter = new SkipFilter(); + } + this.realIpHeader = config.readString("profiler.undertow.realipheader", null); + this.realIpEmptyValue = config.readString("profiler.undertow.realipemptyvalue", null); + + final String tomcatExcludeProfileMethod = config.readString("profiler.undertow.excludemethod", ""); + if (!tomcatExcludeProfileMethod.isEmpty()) { + this.excludeProfileMethodFilter = new ExcludeMethodFilter(tomcatExcludeProfileMethod); + } else { + this.excludeProfileMethodFilter = new SkipFilter(); + } + } + + public boolean isEnable() { + return enable; + } + + public List getBootstrapMains() { + return bootstrapMains; + } + + public boolean isHidePinpointHeader() { + return hidePinpointHeader; + } + + public boolean isTraceRequestParam() { + return traceRequestParam; + } + + public Filter getExcludeUrlFilter() { + return excludeUrlFilter; + } + + public String getRealIpHeader() { + return realIpHeader; + } + + public String getRealIpEmptyValue() { + return realIpEmptyValue; + } + + public Filter getExcludeProfileMethodFilter() { + return excludeProfileMethodFilter; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("UndertowConfig{"); + sb.append("enable=").append(enable); + sb.append(", bootstrapMains=").append(bootstrapMains); + sb.append(", hidePinpointHeader=").append(hidePinpointHeader); + sb.append(", traceRequestParam=").append(traceRequestParam); + sb.append(", excludeUrlFilter=").append(excludeUrlFilter); + sb.append(", realIpHeader='").append(realIpHeader).append('\''); + sb.append(", realIpEmptyValue='").append(realIpEmptyValue).append('\''); + sb.append(", excludeProfileMethodFilter=").append(excludeProfileMethodFilter); + sb.append('}'); + return sb.toString(); + } +} diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowConstants.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowConstants.java new file mode 100644 index 000000000000..72cfab5b9e1f --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowConstants.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.undertow; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; + +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; + +/** + * @author jaehong.kim + * + */ +public final class UndertowConstants { + private UndertowConstants() { + } + + public static final ServiceType UNDERTOW = ServiceTypeFactory.of(1120, "UNDERTOW", RECORD_STATISTICS); + public static final ServiceType UNDERTOW_METHOD = ServiceTypeFactory.of(1121, "UNDERTOW_METHOD"); +} \ No newline at end of file diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowHttpHeaderFilter.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowHttpHeaderFilter.java new file mode 100644 index 000000000000..157793ef3563 --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowHttpHeaderFilter.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.undertow; + +import com.navercorp.pinpoint.bootstrap.context.Header; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HeaderMap; +import io.undertow.util.HttpString; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author jaehong.kim + */ +public class UndertowHttpHeaderFilter { + private final boolean enable; + + public UndertowHttpHeaderFilter(boolean enable) { + this.enable = enable; + } + + public void filter(final HttpServerExchange request) { + if (!enable || request == null || request.getRequestHeaders() == null) { + return; + } + + final HeaderMap headerMap = request.getRequestHeaders(); + final List pinpointHeaderNameList = new ArrayList(); + for (HttpString name : headerMap.getHeaderNames()) { + final String headerName = name.toString(); + if (Header.startWithPinpointHeader(headerName)) { + pinpointHeaderNameList.add(headerName); + } + } + + for (String name : pinpointHeaderNameList) { + headerMap.remove(name); + } + } +} diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowPlugin.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowPlugin.java new file mode 100644 index 000000000000..2bd8c51c8d5e --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowPlugin.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.undertow; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; + +import java.security.ProtectionDomain; + +/** + * @author jaehong.kim + */ +public class UndertowPlugin implements ProfilerPlugin, TransformTemplateAware { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + private TransformTemplate transformTemplate; + + @Override + public void setup(ProfilerPluginSetupContext context) { + final UndertowConfig config = new UndertowConfig(context.getConfig()); + if (!config.isEnable()) { + logger.info("UndertowPlugin disabled"); + return; + } + + if (logger.isInfoEnabled()) { + logger.info("UndertowPlugin config:{}", config); + } + // Entry Point + addConnectors(); + // Add async listener. Servlet 3.0 + addHttpServletRequestImpl(); + } + + + private void addConnectors() { + transformTemplate.transform("io.undertow.server.Connectors", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Entry Point + final InstrumentMethod connectorsExecuteRootHandlerMethod = target.getDeclaredMethod("executeRootHandler", "io.undertow.server.HttpHandler", "io.undertow.server.HttpServerExchange"); + if (connectorsExecuteRootHandlerMethod != null) { + connectorsExecuteRootHandlerMethod.addInterceptor("com.navercorp.pinpoint.plugin.undertow.interceptor.ConnectorsExecuteRootHandlerInterceptor"); + } + return target.toBytecode(); + } + }); + } + + private void addHttpServletRequestImpl() { + transformTemplate.transform("io.undertow.servlet.spec.HttpServletRequestImpl", new TransformCallback() { + + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Add async listener. Servlet 3.0 + final InstrumentMethod startAsyncMethod = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); + if (startAsyncMethod != null) { + startAsyncMethod.addInterceptor("com.navercorp.pinpoint.plugin.undertow.interceptor.HttpServletRequestImplStartAsyncInterceptor"); + } + return target.toBytecode(); + } + }); + } + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } +} \ No newline at end of file diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowTypeProvider.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowTypeProvider.java new file mode 100644 index 000000000000..7fb6732d9200 --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/UndertowTypeProvider.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.undertow; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; + +/** + * @author jaehong.kim + */ +public class UndertowTypeProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(UndertowConstants.UNDERTOW); + context.addServiceType(UndertowConstants.UNDERTOW_METHOD); + } +} diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/interceptor/ConnectorsExecuteRootHandlerInterceptor.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/interceptor/ConnectorsExecuteRootHandlerInterceptor.java new file mode 100644 index 000000000000..e902498f7fc7 --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/interceptor/ConnectorsExecuteRootHandlerInterceptor.java @@ -0,0 +1,127 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.undertow.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServletRequestListenerInterceptorHelper; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.RemoteAddressResolverFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.ArgumentValidator; +import com.navercorp.pinpoint.plugin.undertow.ParameterRecorderFactory; +import com.navercorp.pinpoint.plugin.undertow.UndertowConfig; +import com.navercorp.pinpoint.plugin.undertow.UndertowConstants; +import com.navercorp.pinpoint.plugin.undertow.UndertowHttpHeaderFilter; +import io.undertow.server.HttpServerExchange; + +/** + * @author jaehong.kim + */ +public class ConnectorsExecuteRootHandlerInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private final MethodDescriptor methodDescriptor; + private final ArgumentValidator argumentValidator; + private final UndertowHttpHeaderFilter httpHeaderFilter; + private final ServletRequestListenerInterceptorHelper servletRequestListenerInterceptorHelper; + + public ConnectorsExecuteRootHandlerInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + this.methodDescriptor = descriptor; + this.argumentValidator = new ConnectorsArgumentValidator(); + final UndertowConfig config = new UndertowConfig(traceContext.getProfilerConfig()); + RequestAdaptor requestAdaptor = new HttpServerExchangeAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, config.getRealIpHeader(), config.getRealIpEmptyValue()); + ParameterRecorder parameterRecorder = ParameterRecorderFactory.newParameterRecorderFactory(config.getExcludeProfileMethodFilter(), config.isTraceRequestParam()); + this.servletRequestListenerInterceptorHelper = new ServletRequestListenerInterceptorHelper(UndertowConstants.UNDERTOW, traceContext, requestAdaptor, config.getExcludeUrlFilter(), parameterRecorder); + this.httpHeaderFilter = new UndertowHttpHeaderFilter(config.isHidePinpointHeader()); + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (!argumentValidator.validate(args)) { + return; + } + + try { + final HttpServerExchange request = (HttpServerExchange) args[1]; + this.servletRequestListenerInterceptorHelper.initialized(request, UndertowConstants.UNDERTOW_METHOD, this.methodDescriptor); + this.httpHeaderFilter.filter(request); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); + } + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + if (!argumentValidator.validate(args)) { + return; + } + + try { + final HttpServerExchange request = (HttpServerExchange) args[1]; + final int statusCode = getStatusCode(request); + // TODO Get exception. e.g. request.getAttachment(DefaultResponseListener.EXCEPTION) + this.servletRequestListenerInterceptorHelper.destroyed(request, throwable, statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); + } + } + } + + private int getStatusCode(final HttpServerExchange response) { + try { + return response.getStatusCode(); + } catch (Exception ignored) { + } + return 0; + } + + private class ConnectorsArgumentValidator implements ArgumentValidator { + @Override + public boolean validate(Object[] args) { + if (args == null) { + return false; + } + + if (args.length < 2) { + return false; + } + + if (!(args[1] instanceof HttpServerExchange)) { + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/interceptor/HttpServerExchangeAdaptor.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/interceptor/HttpServerExchangeAdaptor.java new file mode 100644 index 000000000000..d91862b503a1 --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/interceptor/HttpServerExchangeAdaptor.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.undertow.interceptor; + +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.util.SocketAddressUtils; +import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HeaderValues; + +import java.net.InetSocketAddress; + +/** + * @author jaehong.kim + */ +public class HttpServerExchangeAdaptor implements RequestAdaptor { + + @Override + public String getHeader(HttpServerExchange request, String name) { + final HeaderValues values = request.getRequestHeaders().get(name); + if (values != null) { + return values.peekFirst(); + } + return null; + } + + @Override + public String getRpcName(HttpServerExchange request) { + return request.getRequestURI(); + } + + @Override + public String getEndPoint(HttpServerExchange request) { + final InetSocketAddress address = request.getDestinationAddress(); + if (address != null) { + return HostAndPort.toHostAndPortString(SocketAddressUtils.getHostNameFirst(address), address.getPort()); + } + return "Unknown"; + } + + @Override + public String getRemoteAddress(HttpServerExchange request) { + final InetSocketAddress address = request.getSourceAddress(); + if (address != null) { + return SocketAddressUtils.getAddressFirst(address); + } + return null; + } + + @Override + public String getAcceptorHost(HttpServerExchange request) { + return NetworkUtils.getHostFromURL(request.getRequestURI()); + } +} \ No newline at end of file diff --git a/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/interceptor/HttpServletRequestImplStartAsyncInterceptor.java b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/interceptor/HttpServletRequestImplStartAsyncInterceptor.java new file mode 100644 index 000000000000..012112100504 --- /dev/null +++ b/plugins/undertow/src/main/java/com/navercorp/pinpoint/plugin/undertow/interceptor/HttpServletRequestImplStartAsyncInterceptor.java @@ -0,0 +1,111 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.undertow.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.undertow.UndertowAsyncListener; +import com.navercorp.pinpoint.plugin.undertow.UndertowConstants; + +import javax.servlet.AsyncContext; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletRequest; + +/** + * @author jaehong.kim + */ +public class HttpServletRequestImplStartAsyncInterceptor implements AroundInterceptor { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor descriptor; + + public HttpServletRequestImplStartAsyncInterceptor(TraceContext context, MethodDescriptor descriptor) { + this.traceContext = context; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + if (validate(target, result, throwable)) { + final AsyncContext asyncContext = (AsyncContext) result; + final AsyncListener asyncListener = new UndertowAsyncListener(this.traceContext, recorder.recordNextAsyncContext(true)); + asyncContext.addListener(asyncListener); + if (isDebug) { + logger.debug("Add async listener {}", asyncListener); + } + } + recorder.recordServiceType(UndertowConstants.UNDERTOW_METHOD); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + } catch (Throwable t) { + logger.warn("Failed to AFTER process. {}", t.getMessage(), t); + } finally { + trace.traceBlockEnd(); + } + } + + private boolean validate(final Object target, final Object result, final Throwable throwable) { + if (throwable != null || result == null) { + return false; + } + + if (!(target instanceof HttpServletRequest)) { + if (isDebug) { + logger.debug("Invalid target object, The javax.servlet.http.HttpServletRequest interface is not implemented. target={}", target); + } + return false; + } + if (!(result instanceof AsyncContext)) { + if (isDebug) { + logger.debug("Invalid result object, The javax.servlet.AsyncContext interface is not implemented. result={}.", result); + } + return false; + } + return true; + } +} \ No newline at end of file diff --git a/plugins/undertow/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/undertow/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..4f911c373663 --- /dev/null +++ b/plugins/undertow/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.undertow.UndertowPlugin \ No newline at end of file diff --git a/plugins/undertow/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/undertow/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..fba502d4bfab --- /dev/null +++ b/plugins/undertow/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.undertow.UndertowTypeProvider \ No newline at end of file diff --git a/plugins/user/clover.license b/plugins/user/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/user/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-user-plugin diff --git a/plugins/user/src/main/java/com/navercorp/pinpoint/plugin/user/UserPlugin.java b/plugins/user/src/main/java/com/navercorp/pinpoint/plugin/user/UserPlugin.java index f57b174dc4bd..e5288957c337 100644 --- a/plugins/user/src/main/java/com/navercorp/pinpoint/plugin/user/UserPlugin.java +++ b/plugins/user/src/main/java/com/navercorp/pinpoint/plugin/user/UserPlugin.java @@ -74,7 +74,7 @@ private void addUserIncludeClass(final String className, final Set metho public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - final String[] names = methodNames.toArray(new String[methodNames.size()]); + final String[] names = methodNames.toArray(new String[0]); for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(names))) { try { method.addInterceptor("com.navercorp.pinpoint.plugin.user.interceptor.UserIncludeMethodInterceptor"); @@ -99,7 +99,7 @@ private void addMessageQueueClientHandlerMethods(List clientHandlerMetho @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); - final String[] names = methodNames.toArray(new String[methodNames.size()]); + final String[] names = methodNames.toArray(new String[0]); for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(names))) { try { method.addInterceptor("com.navercorp.pinpoint.plugin.user.interceptor.MQExternalClientHandlerInterceptor"); diff --git a/plugins/user/src/main/java/com/navercorp/pinpoint/plugin/user/interceptor/MQExternalClientHandlerInterceptor.java b/plugins/user/src/main/java/com/navercorp/pinpoint/plugin/user/interceptor/MQExternalClientHandlerInterceptor.java index 452a62d3e81b..193205f0a93c 100644 --- a/plugins/user/src/main/java/com/navercorp/pinpoint/plugin/user/interceptor/MQExternalClientHandlerInterceptor.java +++ b/plugins/user/src/main/java/com/navercorp/pinpoint/plugin/user/interceptor/MQExternalClientHandlerInterceptor.java @@ -84,7 +84,6 @@ public void before(Object target, Object[] args) { public void after(Object target, Object[] args, Object result, Throwable throwable) { final AsyncContext asyncContext = getAsyncContext(args); if (asyncContext == null) { - logger.debug("AsyncContext not found"); return; } diff --git a/plugins/vertx/README.md b/plugins/vertx/README.md index dbb41c8d38dc..dc91a667e115 100644 --- a/plugins/vertx/README.md +++ b/plugins/vertx/README.md @@ -1,6 +1,6 @@ ## Vertx HTTP Server/Client. -Currently supports vertx.io 3.3.x, 3.4.1, 3.4.2 +Currently supports vertx.io 3.3.x, 3.4.1, 3.4.2, 3.5.0 ### Pinpoint Configuration pinpoint.config @@ -27,6 +27,12 @@ profiler.vertx.bootstrap.main=io.vertx.core.Starter profiler.vertx.handler.base-packages= ~~~ +#### Set the HttpServerRequestHandler method name. +The argument is io.vertx.core.http.HttpServerRequest. (Since pinpoint version 1.7.2) +~~~ +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept +~~~ + ### Examples If the main class looks like this: ~~~ @@ -50,3 +56,14 @@ profiler.vertx.bootstrap.main=com.navercorp.test.pinpoint.Server profiler.vertx.handler.base-packages=com.navercorp.test.pinpoint ~~~ + +If used the Router class: +~~~ +Router router = Router.router(vertx); +... +vertx.createHttpServer().requestHandler(router::accept).listen(8090); +~~~ + +~~~ +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept +~~~ diff --git a/plugins/vertx/clover.license b/plugins/vertx/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/plugins/vertx/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-vertx-plugin @@ -35,6 +35,7 @@ io.vertx vertx-core + 3.5.0 provided diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/HttpClientRequestClientHeaderAdaptor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/HttpClientRequestClientHeaderAdaptor.java new file mode 100644 index 000000000000..22129cc7642a --- /dev/null +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/HttpClientRequestClientHeaderAdaptor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.vertx; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import io.vertx.core.http.HttpClientRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpClientRequestClientHeaderAdaptor implements ClientHeaderAdaptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(HttpClientRequest httpClientRequest, String name, String value) { + httpClientRequest.putHeader(name, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } +} diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/HttpRequestClientHeaderAdaptor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/HttpRequestClientHeaderAdaptor.java new file mode 100644 index 000000000000..67f003bb4fde --- /dev/null +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/HttpRequestClientHeaderAdaptor.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.vertx; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpRequestClientHeaderAdaptor implements ClientHeaderAdaptor { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + @Override + public void setHeader(HttpRequest httpRequest, String name, String value) { + final HttpHeaders headers = httpRequest.headers(); + if (headers != null) { + headers.set(name, value); + if (isDebug) { + logger.debug("Set header {}={}", name, value); + } + } + } +} diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/HttpServerParameterExtractor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/HttpServerParameterExtractor.java new file mode 100644 index 000000000000..b84758bcfaf1 --- /dev/null +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/HttpServerParameterExtractor.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.vertx; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.common.util.StringUtils; +import io.vertx.core.http.HttpServerRequest; + +import java.util.List; +import java.util.Map; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpServerParameterExtractor implements ParameterExtractor { + + private int eachLimit; + private int totalLimit; + + public HttpServerParameterExtractor(int eachLimit, int totalLimit) { + this.eachLimit = eachLimit; + this.totalLimit = totalLimit; + } + + @Override + public String extractParameter(HttpServerRequest request) { + if (request.params() == null) { + return ""; + } + + final StringBuilder params = new StringBuilder(64); + List> entries = request.params().entries(); + for (Map.Entry entry : entries) { + if (params.length() != 0) { + params.append('&'); + } + // skip appending parameters if parameter size is bigger than totalLimit + if (params.length() > totalLimit) { + params.append("..."); + return params.toString(); + } + + String key = entry.getKey(); + params.append(StringUtils.abbreviate(key, eachLimit)); + params.append('='); + Object value = entry.getValue(); + if (value != null) { + params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); + } + } + return params.toString(); + } +} diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/MethodFilterExtractor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/MethodFilterExtractor.java new file mode 100644 index 000000000000..017035f5186f --- /dev/null +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/MethodFilterExtractor.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.vertx; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.common.util.Assert; +import io.vertx.core.http.HttpServerRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class MethodFilterExtractor implements ParameterExtractor { + + + private final Filter excludeProfileMethodFilter; + + private final ParameterExtractor delegate; + + public MethodFilterExtractor(Filter excludeProfileMethodFilter, ParameterExtractor delegate) { + this.excludeProfileMethodFilter = Assert.requireNonNull(excludeProfileMethodFilter, "excludeProfileMethodFilter must not be null"); + this.delegate = Assert.requireNonNull(delegate, "delegate must not be null"); + } + + @Override + public String extractParameter(HttpServerRequest httpServletRequest) { + if (excludeProfileMethodFilter.filter(httpServletRequest.method().toString())) { + return null; + } + return delegate.extractParameter(httpServletRequest); + } +} diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/ParameterRecorderFactory.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/ParameterRecorderFactory.java new file mode 100644 index 000000000000..ded32fcc4770 --- /dev/null +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/ParameterRecorderFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.vertx; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.DisableParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.HttpParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import io.vertx.core.http.HttpServerRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ParameterRecorderFactory { + public static ParameterRecorder newParameterRecorderFactory(Filter excludeProfileMethodFilter, boolean traceRequestParam) { + if (!traceRequestParam) { + return new DisableParameterRecorder(); + } + ParameterExtractor parameterExtractor = new HttpServerParameterExtractor(64, 512); + ParameterExtractor methodFilterExtractor = new MethodFilterExtractor(excludeProfileMethodFilter, parameterExtractor); + return new HttpParameterRecorder(methodFilterExtractor); + } +} diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxConstants.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxConstants.java index 9b0d923a296f..012094153303 100644 --- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxConstants.java +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxConstants.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -22,7 +22,10 @@ /** * @author jaehong.kim */ -public class VertxConstants { +public final class VertxConstants { + private VertxConstants() { + } + public static final ServiceType VERTX = ServiceTypeFactory.of(1050, "VERTX", ServiceTypeProperty.RECORD_STATISTICS); public static final ServiceType VERTX_INTERNAL = ServiceTypeFactory.of(1051, "VERTX_INTERNAL", "VERTX"); public static final ServiceType VERTX_HTTP_SERVER = ServiceTypeFactory.of(1052, "VERTX_HTTP_SERVER", ServiceTypeProperty.RECORD_STATISTICS); diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxCookieExtractor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxCookieExtractor.java new file mode 100644 index 000000000000..37ccd2b00419 --- /dev/null +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxCookieExtractor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.vertx; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.common.util.StringUtils; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; + +/** + * @author Woonduk Kang(emeroad) + */ +public class VertxCookieExtractor implements CookieExtractor { + @Override + public String getCookie(HttpRequest httpRequest) { + final HttpHeaders headers = httpRequest.headers(); + if (headers != null) { + final String cookie = headers.get("Cookie"); + if (StringUtils.hasLength(cookie)) { + return cookie; + } + } + return null; + } +} diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientConfig.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientConfig.java index aa5040ee5ca8..07a4147aea9b 100644 --- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientConfig.java +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientConfig.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.plugin.vertx; import com.navercorp.pinpoint.bootstrap.config.DumpType; +import com.navercorp.pinpoint.bootstrap.config.HttpDumpConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; /** @@ -25,17 +26,16 @@ public class VertxHttpClientConfig { // client private boolean param = true; - private boolean cookie = false; - private DumpType cookieDumpType = DumpType.EXCEPTION; - private int cookieSamplingRate = 1; + private HttpDumpConfig httpDumpConfig; private boolean statusCode = true; public VertxHttpClientConfig(ProfilerConfig config) { this.param = config.readBoolean("profiler.vertx.http.client.param", true); - this.cookie = config.readBoolean("profiler.vertx.http.client.cookie", false); - this.cookieDumpType = config.readDumpType("profiler.vertx.http.client.cookie.dumptype", DumpType.EXCEPTION); - this.cookieSamplingRate = config.readInt("profiler.vertx.http.client.cookie.sampling.rate", 1); - + boolean cookie = config.readBoolean("profiler.vertx.http.client.cookie", false); + DumpType cookieDumpType = config.readDumpType("profiler.vertx.http.client.cookie.dumptype", DumpType.EXCEPTION); + int cookieSamplingRate = config.readInt("profiler.vertx.http.client.cookie.sampling.rate", 1); + int cookieDumpSize = config.readInt("profiler.vertx.http.client.cookie.dumpsize", 1024); + this.httpDumpConfig = HttpDumpConfig.get(cookie, cookieDumpType, cookieSamplingRate, cookieDumpSize, false, cookieDumpType, 1, 1024); this.statusCode = config.readBoolean("profiler.vertx.http.client.entity.statuscode", true); } @@ -43,19 +43,21 @@ public boolean isParam() { return param; } - public boolean isCookie() { - return cookie; - } - - public DumpType getCookieDumpType() { - return cookieDumpType; - } - - public int getCookieSamplingRate() { - return cookieSamplingRate; + public HttpDumpConfig getHttpDumpConfig() { + return httpDumpConfig; } public boolean isStatusCode() { return statusCode; } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("VertxHttpClientConfig{"); + sb.append("param=").append(param); + sb.append(", httpDumpConfig=").append(httpDumpConfig); + sb.append(", statusCode=").append(statusCode); + sb.append('}'); + return sb.toString(); + } } diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientRequestWrapper.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientRequestWrapper.java new file mode 100644 index 000000000000..ec79ddfaa39a --- /dev/null +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientRequestWrapper.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.vertx; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpRequest; +import io.vertx.core.http.HttpClientRequest; + +/** + * @author jaehong.kim + */ +public class VertxHttpClientRequestWrapper implements ClientRequestWrapper { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final HttpRequest httpRequest; + private final String host; + + + public VertxHttpClientRequestWrapper(final HttpRequest httpRequest, final String host) { + this.httpRequest = Assert.requireNonNull(httpRequest, "httpRequest must not be null"); + this.host = host; + } + + + @Override + public String getDestinationId() { + if (this.host != null) { + return this.host; + } + return "Unknown"; + } + + @Override + public String getUrl() { + return this.httpRequest.uri(); + } + + +} diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpHeaderFilter.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpHeaderFilter.java index 3407841cd9cf..ab77aed94086 100644 --- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpHeaderFilter.java +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpHeaderFilter.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.plugin.vertx; import com.navercorp.pinpoint.bootstrap.context.Header; -import io.vertx.core.http.impl.HttpServerRequestImpl; +import io.vertx.core.http.HttpServerRequest; /** * @author jaehong.kim @@ -29,7 +29,7 @@ public VertxHttpHeaderFilter(boolean enable) { this.enable = enable; } - public void filter(final HttpServerRequestImpl request) { + public void filter(final HttpServerRequest request) { if (!enable || request == null || request.headers() == null) { return; } diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpServerConfig.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpServerConfig.java index 3e4a85f8a1a2..9390ba21aece 100644 --- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpServerConfig.java +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpServerConfig.java @@ -32,6 +32,7 @@ public class VertxHttpServerConfig { private final String realIpEmptyValue; private final Filter excludeProfileMethodFilter; private final boolean hidePinpointHeader; + private final String requestHandlerMethodName; public VertxHttpServerConfig(ProfilerConfig config) { if (config == null) { @@ -56,6 +57,7 @@ public VertxHttpServerConfig(ProfilerConfig config) { this.excludeProfileMethodFilter = new SkipFilter(); } this.hidePinpointHeader = config.readBoolean("profiler.vertx.http.server.hidepinpointheader", true); + this.requestHandlerMethodName = config.readString("profiler.vertx.http.server.request-handler.method.name", "io.vertx.ext.web.impl.RouterImpl.accept"); } public boolean isTraceRequestParam() { @@ -81,4 +83,8 @@ public Filter getExcludeProfileMethodFilter() { public boolean isHidePinpointHeader() { return hidePinpointHeader; } + + public String getRequestHandlerMethodName() { + return requestHandlerMethodName; + } } \ No newline at end of file diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxPlugin.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxPlugin.java index 61daea6e3e7f..4fda72965f8c 100644 --- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxPlugin.java +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxPlugin.java @@ -43,6 +43,7 @@ @InterfaceStability.Unstable public class VertxPlugin implements ProfilerPlugin, MatchableTransformTemplateAware { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isInfo = logger.isInfoEnabled(); private MatchableTransformTemplate transformTemplate; @@ -50,14 +51,15 @@ public class VertxPlugin implements ProfilerPlugin, MatchableTransformTemplateAw public void setup(ProfilerPluginSetupContext context) { final VertxConfig config = new VertxConfig(context.getConfig()); if (!config.isEnable() || (!config.isEnableHttpServer() && !config.isEnableHttpClient())) { - if (logger.isInfoEnabled()) { + if (isInfo) { logger.info("Disable VertxPlugin."); } return; } - if (logger.isInfoEnabled()) { - logger.info("Enable VertxPlugin. version range=[3.3, 3.4]"); + if (isInfo) { + // 3.3 <= x <= 3.5 + logger.info("Enable VertxPlugin. version range=[3.3, 3.5.0]"); } // for vertx.io 3.3.x, 3.4.x @@ -68,7 +70,7 @@ public void setup(ProfilerPluginSetupContext context) { if (!basePackageNames.isEmpty()) { // add async field & interceptor addHandlerInterceptor(basePackageNames); - if (logger.isInfoEnabled()) { + if (isInfo) { logger.info("Adding Vertx Handler. base-packages={}.", config.getHandlerBasePackageNames()); } @@ -80,16 +82,31 @@ public void setup(ProfilerPluginSetupContext context) { } if (config.isEnableHttpServer()) { - if (logger.isInfoEnabled()) { + if (isInfo) { logger.info("Adding Vertx HTTP Server."); } - addServerConnection(); + final VertxHttpServerConfig serverConfig = new VertxHttpServerConfig(context.getConfig()); + final String requestHandlerMethodName = serverConfig.getRequestHandlerMethodName(); + if (requestHandlerMethodName == null || requestHandlerMethodName.isEmpty()) { + logger.warn("Not found 'profiler.vertx.http.server.request-handler.method.name' in config"); + } else { + try { + final String className = toClassName(requestHandlerMethodName); + final String methodName = toMethodName(requestHandlerMethodName); + if (isInfo) { + logger.info("Add request handler method for Vertx HTTP Server. class={}, method={}", className, methodName); + } + addRequestHandlerMethod(className, methodName); + } catch (IllegalArgumentException e) { + logger.warn("Invalid 'profiler.vertx.http.server.request-handler.method.name' value={}", requestHandlerMethodName); + } + } addHttpServerRequestImpl(); addHttpServerResponseImpl(); } if (config.isEnableHttpClient()) { - if (logger.isInfoEnabled()) { + if (isInfo) { logger.info("Adding Vertx HTTP Client."); } addHttpClientImpl(); @@ -110,6 +127,25 @@ List filterBasePackageNames(List basePackageNames) { return list; } + String toClassName(String fullQualifiedMethodName) { + final int classEndPosition = fullQualifiedMethodName.lastIndexOf('.'); + if (classEndPosition <= 0) { + throw new IllegalArgumentException("invalid full qualified method name(" + fullQualifiedMethodName + "). not found method"); + } + + return fullQualifiedMethodName.substring(0, classEndPosition).trim(); + } + + String toMethodName(String fullQualifiedMethodName) { + final int methodBeginPosition = fullQualifiedMethodName.lastIndexOf('.'); + if (methodBeginPosition <= 0 || methodBeginPosition + 1 >= fullQualifiedMethodName.length()) { + throw new IllegalArgumentException("invalid full qualified method name(" + fullQualifiedMethodName + "). not found method"); + } + + return fullQualifiedMethodName.substring(methodBeginPosition + 1).trim(); + } + + private void addHandlerInterceptor(final List basePackageNames) { // basepackageNames AND io.vertx.core.Handler final Matcher matcher = Matchers.newPackageBasedMatcher(basePackageNames, new InterfaceInternalNameMatcherOperand("io.vertx.core.Handler", true)); @@ -160,20 +196,18 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, } // skip executeFromIO() - return target.toBytecode(); } }); } - private void addServerConnection() { - transformTemplate.transform("io.vertx.core.http.impl.ServerConnection", new TransformCallback() { + private void addRequestHandlerMethod(final String className, final String methodName) { + transformTemplate.transform(className, new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); - - final InstrumentMethod handleRequestMethod = target.getDeclaredMethod("handleRequest", "io.vertx.core.http.impl.HttpServerRequestImpl", "io.vertx.core.http.impl.HttpServerResponseImpl"); + final InstrumentMethod handleRequestMethod = target.getDeclaredMethod(methodName, "io.vertx.core.http.HttpServerRequest"); if (handleRequestMethod != null) { // entry point & set asynchronous of req, res. handleRequestMethod.addInterceptor("com.navercorp.pinpoint.plugin.vertx.interceptor.ServerConnectionHandleRequestInterceptor"); @@ -214,7 +248,6 @@ private void addHttpServerResponseImpl() { public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); target.addField(AsyncContextAccessor.class.getName()); - target.addGetter("com.navercorp.pinpoint.plugin.vertx.ResponseGetter", "response"); final InstrumentMethod endMethod = target.getDeclaredMethod("end"); if (endMethod != null) { @@ -314,7 +347,7 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, } // handle. - final InstrumentMethod handleDrainedMethod = target.getDeclaredMethod("handleDrained", "java.lang.Throwable"); + final InstrumentMethod handleDrainedMethod = target.getDeclaredMethod("handleDrained"); if (handleDrainedMethod != null) { handleDrainedMethod.addInterceptor("com.navercorp.pinpoint.plugin.vertx.interceptor.HttpClientRequestImplInterceptor"); } diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplDoRequestInterceptor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplDoRequestInterceptor.java index 83d89d4e301b..63340a42c0db 100644 --- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplDoRequestInterceptor.java +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplDoRequestInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,9 +20,12 @@ import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; import com.navercorp.pinpoint.common.plugin.util.HostAndPort; import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.plugin.vertx.HttpClientRequestClientHeaderAdaptor; import com.navercorp.pinpoint.plugin.vertx.VertxConstants; import io.vertx.core.http.HttpClientRequest; @@ -30,16 +33,19 @@ * @author jaehong.kim */ public class HttpClientImplDoRequestInterceptor implements AroundInterceptor { - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final TraceContext traceContext; private final MethodDescriptor methodDescriptor; + private final RequestTraceWriter requestTraceWriter; public HttpClientImplDoRequestInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { this.traceContext = traceContext; this.methodDescriptor = descriptor; + + ClientHeaderAdaptor clientHeaderAdaptor = new HttpClientRequestClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } @Override @@ -71,14 +77,15 @@ public void after(Object target, Object[] args, Object result, Throwable throwab return; } - HttpClientRequest request = null; + HttpClientRequest resultToRequest = null; if (validate(result)) { - request = (HttpClientRequest) result; + resultToRequest = (HttpClientRequest) result; } + final HttpClientRequest request = resultToRequest; if (!trace.canSampled()) { if (request != null) { - request.putHeader(Header.HTTP_SAMPLED.toString(), SamplingFlagUtils.SAMPLING_RATE_FALSE); + requestTraceWriter.write(request); } return; } diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientStreamInterceptor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientStreamInterceptor.java index b251563c6885..232aa20c8aa2 100644 --- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientStreamInterceptor.java +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientStreamInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,18 +15,25 @@ */ package com.navercorp.pinpoint.plugin.vertx.interceptor; -import com.navercorp.pinpoint.bootstrap.config.DumpType; import com.navercorp.pinpoint.bootstrap.context.*; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils; -import com.navercorp.pinpoint.bootstrap.util.SimpleSampler; -import com.navercorp.pinpoint.bootstrap.util.SimpleSamplerFactory; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientHeaderAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapper; +import com.navercorp.pinpoint.bootstrap.plugin.request.ClientRequestWrapperAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.DefaultRequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceWriter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.CookieRecorderFactory; +import com.navercorp.pinpoint.plugin.vertx.HttpRequestClientHeaderAdaptor; import com.navercorp.pinpoint.plugin.vertx.VertxConstants; +import com.navercorp.pinpoint.plugin.vertx.VertxCookieExtractor; import com.navercorp.pinpoint.plugin.vertx.VertxHttpClientConfig; +import com.navercorp.pinpoint.plugin.vertx.VertxHttpClientRequestWrapper; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpRequest; @@ -34,32 +41,28 @@ * @author jaehong.kim */ public class HttpClientStreamInterceptor implements AroundInterceptor { - private static final int MAX_READ_SIZE = 1024; - private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private boolean param; - private final boolean cookie; - private final DumpType cookieDumpType; - private final SimpleSampler cookieSampler; - private TraceContext traceContext; private MethodDescriptor descriptor; + private final ClientRequestRecorder clientRequestRecorder; + private final CookieRecorder cookieRecorder; + private final RequestTraceWriter requestTraceWriter; public HttpClientStreamInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { this.traceContext = traceContext; this.descriptor = descriptor; final VertxHttpClientConfig config = new VertxHttpClientConfig(traceContext.getProfilerConfig()); - this.param = config.isParam(); - this.cookie = config.isCookie(); - this.cookieDumpType = config.getCookieDumpType(); - if (cookie) { - this.cookieSampler = SimpleSamplerFactory.createSampler(cookie, config.getCookieSamplingRate()); - } else { - this.cookieSampler = null; - } + ClientRequestAdaptor clientRequestAdaptor = ClientRequestWrapperAdaptor.INSTANCE; + this.clientRequestRecorder = new ClientRequestRecorder(config.isParam(), clientRequestAdaptor); + + CookieExtractor cookieExtractor = new VertxCookieExtractor(); + this.cookieRecorder = CookieRecorderFactory.newCookieRecorder(config.getHttpDumpConfig(), cookieExtractor); + + ClientHeaderAdaptor clientHeaderAdaptor = new HttpRequestClientHeaderAdaptor(); + this.requestTraceWriter = new DefaultRequestTraceWriter(clientHeaderAdaptor, traceContext); } @Override @@ -85,32 +88,12 @@ public void before(Object target, Object[] args) { // defense code. return; } - - final String uri = request.uri(); final String host = (String) args[1]; - // generate next trace id. final TraceId nextId = trace.getTraceId().getNextTraceId(); recorder.recordNextSpanId(nextId.getSpanId()); - headers.set(Header.HTTP_TRACE_ID.toString(), nextId.getTransactionId()); - headers.set(Header.HTTP_SPAN_ID.toString(), String.valueOf(nextId.getSpanId())); - headers.set(Header.HTTP_PARENT_SPAN_ID.toString(), String.valueOf(nextId.getParentSpanId())); - headers.set(Header.HTTP_FLAGS.toString(), String.valueOf(nextId.getFlags())); - headers.set(Header.HTTP_PARENT_APPLICATION_NAME.toString(), traceContext.getApplicationName()); - headers.set(Header.HTTP_PARENT_APPLICATION_TYPE.toString(), Short.toString(traceContext.getServerTypeCode())); - - if (host != null) { - headers.set(Header.HTTP_HOST.toString(), host); - recorder.recordDestinationId(host); - } else { - recorder.recordDestinationId("unknown"); - } - - if (uri != null) { - final String httpUrl = InterceptorUtils.getHttpUrl(uri, param); - recorder.recordAttribute(AnnotationKey.HTTP_URL, httpUrl); - } + requestTraceWriter.write(request, nextId, host); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn("BEFORE. Caused:{}", t.getMessage(), t); @@ -137,19 +120,6 @@ private boolean validate(final Object[] args) { return true; } - - private void recordCookie(final HttpHeaders headers, final Trace trace) { - final String cookie = headers.get("Cookie"); - if (cookie == null) { - return; - } - - if (this.cookieSampler.isSampling()) { - final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, StringUtils.abbreviate(cookie, MAX_READ_SIZE)); - } - } - @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { @@ -177,14 +147,10 @@ public void after(Object target, Object[] args, Object result, Throwable throwab return; } - final boolean isException = InterceptorUtils.isThrowable(throwable); - if (cookie) { - if (DumpType.ALWAYS == cookieDumpType) { - recordCookie(headers, trace); - } else if (DumpType.EXCEPTION == cookieDumpType && isException) { - recordCookie(headers, trace); - } - } + final String host = (String) args[1]; + ClientRequestWrapper clientRequest = new VertxHttpClientRequestWrapper(request, host); + this.clientRequestRecorder.record(recorder, clientRequest, throwable); + this.cookieRecorder.record(recorder, request, throwable); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn("AFTER. Caused:{}", t.getMessage(), t); diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpServerRequestAdaptor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpServerRequestAdaptor.java new file mode 100644 index 000000000000..b1d967143d68 --- /dev/null +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpServerRequestAdaptor.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.vertx.interceptor; + +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.net.SocketAddress; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HttpServerRequestAdaptor implements RequestAdaptor { + + public HttpServerRequestAdaptor() { + } + + @Override + public String getHeader(HttpServerRequest request, String name) { + return request.getHeader(name); + } + + + @Override + public String getRpcName(HttpServerRequest request) { + return request.path(); + } + + @Override + public String getEndPoint(HttpServerRequest request) { + if (request.localAddress() != null) { + final int port = request.localAddress().port(); + if (port <= 0) { + return request.host(); + } else { + return request.host() + ":" + port; + } + } + return null; + } + + @Override + public String getRemoteAddress(HttpServerRequest request) { + final SocketAddress socketAddress = request.remoteAddress(); + if (socketAddress != null) { + return socketAddress.toString(); + } + return "unknown"; + } + + @Override + public String getAcceptorHost(HttpServerRequest request) { + return NetworkUtils.getHostFromURL(request.uri().toString()); + } +} diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpServerResponseImplInterceptor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpServerResponseImplInterceptor.java index a9f7b880e964..8feca008c0fb 100644 --- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpServerResponseImplInterceptor.java +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpServerResponseImplInterceptor.java @@ -15,11 +15,15 @@ */ package com.navercorp.pinpoint.plugin.vertx.interceptor; -import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.plugin.http.HttpStatusCodeRecorder; -import com.navercorp.pinpoint.plugin.vertx.ResponseGetter; import com.navercorp.pinpoint.plugin.vertx.VertxConstants; -import io.netty.handler.codec.http.HttpResponse; +import io.vertx.core.http.impl.HttpServerResponseImpl; /** * @author jaehong.kim @@ -44,15 +48,15 @@ public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] a recorder.recordServiceType(VertxConstants.VERTX_HTTP_SERVER_INTERNAL); recorder.recordException(throwable); - if (target instanceof ResponseGetter) { - final HttpResponse response = ((ResponseGetter) target)._$PINPOINT$_getResponse(); + if (target instanceof HttpServerResponseImpl) { + final HttpServerResponseImpl response = (HttpServerResponseImpl) target; // TODO more simple. final AsyncContext asyncContext = getAsyncContext(target); if (asyncContext != null) { final Trace trace = asyncContext.currentAsyncTraceObject(); if (trace != null) { final SpanRecorder spanRecorder = trace.getSpanRecorder(); - this.httpStatusCodeRecorder.record(spanRecorder, response.status().code()); + this.httpStatusCodeRecorder.record(spanRecorder, response.getStatusCode()); } } } diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/ServerConnectionHandleRequestInterceptor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/ServerConnectionHandleRequestInterceptor.java index f5eb47730420..d9f71748805d 100644 --- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/ServerConnectionHandleRequestInterceptor.java +++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/ServerConnectionHandleRequestInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,27 +17,29 @@ import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.context.*; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.context.scope.TraceScope; import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderHandler; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.RemoteAddressResolverFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderRecorder; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; -import com.navercorp.pinpoint.bootstrap.util.NumberUtils; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestTraceReader; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServerRequestRecorder; +import com.navercorp.pinpoint.plugin.vertx.ParameterRecorderFactory; import com.navercorp.pinpoint.plugin.vertx.VertxConstants; import com.navercorp.pinpoint.plugin.vertx.VertxHttpHeaderFilter; import com.navercorp.pinpoint.plugin.vertx.VertxHttpServerConfig; import com.navercorp.pinpoint.plugin.vertx.VertxHttpServerMethodDescriptor; -import io.vertx.core.http.impl.HttpServerRequestImpl; -import io.vertx.core.http.impl.HttpServerResponseImpl; - -import java.util.Map; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; /** * @author jaehong.kim @@ -50,12 +52,13 @@ public class ServerConnectionHandleRequestInterceptor implements AroundIntercept private final boolean isDebug = logger.isDebugEnabled(); private final boolean isTrace = logger.isTraceEnabled(); - private final boolean isTraceRequestParam; private final Filter excludeUrlFilter; - private final Filter excludeProfileMethodFilter; - private final RemoteAddressResolver remoteAddressResolver; - private final ProxyHttpHeaderRecorder proxyHttpHeaderRecorder; + + private final ProxyHttpHeaderRecorder proxyHttpHeaderRecorder; private final VertxHttpHeaderFilter httpHeaderFilter; + private final ServerRequestRecorder serverRequestRecorder; + private final RequestTraceReader requestTraceReader; + private final ParameterRecorder parameterRecorder; private TraceContext traceContext; private MethodDescriptor descriptor; @@ -66,21 +69,19 @@ public ServerConnectionHandleRequestInterceptor(final TraceContext traceContext, final VertxHttpServerConfig config = new VertxHttpServerConfig(traceContext.getProfilerConfig()); this.excludeUrlFilter = config.getExcludeUrlFilter(); - final String proxyIpHeader = config.getRealIpHeader(); - if (proxyIpHeader == null || proxyIpHeader.isEmpty()) { - this.remoteAddressResolver = new Bypass(); - } else { - final String tomcatRealIpEmptyValue = config.getRealIpEmptyValue(); - this.remoteAddressResolver = new RealIpHeaderResolver(proxyIpHeader, tomcatRealIpEmptyValue); - } - this.isTraceRequestParam = config.isTraceRequestParam(); - this.excludeProfileMethodFilter = config.getExcludeProfileMethodFilter(); - this.proxyHttpHeaderRecorder = new ProxyHttpHeaderRecorder(traceContext.getProfilerConfig().isProxyHttpHeaderEnable()); - this.httpHeaderFilter = new VertxHttpHeaderFilter(config.isHidePinpointHeader()); + RequestAdaptor requestAdaptor = new HttpServerRequestAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, config.getRealIpHeader(), config.getRealIpEmptyValue()); + this.parameterRecorder = ParameterRecorderFactory.newParameterRecorderFactory(config.getExcludeProfileMethodFilter(), config.isTraceRequestParam()); + + this.proxyHttpHeaderRecorder = new ProxyHttpHeaderRecorder(traceContext.getProfilerConfig().isProxyHttpHeaderEnable(), requestAdaptor); + this.httpHeaderFilter = new VertxHttpHeaderFilter(config.isHidePinpointHeader()); + this.serverRequestRecorder = new ServerRequestRecorder(requestAdaptor); + this.requestTraceReader = new RequestTraceReader(traceContext, requestAdaptor, true); traceContext.cacheApi(VERTX_HTTP_SERVER_METHOD_DESCRIPTOR); } + @Override public void before(Object target, Object[] args) { if (isDebug) { @@ -98,8 +99,14 @@ public void before(Object target, Object[] args) { return; } - final HttpServerRequestImpl request = (HttpServerRequestImpl) args[0]; - final HttpServerResponseImpl response = (HttpServerResponseImpl) args[1]; + final HttpServerRequest request = (HttpServerRequest) args[0]; + final HttpServerResponse response = request.response(); + if (!(response instanceof AsyncContextAccessor)) { + if (isDebug) { + logger.debug("Invalid response. Need metadata accessor({}).", AsyncContextAccessor.class.getName()); + } + return; + } // create trace for standalone entry point. final Trace trace = createTrace(request); @@ -132,14 +139,14 @@ public void before(Object target, Object[] args) { } private boolean validate(final Object[] args) { - if (args == null || args.length < 2) { + if (args == null || args.length < 1) { if (isDebug) { logger.debug("Invalid args object. args={}.", args); } return false; } - if (!(args[0] instanceof HttpServerRequestImpl)) { + if (!(args[0] instanceof HttpServerRequest)) { if (isDebug) { logger.debug("Invalid args[0] object. {}.", args[0]); } @@ -153,21 +160,6 @@ private boolean validate(final Object[] args) { return false; } - - if (!(args[1] instanceof HttpServerResponseImpl)) { - if (isDebug) { - logger.debug("Invalid args[1] object. {}.", args[1]); - } - return false; - } - - if (!(args[1] instanceof AsyncContextAccessor)) { - if (isDebug) { - logger.debug("Invalid args[1] object. Need metadata accessor({}).", AsyncContextAccessor.class.getName()); - } - return false; - } - return true; } @@ -212,15 +204,8 @@ public void after(Object target, Object[] args, Object result, Throwable throwab recorder.recordApi(descriptor); recorder.recordException(throwable); if (validate(args)) { - if (this.isTraceRequestParam) { - final HttpServerRequestImpl request = (HttpServerRequestImpl) args[0]; - if (!excludeProfileMethodFilter.filter(request.method().toString())) { - final String parameters = getRequestParameter(request, 64, 512); - if (parameters != null && !parameters.isEmpty()) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM, parameters); - } - } - } + final HttpServerRequest request = (HttpServerRequest) args[0]; + parameterRecorder.record(recorder, request, throwable); } } catch (Throwable t) { if (logger.isWarnEnabled()) { @@ -232,7 +217,7 @@ public void after(Object target, Object[] args, Object result, Throwable throwab } } - private Trace createTrace(final HttpServerRequestImpl request) { + private Trace createTrace(final HttpServerRequest request) { final String requestURI = request.path(); if (requestURI != null && excludeUrlFilter.filter(requestURI)) { // skip request. @@ -242,65 +227,23 @@ private Trace createTrace(final HttpServerRequestImpl request) { return null; } - final boolean sampling = samplingEnable(request); - if (!sampling) { - final Trace trace = traceContext.disableSampling(); - if (isDebug) { - logger.debug("Remote call sampling flag found. skip trace requestUrl:{}, remoteAddr:{}", request.path(), request.remoteAddress()); - } - if (!initScope(trace)) { - // invalid scope. - deleteTrace(trace); - return null; - } - - return trace; + final Trace trace = this.requestTraceReader.read(request); + if (trace.canSampled()) { + final SpanRecorder recorder = trace.getSpanRecorder(); + // root + recorder.recordServiceType(VertxConstants.VERTX_HTTP_SERVER); + recorder.recordApi(VERTX_HTTP_SERVER_METHOD_DESCRIPTOR); + this.serverRequestRecorder.record(recorder, request); + // record proxy HTTP header. + this.proxyHttpHeaderRecorder.record(recorder, request); } - final TraceId traceId = populateTraceIdFromRequest(request); - if (traceId != null) { - final Trace trace = traceContext.continueAsyncTraceObject(traceId); - if (trace.canSampled()) { - final SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - if (isDebug) { - logger.debug("TraceID exist. continue trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.path(), request.remoteAddress()); - } - } else { - if (isDebug) { - logger.debug("TraceID exist. camSampled is false. skip trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.path(), request.remoteAddress()); - } - } - if (!initScope(trace)) { - // invalid scope. - deleteTrace(trace); - return null; - } - - return trace; - } else { - // make asynchronous trace. - final Trace trace = traceContext.newAsyncTraceObject(); - if (trace.canSampled()) { - final SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - if (isDebug) { - logger.debug("TraceID not exist. start new trace. requestUrl:{}, remoteAddr:{}", request.path(), request.remoteAddress()); - } - } else { - if (isDebug) { - logger.debug("TraceID not exist. camSampled is false. skip trace. requestUrl:{}, remoteAddr:{}", request.path(), request.remoteAddress()); - } - } - - if (!initScope(trace)) { - // invalid scope. - deleteTrace(trace); - return null; - } - - return trace; + if (!initScope(trace)) { + // invalid scope. + deleteTrace(trace); + return null; } + return trace; } private void deleteTrace(final Trace trace) { @@ -308,107 +251,7 @@ private void deleteTrace(final Trace trace) { trace.close(); } - private boolean samplingEnable(HttpServerRequestImpl request) { - // optional value - final String samplingFlag = request.getHeader(Header.HTTP_SAMPLED.toString()); - if (isDebug) { - logger.debug("SamplingFlag={}", samplingFlag); - } - return SamplingFlagUtils.isSamplingFlag(samplingFlag); - } - - private TraceId populateTraceIdFromRequest(HttpServerRequestImpl request) { - final String transactionId = request.getHeader(Header.HTTP_TRACE_ID.toString()); - if (transactionId != null) { - final long parentSpanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_PARENT_SPAN_ID.toString()), SpanId.NULL); - final long spanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_SPAN_ID.toString()), SpanId.NULL); - final short flags = NumberUtils.parseShort(request.getHeader(Header.HTTP_FLAGS.toString()), (short) 0); - final TraceId id = traceContext.createTraceId(transactionId, parentSpanID, spanID, flags); - if (isDebug) { - logger.debug("TraceID exist. continue trace. {}", id); - } - return id; - } else { - return null; - } - } - - - private void recordRootSpan(final SpanRecorder recorder, final HttpServerRequestImpl request) { - // root - recorder.recordServiceType(VertxConstants.VERTX_HTTP_SERVER); - final String requestURL = request.path(); - if (requestURL != null) { - recorder.recordRpcName(requestURL); - } - - if (request.localAddress() != null) { - final int port = request.localAddress().port(); - if (port <= 0) { - recorder.recordEndPoint(request.host()); - } else { - recorder.recordEndPoint(request.host() + ":" + port); - } - } - - final String remoteAddr = remoteAddressResolver.resolve(request); - recorder.recordRemoteAddress(remoteAddr); - - if (!recorder.isRoot()) { - recordParentInfo(recorder, request); - } - recorder.recordApi(VERTX_HTTP_SERVER_METHOD_DESCRIPTOR); - - // record proxy HTTP header. - this.proxyHttpHeaderRecorder.record(recorder, new ProxyHttpHeaderHandler() { - @Override - public String read(String name) { - return request.getHeader(name); - } - }); - } - - private void recordParentInfo(SpanRecorder recorder, HttpServerRequestImpl request) { - String parentApplicationName = request.getHeader(Header.HTTP_PARENT_APPLICATION_NAME.toString()); - if (parentApplicationName != null) { - final String host = request.getHeader(Header.HTTP_HOST.toString()); - if (host != null) { - recorder.recordAcceptorHost(host); - } else { - recorder.recordAcceptorHost(NetworkUtils.getHostFromURL(request.uri().toString())); - } - final String type = request.getHeader(Header.HTTP_PARENT_APPLICATION_TYPE.toString()); - final short parentApplicationType = NumberUtils.parseShort(type, ServiceType.UNDEFINED.getCode()); - recorder.recordParentApplication(parentApplicationName, parentApplicationType); - } - } - - private String getRequestParameter(HttpServerRequestImpl request, int eachLimit, int totalLimit) { - if (request.params() == null) { - return ""; - } - final StringBuilder params = new StringBuilder(64); - for (Map.Entry entry : request.params().entries()) { - if (params.length() != 0) { - params.append('&'); - } - // skip appending parameters if parameter size is bigger than totalLimit - if (params.length() > totalLimit) { - params.append("..."); - return params.toString(); - } - - String key = entry.getKey(); - params.append(StringUtils.abbreviate(key, eachLimit)); - params.append('='); - Object value = entry.getValue(); - if (value != null) { - params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); - } - } - return params.toString(); - } private boolean initScope(final Trace trace) { // add user scope. @@ -459,61 +302,6 @@ private boolean isEndScope(final Trace trace) { return scope != null && !scope.isActive(); } - public static class Bypass implements RemoteAddressResolver { - @Override - public String resolve(T servletRequest) { - if (servletRequest.remoteAddress() != null) { - return servletRequest.remoteAddress().toString(); - } - return "unknown"; - } - } - public static class RealIpHeaderResolver implements RemoteAddressResolver { - - public static final String X_FORWARDED_FOR = "x-forwarded-for"; - public static final String X_REAL_IP = "x-real-ip"; - public static final String UNKNOWN = "unknown"; - - private final String realIpHeaderName; - private final String emptyHeaderValue; - - public RealIpHeaderResolver() { - this(X_FORWARDED_FOR, UNKNOWN); - } - - public RealIpHeaderResolver(String realIpHeaderName, String emptyHeaderValue) { - if (realIpHeaderName == null) { - throw new NullPointerException("realIpHeaderName must not be null"); - } - this.realIpHeaderName = realIpHeaderName; - this.emptyHeaderValue = emptyHeaderValue; - } - - @Override - public String resolve(T httpServletRequest) { - final String realIp = httpServletRequest.getHeader(this.realIpHeaderName); - if (StringUtils.isEmpty(realIp)) { - if (httpServletRequest.remoteAddress() != null) { - return httpServletRequest.remoteAddress().toString(); - } - return ""; - } - - if (emptyHeaderValue != null && emptyHeaderValue.equalsIgnoreCase(realIp)) { - if (httpServletRequest.remoteAddress() != null) { - return httpServletRequest.remoteAddress().toString(); - } - return ""; - } - - final int firstIndex = realIp.indexOf(','); - if (firstIndex == -1) { - return realIp; - } else { - return realIp.substring(0, firstIndex); - } - } - } } \ No newline at end of file diff --git a/plugins/vertx/src/test/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientConfigTest.java b/plugins/vertx/src/test/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientConfigTest.java index 5a4f6274a3c5..8c7fce30ca3e 100644 --- a/plugins/vertx/src/test/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientConfigTest.java +++ b/plugins/vertx/src/test/java/com/navercorp/pinpoint/plugin/vertx/VertxHttpClientConfigTest.java @@ -42,9 +42,6 @@ public void config() { VertxHttpClientConfig config = new VertxHttpClientConfig(profilerConfig); assertEquals(true, config.isParam()); - assertEquals(true, config.isCookie()); - assertEquals(DumpType.EXCEPTION, config.getCookieDumpType()); - assertEquals(1, config.getCookieSamplingRate()); assertEquals(true, config.isStatusCode()); properties = new Properties(); @@ -58,9 +55,6 @@ public void config() { config = new VertxHttpClientConfig(profilerConfig); assertEquals(false, config.isParam()); - assertEquals(false, config.isCookie()); - assertEquals(DumpType.ALWAYS, config.getCookieDumpType()); - assertEquals(99, config.getCookieSamplingRate()); assertEquals(false, config.isStatusCode()); } } \ No newline at end of file diff --git a/plugins/weblogic/.gitignore b/plugins/weblogic/.gitignore new file mode 100644 index 000000000000..050d1ad3a284 --- /dev/null +++ b/plugins/weblogic/.gitignore @@ -0,0 +1,53 @@ +/target/ +/.settings/ +/.classpath +/.project +/*.iml + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/plugins/weblogic/README.md b/plugins/weblogic/README.md new file mode 100644 index 000000000000..c01fbd9cb590 --- /dev/null +++ b/plugins/weblogic/README.md @@ -0,0 +1,10 @@ +Add the agent parameter (-javaagent:$AGENT_PATH....) in start shell under the domains + +For example: +1. In Windows, you should find the file: 'startWeblogic.cmd'. Then, add the agent parameter (-javaagent:$AGENT_PATH....) after 'set SAVE_JAVA_OPTIONS=%JAVA_OPTIONS%' as following: + +set SAVE_JAVA_OPTIONS=%JAVA_OPTIONS% -javaagent:$AGENT_PATH.... + +2. In Linux(Unix), you should find the file: 'startWeblogic.sh'. Then, add the agent parameter (-javaagent:$AGENT_PATH....) after 'SAVE_JAVA_OPTIONS="${JAVA_OPTIONS}' as following: + +SAVE_JAVA_OPTIONS="${JAVA_OPTIONS} -javaagent:$AGENT_PATH...." diff --git a/plugins/weblogic/pom.xml b/plugins/weblogic/pom.xml new file mode 100644 index 000000000000..9650d7cc293c --- /dev/null +++ b/plugins/weblogic/pom.xml @@ -0,0 +1,107 @@ + + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint + ../.. + 1.8.1-SNAPSHOT + + + pinpoint-weblogic-plugin + pinpoint-weblogic-plugin + jar + + + com.navercorp.pinpoint + pinpoint-bootstrap-core + provided + + + javax.servlet + javax.servlet-api + provided + + + + com.navercorp.pinpoint + pinpoint-common-servlet + ${project.version} + compile + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.10 + + + generate-sources + + add-source + + + + src/main/java-oracle + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + com/navercorp/**/* + META-INF/**/* + + + + + + org.apache.maven.plugins + maven-shade-plugin + ${plugin.shade.version} + + + package + + shade + + + + + com.navercorp.pinpoint.plugin.common.servlet + com.navercorp.pinpoint.plugin.weblogic.common.servlet + + + + ${project.build.directory}/dependency-reduced-pom.xml + + + + + + + + diff --git a/plugins/weblogic/src/main/java-oracle/weblogic/servlet/internal/ServletRequestImpl.java b/plugins/weblogic/src/main/java-oracle/weblogic/servlet/internal/ServletRequestImpl.java new file mode 100644 index 000000000000..17424546134b --- /dev/null +++ b/plugins/weblogic/src/main/java-oracle/weblogic/servlet/internal/ServletRequestImpl.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package weblogic.servlet.internal; + +/** + * @author jaehong.kim + */ +public class ServletRequestImpl { + + public String getMethod() { + return ""; + } + + public String getRequestURI() { + return ""; + } + + public String getHeader(String var1) { + return ""; + } + + public String getQueryString() { + return ""; + } + + public int getServerPort() { + return 0; + } + + public String getServerName() { + return ""; + } + + public String getRemoteAddr() { + return ""; + } + + // Dummy + public ServletResponseImpl getResponse() { + return null; + } +} diff --git a/plugins/weblogic/src/main/java-oracle/weblogic/servlet/internal/ServletResponseImpl.java b/plugins/weblogic/src/main/java-oracle/weblogic/servlet/internal/ServletResponseImpl.java new file mode 100644 index 000000000000..51153749d2e2 --- /dev/null +++ b/plugins/weblogic/src/main/java-oracle/weblogic/servlet/internal/ServletResponseImpl.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package weblogic.servlet.internal; + +/** + * @author jaehong.kim + */ +public class ServletResponseImpl { + + // Dummy + public int getStatus() { + return 0; + } +} \ No newline at end of file diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/MethodFilterExtractor.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/MethodFilterExtractor.java new file mode 100644 index 000000000000..22021d40e849 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/MethodFilterExtractor.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.weblogic; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import weblogic.servlet.internal.ServletRequestImpl; + +/** + * @author jaehong.kim + */ +public class MethodFilterExtractor implements ParameterExtractor { + + private final Filter excludeProfileMethodFilter; + + private final ParameterExtractor delegate; + + public MethodFilterExtractor(Filter excludeProfileMethodFilter, ParameterExtractor delegate) { + this.excludeProfileMethodFilter = excludeProfileMethodFilter; + this.delegate = delegate; + } + + @Override + public String extractParameter(ServletRequestImpl request) { + if (excludeProfileMethodFilter.filter(request.getMethod())) { + return null; + } + return delegate.extractParameter(request); + } +} diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/ParameterRecorderFactory.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/ParameterRecorderFactory.java new file mode 100644 index 000000000000..5277032e1851 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/ParameterRecorderFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.weblogic; + +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.DisableParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.HttpParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import weblogic.servlet.internal.ServletRequestImpl; + +/** + * @author jaehong.kim + */ +public class ParameterRecorderFactory { + public static ParameterRecorder newParameterRecorderFactory(Filter excludeProfileMethodFilter, boolean traceRequestParam) { + if (!traceRequestParam) { + return new DisableParameterRecorder(); + } + ParameterExtractor parameterExtractor = new ServletRequestImplParameterExtractor(64, 512); + ParameterExtractor methodFilterExtractor = new MethodFilterExtractor(excludeProfileMethodFilter, parameterExtractor); + return new HttpParameterRecorder(methodFilterExtractor); + } +} diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/ResponseGetter.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/ResponseGetter.java new file mode 100644 index 000000000000..a5ff3bd46377 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/ResponseGetter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.weblogic; + +import javax.servlet.ServletResponse; + +/** + * @author jaehong.kim + */ +public interface ResponseGetter { + ServletResponse _$PINPOINT$_getResponse(); +} diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/ServletRequestImplParameterExtractor.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/ServletRequestImplParameterExtractor.java new file mode 100644 index 000000000000..ac1d07d50f7b --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/ServletRequestImplParameterExtractor.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.weblogic; + +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.common.util.StringUtils; +import weblogic.servlet.internal.ServletRequestImpl; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author jaehong.kim + */ +public class ServletRequestImplParameterExtractor implements ParameterExtractor { + private int eachLimit; + private int totalLimit; + + public ServletRequestImplParameterExtractor(int eachLimit, int totalLimit) { + this.eachLimit = eachLimit; + this.totalLimit = totalLimit; + } + + @Override + public String extractParameter(ServletRequestImpl request) { + String queryString = request.getQueryString(); + final StringBuilder params = new StringBuilder(64); + try { + Map query_pairs = splitQuery(queryString); + + Iterator attrs = query_pairs.keySet().iterator(); + + while (attrs.hasNext()) { + if (params.length() != 0) { + params.append('&'); + } + // skip appending parameters if parameter size is bigger than + // totalLimit + if (params.length() > totalLimit) { + params.append("..."); + return params.toString(); + } + String key = attrs.next(); + params.append(StringUtils.abbreviate(key, eachLimit)); + params.append("="); + String value = query_pairs.get(key); + if (value != null) { + params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); + } + } + } catch (UnsupportedEncodingException e) { + } + return params.toString(); + } + + private Map splitQuery(String query) throws UnsupportedEncodingException { + Map query_pairs = new LinkedHashMap(); + if (query != null) { + String[] pairs = query.split("&"); + for (String pair : pairs) { + int idx = pair.indexOf("="); + if (idx > 0) + query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); + } + } + return query_pairs; + } +} \ No newline at end of file diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicAsyncListener.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicAsyncListener.java new file mode 100644 index 000000000000..9f51c0fe19b4 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicAsyncListener.java @@ -0,0 +1,127 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.weblogic; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.AsyncListenerInterceptorHelper; +import weblogic.servlet.internal.ServletResponseImpl; + +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.ServletResponse; +import java.io.IOException; + +/** + * @author jaehong.kim + */ +public class WeblogicAsyncListener implements AsyncListener { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private final AsyncListenerInterceptorHelper asyncListenerInterceptorHelper; + + public WeblogicAsyncListener(final TraceContext traceContext, final AsyncContext asyncContext) { + this.asyncListenerInterceptorHelper = new AsyncListenerInterceptorHelper(traceContext, asyncContext); + } + + @Override + public void onComplete(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Complete asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + final int statusCode = getStatusCode(asyncEvent); + this.asyncListenerInterceptorHelper.complete(asyncEvent.getThrowable(), statusCode); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + } + + @Override + public void onTimeout(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Timeout asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.timeout(asyncEvent.getThrowable()); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onError(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Error asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isInfo) { + logger.info("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.error(asyncEvent.getThrowable()); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + } + + @Override + public void onStartAsync(AsyncEvent asyncEvent) throws IOException { + } + + private int getStatusCode(final AsyncEvent asyncEvent) { + try { + if (asyncEvent.getAsyncContext() instanceof ResponseGetter) { + final ServletResponse response = ((ResponseGetter) asyncEvent.getAsyncContext())._$PINPOINT$_getResponse(); + if (response instanceof ServletResponseImpl) { + return ((ServletResponseImpl) response).getStatus(); + } + } + } catch (Exception ignored) { + // Expected exception: java.lang.IllegalStateException: [HTTP:101402]Cannot get Request or Response when the current state is completed or dispatched + } + return 0; + } +} \ No newline at end of file diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicConfiguration.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicConfiguration.java new file mode 100644 index 000000000000..d811a9088204 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicConfiguration.java @@ -0,0 +1,112 @@ +/* + * Copyright 2016 Pinpoint contributors and NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.weblogic; + +import java.util.List; + +import com.navercorp.pinpoint.bootstrap.config.ExcludeMethodFilter; +import com.navercorp.pinpoint.bootstrap.config.ExcludePathFilter; +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.bootstrap.config.SkipFilter; + +/** + * @author andyspan + * @author jaehong.kim + */ +public class WeblogicConfiguration { + private final boolean enable; + private final List bootstrapMains; + private final Filter excludeUrlFilter; + private final Filter excludeProfileMethodFilter; + private final String realIpHeader; + private final String realIpEmptyValue; + private final boolean traceRequestParam; + private final boolean hidePinpointHeader; + + public WeblogicConfiguration(ProfilerConfig config) { + this.enable = config.readBoolean("profiler.weblogic.enable", true); + this.bootstrapMains = config.readList("profiler.weblogic.bootstrap.main"); + final String weblogicExcludeURL = config.readString("profiler.weblogic.excludeurl", ""); + + this.realIpHeader = config.readString("profiler.weblogic.realipheader", null); + this.realIpEmptyValue = config.readString("profiler.weblogic.realipemptyvalue", null); + if (!weblogicExcludeURL.isEmpty()) { + this.excludeUrlFilter = new ExcludePathFilter(weblogicExcludeURL); + } else { + this.excludeUrlFilter = new SkipFilter(); + } + final String excludeProfileMethod = config.readString("profiler.weblogic.excludemethod", ""); + if (!excludeProfileMethod.isEmpty()) { + this.excludeProfileMethodFilter = new ExcludeMethodFilter(excludeProfileMethod); + } else { + this.excludeProfileMethodFilter = new SkipFilter(); + } + this.traceRequestParam = config.readBoolean("profiler.weblogic.tracerequestparam", true); + this.hidePinpointHeader = config.readBoolean("profiler.weblogic.hidepinpointheader", true); + } + + public Filter getExcludeUrlFilter() { + return excludeUrlFilter; + } + + public boolean isEnable() { + return enable; + } + + public List getWeblgoicBootstrapMains() { + return bootstrapMains; + } + + public boolean isTraceRequestParam() { + return traceRequestParam; + } + + public List getBootstrapMains() { + return bootstrapMains; + } + + public Filter getExcludeProfileMethodFilter() { + return excludeProfileMethodFilter; + } + + public String getRealIpHeader() { + return realIpHeader; + } + + public String getRealIpEmptyValue() { + return realIpEmptyValue; + } + + public boolean isHidePinpointHeader() { + return hidePinpointHeader; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("WeblogicConfiguration{"); + sb.append("enable=").append(enable); + sb.append(", bootstrapMains=").append(bootstrapMains); + sb.append(", excludeUrlFilter=").append(excludeUrlFilter); + sb.append(", excludeProfileMethodFilter=").append(excludeProfileMethodFilter); + sb.append(", realIpHeader='").append(realIpHeader).append('\''); + sb.append(", realIpEmptyValue='").append(realIpEmptyValue).append('\''); + sb.append(", traceRequestParam=").append(traceRequestParam); + sb.append(", hidePinpointHeader=").append(hidePinpointHeader); + sb.append('}'); + return sb.toString(); + } +} diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicConstants.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicConstants.java new file mode 100644 index 000000000000..3793a4cfda0b --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicConstants.java @@ -0,0 +1,32 @@ +/* + * Copyright 2016 Pinpoint contributors and NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.weblogic; + +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.*; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; +/** + * + * @author andyspan + * + */ +public final class WeblogicConstants { + private WeblogicConstants() { + } + public static final ServiceType WEBLOGIC = ServiceTypeFactory.of(1070, "WEBLOGIC", RECORD_STATISTICS); + public static final ServiceType WEBLOGIC_METHOD = ServiceTypeFactory.of(1071, "WEBLOGIC_METHOD"); +} diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicDetector.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicDetector.java new file mode 100644 index 000000000000..dfec1c78a520 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicDetector.java @@ -0,0 +1,52 @@ +/* + * Copyright 2016 Pinpoint contributors and NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.weblogic; + +import java.util.Arrays; +import java.util.List; + +import com.navercorp.pinpoint.bootstrap.plugin.ApplicationTypeDetector; +import com.navercorp.pinpoint.bootstrap.resolver.ConditionProvider; +import com.navercorp.pinpoint.common.trace.ServiceType; +/** + * + * @author andyspan + * + */ +public class WeblogicDetector implements ApplicationTypeDetector { + + private static final String DEFAULT_BOOTSTRAP_MAIN = "weblogic.Server"; + + private final List bootstrapMains; + + public WeblogicDetector(List bootstrapMains) { + if (bootstrapMains == null || bootstrapMains.isEmpty()) { + this.bootstrapMains = Arrays.asList(DEFAULT_BOOTSTRAP_MAIN); + } else { + this.bootstrapMains = bootstrapMains; + } +} + + @Override + public ServiceType getApplicationType() { + return WeblogicConstants.WEBLOGIC; + } + + @Override + public boolean detect(ConditionProvider provider) { + return provider.checkMainClass(bootstrapMains); + } +} diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicPlugin.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicPlugin.java new file mode 100644 index 000000000000..3569d8dda557 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicPlugin.java @@ -0,0 +1,110 @@ +/* + * Copyright 2016 Pinpoint contributors and NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.weblogic; + + +import java.security.ProtectionDomain; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; +import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; +import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; + +/** + * @author andyspan + * @author jaehong.kim + */ +public class WeblogicPlugin implements ProfilerPlugin, TransformTemplateAware { + + private TransformTemplate transformTemplate; + protected PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + @Override + public void setup(ProfilerPluginSetupContext context) { + final WeblogicConfiguration config = new WeblogicConfiguration(context.getConfig()); + if (!config.isEnable()) { + logger.info("WeblogicPlugin disabled"); + return; + } + logger.info("WeblogicPlugin config={}", config); + + context.addApplicationTypeDetector(new WeblogicDetector(config.getBootstrapMains())); + + // Add async listener. Servlet 3.0 & Hide pinpoint headers + addServletRequestImpl(config); + // Entry Point + addServerInterceptor(); + // Add response getter + addAsyncContextImpl(); + } + + private void addServletRequestImpl(final WeblogicConfiguration config) { + transformTemplate.transform("weblogic.servlet.internal.ServletRequestImpl", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + if (config.isHidePinpointHeader()) { + // Hide pinpoint headers + target.weave("com.navercorp.pinpoint.plugin.weblogic.aspect.ServletRequestImplAspect"); + } + + // Add async listener. Servlet 3.0 + final InstrumentMethod startAsyncMethodEditor = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); + if (startAsyncMethodEditor != null) { + startAsyncMethodEditor.addInterceptor("com.navercorp.pinpoint.plugin.weblogic.interceptor.ServletRequestImplStartAsyncInterceptor"); + } + return target.toBytecode(); + } + }); + } + + private void addServerInterceptor() { + transformTemplate.transform("weblogic.servlet.internal.WebAppServletContext", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + final InstrumentMethod handleMethodEditorBuilder = target.getDeclaredMethod("execute", "weblogic.servlet.internal.ServletRequestImpl", "weblogic.servlet.internal.ServletResponseImpl"); + if (handleMethodEditorBuilder != null) { + handleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.weblogic.interceptor.WebAppServletContextExecuteInterceptor"); + } + return target.toBytecode(); + } + }); + } + + private void addAsyncContextImpl() { + transformTemplate.transform("weblogic.servlet.internal.async.AsyncContextImpl", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addGetter("com.navercorp.pinpoint.plugin.weblogic.ResponseGetter", "response"); + return target.toBytecode(); + } + }); + } + + @Override + public void setTransformTemplate(TransformTemplate transformTemplate) { + this.transformTemplate = transformTemplate; + } +} \ No newline at end of file diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicTypeProvider.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicTypeProvider.java new file mode 100644 index 000000000000..e42d32c1136d --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/WeblogicTypeProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2016 Pinpoint contributors and NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.plugin.weblogic; + +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext; +/** + * + * @author andyspan + * + */ +public class WeblogicTypeProvider implements TraceMetadataProvider { + + @Override + public void setup(TraceMetadataSetupContext context) { + context.addServiceType(WeblogicConstants.WEBLOGIC); + context.addServiceType(WeblogicConstants.WEBLOGIC_METHOD); + } +} diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/aspect/ServletRequestImplAspect.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/aspect/ServletRequestImplAspect.java new file mode 100644 index 000000000000..5c72331fe380 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/aspect/ServletRequestImplAspect.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.weblogic.aspect; + +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; +import com.navercorp.pinpoint.common.util.DelegateEnumeration; + +import java.util.Enumeration; + +/** + * @author jaehong.kim + */ +@Aspect +public abstract class ServletRequestImplAspect { + @PointCut + public Enumeration getHeaderNames() { + return new DelegateEnumeration(__getHeaderNames(), Header.FILTER); + } + + @JointPoint + abstract Enumeration __getHeaderNames(); +} diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/interceptor/ServletRequestImplAdaptor.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/interceptor/ServletRequestImplAdaptor.java new file mode 100644 index 000000000000..ac2056c50716 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/interceptor/ServletRequestImplAdaptor.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.weblogic.interceptor; + +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; +import weblogic.servlet.internal.ServletRequestImpl; + +/** + * @author jaehong.kim + */ +public class ServletRequestImplAdaptor implements RequestAdaptor { + @Override + public String getHeader(ServletRequestImpl request, String name) { + return request.getHeader(name); + } + + @Override + public String getRpcName(ServletRequestImpl request) { + return request.getRequestURI(); + } + + @Override + public String getEndPoint(ServletRequestImpl request) { + final int port = request.getServerPort(); + final String endPoint = request.getServerName() + ":" + port; + return endPoint; + } + + @Override + public String getRemoteAddress(ServletRequestImpl request) { + return request.getRemoteAddr(); + } + + @Override + public String getAcceptorHost(ServletRequestImpl request) { + return NetworkUtils.getHostFromURL(request.getRequestURI()); + } +} diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/interceptor/ServletRequestImplStartAsyncInterceptor.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/interceptor/ServletRequestImplStartAsyncInterceptor.java new file mode 100644 index 000000000000..bcdb0b0397bf --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/interceptor/ServletRequestImplStartAsyncInterceptor.java @@ -0,0 +1,112 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.weblogic.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.weblogic.WeblogicAsyncListener; +import com.navercorp.pinpoint.plugin.weblogic.WeblogicConstants; + +import javax.servlet.AsyncContext; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletRequest; + +/** + * @author jaehong.kim + */ +public class ServletRequestImplStartAsyncInterceptor implements AroundInterceptor { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor descriptor; + + public ServletRequestImplStartAsyncInterceptor(TraceContext context, MethodDescriptor descriptor) { + this.traceContext = context; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + if (validate(target, result, throwable)) { + final AsyncContext asyncContext = (AsyncContext) result; + final AsyncListener asyncListener = new WeblogicAsyncListener(this.traceContext, recorder.recordNextAsyncContext(true)); + asyncContext.addListener(asyncListener); + if (isDebug) { + logger.debug("Add async listener {}", asyncListener); + } + } + recorder.recordServiceType(WeblogicConstants.WEBLOGIC_METHOD); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + } catch (Throwable t) { + logger.warn("Failed to AFTER process. {}", t.getMessage(), t); + } finally { + trace.traceBlockEnd(); + } + } + + private boolean validate(final Object target, final Object result, final Throwable throwable) { + if (throwable != null || result == null) { + return false; + } + + if (!(target instanceof HttpServletRequest)) { + if (isDebug) { + logger.debug("Invalid target object. The javax.servlet.http.HttpServletRequest interface is not implemented. target={}", target); + } + return false; + } + + if (!(result instanceof AsyncContext)) { + if (isDebug) { + logger.debug("Invalid result object. The javax.servlet.AsyncContext interface is not implemented. result={}", result); + } + return false; + } + return true; + } +} \ No newline at end of file diff --git a/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/interceptor/WebAppServletContextExecuteInterceptor.java b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/interceptor/WebAppServletContextExecuteInterceptor.java new file mode 100644 index 000000000000..e64c9dec7026 --- /dev/null +++ b/plugins/weblogic/src/main/java/com/navercorp/pinpoint/plugin/weblogic/interceptor/WebAppServletContextExecuteInterceptor.java @@ -0,0 +1,124 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.weblogic.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServletRequestListenerInterceptorHelper; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.RemoteAddressResolverFactory; +import com.navercorp.pinpoint.plugin.weblogic.ParameterRecorderFactory; +import com.navercorp.pinpoint.plugin.weblogic.WeblogicConfiguration; +import com.navercorp.pinpoint.plugin.weblogic.WeblogicConstants; +import weblogic.servlet.internal.ServletRequestImpl; +import weblogic.servlet.internal.ServletResponseImpl; + +/** + * @author andyspan + * @author jaehong.kim + */ +public class WebAppServletContextExecuteInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + private final boolean isInfo = logger.isInfoEnabled(); + + private MethodDescriptor methodDescriptor; + private ServletRequestListenerInterceptorHelper servletRequestListenerInterceptorHelper; + + public WebAppServletContextExecuteInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + + this.methodDescriptor = methodDescriptor; + final WeblogicConfiguration config = new WeblogicConfiguration(traceContext.getProfilerConfig()); + RequestAdaptor requestAdaptor = new ServletRequestImplAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, config.getRealIpHeader(), config.getRealIpEmptyValue()); + ParameterRecorder parameterRecorder = ParameterRecorderFactory.newParameterRecorderFactory(config.getExcludeProfileMethodFilter(), config.isTraceRequestParam()); + this.servletRequestListenerInterceptorHelper = new ServletRequestListenerInterceptorHelper(WeblogicConstants.WEBLOGIC, traceContext, requestAdaptor, config.getExcludeUrlFilter(), parameterRecorder); + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (!validate(args)) { + return; + } + + try { + final ServletRequestImpl request = (ServletRequestImpl) args[0]; + this.servletRequestListenerInterceptorHelper.initialized(request, WeblogicConstants.WEBLOGIC_METHOD, this.methodDescriptor); + } catch (Throwable t) { + if (isInfo) { + logger.info("Failed to servlet request event handle.", t); + } + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + if (!validate(args)) { + return; + } + + try { + final ServletRequestImpl request = (ServletRequestImpl) args[0]; + final ServletResponseImpl response = (ServletResponseImpl) args[1]; + final int statusCode = getStatusCode(response); + this.servletRequestListenerInterceptorHelper.destroyed(request, throwable, statusCode); + } catch (Throwable t) { + logger.info("Failed to servlet request event handle.", t); + } + } + + private boolean validate(final Object[] args) { + if (args == null || args.length < 2) { + return false; + } + + if (!(args[0] instanceof ServletRequestImpl)) { + if (isDebug) { + logger.debug("Invalid args[0] object, Not implemented of weblogic.servlet.internal.ServletRequestImpl. args[0]={}", args[0]); + } + return false; + } + + if (!(args[1] instanceof ServletResponseImpl)) { + if (isDebug) { + logger.debug("Invalid args[1] object, Not implemented of weblogic.servlet.internal.ServletResponseImpl. args[1]={}.", args[1]); + } + return false; + } + return true; + } + + private int getStatusCode(final ServletResponseImpl response) { + try { + return response.getStatus(); + } catch (Exception ignored) { + } + return 0; + } +} \ No newline at end of file diff --git a/plugins/weblogic/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin b/plugins/weblogic/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin new file mode 100644 index 000000000000..947a1cb711b0 --- /dev/null +++ b/plugins/weblogic/src/main/resources/META-INF/services/com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.weblogic.WeblogicPlugin \ No newline at end of file diff --git a/plugins/weblogic/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider b/plugins/weblogic/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider new file mode 100644 index 000000000000..64987c09bbf6 --- /dev/null +++ b/plugins/weblogic/src/main/resources/META-INF/services/com.navercorp.pinpoint.common.trace.TraceMetadataProvider @@ -0,0 +1 @@ +com.navercorp.pinpoint.plugin.weblogic.WeblogicTypeProvider diff --git a/plugins/weblogic/src/test/resources/pinpoint.config b/plugins/weblogic/src/test/resources/pinpoint.config new file mode 100644 index 000000000000..3450ed090f83 --- /dev/null +++ b/plugins/weblogic/src/test/resources/pinpoint.config @@ -0,0 +1,577 @@ +# +# Pinpoint agent configuration +# + +########################################################### +# Collector server # +########################################################### +profiler.collector.ip=10.4.55.170 + +# placeHolder support "${key}" +profiler.collector.span.ip=${profiler.collector.ip} +profiler.collector.span.port=9996 + +# placeHolder support "${key}" +profiler.collector.stat.ip=${profiler.collector.ip} +profiler.collector.stat.port=9995 + +# placeHolder support "${key}" +profiler.collector.tcp.ip=${profiler.collector.ip} +profiler.collector.tcp.port=9994 + +########################################################### +# Profiler Global Configuration # +########################################################### +profiler.enable=true + +profiler.interceptorregistry.size=8192 +profiler.jvm.collect.interval=1000 + +# Allow to add detailed collector's metrics +profiler.jvm.collect.detailed.metrics=true + +# Allow sampling. +profiler.sampling.enable=true + +# 1 out of n transactions will be sampled where n is the rate. (20: 5%) +profiler.sampling.rate=20 + +# Allow buffering when flushing span to IO. +profiler.io.buffering.enable=true + +# How many spans to store if buffering enabled. +profiler.io.buffering.buffersize=20 + +# Capacity of the SpanDataSender write queue. +profiler.spandatasender.write.queue.size=5120 +#profiler.spandatasender.socket.sendbuffersize=1048576 +#profiler.spandatasender.socket.timeout=3000 +profiler.spandatasender.chunk.size=16384 +profiler.spandatasender.socket.type=OIO + +# Capacity of the StatDataSender write queue. +profiler.statdatasender.write.queue.size=5120 +#profiler.statdatasender.socket.sendbuffersize=1048576 +#profiler.statdatasender.socket.timeout=3000 +profiler.statdatasender.chunk.size=16384 +profiler.statdatasender.socket.type=OIO + +# Interval to retry sending agent info. Unit is milliseconds. +profiler.agentInfo.send.retry.interval=300000 + +# Allow TCP data command. +profiler.tcpdatasender.command.accept.enable=true + +# Trace Agent active thread info. +profiler.pinpoint.activethread=true + +## Call Stack +# Set max depth, if -1 is unlimited and min is 2. +profiler.callstack.max.depth=64 + +# weather or not to propagate exceptions occurred at interceptor +profiler.interceptor.exception.propagate=false + +# Allow bytecode framework (JAVASSIST or ASM) +profiler.instrument.engine=ASM + +# bytecode dump option +# java bytecode debug option +bytecode.dump.enable=false +#bytecode.dump.classlist=com.naver.user.UserService,com.pinpoint.debug.TestClass +bytecode.dump.classlist= +bytecode.dump.bytecode=false +bytecode.dump.verify=false +bytecode.dump.asm=false + +########################################################### +# application type # +########################################################### +#profiler.applicationservertype=TOMCAT +#profiler.applicationservertype=BLOC + +########################################################### +# application type detect order # +########################################################### +profiler.type.detect.order= + +profiler.plugin.disable= + +########################################################### +# user defined classes # +########################################################### +# Specify classes and methods you want to profile here. + +# Needs to be a comma separated list of fully qualified class names, or fully qualified package names with wild card class. +profiler.include= +# Ex: foo.bar.MyClass, foo.baz.* + +# Needs to be a comma separated list of fully qualified method names. Wild card not supported. +profiler.entrypoint= +# Ex: foo.bar.MyClass.myMethod, foo.bar.MyClass.anotherMethod + +#weblogic start +profiler.weblogic.enable = true +profiler.weblogic.bootstrap.main = weblogic.Server +profiler.weblogic.excludeurl = /aa/test.html, /bb/exclude.html +#weblogic end + +###websphere start +profiler.websphere.enable = true +profiler.websphere.excludeurl = /aa/test.html, /bb/exclude.html +###webspher end + +########################################################### +# TOMCAT # +########################################################### +profiler.tomcat.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap +# Check pre-conditions when registering class file transformers mainly due to JBoss plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.apache.catalina.startup.Bootstrap, +# or SpringBoot's launchers. +# Set this to false to bypass this check entirely (such as when launching standalone applications running embedded Tomcat). +profiler.tomcat.conditional.transform=true +# Hide pinpoint headers. +profiler.tomcat.hidepinpointheader=true +# URLs to exclude from tracing +profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html +profiler.tomcat.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.tomcat.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.tomcat.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.tomcat.realipemptyvalue}, Ignore header value. +#profiler.tomcat.realipemptyvalue=unknown + + +########################################################### +# JETTY # +########################################################### +profiler.jetty.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main +# URLs to exclude from tracing +profiler.jetty.excludeUrl= + + +########################################################### +# DUBBO # +########################################################### +profiler.dubbo.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.dubbo.bootstrap.main=com.alibaba.dubbo.container.Main + + +########################################################### +# JBOSS # +########################################################### +profiler.jboss.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.jboss.bootstrap.main=org.jboss.modules.Main +# Check pre-conditions when registering class file transformers mainly due to Tomcat plugin transforming the same class. +# Setting this to true currently adds transformers only if the application was launched via org.jboss.modules.Main. +# Set this to false to bypass this check entirely. +profiler.jboss.conditional.transform=true +# Hide pinpoint headers. +profiler.jboss.hidepinpointheader=true +# URLs to exclude from tracing +profiler.jboss.excludeurl= +# HTTP Request methods to exclude from tracing +#profiler.jboss.excludemethod= +profiler.jboss.tracerequestparam=true + +# original IP address header +# https://en.wikipedia.org/wiki/X-Forwarded-For +#profiler.jboss.realipheader=X-Forwarded-For +# nginx real ip header +#profiler.jboss.realipheader=X-Real-IP +# optional parameter, If the header value is ${profiler.jboss.realipemptyvalue}, Ignore header value. +#profiler.jboss.realipemptyvalue=unknown + + +########################################################### +# SPRING BOOT # +########################################################### +profiler.springboot.enable=true +# Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. +profiler.springboot.bootstrap.main=org.springframework.boot.loader.JarLauncher, org.springframework.boot.loader.WarLauncher, org.springframework.boot.loader.PropertiesLauncher + + +########################################################### +# JDBC # +########################################################### +# Profile JDBC drivers. +profiler.jdbc=true +# Size of cache. Fixed maximum. +profiler.jdbc.sqlcachesize=1024 +# trace bindvalues for PreparedStatements +profiler.jdbc.tracesqlbindvalue=true +# Maximum bindvalue size. +profiler.jdbc.maxsqlbindvaluesize=1024 + +# +# MYSQL +# +# Profile MySQL. +profiler.jdbc.mysql=true +# Allow profiling of setautocommit. +profiler.jdbc.mysql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mysql.commit=true +# Allow profiling of rollback. +profiler.jdbc.mysql.rollback=true +# Trace bindvalues for MySQL PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mysql.tracesqlbindvalue=true + +# +# MARIADB +# +# Profile MariaDB +profiler.jdbc.mariadb=true +# Allow profiling of setautocommit. +profiler.jdbc.mariadb.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.mariadb.commit=true +# Allow profiling of rollback. +profiler.jdbc.mariadb.rollback=true +# Trace bindvalues for MariaDB PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.mariadb.tracesqlbindvalue=true + +# +# MSSQL Jtds +# +# Profile jTDS. +profiler.jdbc.jtds=true +# Allow profiling of setautocommit. +profiler.jdbc.jtds.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.jtds.commit=true +# Allow profiling of rollback. +profiler.jdbc.jtds.rollback=true +# Trace bindvalues for jTDS PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.jtds.tracesqlbindvalue=true + +# +# Oracle +# +# Profile Oracle + DB. +profiler.jdbc.oracle=true +# Allow profiling of setautocommit. +profiler.jdbc.oracle.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.oracle.commit=true +# Allow profiling of rollback. +profiler.jdbc.oracle.rollback=true +# Trace bindvalues for Oracle PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.oracle.tracesqlbindvalue=true + +# +# CUBRID +# +# Profile CUBRID. +profiler.jdbc.cubrid=true +# Allow profiling of setautocommit. +profiler.jdbc.cubrid.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.cubrid.commit=true +# Allow profiling of rollback. +profiler.jdbc.cubrid.rollback=true +# Trace bindvalues for CUBRID PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.jdbc.cubrid.tracesqlbindvalue=true + +# +# DBCP +# +# Profile DBCP. +profiler.jdbc.dbcp=true +profiler.jdbc.dbcp.connectionclose=true + +# +# CASSANDRA +# +# Profile CASSANDRA. +profiler.cassandra=true +# Trace bindvalues for CASSANDRA PreparedStatements (overrides profiler.jdbc.tracesqlbindvalue) +#profiler.cassandra.tracecqlbindvalue=true + +# +# PostgreSQL +# +# Profile PostgreSQL. +profiler.jdbc.postgresql=true +# Allow profiling of setautocommit. +profiler.jdbc.postgresql.setautocommit=true +# Allow profiling of commit. +profiler.jdbc.postgresql.commit=true +# Allow profiling of rollback. +profiler.jdbc.postgresql.rollback=true + + +########################################################### +# Apache HTTP Client 3.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient3.param=true + +# Record Cookies. +profiler.apache.httpclient3.cookie=true + +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.cookie.dumptype=ALWAYS +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient3.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient3.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient3.entity.dumptype=ALWAYS +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient3.entity.sampling.rate=1 + +# Record IO time. +profiler.apache.httpclient3.io=true + +########################################################### +# Apache HTTP Client 4.x # +########################################################### +# Record Parameter. +profiler.apache.httpclient4.param=true + +# Record cookies. +profiler.apache.httpclient4.cookie=true + +# When cookies should be dumped. It could be ALWAYS or EXCEPTION. +profiler.apache.httpclient4.cookie.dumptype=ALWAYS + +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.apache.httpclient4.cookie.sampling.rate=1 + +# Dump entities of POST and PUT requests. Limited to entities where HttpEntity.isRepeatable() == true. +profiler.apache.httpclient4.entity=true + +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.apache.httpclient4.entity.dumptype=ALWAYS + +# 1 out of n entities will be sampled where n is the rate. (10: 10%) +profiler.apache.httpclient4.entity.sampling.rate=1 + +# Allow profiling status code value. +profiler.apache.httpclient4.entity.statuscode=true + +# Record IO time. +profiler.apache.httpclient4.io=true + +# Not supported yet. +#profiler.apache.nio.httpclient4=true + +########################################################### +# JDK HTTPURLConnection # +########################################################### +# Profile parameter. +profiler.jdk.http.param=true + +########################################################### +# Ning Async HTTP Client # +########################################################### +# Profile Ning Async HTTP Client. +profiler.ning.asynchttpclient=true +# Record cookies. +profiler.ning.asynchttpclient.cookie=true +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS +# Cookie dump size. +profiler.ning.asynchttpclient.cookie.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.cookie.sampling.rate=1 +# Record Entities. +profiler.ning.asynchttpclient.entity=true +# When to dump entities. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.entity.dumptype=ALWAYS +# Entity dump size. +profiler.ning.asynchttpclient.entity.dumpsize=1024 +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.entity.sampling.rate=1 +# Record parameters. +profiler.ning.asynchttpclient.param=true +# When to dump parameters. Either ALWAYS or EXCEPTION. +profiler.ning.asynchttpclient.param.dumptype=ALWAYS +# Parameter dump size. +profiler.ning.asynchttpclient.param.dumpsize=1024 +# 1 out of n parameters will be sampled where n is the rate. (1: 100%) +profiler.ning.asynchttpclient.param.sampling.rate=1 + + +########################################################### +# Arcus # +########################################################### +# Profile Arcus. +profiler.arcus=true +# Record keytrace. +profiler.arcus.keytrace=true + +########################################################### +# Memcached # +########################################################### +# Profile Memecached. +profiler.memcached=true +# Record keytrace +profiler.memcached.keytrace=true + +########################################################### +# Thrift # +########################################################### +# Profile Thrift +profiler.thrift.client=true +profiler.thrift.client.async=true +# Profile processor. +profiler.thrift.processor=true +profiler.thrift.processor.async=true +# Allow recording arguments. +profiler.thrift.service.args=true +# Allow recording result. +profiler.thrift.service.result=true + + +########################################################### +# ibatis # +########################################################### +# Profile ibatis. +profiler.orm.ibatis=true + +########################################################### +# mybatis # +########################################################### +# Profile mybatis +profiler.orm.mybatis=true + +########################################################### +# spring-beans +########################################################### +# Profile spring-beans +profiler.spring.beans=false + +# filters +# filter +# filter OR filters +# filter +# value +# value AND filter +# value +# token +# token OR token +# token +# profiler.spring.beans.n.scope= [component-scan | post-processor] default is component-scan. +# profiler.spring.beans.n.base-packages= [package name, ...] +# profiler.spring.beans.n.name.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.class.pattern= [regex pattern, regex:regex pattern, antstyle:antstyle pattern, ...] +# profiler.spring.beans.n.annotation= [annotation name, ...] +# +# Scope: +# component-scan: or @ComponentScan +# post-processor: BeanPostProcessor - Slow!!! +# +# ANT Style pattern rules: +# ? - matches on character +# * - matches zero or more characters +# ** - matches zero or more 'directories' in a path + +# Examples +# profiler.spring.beans.1.name.scope=component-scan +# profiler.spring.beans.1.base-packages=com.foo, com.bar +# profiler.spring.beans.1.name.pattern=.*Foo, regex:.*Bar, antstyle:*Controller +# profiler.spring.beans.1.class.pattern= +# profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository +# +# profiler.spring.beans.2.name.scope=post-processor +# profiler.spring.beans.2.base-packages=com.foo +# profiler.spring.beans.2.name.pattern= +# profiler.spring.beans.2.class.pattern=antstyle:com.foo.repository.*Repository, antstyle:com.foo.Service.Main* +# profiler.spring.beans.2.annotation= + +profiler.spring.beans.1.name.scope=component-scan +profiler.spring.beans.1.base-packages= +profiler.spring.beans.1.name.pattern= +profiler.spring.beans.1.class.pattern= +profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository + +profiler.spring.beans.mark.error=false +########################################################### +# log4j (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.log4j.logging.transactioninfo=false + +########################################################### +# logback (guide url : https://github.com/naver/pinpoint/blob/master/doc/per-request_feature_guide.md) +########################################################### +profiler.logback.logging.transactioninfo=false + +########################################################### +# google httpclient +########################################################### +# Profile async. +profiler.google.httpclient.async=true + +########################################################### +# redis +########################################################### +profiler.redis.pipeline +profiler.redis=true +profiler.redis.io=true + +########################################################### +# OkHttp +########################################################### +# Record param. +profiler.okhttp.param=true + +# Record Cookies. +profiler.okhttp.cookie=false + +# When to dump cookies. Either ALWAYS or EXCEPTION. +profiler.okhttp.cookie.dumptype=EXCEPTION + +# 1 out of n cookies will be sampled where n is the rate. (1: 100%) +profiler.okhttp.cookie.sampling.rate=10 + +profiler.okhttp.async=true + +########################################################### +# gson +########################################################### +profiler.json.gson=false + +########################################################### +# jackson +########################################################### +profiler.json.jackson=false + +########################################################### +# json-lib +########################################################### +profiler.json.jsonlib=false + +########################################################### +# ActiveMQ Client +########################################################### +profiler.activemq.client.enable=true +profiler.activemq.client.producer.enable=true +profiler.activemq.client.consumer.enable=true + +# ActiveMQ destination path separator (default is ".") +profiler.activemq.client.destination.separator= + +# ActiveMQ destinations to exclude from tracing (comma seprated list of ant-matched destinations) +profiler.activemq.client.destination.exclude= + +########################################################### +# Hystrix +########################################################### +profiler.hystrix=true + +# Number of anonymous inner classes in HystrixCommand to check and transform. (default is 3 as of 1.5.3) +#profiler.hystrix.command.num.anonymousInnerClass=3 diff --git a/plugins/websphere/clover.license b/plugins/websphere/clover.license deleted file mode 100644 index a26812effe7c..000000000000 --- a/plugins/websphere/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 @@ -5,7 +21,7 @@ com.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-websphere-plugin @@ -23,6 +39,12 @@ javax.servlet-api provided + + com.navercorp.pinpoint + pinpoint-common-servlet + ${project.version} + compile + @@ -38,7 +60,6 @@ src/main/java-ibm - src/main/java-oracle @@ -54,6 +75,30 @@ + + org.apache.maven.plugins + maven-shade-plugin + ${plugin.shade.version} + + + package + + shade + + + + + com.navercorp.pinpoint.plugin.common.servlet + com.navercorp.pinpoint.plugin.websphere.common.servlet + + + + ${project.build.directory}/dependency-reduced-pom.xml + + + + + diff --git a/plugins/websphere/src/main/java-ibm/com/ibm/ws/webcontainer/channel/WCCResponseImpl.java b/plugins/websphere/src/main/java-ibm/com/ibm/ws/webcontainer/channel/WCCResponseImpl.java new file mode 100644 index 000000000000..0abf6003d8f3 --- /dev/null +++ b/plugins/websphere/src/main/java-ibm/com/ibm/ws/webcontainer/channel/WCCResponseImpl.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ibm.ws.webcontainer.channel; + +import com.ibm.wsspi.http.channel.HttpResponseMessage; + +/** + * @author jaehong.kim + */ +public class WCCResponseImpl { + // Dummy + public HttpResponseMessage getHttpResponse() { + return null; + } +} diff --git a/plugins/websphere/src/main/java-ibm/com/ibm/ws/webcontainer/srt/SRTServletRequest.java b/plugins/websphere/src/main/java-ibm/com/ibm/ws/webcontainer/srt/SRTServletRequest.java new file mode 100644 index 000000000000..96700af56431 --- /dev/null +++ b/plugins/websphere/src/main/java-ibm/com/ibm/ws/webcontainer/srt/SRTServletRequest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ibm.ws.webcontainer.srt; + +import com.ibm.wsspi.webcontainer.servlet.IExtendedResponse; + +/** + * @author jaehong.kim + */ +public class SRTServletRequest { + // Dummy + public IExtendedResponse getResponse() { + return null; + } +} diff --git a/plugins/websphere/src/main/java-ibm/com/ibm/ws/webcontainer/srt/SRTServletResponse.java b/plugins/websphere/src/main/java-ibm/com/ibm/ws/webcontainer/srt/SRTServletResponse.java new file mode 100644 index 000000000000..90ea9fd69085 --- /dev/null +++ b/plugins/websphere/src/main/java-ibm/com/ibm/ws/webcontainer/srt/SRTServletResponse.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ibm.ws.webcontainer.srt; + +/** + * @author jaehong.kim + */ +public class SRTServletResponse { + // Dummy + public int getStatusCode() { + return 0; + } +} diff --git a/plugins/websphere/src/main/java-ibm/com/ibm/wsspi/http/channel/HttpResponseMessage.java b/plugins/websphere/src/main/java-ibm/com/ibm/wsspi/http/channel/HttpResponseMessage.java new file mode 100644 index 000000000000..3de574cac31f --- /dev/null +++ b/plugins/websphere/src/main/java-ibm/com/ibm/wsspi/http/channel/HttpResponseMessage.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ibm.wsspi.http.channel; + +/** + * @author jaehong.kim + */ +public interface HttpResponseMessage { + // Dummy + int getStatusCodeAsInt(); +} \ No newline at end of file diff --git a/plugins/websphere/src/main/java-ibm/com/ibm/wsspi/webcontainer/servlet/IExtendedResponse.java b/plugins/websphere/src/main/java-ibm/com/ibm/wsspi/webcontainer/servlet/IExtendedResponse.java new file mode 100644 index 000000000000..21724a34e3af --- /dev/null +++ b/plugins/websphere/src/main/java-ibm/com/ibm/wsspi/webcontainer/servlet/IExtendedResponse.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ibm.wsspi.webcontainer.servlet; + +/** + * @author jaehong.kim + */ +public interface IExtendedResponse { + int getStatusCode(); +} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/IRequestParameterExtractor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/IRequestParameterExtractor.java new file mode 100644 index 000000000000..cfe628eee6b6 --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/IRequestParameterExtractor.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere; + +import com.ibm.websphere.servlet.request.IRequest; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.common.util.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author jaehong.kim + */ +public class IRequestParameterExtractor implements ParameterExtractor { + + private int eachLimit; + private int totalLimit; + + public IRequestParameterExtractor(int eachLimit, int totalLimit) { + this.eachLimit = eachLimit; + this.totalLimit = totalLimit; + } + + @Override + public String extractParameter(IRequest request) { + String queryString = request.getQueryString(); + final StringBuilder params = new StringBuilder(64); + try { + Map query_pairs = splitQuery(queryString); + for (Map.Entry entry : query_pairs.entrySet()) { + if (params.length() != 0) { + params.append('&'); + } + // skip appending parameters if parameter size is bigger than + // totalLimit + if (params.length() > totalLimit) { + params.append("..."); + return params.toString(); + } + String key = entry.getKey(); + params.append(StringUtils.abbreviate(key, eachLimit)); + params.append('='); + String value = entry.getValue(); + if (value != null) { + params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); + } + } + } catch (UnsupportedEncodingException e) { + } + return params.toString(); + } + + private Map splitQuery(String query) throws UnsupportedEncodingException { + Map query_pairs = new LinkedHashMap(); + if (query != null) { + String[] pairs = query.split("&"); + for (String pair : pairs) { + int idx = pair.indexOf('='); + query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); + } + } + return query_pairs; + } +} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/InitResponseGetter.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/InitResponseGetter.java new file mode 100644 index 000000000000..6fc26bc75e6b --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/InitResponseGetter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere; + +import com.ibm.wsspi.webcontainer.servlet.IExtendedResponse; + +/** + * @author jaehong.kim + */ +public interface InitResponseGetter { + IExtendedResponse _$PINPOINT$_getInitResponse(); +} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/MethodFilterExtractor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/MethodFilterExtractor.java new file mode 100644 index 000000000000..5f62389e5335 --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/MethodFilterExtractor.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere; + +import com.ibm.websphere.servlet.request.IRequest; +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author jaehong.kim + */ +public class MethodFilterExtractor implements ParameterExtractor { + private final Filter excludeProfileMethodFilter; + + private final ParameterExtractor delegate; + + public MethodFilterExtractor(Filter excludeProfileMethodFilter, ParameterExtractor delegate) { + this.excludeProfileMethodFilter = Assert.requireNonNull(excludeProfileMethodFilter, "excludeProfileMethodFilter must not be null"); + this.delegate = Assert.requireNonNull(delegate, "delegate must not be null"); + } + + @Override + public String extractParameter(IRequest request) { + if (excludeProfileMethodFilter.filter(request.getMethod())) { + return null; + } + return delegate.extractParameter(request); + } +} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/ParameterRecorderFactory.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/ParameterRecorderFactory.java new file mode 100644 index 000000000000..58a368e92bd1 --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/ParameterRecorderFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere; + +import com.ibm.websphere.servlet.request.IRequest; +import com.navercorp.pinpoint.bootstrap.config.Filter; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.DisableParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.HttpParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterExtractor; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; + +/** + * @author jaehong.kim + */ +public class ParameterRecorderFactory { + public static ParameterRecorder newParameterRecorderFactory(Filter excludeProfileMethodFilter, boolean traceRequestParam) { + if (!traceRequestParam) { + return new DisableParameterRecorder(); + } + ParameterExtractor parameterExtractor = new IRequestParameterExtractor(64, 512); + ParameterExtractor methodFilterExtractor = new MethodFilterExtractor(excludeProfileMethodFilter, parameterExtractor); + return new HttpParameterRecorder(methodFilterExtractor); + } +} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/StatusCodeAccessor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/StatusCodeAccessor.java new file mode 100644 index 000000000000..af2b81757a75 --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/StatusCodeAccessor.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere; + +/** + * @author jaehong.kim + */ +public interface StatusCodeAccessor { + void _$PINPOINT$_setStatusCode(int statusCode); + + int _$PINPOINT$_getStatusCode(); +} \ No newline at end of file diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereAsyncListener.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereAsyncListener.java new file mode 100644 index 000000000000..36cd131566ff --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereAsyncListener.java @@ -0,0 +1,117 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.AsyncListenerInterceptorHelper; + +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import java.io.IOException; + +/** + * @author jaehong.kim + */ +public class WebsphereAsyncListener implements AsyncListener { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final AsyncListenerInterceptorHelper asyncListenerInterceptorHelper; + + public WebsphereAsyncListener(final TraceContext traceContext, final AsyncContext asyncContext) { + this.asyncListenerInterceptorHelper = new AsyncListenerInterceptorHelper(traceContext, asyncContext); + } + + @Override + public void onComplete(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Complete asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + final int statusCode = getStatusCode(asyncEvent); + this.asyncListenerInterceptorHelper.complete(asyncEvent.getThrowable(), statusCode); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onTimeout(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Timeout asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.timeout(asyncEvent.getThrowable()); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onError(AsyncEvent asyncEvent) throws IOException { + if (isDebug) { + logger.debug("Error asynchronous operation. event={}", asyncEvent); + } + + if (asyncEvent == null) { + if (isDebug) { + logger.debug("Invalid event. event is null"); + } + return; + } + + try { + this.asyncListenerInterceptorHelper.error(asyncEvent.getThrowable()); + } catch (Throwable t) { + logger.info("Failed to async event handle. event={}", asyncEvent, t); + } + } + + @Override + public void onStartAsync(AsyncEvent asyncEvent) throws IOException { + } + + private int getStatusCode(final AsyncEvent asyncEvent) { + try { + if (asyncEvent.getAsyncContext() instanceof InitResponseGetter) { + final InitResponseGetter getter = (InitResponseGetter) asyncEvent.getAsyncContext(); + return getter._$PINPOINT$_getInitResponse().getStatusCode(); + } + } catch (Exception ignored) { + } + return 0; + } +} \ No newline at end of file diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereConfiguration.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereConfiguration.java index 0dec7bf8507d..5c53716af066 100644 --- a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereConfiguration.java +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereConfiguration.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,26 +14,101 @@ */ package com.navercorp.pinpoint.plugin.websphere; +import com.navercorp.pinpoint.bootstrap.config.ExcludeMethodFilter; import com.navercorp.pinpoint.bootstrap.config.ExcludePathFilter; import com.navercorp.pinpoint.bootstrap.config.Filter; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.config.SkipFilter; +import com.navercorp.pinpoint.common.util.Assert; +import java.util.List; + +/** + * @author sjmittal + * @author jaehong.kim + */ public class WebsphereConfiguration { - private final Filter websphereExcludeUrlFilter; + private final boolean enable; + + private final boolean traceRequestParam; + private final List bootstrapMains; + private final String realIpHeader; + private final String realIpEmptyValue; + + private final Filter excludeUrlFilter; + private final Filter excludeProfileMethodFilter; + private final boolean hidePinpointHeader; public WebsphereConfiguration(ProfilerConfig config) { - final String websphereExcludeURL = config.readString("profiler.websphere.excludeurl", ""); + Assert.requireNonNull(config, "config must not be null"); - if (!websphereExcludeURL.isEmpty()) { - this.websphereExcludeUrlFilter = new ExcludePathFilter(websphereExcludeURL); - } else{ - this.websphereExcludeUrlFilter = new SkipFilter(); + // plugin + this.enable = config.readBoolean("profiler.websphere.enable", true); + this.bootstrapMains = config.readList("profiler.websphere.bootstrap.main"); + // runtime + this.traceRequestParam = config.readBoolean("profiler.websphere.tracerequestparam", true); + this.realIpHeader = config.readString("profiler.websphere.realipheader", null); + this.realIpEmptyValue = config.readString("profiler.websphere.realipemptyvalue", null); + final String excludeURL = config.readString("profiler.websphere.excludeurl", ""); + if (!excludeURL.isEmpty()) { + this.excludeUrlFilter = new ExcludePathFilter(excludeURL); + } else { + this.excludeUrlFilter = new SkipFilter(); + } + final String excludeProfileMethod = config.readString("profiler.websphere.excludemethod", ""); + if (!excludeProfileMethod.isEmpty()) { + this.excludeProfileMethodFilter = new ExcludeMethodFilter(excludeProfileMethod); + } else { + this.excludeProfileMethodFilter = new SkipFilter(); } + this.hidePinpointHeader = config.readBoolean("profiler.websphere.hidepinpointheader", true); + } + + public boolean isEnable() { + return enable; + } + + public List getBootstrapMains() { + return bootstrapMains; + } + + public boolean isTraceRequestParam() { + return traceRequestParam; + } + + public String getRealIpHeader() { + return realIpHeader; + } + + public String getRealIpEmptyValue() { + return realIpEmptyValue; + } + + public Filter getExcludeProfileMethodFilter() { + return excludeProfileMethodFilter; + } + + public Filter getExcludeUrlFilter() { + return excludeUrlFilter; + } + + public boolean isHidePinpointHeader() { + return hidePinpointHeader; } - public Filter getWebsphereExcludeUrlFilter() { - return websphereExcludeUrlFilter; + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("WebsphereConfiguration{"); + sb.append("enable=").append(enable); + sb.append(", traceRequestParam=").append(traceRequestParam); + sb.append(", bootstrapMains=").append(bootstrapMains); + sb.append(", realIpHeader='").append(realIpHeader).append('\''); + sb.append(", realIpEmptyValue='").append(realIpEmptyValue).append('\''); + sb.append(", excludeUrlFilter=").append(excludeUrlFilter); + sb.append(", excludeProfileMethodFilter=").append(excludeProfileMethodFilter); + sb.append(", hidePinpointHeader=").append(hidePinpointHeader); + sb.append('}'); + return sb.toString(); } } diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereConstants.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereConstants.java index 2c9e2d03dd73..b707a860d5da 100644 --- a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereConstants.java +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereConstants.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,18 +19,14 @@ import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; +/** + * @author sjmittal + */ public final class WebsphereConstants { private WebsphereConstants() { } - public static final String TYPE_NAME = "WEBSPHERE"; - public static final ServiceType WEBSPHERE = ServiceTypeFactory.of(1060, "WEBSPHERE", RECORD_STATISTICS); public static final ServiceType WEBSPHERE_METHOD = ServiceTypeFactory.of(1061, "WEBSPHERE_METHOD"); - - public static final String METADATA_TRACE = "trace"; - public static final String METADATA_ASYNC = "async"; - public static final String METADATA_ASYNC_TRACE_ID = "asyncTraceId"; - - public static final String ATTRIBUTE_PINPOINT_TRACE = "PINPOINT_TRACE"; + public static final String STATUS_CODE_ACCESSOR = "com.navercorp.pinpoint.plugin.websphere.StatusCodeAccessor"; } diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereDetector.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereDetector.java index 703539c59dfe..76f7c800f044 100644 --- a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereDetector.java +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereDetector.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,9 +18,25 @@ import com.navercorp.pinpoint.bootstrap.resolver.ConditionProvider; import com.navercorp.pinpoint.common.trace.ServiceType; +import java.util.Arrays; +import java.util.List; + +/** + * @author sjmittal + * @author jaehong.kim + */ public class WebsphereDetector implements ApplicationTypeDetector { private static final String REQUIRED_MAIN_CLASS = "com.ibm.wsspi.bootstrap.WSPreLauncher"; + private final List bootstrapMains; + + public WebsphereDetector(List bootstrapMains) { + if (bootstrapMains == null || bootstrapMains.isEmpty()) { + this.bootstrapMains = Arrays.asList(REQUIRED_MAIN_CLASS); + } else { + this.bootstrapMains = bootstrapMains; + } + } @Override public ServiceType getApplicationType() { @@ -29,6 +45,6 @@ public ServiceType getApplicationType() { @Override public boolean detect(ConditionProvider provider) { - return provider.checkMainClass(REQUIRED_MAIN_CLASS); + return provider.checkMainClass(this.bootstrapMains); } } diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebspherePlugin.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebspherePlugin.java index 72bfa14a8274..df460556da42 100644 --- a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebspherePlugin.java +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebspherePlugin.java @@ -3,9 +3,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,8 +14,6 @@ */ package com.navercorp.pinpoint.plugin.websphere; -import static com.navercorp.pinpoint.common.util.VarArgs.va; - import java.security.ProtectionDomain; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; @@ -25,33 +23,97 @@ import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate; import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +/** + * @author sjmittal + * @author jaehong.kim + */ public class WebspherePlugin implements ProfilerPlugin, TransformTemplateAware { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private TransformTemplate transformTemplate; @Override public void setup(ProfilerPluginSetupContext context) { - context.addApplicationTypeDetector(new WebsphereDetector()); - WebsphereConfiguration config = new WebsphereConfiguration(context.getConfig()); - - addServerInterceptor(config); + final WebsphereConfiguration config = new WebsphereConfiguration(context.getConfig()); + if (!config.isEnable()) { + logger.info("WebspherePlugin disabled"); + return; + } + logger.info("WebspherePlugin config:{}", config); + + context.addApplicationTypeDetector(new WebsphereDetector(config.getBootstrapMains())); + + // Hide pinpoint header & Add async listener. Servlet 3.0 + addSRTServletRequest(config); + // Entry Point + addWSWebContainer(); + // Set status code + addWCCResponseImpl(); + addWSAsyncContextImpl(); } - private void addServerInterceptor(final WebsphereConfiguration config){ - transformTemplate.transform("com.ibm.ws.webcontainer.WSWebContainer", new TransformCallback() { + private void addSRTServletRequest(final WebsphereConfiguration config) { + transformTemplate.transform("com.ibm.ws.webcontainer.srt.SRTServletRequest", new TransformCallback() { @Override public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { - InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + if (config.isHidePinpointHeader()) { + // Hide pinpoint headers + target.weave("com.navercorp.pinpoint.plugin.websphere.aspect.SRTServletRequestAspect"); + } - InstrumentMethod handleMethodEditorBuilder = target.getDeclaredMethod("handleRequest", "com.ibm.websphere.servlet.request.IRequest", "com.ibm.websphere.servlet.response.IResponse"); + // Add async listener. Servlet 3.0 + final InstrumentMethod startAsyncMethodEditor = target.getDeclaredMethod("startAsync", "javax.servlet.ServletRequest", "javax.servlet.ServletResponse"); + if (startAsyncMethodEditor != null) { + startAsyncMethodEditor.addInterceptor("com.navercorp.pinpoint.plugin.websphere.interceptor.WCCRequestImplStartAsyncInterceptor"); + } + return target.toBytecode(); + } + }); + } + + private void addWSWebContainer() { + transformTemplate.transform("com.ibm.ws.webcontainer.WSWebContainer", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + // Clear remained trace - defense code + final InstrumentMethod handleMethodEditorBuilder = target.getDeclaredMethod("handleRequest", "com.ibm.websphere.servlet.request.IRequest", "com.ibm.websphere.servlet.response.IResponse"); if (handleMethodEditorBuilder != null) { - handleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.websphere.interceptor.ServerHandleInterceptor", va(config.getWebsphereExcludeUrlFilter())); - return target.toBytecode(); + handleMethodEditorBuilder.addInterceptor("com.navercorp.pinpoint.plugin.websphere.interceptor.WebContainerHandleRequestInterceptor"); } + return target.toBytecode(); + } + }); + } + + + private void addWCCResponseImpl() { + transformTemplate.transform("com.ibm.ws.webcontainer.channel.WCCResponseImpl", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addField(WebsphereConstants.STATUS_CODE_ACCESSOR); + final InstrumentMethod setStatusCodeMethod = target.getDeclaredMethod("setStatusCode", "int"); + if (setStatusCodeMethod != null) { + setStatusCodeMethod.addInterceptor("com.navercorp.pinpoint.plugin.websphere.interceptor.WCCResponseImplInterceptor"); + } + return target.toBytecode(); + } + }); + } + private void addWSAsyncContextImpl() { + transformTemplate.transform("com.ibm.ws.webcontainer.async.WSAsyncContextImpl", new TransformCallback() { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer); + target.addGetter("com.navercorp.pinpoint.plugin.websphere.InitResponseGetter", "initResponse"); return target.toBytecode(); } }); @@ -61,4 +123,4 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, public void setTransformTemplate(TransformTemplate transformTemplate) { this.transformTemplate = transformTemplate; } -} +} \ No newline at end of file diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereSyncMethodDescriptor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereSyncMethodDescriptor.java deleted file mode 100644 index 6baa4f30d83c..000000000000 --- a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/WebsphereSyncMethodDescriptor.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.websphere; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.common.trace.MethodType; - -public class WebsphereSyncMethodDescriptor implements MethodDescriptor{ - - private int apiId = 0; - private int type = MethodType.WEB_REQUEST; - - @Override - public String getMethodName() { - return ""; - } - - @Override - public String getClassName() { - return ""; - } - - @Override - public String[] getParameterTypes() { - return null; - } - - @Override - public String[] getParameterVariableName() { - return null; - } - - @Override - public String getParameterDescriptor() { - return "()"; - } - - @Override - public int getLineNumber() { - return -1; - } - - @Override - public String getFullName() { - return WebsphereSyncMethodDescriptor.class.getName(); - } - - @Override - public void setApiId(int apiId) { - this.apiId = apiId; - } - - @Override - public int getApiId() { - return apiId; - } - - @Override - public String getApiDescriptor() { - return "Websphere Servlet Process"; - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } -} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/aspect/SRTServletRequestAspect.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/aspect/SRTServletRequestAspect.java new file mode 100644 index 000000000000..5a4495044bff --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/aspect/SRTServletRequestAspect.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere.aspect; + +import com.navercorp.pinpoint.bootstrap.context.Header; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; +import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; +import com.navercorp.pinpoint.common.util.DelegateEnumeration; + +import java.util.Enumeration; + +/** + * @author jaehong.kim + */ +@Aspect +public abstract class SRTServletRequestAspect { + @PointCut + public Enumeration getHeaderNames() { + return new DelegateEnumeration(__getHeaderNames(), Header.FILTER); + } + + @JointPoint + abstract Enumeration __getHeaderNames(); +} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/AbstractServerHandleInterceptor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/AbstractServerHandleInterceptor.java deleted file mode 100644 index 8e7cd7c99bb1..000000000000 --- a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/AbstractServerHandleInterceptor.java +++ /dev/null @@ -1,309 +0,0 @@ -/** - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.plugin.websphere.interceptor; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.ibm.websphere.servlet.request.IRequest; -import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.context.Header; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.bootstrap.context.SpanId; -import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; -import com.navercorp.pinpoint.bootstrap.context.Trace; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; -import com.navercorp.pinpoint.bootstrap.logging.PLogger; -import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderHandler; -import com.navercorp.pinpoint.bootstrap.plugin.proxy.ProxyHttpHeaderRecorder; -import com.navercorp.pinpoint.bootstrap.sampler.SamplingFlagUtils; -import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; -import com.navercorp.pinpoint.bootstrap.util.NumberUtils; -import com.navercorp.pinpoint.common.plugin.util.HostAndPort; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.plugin.websphere.WebsphereConstants; -import com.navercorp.pinpoint.plugin.websphere.WebsphereSyncMethodDescriptor; - -public abstract class AbstractServerHandleInterceptor implements AroundInterceptor { - - public static final WebsphereSyncMethodDescriptor WEBSPHERE_SYNC_API_TAG = new WebsphereSyncMethodDescriptor(); - - protected PLogger logger = PLoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - private final boolean isTrace = logger.isTraceEnabled(); - - private final MethodDescriptor methodDescriptor; - private final TraceContext traceContext; - private final Filter excludeUrlFilter; - private final ProxyHttpHeaderRecorder proxyHttpHeaderRecorder; - - public AbstractServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor, Filter excludeFilter) { - - this.traceContext = traceContext; - this.methodDescriptor = descriptor; - this.excludeUrlFilter = excludeFilter; - this.proxyHttpHeaderRecorder = new ProxyHttpHeaderRecorder(traceContext.getProfilerConfig().isProxyHttpHeaderEnable()); - - traceContext.cacheApi(WEBSPHERE_SYNC_API_TAG); - } - - protected abstract IRequest getRequest(Object[] args); - - @Override - public void before(Object target, Object[] args) { - if (isDebug) { - logger.beforeInterceptor(target, args); - } - - try { - final Trace trace = createTrace(target, args); - if (trace == null) { - return; - } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - return; - } - // ------------------------------------------------------ - SpanEventRecorder recorder = trace.traceBlockBegin(); - recorder.recordServiceType(WebsphereConstants.WEBSPHERE_METHOD); - } catch (Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("before. Caused:{}", th.getMessage(), th); - } - } - } - - - private Trace createTrace(Object target, Object[] args) { - final IRequest request = getRequest(args); - - final String requestURI = request.getRequestURI(); - if (excludeUrlFilter.filter(requestURI)) { - if (isTrace) { - logger.trace("filter requestURI:{}", requestURI); - } - return null; - } - // check sampling flag from client. If the flag is false, do not sample this request. - final boolean sampling = samplingEnable(request); - if (!sampling) { - // Even if this transaction is not a sampling target, we have to create Trace object to mark 'not sampling'. - // For example, if this transaction invokes rpc call, we can add parameter to tell remote node 'don't sample this transaction' - final Trace trace = traceContext.disableSampling(); - if (isDebug) { - logger.debug("remotecall sampling flag found. skip trace requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - return trace; - } - - final TraceId traceId = populateTraceIdFromRequest(request); - if (traceId != null) { - final Trace trace = traceContext.continueTraceObject(traceId); - if (trace.canSampled()) { - SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - if (isDebug) { - logger.debug("TraceID exist. continue trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), request.getRemoteAddr()); - } - } else { - if (isDebug) { - logger.debug("TraceID exist. camSampled is false. skip trace. traceId:{}, requestUrl:{}, remoteAddr:{}", traceId, request.getRequestURI(), request.getRemoteAddr()); - } - } - return trace; - } else { - final Trace trace = traceContext.newTraceObject(); - if (trace.canSampled()) { - SpanRecorder recorder = trace.getSpanRecorder(); - recordRootSpan(recorder, request); - if (isDebug) { - logger.debug("TraceID not exist. start new trace. requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - } else { - if (isDebug) { - logger.debug("TraceID not exist. camSampled is false. skip trace. requestUrl:{}, remoteAddr:{}", request.getRequestURI(), request.getRemoteAddr()); - } - } - return trace; - } - } - - @Override - public void after(Object target, Object[] args, Object result, Throwable throwable) { - if (isDebug) { - logger.afterInterceptor(target, args, result, throwable); - } - - final Trace trace = traceContext.currentRawTraceObject(); - if (trace == null) { - return; - } - // TODO STATDISABLE this logic was added to disable statistics tracing - if (!trace.canSampled()) { - traceContext.removeTraceObject(); - return; - } - // ------------------------------------------------------ - try { - SpanEventRecorder recorder = trace.currentSpanEventRecorder(); - final IRequest request = getRequest(args); - final String parameters = getRequestParameter(request, 64, 512); - if (StringUtils.hasLength(parameters)) { - recorder.recordAttribute(AnnotationKey.HTTP_PARAM, parameters); - } - - recorder.recordApi(methodDescriptor); - recorder.recordException(throwable); - } catch (Throwable th) { - if (logger.isWarnEnabled()) { - logger.warn("after. Caused:{}", th.getMessage(), th); - } - } finally { - traceContext.removeTraceObject(); - deleteTrace(trace, target, args, result, throwable); - } - } - - private boolean samplingEnable(IRequest request) { - // optional value - final String samplingFlag = request.getHeader(Header.HTTP_SAMPLED.toString()); - if (isDebug) { - logger.debug("SamplingFlag:{}", samplingFlag); - } - return SamplingFlagUtils.isSamplingFlag(samplingFlag); - } - - private String getRequestParameter(IRequest request, int eachLimit, int totalLimit) { - String queryString = request.getQueryString(); - final StringBuilder params = new StringBuilder(64); - try { - Map query_pairs = splitQuery(queryString); - for (Map.Entry entry : query_pairs.entrySet()) { - if (params.length() != 0) { - params.append('&'); - } - // skip appending parameters if parameter size is bigger than - // totalLimit - if (params.length() > totalLimit) { - params.append("..."); - return params.toString(); - } - String key = entry.getKey(); - params.append(StringUtils.abbreviate(key, eachLimit)); - params.append('='); - String value = entry.getValue(); - if (value != null) { - params.append(StringUtils.abbreviate(StringUtils.toString(value), eachLimit)); - } - } - } catch (UnsupportedEncodingException e) { - logger.error("[Websphere] Fail to parse query {}", queryString, e); - } - return params.toString(); - } - - private Map splitQuery(String query) throws UnsupportedEncodingException { - Map query_pairs = new LinkedHashMap(); - if (query != null) { - String[] pairs = query.split("&"); - for (String pair : pairs) { - int idx = pair.indexOf('='); - query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); - } - } - return query_pairs; - } - - private void recordParentInfo(SpanRecorder recorder, IRequest request) { - String parentApplicationName = request.getHeader(Header.HTTP_PARENT_APPLICATION_NAME.toString()); - if (parentApplicationName != null) { - final String host = request.getHeader(Header.HTTP_HOST.toString()); - if (host != null) { - recorder.recordAcceptorHost(host); - } else { - recorder.recordAcceptorHost(NetworkUtils.getHostFromURL(request.getRequestURI())); - } - final String type = request.getHeader(Header.HTTP_PARENT_APPLICATION_TYPE.toString()); - final short parentApplicationType = NumberUtils.parseShort(type, ServiceType.UNDEFINED.getCode()); - recorder.recordParentApplication(parentApplicationName, parentApplicationType); - } - } - - private void recordRootSpan(final SpanRecorder recorder, final IRequest request) { - // root - recorder.recordServiceType(WebsphereConstants.WEBSPHERE); - - final String requestURL = request.getRequestURI(); - recorder.recordRpcName(requestURL); - - final int port = request.getServerPort(); - final String endPoint = HostAndPort.toHostAndPortString(request.getServerName(), port); - recorder.recordEndPoint(endPoint); - - final String remoteAddr = request.getRemoteAddr(); - recorder.recordRemoteAddress(remoteAddr); - - if (!recorder.isRoot()) { - recordParentInfo(recorder, request); - } - recorder.recordApi(WEBSPHERE_SYNC_API_TAG); - - // record proxy HTTP headers. - this.proxyHttpHeaderRecorder.record(recorder, new ProxyHttpHeaderHandler() { - @Override - public String read(String name) { - return request.getHeader(name); - } - }); - } - - /** - * Populate source trace from HTTP Header. - * - * @param request - * @return TraceId when it is possible to get a transactionId from Http header. if not possible return null - */ - private TraceId populateTraceIdFromRequest(IRequest request) { - - String transactionId = request.getHeader(Header.HTTP_TRACE_ID.toString()); - if (transactionId != null) { - long parentSpanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_PARENT_SPAN_ID.toString()), SpanId.NULL); - long spanID = NumberUtils.parseLong(request.getHeader(Header.HTTP_SPAN_ID.toString()), SpanId.NULL); - short flags = NumberUtils.parseShort(request.getHeader(Header.HTTP_FLAGS.toString()), (short) 0); - - final TraceId id = traceContext.createTraceId(transactionId, parentSpanID, spanID, flags); - if (isDebug) { - logger.debug("TraceID exist. continue trace. {}", id); - } - return id; - } else { - return null; - } - } - - private void deleteTrace(Trace trace, Object target, Object[] args, Object result, Throwable throwable) { - trace.traceBlockEnd(); - trace.close(); - } -} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/IRequestAdaptor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/IRequestAdaptor.java new file mode 100644 index 000000000000..eee2cbeb682c --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/IRequestAdaptor.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere.interceptor; + +import com.ibm.websphere.servlet.request.IRequest; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.util.NetworkUtils; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; + +/** + * @author Woonduk Kang(emeroad) + */ +public class IRequestAdaptor implements RequestAdaptor { + @Override + public String getHeader(IRequest request, String name) { + return request.getHeader(name); + } + + @Override + public String getRpcName(IRequest request) { + return request.getRequestURI(); + } + + @Override + public String getEndPoint(IRequest request) { + final int port = request.getServerPort(); + final String endPoint = HostAndPort.toHostAndPortString(request.getServerName(), port); + return endPoint; + } + + @Override + public String getRemoteAddress(IRequest request) { + return request.getRemoteAddr(); + } + + @Override + public String getAcceptorHost(IRequest request) { + return NetworkUtils.getHostFromURL(request.getRequestURI()); + } +} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/ServerHandleInterceptor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/ServerHandleInterceptor.java deleted file mode 100644 index 57e77414d513..000000000000 --- a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/ServerHandleInterceptor.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.navercorp.pinpoint.plugin.websphere.interceptor; - -import com.navercorp.pinpoint.bootstrap.config.Filter; -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.ibm.websphere.servlet.request.IRequest; - -/** - * @author Sachin Mittal - */ -public class ServerHandleInterceptor extends AbstractServerHandleInterceptor { - - public ServerHandleInterceptor(TraceContext traceContext, MethodDescriptor descriptor, Filter excludeFilter) { - super(traceContext, descriptor, excludeFilter); - } - - @Override - protected IRequest getRequest(Object[] args) { - final Object iRequestObject = args[0]; - if (!(iRequestObject instanceof com.ibm.websphere.servlet.request.IRequest)) { - return null; - } - return (IRequest) iRequestObject; - } - -} diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/WCCRequestImplStartAsyncInterceptor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/WCCRequestImplStartAsyncInterceptor.java new file mode 100644 index 000000000000..56d16c20d22b --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/WCCRequestImplStartAsyncInterceptor.java @@ -0,0 +1,109 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.Trace; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.websphere.WebsphereAsyncListener; +import com.navercorp.pinpoint.plugin.websphere.WebsphereConstants; + +import javax.servlet.AsyncContext; +import javax.servlet.AsyncListener; +import javax.servlet.http.HttpServletRequest; + +/** + * @author jaehong.kim + */ +public class WCCRequestImplStartAsyncInterceptor implements AroundInterceptor { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor descriptor; + + public WCCRequestImplStartAsyncInterceptor(TraceContext context, MethodDescriptor descriptor) { + this.traceContext = context; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + trace.traceBlockBegin(); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + final Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + + try { + final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); + if (validate(target, result, throwable)) { + final AsyncContext asyncContext = (AsyncContext) result; + final AsyncListener asyncListener = new WebsphereAsyncListener(this.traceContext, recorder.recordNextAsyncContext(true)); + asyncContext.addListener(asyncListener); + if (isDebug) { + logger.debug("Add async listener {}", asyncListener); + } + } + recorder.recordServiceType(WebsphereConstants.WEBSPHERE_METHOD); + recorder.recordApi(descriptor); + recorder.recordException(throwable); + } catch (Throwable t) { + logger.warn("Failed to AFTER process. {}", t.getMessage(), t); + } finally { + trace.traceBlockEnd(); + } + } + + private boolean validate(final Object target, final Object result, final Throwable throwable) { + if (throwable != null || result == null) { + return false; + } + + if (!(target instanceof HttpServletRequest)) { + logger.debug("Invalid target object, Not implemented of javax.servlet.http.HttpServletRequest. target={}", target); + return false; + } + + if (!(result instanceof AsyncContext)) { + logger.debug("Invalid result object, Not implemented of javax.servlet.AsyncContext. result={}.", result); + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/WCCResponseImplInterceptor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/WCCResponseImplInterceptor.java new file mode 100644 index 000000000000..8f1ff6672c9f --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/WCCResponseImplInterceptor.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.plugin.websphere.StatusCodeAccessor; + +public class WCCResponseImplInterceptor implements AroundInterceptor { + private PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private boolean isDebug = logger.isDebugEnabled(); + + private TraceContext traceContext; + private MethodDescriptor descriptor; + + public WCCResponseImplInterceptor(TraceContext context, MethodDescriptor descriptor) { + this.traceContext = context; + this.descriptor = descriptor; + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (target instanceof StatusCodeAccessor) { + if (args[0] instanceof Integer) { + final int statusCode = (Integer) args[0]; + final StatusCodeAccessor accessor = (StatusCodeAccessor) target; + accessor._$PINPOINT$_setStatusCode(statusCode); + } + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + } +} \ No newline at end of file diff --git a/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/WebContainerHandleRequestInterceptor.java b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/WebContainerHandleRequestInterceptor.java new file mode 100644 index 000000000000..7c99b6fb3a4e --- /dev/null +++ b/plugins/websphere/src/main/java/com/navercorp/pinpoint/plugin/websphere/interceptor/WebContainerHandleRequestInterceptor.java @@ -0,0 +1,115 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.plugin.websphere.interceptor; + +import com.ibm.websphere.servlet.request.IRequest; +import com.ibm.websphere.servlet.response.IResponse; +import com.ibm.ws.webcontainer.channel.WCCResponseImpl; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.request.RequestAdaptor; +import com.navercorp.pinpoint.bootstrap.plugin.request.ServletRequestListenerInterceptorHelper; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.ParameterRecorder; +import com.navercorp.pinpoint.bootstrap.plugin.request.util.RemoteAddressResolverFactory; +import com.navercorp.pinpoint.plugin.common.servlet.util.ArgumentValidator; +import com.navercorp.pinpoint.plugin.common.servlet.util.ServletArgumentValidator; +import com.navercorp.pinpoint.plugin.websphere.ParameterRecorderFactory; +import com.navercorp.pinpoint.plugin.websphere.StatusCodeAccessor; +import com.navercorp.pinpoint.plugin.websphere.WebsphereConfiguration; +import com.navercorp.pinpoint.plugin.websphere.WebsphereConstants; + + +/** + * @author sjmittal + * @author jaehong.kim + */ +public class WebContainerHandleRequestInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + private final MethodDescriptor methodDescriptor; + private final ArgumentValidator argumentValidator; + private final ServletRequestListenerInterceptorHelper servletRequestListenerInterceptorHelper; + + public WebContainerHandleRequestInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + + this.methodDescriptor = descriptor; + + this.argumentValidator = new ServletArgumentValidator(logger, 0, IRequest.class, 1, IResponse.class); + final WebsphereConfiguration config = new WebsphereConfiguration(traceContext.getProfilerConfig()); + RequestAdaptor requestAdaptor = new IRequestAdaptor(); + requestAdaptor = RemoteAddressResolverFactory.wrapRealIpSupport(requestAdaptor, config.getRealIpHeader(), config.getRealIpEmptyValue()); + final ParameterRecorder parameterRecorder = ParameterRecorderFactory.newParameterRecorderFactory(config.getExcludeProfileMethodFilter(), config.isTraceRequestParam()); + this.servletRequestListenerInterceptorHelper = new ServletRequestListenerInterceptorHelper(WebsphereConstants.WEBSPHERE, traceContext, requestAdaptor, config.getExcludeUrlFilter(), parameterRecorder); + } + + @Override + public void before(Object target, Object[] args) { + if (isDebug) { + logger.beforeInterceptor(target, args); + } + + if (!argumentValidator.validate(args)) { + return; + } + + try { + final IRequest request = (IRequest) args[0]; + this.servletRequestListenerInterceptorHelper.initialized(request, WebsphereConstants.WEBSPHERE_METHOD, this.methodDescriptor); + } catch (Throwable t) { + logger.info("Failed to servlet request event handle.", t); + } + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + if (!argumentValidator.validate(args)) { + return; + } + + try { + final IRequest request = (IRequest) args[0]; + final IResponse response = (IResponse) args[1]; + final int statusCode = getStatusCode(response); + this.servletRequestListenerInterceptorHelper.destroyed(request, throwable, statusCode); + } catch (Throwable t) { + logger.info("Failed to servlet request event handle.", t); + } + } + + + private int getStatusCode(final IResponse response) { + try { + if (response instanceof StatusCodeAccessor) { + final StatusCodeAccessor accessor = (StatusCodeAccessor) response; + return accessor._$PINPOINT$_getStatusCode(); + } else if (response instanceof WCCResponseImpl) { + WCCResponseImpl r = (WCCResponseImpl) response; + return r.getHttpResponse().getStatusCodeAsInt(); + } + } catch (Exception ignored) { + } + return 0; + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9b1e47b62ea3..4b5faf31d2d5 100644 --- a/pom.xml +++ b/pom.xml @@ -1,3 +1,19 @@ + + 4.0.0 @@ -7,7 +23,7 @@ com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint pom @@ -49,9 +65,12 @@ annotations agent + agent-it bootstrap-core bootstrap-core-optional bootstrap + bootstrap-java8 + bootstrap-java9 collector commons commons-hbase @@ -63,6 +82,7 @@ profiler-test rpc thrift + grpc test web hbase @@ -74,20 +94,43 @@ 1.6 ${env.JAVA_6_HOME} ${jdk.home} + + 1.7.21 3.1.2 - 8.1.12.v20130726 - 2.6.7 - 4.3 - 2.4.2 - ${basedir}/clover.license - 4.3.8.RELEASE - 3.0.7.RELEASE - 4.2.2.RELEASE - 0.4.3 - 2.1.7.1 + + + 2.6.6 + 2.9.7 + + 4.5.6 + 4.4.10 + 4.3.20.RELEASE + 3.0.9.RELEASE + 4.2.8.RELEASE + 7.0 + 0.11.0 + 2.6.11 + + + 3.8.0 + 3.1.0 + 2.22.0 + 2.22.0 + 3.1.1 + 3.1.0 + 3.2.2 + 3.1.0 + + + 4.2.1 + 3.1.7 + 3.9.0 + + 3.0.0-M2 + 1.16 + java16 - 2.5.3 @@ -140,6 +183,11 @@ pinpoint-thrift ${project.version} + + com.navercorp.pinpoint + pinpoint-grpc + ${project.version} + com.navercorp.pinpoint pinpoint-bootstrap-core @@ -155,6 +203,16 @@ pinpoint-bootstrap ${project.version} + + com.navercorp.pinpoint + pinpoint-bootstrap-java8 + ${project.version} + + + com.navercorp.pinpoint + pinpoint-bootstrap-java9 + ${project.version} + com.navercorp.pinpoint pinpoint-profiler @@ -341,7 +399,7 @@ org.apache.hbase hbase-shaded-client - 1.2.4 + 1.2.6.1 @@ -372,11 +430,6 @@ 1.2.16 - - commons-dbcp - commons-dbcp - 1.4 - org.apache.commons commons-dbcp2 @@ -392,38 +445,11 @@ mybatis-spring 1.2.2 - - org.mariadb.jdbc - mariadb-java-client - 1.3.4 - mysql mysql-connector-java 5.1.45 - - org.postgresql - postgresql - 9.4.1207 - - - net.sourceforge.jtds - jtds - 1.2.8 - - - - com.ning - async-http-client - 1.8.3 - - - - org.asynchttpclient - async-http-client - 2.0.32 - io.netty @@ -435,41 +461,12 @@ netty-all 4.0.18.Final - - org.apache.tomcat - catalina - 6.0.43 - - - org.apache.tomcat - coyote - 6.0.43 - - - com.navercorp.arcus - arcus-java-client - 1.8.1 - + net.sf.ehcache ehcache-core - 2.6.9 - - - net.sf.ehcache - ehcache - 1.6.2 - - - com.datastax.cassandra - cassandra-driver-core - ${cassandra.driver.version} - - - org.springframework.data - spring-data-redis - 1.1.1.RELEASE + ${ehcache.version} @@ -480,45 +477,7 @@ org.apache.httpcomponents httpcore - ${httpcomponents.version} - - - org.apache.httpcomponents - httpcore-nio - ${httpcomponents.version} - - - org.apache.httpcomponents - httpasyncclient - 4.0 - - - commons-httpclient - commons-httpclient - 3.1 - - - - com.google.http-client - google-http-client - 1.20.0 - - - - com.squareup.okhttp - okhttp - 2.5.0 - - - com.squareup.okhttp3 - okhttp - 3.8.1 - - - - redis.clients - jedis - ${jedis.version} + ${httpcomponents-core.version} @@ -576,34 +535,48 @@ org.javassist javassist - 3.21.0-GA + 3.23.1-GA cglib cglib-nodep - 2.2 + 3.2.8 org.ow2.asm - asm-debug-all - 5.2 + asm + ${asm.version} + + + org.ow2.asm + asm-commons + ${asm.version} + + + org.ow2.asm + asm-util + ${asm.version} + + + org.ow2.asm + asm-tree + ${asm.version} + + + org.ow2.asm + asm-analysis + ${asm.version} org.aspectj aspectjweaver - 1.8.10 + 1.9.1 - - org.apache.tomcat - servlet-api - 6.0.35 - - javax.servlet javax.servlet-api @@ -661,11 +634,27 @@ + + org.apache.curator + curator-framework + 4.0.1 + + + zookeeper + org.apache.zookeeper + + + org.apache.curator + curator-test + + + + org.apache.curator curator-test - 2.6.0 + 2.12.0 zookeeper @@ -677,7 +666,7 @@ org.apache.thrift libthrift - 0.10.0 + ${thrift.version} org.apache.httpcomponents @@ -705,46 +694,6 @@ 4.1.0 - - org.apache.activemq - activemq-client - 5.13.2 - - - - org.apache.cxf - cxf-rt-frontend-jaxws - 2.7.18 - - - org.apache.cxf - cxf-rt-transports-http - 2.7.18 - - - - com.netflix.hystrix - hystrix-core - 1.5.12 - - - - io.vertx - vertx-core - 3.3.3 - - - - io.reactivex - rxjava - 1.2.0 - - - - org.springframework.amqp - spring-rabbit - 1.4.4.RELEASE - @@ -775,12 +724,14 @@ ${basedir}/src/test/resources + + org.apache.maven.plugins maven-war-plugin - 2.6 + ${plugin.war.version} true classes @@ -790,15 +741,17 @@ org.apache.maven.plugins maven-jar-plugin - 2.6 + ${plugin.jar.version} + + org.apache.maven.plugins maven-resources-plugin - 2.7 + ${plugin.resources.version} ${encoding} @@ -806,7 +759,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.5.1 + ${plugin.compiler.version} ${jdk.version} ${jdk.version} @@ -822,7 +775,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.19.1 + ${plugin.surefire.version} **/Mock* @@ -836,16 +789,24 @@ - com.atlassian.maven.plugins - maven-clover2-plugin - 4.0.6 + org.openclover + clover-maven-plugin + ${plugin.clover.version} ${encoding} ${jdk.version} true true false - ${cloverLicenseLocation} + + + false false @@ -857,17 +818,17 @@ - org.codehaus.mojo - findbugs-maven-plugin - 3.0.3 + com.github.spotbugs + spotbugs-maven-plugin + ${plugin.spotbugs.version} - findbugs-exclude.xml + ${maven.multiModuleProjectDirectory}/spotbugs-exclude.xml org.apache.maven.plugins maven-enforcer-plugin - 1.4.1 + ${plugin.enforcer.version} enforce-pinpoint-build-requirements @@ -878,11 +839,14 @@ - 3.2 + 3.5 - 1.7 + 1.8 + + JAVA_HOME + JAVA_6_HOME @@ -892,24 +856,19 @@ JAVA_8_HOME + + JAVA_9_HOME + true - - com.spotify - docker-maven-plugin - ${docker.maven.plugin.version} - - true - - org.apache.maven.plugins maven-pmd-plugin - 3.6 + ${plugin.pmd.version} true ${encoding} @@ -952,7 +911,7 @@ org.codehaus.mojo animal-sniffer-maven-plugin - 1.15 + ${plugin.animal-sniffer.version} org.codehaus.mojo.signature @@ -973,38 +932,31 @@ + + + org.apache.maven.plugins + maven-site-plugin + 3.7.1 + - org.apache.maven.plugins - maven-jxr-plugin - false + com.github.spotbugs + spotbugs-maven-plugin + ${plugin.spotbugs.version} - true - ${encoding} - ${encoding} - Pinpoint ${project.version} Cross Reference - Pinpoint ${project.version} Cross Reference - - 2.5 - - - org.codehaus.mojo - findbugs-maven-plugin - - findbugs-exclude.xml + ${maven.multiModuleProjectDirectory}/spotbugs-exclude.xml true - ${project.build.directory}/findbugs + ${project.build.directory}/spotbugs - 3.0.3 org.apache.maven.plugins maven-pmd-plugin - 3.6 + ${plugin.pmd.version} true ${encoding} @@ -1021,12 +973,20 @@ - com.atlassian.maven.plugins - maven-clover2-plugin - 4.0.6 + org.openclover + clover-maven-plugin + ${plugin.clover.version} true - clover.license + + + ${encoding} ${jdk.version} @@ -1037,6 +997,26 @@ + + + + org.apache.maven.plugins + maven-site-plugin + 3.7.1 + + + org.apache.maven.plugins + maven-jxr-plugin + 2.5 + false + + true + ${encoding} + ${encoding} + Pinpoint ${project.version} Cross Reference + Pinpoint ${project.version} Cross Reference + + @@ -1044,9 +1024,6 @@ local - - true - local @@ -1054,6 +1031,9 @@ release + + true + release diff --git a/profiler-optional/clover.license b/profiler-optional/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/profiler-optional/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-profiler-optional @@ -15,6 +31,7 @@ profiler-optional-jdk6 profiler-optional-jdk7 profiler-optional-jdk8 + profiler-optional-jdk9 profiler-optional-parent @@ -29,12 +46,29 @@ pinpoint-profiler-optional-jdk7 ${project.version} - - - - - - + + com.navercorp.pinpoint + pinpoint-profiler-optional-jdk8 + ${project.version} + + + com.navercorp.pinpoint + pinpoint-profiler-optional-jdk9 + ${project.version} + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + ${plugin.animal-sniffer.version} + + true + + + + + \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk6/clover.license b/profiler-optional/profiler-optional-jdk6/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/profiler-optional/profiler-optional-jdk6/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint-profiler-optional-parent ../profiler-optional-parent - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-profiler-optional-jdk6 diff --git a/profiler-optional/profiler-optional-jdk6/src/main/java-oracle/com/sun/management/UnixOperatingSystemMXBean.java b/profiler-optional/profiler-optional-jdk6/src/main/java-oracle/com/sun/management/UnixOperatingSystemMXBean.java new file mode 100644 index 000000000000..dcf84586089b --- /dev/null +++ b/profiler-optional/profiler-optional-jdk6/src/main/java-oracle/com/sun/management/UnixOperatingSystemMXBean.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.sun.management; + +/** + * @author Roy Kim + */ +public interface UnixOperatingSystemMXBean extends java.lang.management.OperatingSystemMXBean { + + long getOpenFileDescriptorCount(); +} diff --git a/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/JvmCpuUsageCalculator.java b/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/JvmCpuUsageCalculator.java index cee669e9b80e..a4c2bdf899c0 100644 --- a/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/JvmCpuUsageCalculator.java +++ b/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/JvmCpuUsageCalculator.java @@ -46,12 +46,14 @@ public double getJvmCpuUsage(final long cpuTimeNS, final long upTimeMS) { final long diffUpTimeMS = upTimeMS - lastUpTimeMS; final long totalUpTimeNS = (diffUpTimeMS * 1000000) * CPU_COUNT; - final double cpuLoad = totalUpTimeNS > 0 ? - Math.min(100F, totalCpuTimeNS / (float) totalUpTimeNS) : UNSUPPORTED; + double cpuUsage = UNSUPPORTED; + if (totalUpTimeNS > 0) { + cpuUsage = Math.min(100F, totalCpuTimeNS / (float) totalUpTimeNS); + } this.lastCpuTimeNS = cpuTimeNS; this.lastUpTimeMS = upTimeMS; - return cpuLoad; + return cpuUsage; } } diff --git a/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/ibm/Java6CpuLoadMetric.java b/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/ibm/Java6CpuLoadMetric.java index 6faf29537b21..d54426415f4c 100644 --- a/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/ibm/Java6CpuLoadMetric.java +++ b/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/ibm/Java6CpuLoadMetric.java @@ -16,11 +16,15 @@ package com.navercorp.pinpoint.profiler.monitor.metric.cpu.ibm; +import com.ibm.lang.management.OperatingSystemMXBean; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetric; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetricSnapshot; +import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuUsageProvider; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.JvmCpuUsageCalculator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.lang.management.OperatingSystemMXBean; +import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; /** @@ -28,32 +32,58 @@ */ public class Java6CpuLoadMetric implements CpuLoadMetric { - private final JvmCpuUsageCalculator jvmCpuUsageCalculator = new JvmCpuUsageCalculator(); - private final com.ibm.lang.management.OperatingSystemMXBean operatingSystemMXBean; - private final RuntimeMXBean runtimeMXBean; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public Java6CpuLoadMetric(OperatingSystemMXBean operatingSystemMXBean, RuntimeMXBean runtimeMXBean) { + private CpuUsageProvider jvmCpuUsageProvider; + + public Java6CpuLoadMetric() { + final OperatingSystemMXBean operatingSystemMXBean = (com.ibm.lang.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); if (operatingSystemMXBean == null) { - throw new NullPointerException("operatingSystemMXBean must not be null"); + throw new IllegalStateException("OperatingSystemMXBean not available"); + } + RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); + if (runtimeMXBean == null) { + throw new IllegalStateException("RuntimeMXBean not available"); } - this.operatingSystemMXBean = (com.ibm.lang.management.OperatingSystemMXBean) operatingSystemMXBean; - this.runtimeMXBean = runtimeMXBean; + + CpuUsageProvider jvmCpuUsageProvider = new JvmCpuUsageProvider(operatingSystemMXBean, runtimeMXBean); + try { + jvmCpuUsageProvider.getCpuUsage(); + } catch (NoSuchMethodError e) { + logger.warn("Expected method not found for retrieving jvm cpu usage. Cause : {}", e.getMessage()); + jvmCpuUsageProvider = CpuUsageProvider.UNSUPPORTED; + } + this.jvmCpuUsageProvider = jvmCpuUsageProvider; } @Override public CpuLoadMetricSnapshot getSnapshot() { - double jvmCpuUsage = UNCOLLECTED_USAGE; - if (runtimeMXBean != null) { - long cpuTimeNS = operatingSystemMXBean.getProcessCpuTimeByNS(); - long upTimeMS = runtimeMXBean.getUptime(); - jvmCpuUsage = jvmCpuUsageCalculator.getJvmCpuUsage(cpuTimeNS, upTimeMS); - } - double systemCpuUsage = operatingSystemMXBean.getSystemCpuLoad(); - return new CpuLoadMetricSnapshot(jvmCpuUsage, systemCpuUsage); + double jvmCpuUsage = jvmCpuUsageProvider.getCpuUsage(); + return new CpuLoadMetricSnapshot(jvmCpuUsage, UNCOLLECTED_USAGE); } @Override public String toString() { return "CpuLoadMetric for IBM Java 1.6"; } + + private static class JvmCpuUsageProvider implements CpuUsageProvider { + + private final JvmCpuUsageCalculator jvmCpuUsageCalculator = new JvmCpuUsageCalculator(); + + private final OperatingSystemMXBean operatingSystemMXBean; + private final RuntimeMXBean runtimeMXBean; + + private JvmCpuUsageProvider(OperatingSystemMXBean operatingSystemMXBean, RuntimeMXBean runtimeMXBean) { + this.operatingSystemMXBean = operatingSystemMXBean; + this.runtimeMXBean = runtimeMXBean; + } + + @Override + public double getCpuUsage() { + long cpuTimeNS = operatingSystemMXBean.getProcessCpuTimeByNS(); + long upTimeMS = runtimeMXBean.getUptime(); + return jvmCpuUsageCalculator.getJvmCpuUsage(cpuTimeNS, upTimeMS); + } + } } diff --git a/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/oracle/Java6CpuLoadMetric.java b/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/oracle/Java6CpuLoadMetric.java index e3fe36eef104..d4f9ee627ac1 100644 --- a/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/oracle/Java6CpuLoadMetric.java +++ b/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/oracle/Java6CpuLoadMetric.java @@ -18,9 +18,13 @@ import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetric; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetricSnapshot; +import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuUsageProvider; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.JvmCpuUsageCalculator; +import com.sun.management.OperatingSystemMXBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.lang.management.OperatingSystemMXBean; +import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; /** @@ -28,32 +32,58 @@ */ public class Java6CpuLoadMetric implements CpuLoadMetric { - private final JvmCpuUsageCalculator jvmCpuUsageCalculator = new JvmCpuUsageCalculator(); - private final com.sun.management.OperatingSystemMXBean operatingSystemMXBean; - private final RuntimeMXBean runtimeMXBean; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public Java6CpuLoadMetric(OperatingSystemMXBean operatingSystemMXBean, RuntimeMXBean runtimeMXBean) { + private final CpuUsageProvider jvmCpuUsageProvider; + + public Java6CpuLoadMetric() { + final OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); if (operatingSystemMXBean == null) { - throw new NullPointerException("operatingSystemMXBean must not be null"); + throw new IllegalStateException("OperatingSystemMXBean not available"); + } + final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); + if (runtimeMXBean == null) { + throw new IllegalStateException("RuntimeMXBean not available"); } - this.operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) operatingSystemMXBean; - this.runtimeMXBean = runtimeMXBean; + + CpuUsageProvider jvmCpuUsageProvider = new JvmCpuUsageProvider(operatingSystemMXBean, runtimeMXBean); + try { + jvmCpuUsageProvider.getCpuUsage(); + } catch (NoSuchMethodError e) { + logger.warn("Expected method not found for retrieving jvm cpu usage. Cause : {}", e.getMessage()); + jvmCpuUsageProvider = CpuUsageProvider.UNSUPPORTED; + } + this.jvmCpuUsageProvider = jvmCpuUsageProvider; } @Override public CpuLoadMetricSnapshot getSnapshot() { - double jvmCpuUsage = UNCOLLECTED_USAGE; - if (runtimeMXBean != null) { - long cpuTimeNS = operatingSystemMXBean.getProcessCpuTime(); - long upTimeMS = runtimeMXBean.getUptime(); - jvmCpuUsage = jvmCpuUsageCalculator.getJvmCpuUsage(cpuTimeNS, upTimeMS); - } - double systemCpuUsage = UNCOLLECTED_USAGE; - return new CpuLoadMetricSnapshot(jvmCpuUsage, systemCpuUsage); + double jvmCpuUsage = jvmCpuUsageProvider.getCpuUsage(); + return new CpuLoadMetricSnapshot(jvmCpuUsage, UNCOLLECTED_USAGE); } @Override public String toString() { return "CpuLoadMetric for Oracle Java 1.6"; } + + private static class JvmCpuUsageProvider implements CpuUsageProvider { + + private final JvmCpuUsageCalculator jvmCpuUsageCalculator = new JvmCpuUsageCalculator(); + + private final OperatingSystemMXBean operatingSystemMXBean; + private final RuntimeMXBean runtimeMXBean; + + private JvmCpuUsageProvider(OperatingSystemMXBean operatingSystemMXBean, RuntimeMXBean runtimeMXBean) { + this.operatingSystemMXBean = operatingSystemMXBean; + this.runtimeMXBean = runtimeMXBean; + } + + @Override + public double getCpuUsage() { + long cpuTimeNS = operatingSystemMXBean.getProcessCpuTime(); + long upTimeMS = runtimeMXBean.getUptime(); + return jvmCpuUsageCalculator.getJvmCpuUsage(cpuTimeNS, upTimeMS); + } + } } diff --git a/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/oracle/DefaultFileDescriptorMetric.java b/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/oracle/DefaultFileDescriptorMetric.java new file mode 100644 index 000000000000..1b927477932d --- /dev/null +++ b/profiler-optional/profiler-optional-jdk6/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/oracle/DefaultFileDescriptorMetric.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.oracle; + +import com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.FileDescriptorMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.FileDescriptorMetricSnapshot; + +import java.lang.management.OperatingSystemMXBean; + +/** + * @author Roy Kim + */ +public class DefaultFileDescriptorMetric implements FileDescriptorMetric { + + private final com.sun.management.UnixOperatingSystemMXBean unixOperatingSystemMXBean; + + public DefaultFileDescriptorMetric(OperatingSystemMXBean operatingSystemMXBean) { + if (operatingSystemMXBean == null) { + throw new NullPointerException("operatingSystemMXBean must not be null"); + } + this.unixOperatingSystemMXBean = (com.sun.management.UnixOperatingSystemMXBean) operatingSystemMXBean; + } + + @Override + public FileDescriptorMetricSnapshot getSnapshot() { + + long openFileDescriptorCount = unixOperatingSystemMXBean.getOpenFileDescriptorCount(); + return new FileDescriptorMetricSnapshot(openFileDescriptorCount); + } + + @Override + public String toString() { + return "FileDescriptorMetric for Oracle Java 1.5+"; + } +} diff --git a/profiler-optional/profiler-optional-jdk7/clover.license b/profiler-optional/profiler-optional-jdk7/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/profiler-optional/profiler-optional-jdk7/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + + @@ -7,7 +23,7 @@ com.navercorp.pinpoint pinpoint-profiler-optional-parent ../profiler-optional-parent - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-profiler-optional-jdk7 @@ -22,15 +38,51 @@ - org.javassist - javassist + org.ow2.asm + asm + test + + + org.ow2.asm + asm-commons test org.ow2.asm - asm-debug-all + asm-util + test + + + org.ow2.asm + asm-tree test + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + ${plugin.animal-sniffer.version} + + + org.codehaus.mojo.signature + java17 + 1.0 + + + + + ensure-java-${jdk.version}-class-library + test + + check + + + + + + + \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/DefaultBufferMetric.java b/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/DefaultBufferMetric.java new file mode 100644 index 000000000000..3290a40d6499 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/DefaultBufferMetric.java @@ -0,0 +1,90 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.buffer; + +import javax.management.ObjectName; +import java.lang.management.BufferPoolMXBean; +import java.lang.management.ManagementFactory; +import java.util.List; + +/** + * @author Roy Kim + */ +public class DefaultBufferMetric implements BufferMetric { + + private final BufferPoolMXBean direct; + private final BufferPoolMXBean mapped; + + public DefaultBufferMetric() { + List pools = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); + this.direct = getBufferPool(pools, BufferType.DIRECT.getName()); + this.mapped = getBufferPool(pools, BufferType.MAPPED.getName()); + } + + private BufferPoolMXBean getBufferPool(List pools, String type) { + for (BufferPoolMXBean pool : pools) { + final String poolName = pool.getName(); + if (poolName.equals(type)) { + return pool; + } + } + return new EmptyBufferPoolMXBean(); + } + + @Override + public BufferMetricSnapshot getSnapshot() { + + final long directCount = direct.getCount(); + final long directMemoryUsed = direct.getMemoryUsed(); + final long mappedCount = mapped.getCount(); + final long mappedMemoryUsed = mapped.getMemoryUsed(); + + return new BufferMetricSnapshot(directCount, directMemoryUsed, mappedCount, mappedMemoryUsed); + } + + @Override + public String toString() { + return "DefaultBufferMetric"; + } + + private static class EmptyBufferPoolMXBean implements BufferPoolMXBean { + @Override + public ObjectName getObjectName() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public long getCount() { + return UNCOLLECTED_VALUE; + } + + @Override + public long getTotalCapacity() { + return UNCOLLECTED_VALUE; + } + + @Override + public long getMemoryUsed() { + return UNCOLLECTED_VALUE; + } + } +} diff --git a/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/ibm/DefaultCpuLoadMetric.java b/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/ibm/DefaultCpuLoadMetric.java index 7d6abb3b2c8b..1baeb68910f1 100644 --- a/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/ibm/DefaultCpuLoadMetric.java +++ b/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/ibm/DefaultCpuLoadMetric.java @@ -16,29 +16,54 @@ package com.navercorp.pinpoint.profiler.monitor.metric.cpu.ibm; +import com.ibm.lang.management.OperatingSystemMXBean; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetric; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetricSnapshot; +import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuUsageProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.lang.management.OperatingSystemMXBean; +import java.lang.management.ManagementFactory; /** * @author HyunGil Jeong */ public class DefaultCpuLoadMetric implements CpuLoadMetric { - private final com.ibm.lang.management.OperatingSystemMXBean operatingSystemMXBean; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public DefaultCpuLoadMetric(OperatingSystemMXBean operatingSystemMXBean) { + private final CpuUsageProvider jvmCpuUsageProvider; + private final CpuUsageProvider systemCpuUsageProvider; + + public DefaultCpuLoadMetric() { + final OperatingSystemMXBean operatingSystemMXBean = (com.ibm.lang.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); if (operatingSystemMXBean == null) { - throw new NullPointerException("operatingSystemMXBean must not be null"); + throw new IllegalStateException("OperatingSystemMXBean not available"); + } + + CpuUsageProvider jvmCpuUsageProvider = new JvmCpuUsageProvider(operatingSystemMXBean); + try { + jvmCpuUsageProvider.getCpuUsage(); + } catch (NoSuchMethodError e) { + logger.warn("Expected method not found for retrieving jvm cpu usage. Cause : {}", e.getMessage()); + jvmCpuUsageProvider = CpuUsageProvider.UNSUPPORTED; + } + this.jvmCpuUsageProvider = jvmCpuUsageProvider; + + CpuUsageProvider systemCpuUsageProvider = new SystemCpuUsageProvider(operatingSystemMXBean); + try { + systemCpuUsageProvider.getCpuUsage(); + } catch (NoSuchMethodError e) { + logger.warn("Expected method not found for retrieving system cpu usage. Cause : {}", e.getMessage()); + systemCpuUsageProvider = CpuUsageProvider.UNSUPPORTED; } - this.operatingSystemMXBean = (com.ibm.lang.management.OperatingSystemMXBean) operatingSystemMXBean; + this.systemCpuUsageProvider = systemCpuUsageProvider; } @Override public CpuLoadMetricSnapshot getSnapshot() { - double jvmCpuUsage = operatingSystemMXBean.getProcessCpuLoad(); - double systemCpuUsage = operatingSystemMXBean.getSystemCpuLoad(); + double jvmCpuUsage = jvmCpuUsageProvider.getCpuUsage(); + double systemCpuUsage = systemCpuUsageProvider.getCpuUsage(); return new CpuLoadMetricSnapshot(jvmCpuUsage, systemCpuUsage); } @@ -46,4 +71,32 @@ public CpuLoadMetricSnapshot getSnapshot() { public String toString() { return "CpuLoadMetric for IBM Java 1.7+"; } + + private static class JvmCpuUsageProvider implements CpuUsageProvider { + + private final OperatingSystemMXBean operatingSystemMXBean; + + private JvmCpuUsageProvider(OperatingSystemMXBean operatingSystemMXBean) { + this.operatingSystemMXBean = operatingSystemMXBean; + } + + @Override + public double getCpuUsage() { + return operatingSystemMXBean.getProcessCpuLoad(); + } + } + + private static class SystemCpuUsageProvider implements CpuUsageProvider { + + private final OperatingSystemMXBean operatingSystemMXBean; + + private SystemCpuUsageProvider(OperatingSystemMXBean operatingSystemMXBean) { + this.operatingSystemMXBean = operatingSystemMXBean; + } + + @Override + public double getCpuUsage() { + return operatingSystemMXBean.getSystemCpuLoad(); + } + } } diff --git a/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/oracle/DefaultCpuLoadMetric.java b/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/oracle/DefaultCpuLoadMetric.java index 9954ba770128..5f3d011674a4 100644 --- a/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/oracle/DefaultCpuLoadMetric.java +++ b/profiler-optional/profiler-optional-jdk7/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/oracle/DefaultCpuLoadMetric.java @@ -18,27 +18,52 @@ import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetric; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetricSnapshot; +import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuUsageProvider; +import com.sun.management.OperatingSystemMXBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.lang.management.OperatingSystemMXBean; +import java.lang.management.ManagementFactory; /** * @author HyunGil Jeong */ public class DefaultCpuLoadMetric implements CpuLoadMetric { - private final com.sun.management.OperatingSystemMXBean operatingSystemMXBean; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public DefaultCpuLoadMetric(OperatingSystemMXBean operatingSystemMXBean) { + private final CpuUsageProvider jvmCpuUsageProvider; + private final CpuUsageProvider systemCpuUsageProvider; + + public DefaultCpuLoadMetric() { + final OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); if (operatingSystemMXBean == null) { - throw new NullPointerException("operatingSystemMXBean must not be null"); + throw new IllegalStateException("OperatingSystemMXBean not available"); + } + + CpuUsageProvider jvmCpuUsageProvider = new JvmCpuUsageProvider(operatingSystemMXBean); + try { + jvmCpuUsageProvider.getCpuUsage(); + } catch (NoSuchMethodError e) { + logger.warn("Expected method not found for retrieving jvm cpu usage. Cause : {}", e.getMessage()); + jvmCpuUsageProvider = CpuUsageProvider.UNSUPPORTED; + } + this.jvmCpuUsageProvider = jvmCpuUsageProvider; + + CpuUsageProvider systemCpuUsageProvider = new SystemCpuUsageProvider(operatingSystemMXBean); + try { + systemCpuUsageProvider.getCpuUsage(); + } catch (NoSuchMethodError e) { + logger.warn("Expected method not found for retrieving system cpu usage. Cause : {}", e.getMessage()); + systemCpuUsageProvider = CpuUsageProvider.UNSUPPORTED; } - this.operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) operatingSystemMXBean; + this.systemCpuUsageProvider = systemCpuUsageProvider; } @Override public CpuLoadMetricSnapshot getSnapshot() { - double jvmCpuUsage = operatingSystemMXBean.getProcessCpuLoad(); - double systemCpuUsage = operatingSystemMXBean.getSystemCpuLoad(); + double jvmCpuUsage = jvmCpuUsageProvider.getCpuUsage(); + double systemCpuUsage = systemCpuUsageProvider.getCpuUsage(); return new CpuLoadMetricSnapshot(jvmCpuUsage, systemCpuUsage); } @@ -46,4 +71,32 @@ public CpuLoadMetricSnapshot getSnapshot() { public String toString() { return "CpuLoadMetric for Oracle Java 1.7+"; } + + private static class JvmCpuUsageProvider implements CpuUsageProvider { + + private final OperatingSystemMXBean operatingSystemMXBean; + + private JvmCpuUsageProvider(OperatingSystemMXBean operatingSystemMXBean) { + this.operatingSystemMXBean = operatingSystemMXBean; + } + + @Override + public double getCpuUsage() { + return operatingSystemMXBean.getProcessCpuLoad(); + } + } + + private static class SystemCpuUsageProvider implements CpuUsageProvider { + + private final OperatingSystemMXBean operatingSystemMXBean; + + private SystemCpuUsageProvider(OperatingSystemMXBean operatingSystemMXBean) { + this.operatingSystemMXBean = operatingSystemMXBean; + } + + @Override + public double getCpuUsage() { + return operatingSystemMXBean.getSystemCpuLoad(); + } + } } diff --git a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/CustomURLClassLoader.java b/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/CustomURLClassLoader.java deleted file mode 100644 index 458f37150e6c..000000000000 --- a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/CustomURLClassLoader.java +++ /dev/null @@ -1,32 +0,0 @@ -package bug_regression_jdk7.javassist; - -import java.net.URL; -import java.net.URLClassLoader; - -/** - * @author Woonduk Kang(emeroad) - */ -public class CustomURLClassLoader extends URLClassLoader { - - public CustomURLClassLoader(URL[] urls, ClassLoader parent) { - super(urls, parent); - } - - public CustomURLClassLoader(URL[] urls) { - super(urls); - } - - public Class defineClass0(String name, byte[] bytes) { - return this.defineClass(name, bytes, 0, bytes.length); - } - - public Class defineClass0(String name, byte[] bytes, int off, int length) { - return super.defineClass(name, bytes, off, length); - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - return super.loadClass(name); - } -} - diff --git a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/InvalidStackMapFrame.java b/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/InvalidStackMapFrame.java deleted file mode 100644 index fe741b2ce392..000000000000 --- a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/InvalidStackMapFrame.java +++ /dev/null @@ -1,25 +0,0 @@ -package bug_regression_jdk7.javassist; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public class InvalidStackMapFrame { - - public void bytecodeVerifyError() { - // javassist bug : invalid stack map frame - List test = new ArrayList(); - String[] newLine = new String[10]; - for (Integer idx : test) { - String address = newLine[1]; - int tabPos = -1; - if (tabPos != -1) { - address = address.substring(tabPos + 1); - } - newLine[4] = address; - } - - } -} diff --git a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/JavassistVerifyErrorTest.java b/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/JavassistVerifyErrorTest.java deleted file mode 100644 index ba5bf79185b3..000000000000 --- a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/JavassistVerifyErrorTest.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bug_regression_jdk7.javassist; - -import bug_regression_jdk7.javassist.asm.BytecodeVerifyTestClassVisitor; -import com.navercorp.pinpoint.profiler.instrument.ASMBytecodeDisassembler; -import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.LoaderClassPath; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.InputStream; -import java.net.URL; - -/** - * @author Woonduk Kang(emeroad) - */ -public class JavassistVerifyErrorTest { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private static final String INVALID_STACK_MAP_FRAME = "bug_regression_jdk7.javassist.InvalidStackMapFrame"; - - /** - * bug id - * https://github.com/naver/pinpoint/issues/1807 - * @throws Exception - */ - @Ignore("fixed Javassist 3.21.0-GA") - @Test - public void bug_regression_BytecodeVerifyError_Invalid_StackMapFrame() throws Exception { - - CustomURLClassLoader classLoader = new CustomURLClassLoader(new URL[]{}, Thread.currentThread().getContextClassLoader()); - - ClassPool classPool = new ClassPool(true); - classPool.appendClassPath(new LoaderClassPath(classLoader)); - - final CtClass ctClass = classPool.get(INVALID_STACK_MAP_FRAME); - final CtMethod method = ctClass.getDeclaredMethod("bytecodeVerifyError"); - method.addLocalVariable("test_localVariable", CtClass.intType); - method.insertBefore("{ test_localVariable = 1; }"); - - final byte[] bytecode = ctClass.toBytecode(); - classLoader.defineClass0(INVALID_STACK_MAP_FRAME, bytecode); - try { - Class.forName(INVALID_STACK_MAP_FRAME, true, classLoader); - Assert.fail("VerifyError"); - } catch (VerifyError e) { - logger.debug("verifyError:{}", e.getMessage(), e); - } - - - final ASMBytecodeDisassembler bytecodeDisassembler = new ASMBytecodeDisassembler(); - - final String dumpBytecode = bytecodeDisassembler.dumpBytecode(bytecode); - logger.debug("dumpBytecode:{}", dumpBytecode); - -// javassist bug : invalid stack map frame -// 00013 InvalidStackMapFrame ArrayList String Iterator I : : FRAME FULL [bug_regression_jdk7/javassist/InvalidStackMapFrame java/util/ArrayList [[[java/lang/Object->[Ljava/lang/String;]]] java/util/Iterator T T T I] [] - final String verify = bytecodeDisassembler.dumpVerify(bytecode, classLoader); - logger.debug("dumpVerify:{}", verify); - - final String dumpAsm = bytecodeDisassembler.dumpASM(bytecode); - logger.debug("dumpAsm :{}", dumpAsm); - - } - - - @Test - public void asm_stackmapframe_check() throws Exception { - - CustomURLClassLoader classLoader = new CustomURLClassLoader(new URL[]{}, Thread.currentThread().getContextClassLoader()); - final InputStream stream = classLoader.getResourceAsStream(JavaAssistUtils.javaNameToJvmName(INVALID_STACK_MAP_FRAME) + ".class"); - - ClassReader cr = new ClassReader(stream); - ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - ClassVisitor cv = new BytecodeVerifyTestClassVisitor(cw); - cr.accept(cv, ClassReader.EXPAND_FRAMES | ClassReader.SKIP_DEBUG); - - byte[] bytecode = cw.toByteArray(); - classLoader.defineClass0(INVALID_STACK_MAP_FRAME, bytecode); - - final Class aClass = Class.forName(INVALID_STACK_MAP_FRAME, true, classLoader); - Assert.assertSame(aClass.getClassLoader(), classLoader); - - - final ASMBytecodeDisassembler bytecodeDisassembler = new ASMBytecodeDisassembler(); - - final String dumpBytecode = bytecodeDisassembler.dumpBytecode(bytecode); - logger.debug("dumpBytecode:{}", dumpBytecode); - - final String verify = bytecodeDisassembler.dumpVerify(bytecode, classLoader); - logger.debug("dumpVerify:{}", verify); - -// final String dumpAsm = bytecodeDisassembler.dumpASM(bytecode); -// logger.debug("dumpAsm :{}", dumpAsm); - - } -} diff --git a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/asm/AddIntVariableMethodAdapter.java b/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/asm/AddIntVariableMethodAdapter.java deleted file mode 100644 index 799cce8590b3..000000000000 --- a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/asm/AddIntVariableMethodAdapter.java +++ /dev/null @@ -1,36 +0,0 @@ -package bug_regression_jdk7.javassist.asm; - -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.commons.AdviceAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Woonduk Kang(emeroad) - */ -public class AddIntVariableMethodAdapter extends AdviceAdapter { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private String name; - - public AddIntVariableMethodAdapter(MethodVisitor mv, int acc, String name, String desc) { - super(Opcodes.ASM5, mv, acc, name, desc); - this.name = name; - - } - - @Override - public void visitMaxs(int maxStack, int maxLocals) { - super.visitMaxs(maxStack + 1, maxLocals); - } - - @Override - protected void onMethodEnter() { - logger.debug("onMethodEnter() add int local variable inst:ISTORE_7 {}", name); - mv.visitInsn(Opcodes.ICONST_0); - mv.visitVarInsn(Opcodes.ISTORE, 7); - } - -} diff --git a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/asm/BytecodeVerifyTestClassVisitor.java b/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/asm/BytecodeVerifyTestClassVisitor.java deleted file mode 100644 index 08920254098f..000000000000 --- a/profiler-optional/profiler-optional-jdk7/src/test/java/bug_regression_jdk7/javassist/asm/BytecodeVerifyTestClassVisitor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2016 Naver Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package bug_regression_jdk7.javassist.asm; - -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Woonduk Kang(emeroad) - */ -public class BytecodeVerifyTestClassVisitor extends ClassVisitor { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private String name; - - public BytecodeVerifyTestClassVisitor(final ClassVisitor cv) { - super(Opcodes.ASM5, cv); - } - - @Override - public void visit(final int version, final int access, final String name, - final String signature, final String superName, - final String[] interfaces) { - this.name = name; - super.visit(version, access, name, signature, superName, interfaces); - } - - @Override - public MethodVisitor visitMethod(final int access, final String name, - final String desc, final String signature, final String[] exceptions) { - - MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); - logger.debug("mv:{}", mv); - logger.debug("name:{}", name); - logger.debug("desc:{}", desc); - logger.debug("signature:{}", signature); - if (name.contains("bytecodeVerifyError")) { - return new AddIntVariableMethodAdapter(mv, Opcodes.ACC_PUBLIC, name, "()V"); - } - return mv; - } -} diff --git a/profiler-optional/profiler-optional-jdk7/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/DefaultBufferMetricTest.java b/profiler-optional/profiler-optional-jdk7/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/DefaultBufferMetricTest.java new file mode 100644 index 000000000000..ac5c89cd2e7a --- /dev/null +++ b/profiler-optional/profiler-optional-jdk7/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/DefaultBufferMetricTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.buffer; + +import com.google.inject.Provider; +import com.navercorp.pinpoint.profiler.context.provider.stat.buffer.BufferMetricProvider; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultBufferMetricTest { + + @Test + public void getSnapshot() { + BufferMetric defaultBufferMetric = new DefaultBufferMetric(); + BufferMetricSnapshot snapshot = defaultBufferMetric.getSnapshot(); + + Assert.assertNotEquals(snapshot.getDirectCount(), BufferMetric.UNCOLLECTED_VALUE); + Assert.assertNotEquals(snapshot.getDirectMemoryUsed(), BufferMetric.UNCOLLECTED_VALUE); + Assert.assertNotEquals(snapshot.getMappedCount(), BufferMetric.UNCOLLECTED_VALUE); + Assert.assertNotEquals(snapshot.getMappedMemoryUsed(), BufferMetric.UNCOLLECTED_VALUE); + } + + @Test + public void provider() { + Provider provider = new BufferMetricProvider(); + BufferMetric bufferMetric = provider.get(); + BufferMetricSnapshot snapshot = bufferMetric.getSnapshot(); + + Assert.assertNotEquals(snapshot.getDirectCount(), BufferMetric.UNCOLLECTED_VALUE); + } +} \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk8/clover.license b/profiler-optional/profiler-optional-jdk8/clover.license deleted file mode 100644 index a26812effe7c..000000000000 --- a/profiler-optional/profiler-optional-jdk8/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + + @@ -7,7 +23,7 @@ com.navercorp.pinpoint pinpoint-profiler-optional-parent ../profiler-optional-parent - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-profiler-optional-jdk8 @@ -18,6 +34,7 @@ 1.8 ${env.JAVA_8_HOME} + java18 @@ -43,7 +60,7 @@ org.apache.maven.plugins maven-failsafe-plugin - 2.18.1 + ${plugin.failsafe.version} diff --git a/profiler-optional/profiler-optional-jdk8/src/main/java-ibm/com/ibm/lang/management/OperatingSystemMXBean.java b/profiler-optional/profiler-optional-jdk8/src/main/java-ibm/com/ibm/lang/management/OperatingSystemMXBean.java new file mode 100644 index 000000000000..b965c3a3315a --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/main/java-ibm/com/ibm/lang/management/OperatingSystemMXBean.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ibm.lang.management; + +/** + * @author Roy Kim + */ +public interface OperatingSystemMXBean extends java.lang.management.OperatingSystemMXBean{ + +} diff --git a/profiler-optional/profiler-optional-jdk8/src/main/java-ibm/com/ibm/lang/management/UnixOperatingSystemMXBean.java b/profiler-optional/profiler-optional-jdk8/src/main/java-ibm/com/ibm/lang/management/UnixOperatingSystemMXBean.java new file mode 100644 index 000000000000..72c81e43061c --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/main/java-ibm/com/ibm/lang/management/UnixOperatingSystemMXBean.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ibm.lang.management; + +/** + * @author Roy Kim + */ +public interface UnixOperatingSystemMXBean extends com.ibm.lang.management.OperatingSystemMXBean { + + long getOpenFileDescriptorCount(); +} diff --git a/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryClassAdaptor.java b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryClassAdaptor.java new file mode 100644 index 000000000000..371a74989f1b --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryClassAdaptor.java @@ -0,0 +1,89 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda; + +import com.navercorp.pinpoint.common.util.IOUtils; +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.JvmVersion; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author Woonduk Kang(emeroad) + */ +public class LambdaFactoryClassAdaptor { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static final String lambdaFactoryClassName = "java/lang/invoke/InnerClassLambdaMetafactory"; + private static final String lambdaFactoryMethodName = "spinInnerClass"; + + + + + public LambdaFactoryClassAdaptor() { + } + + public byte[] loadTransformedBytecode() throws IOException { + String classResourceName = lambdaFactoryClassName.concat(".class"); + InputStream stream = ClassLoader.getSystemResourceAsStream(classResourceName); + byte[] bytes = IOUtils.toByteArray(stream); + LambdaClass lambdaClass = getLambdaClass(); + return transform(bytes, lambdaClass); + } + + private LambdaClass getLambdaClass() { + if (JvmUtils.getVersion().onOrAfter(JvmVersion.JAVA_9)) { + return new LambdaClassJava9(); + } else { + return new LambdaClassJava8(); + } + } + + public byte[] transform(byte[] bytes, LambdaClass lambdaClass) { + if (bytes == null) { + throw new NullPointerException("bytes must not be null"); + } + + final ClassReader reader = new ClassReader(bytes); + final ClassWriter writer = new ClassWriter(reader, 0); + + final String unsafeClass = lambdaClass.getUnsafeClass(); + final String unsafeMethod = lambdaClass.getUnsafeMethod(); + final String delegateClassName = lambdaClass.getDelegateClass(); + final String delegateMethodName = lambdaClass.getDelegateMethod(); + + MethodInstReplacer methodInstReplacer = new MethodInstReplacer(writer, lambdaFactoryMethodName, + unsafeClass, unsafeMethod, delegateClassName, delegateMethodName); + reader.accept(methodInstReplacer, 0); + + if (!lambdaFactoryClassName.equals(methodInstReplacer.getClassName())) { + throw new IllegalArgumentException("unexpected class " + methodInstReplacer.getClassName()); + } + + if (methodInstReplacer.getTransformCount() != 1) { + logger.warn("unexpected {}.{} invoke count {}", unsafeClass, unsafeMethod, methodInstReplacer.getTransformCount()); + // dump bytecode + } + return writer.toByteArray(); + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/MethodInstReplacer.java b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/MethodInstReplacer.java new file mode 100644 index 000000000000..b753a4c94924 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/MethodInstReplacer.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.instrument.ASMVersion; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class MethodInstReplacer extends ClassVisitor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private String className; + private final String methodName; + private final String targetClassName; + private final String targetMethodName; + private final String delegateClassName; + private final String delegateMethodName; + private int transformCount = 0; + + public MethodInstReplacer(ClassVisitor classVisitor, String methodName, + String targetClassName, String targetMethodName, + String delegateClassName, String delegateMethodName) { + super(ASMVersion.VERSION, classVisitor); + this.methodName = Assert.requireNonNull(methodName, "methodName must not be null"); + + this.targetClassName = Assert.requireNonNull(targetClassName, "targetClassName must not be null"); + this.targetMethodName = Assert.requireNonNull(targetMethodName, "targetMethodName must not be null"); + + this.delegateClassName = Assert.requireNonNull(delegateClassName, "delegateClassName must not be null"); + this.delegateMethodName = Assert.requireNonNull(delegateMethodName, "delegateMethodName must not be null"); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + this.className = name; + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + if (methodName.equals(name)) { + logger.info("visitMethod {} desc:{} {}", name, descriptor); + + final MethodVisitor superMethodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions); + return new MethodVisitor(ASMVersion.VERSION, superMethodVisitor) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { + if (targetClassName.equals(owner) && targetMethodName.equals(name)) { + if (logger.isInfoEnabled()) { + logger.info("replace MethodInsn {}.{}() -> {}.{}()", owner, name, delegateClassName, delegateMethodName); + } + transformCount++; + super.visitMethodInsn(Opcodes.INVOKESTATIC, delegateClassName, delegateMethodName, descriptor, isInterface); + } else { + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); + } + } + }; + } + return super.visitMethod(access, name, descriptor, signature, exceptions); + } + + public String getClassName() { + return className; + } + + public int getTransformCount() { + return transformCount; + } + +} diff --git a/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/ibm/DefaultFileDescriptorMetric.java b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/ibm/DefaultFileDescriptorMetric.java new file mode 100644 index 000000000000..0ec5bf5aecc8 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/ibm/DefaultFileDescriptorMetric.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.ibm; + +import com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.FileDescriptorMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.FileDescriptorMetricSnapshot; +import java.lang.management.OperatingSystemMXBean; + +/** + * @author Roy Kim + */ +public class DefaultFileDescriptorMetric implements FileDescriptorMetric { + + private final com.ibm.lang.management.UnixOperatingSystemMXBean unixOperatingSystemMXBean; + + public DefaultFileDescriptorMetric(OperatingSystemMXBean operatingSystemMXBean) { + if (operatingSystemMXBean == null) { + throw new NullPointerException("operatingSystemMXBean must not be null"); + } + this.unixOperatingSystemMXBean = (com.ibm.lang.management.UnixOperatingSystemMXBean) operatingSystemMXBean; + } + + @Override + public FileDescriptorMetricSnapshot getSnapshot() { + + long openFileDescriptorCount = unixOperatingSystemMXBean.getOpenFileDescriptorCount(); + return new FileDescriptorMetricSnapshot(openFileDescriptorCount); + } + + @Override + public String toString() { + return "FileDescriptorMetric for IBM Java 1.8+"; + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/util/Java8Counter.java b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/util/Java8Counter.java new file mode 100644 index 000000000000..725fce4d5b78 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/util/Java8Counter.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.util; + +import java.util.concurrent.atomic.LongAdder; + +/** + * @author Woonduk Kang(emeroad) + */ +public class Java8Counter implements Counter { + private final LongAdder longAdder = new LongAdder(); + @Override + public void increment() { + longAdder.increment(); + } + + @Override + public void add(long x) { + longAdder.add(x); + } + + @Override + public long longValue() { + return longAdder.longValue(); + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/util/Java8CounterFactory.java b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/util/Java8CounterFactory.java new file mode 100644 index 000000000000..5f407773d7bb --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/main/java/com/navercorp/pinpoint/profiler/util/Java8CounterFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.util; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class Java8CounterFactory implements CounterFactory.ObjectFactory { + + public Java8CounterFactory() { + } + + @Override + public Counter newInstance() { + return new Java8Counter(); + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/DefineClassUtils.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/DefineClassUtils.java new file mode 100644 index 000000000000..f1f515536aa7 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/DefineClassUtils.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.classloading; + + +/** + * for package access + * @author Woonduk Kang(emeroad) + */ +public class DefineClassUtils { + private static final DefineClass defineClass = new ReflectionDefineClass(); + + public static Class defineClass(ClassLoader classLoader, String name, byte[] bytes) { + return defineClass.defineClass(classLoader, name, bytes); + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/ByteCodeDumper.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/ByteCodeDumper.java new file mode 100644 index 000000000000..6859f3381d69 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/ByteCodeDumper.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda; + +import com.navercorp.pinpoint.profiler.instrument.ASMBytecodeDisassembler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class ByteCodeDumper { + private static final Logger logger = LoggerFactory.getLogger(ByteCodeDumper.class); + + private static final ASMBytecodeDisassembler disassembler = new ASMBytecodeDisassembler(); + + public static void dumpByteCode(byte[] bytes) { + String asmCode = disassembler.dumpASM(bytes); + logger.trace("asm----- \n{}", asmCode); + + + String byteCode = disassembler.dumpBytecode(bytes); + logger.trace("bytecode---- \n{}", byteCode); + + } + + public static void verify(byte[] bytes, ClassLoader classLoader) { + String verify = disassembler.dumpVerify(bytes, classLoader); + logger.trace("verify---- \n{}", verify); + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryClassAdaptorTest.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryClassAdaptorTest.java new file mode 100644 index 000000000000..0e6d414deacc --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryClassAdaptorTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * @author Woonduk Kang(emeroad) + */ +public class LambdaFactoryClassAdaptorTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + + @Test + public void transform() throws IOException { + + LambdaFactoryClassAdaptor lambdaFactoryClassAdaptor = new LambdaFactoryClassAdaptor(); + byte[] transform = lambdaFactoryClassAdaptor.loadTransformedBytecode(); + + ByteCodeDumper.verify(transform, ClassLoader.getSystemClassLoader()); + + } + + +} \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryTest.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryTest.java new file mode 100644 index 000000000000..0f7cfc1a30be --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaFactoryTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda; + +import com.navercorp.pinpoint.common.util.IOUtils; +import com.navercorp.pinpoint.profiler.instrument.ASMBytecodeDisassembler; +import com.navercorp.pinpoint.profiler.instrument.ASMVersion; +import com.navercorp.pinpoint.profiler.instrument.classloading.DefineClassUtils; +import com.navercorp.pinpoint.profiler.instrument.lambda.mock.DefineAnonymousClassDelegator; +import com.navercorp.pinpoint.profiler.instrument.lambda.mock.UnsafeClassMock; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.junit.Assert; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.commons.ClassRemapper; +import org.objectweb.asm.commons.Remapper; +import org.objectweb.asm.commons.SimpleRemapper; +import org.objectweb.asm.tree.ClassNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * @author Woonduk Kang(emeroad) + */ +public class LambdaFactoryTest { + + private static final String lambdaMetaFactory = "java.lang.invoke.InnerClassLambdaMetafactory"; + private static final String lambdaMetaFactoryResourceName = JavaAssistUtils.javaClassNameToJvmResourceName(lambdaMetaFactory); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + + private final ASMBytecodeDisassembler disassembler = new ASMBytecodeDisassembler(); + + @Test + public void dumpInnerClassLamdbaMetaFactory() throws IOException { + InputStream resourceStream = ClassLoader.getSystemResourceAsStream(lambdaMetaFactoryResourceName); + byte[] bytes = IOUtils.toByteArray(resourceStream); + logger.debug("dump-------"); + ByteCodeDumper.dumpByteCode(bytes); + } + + + + @Test + public void transformTest() throws IOException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { + + ClassLoader classLoader = this.getClass().getClassLoader(); + String name = JavaAssistUtils.javaClassNameToJvmResourceName(UnsafeClassMock.class.getName()); + InputStream resourceStream = ClassLoader.getSystemResourceAsStream(name); + byte[] bytes = IOUtils.toByteArray(resourceStream); + logger.info("dump-------"); + ByteCodeDumper.dumpByteCode(bytes); + + ClassReader reader = new ClassReader(bytes, 0, bytes.length); + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + String delegateClassName = "com/navercorp/pinpoint/profiler/instrument/lambda/mock/DefineAnonymousClassDelegator"; + String delegateMethod = "delegate"; + MethodInstReplacer replacer = new MethodInstReplacer(writer, "test", + "com/navercorp/pinpoint/profiler/instrument/lambda/mock/UnsafeMock", "defineAnonymousClass", + delegateClassName, delegateMethod + ); + + renameClass(reader, replacer); + + byte[] bytes1 = writer.toByteArray(); + ClassReader newReader1 = new ClassReader(bytes1); + ClassNode node = new ClassNode(ASMVersion.VERSION); + newReader1.accept(node, 0); + + logger.debug("dump-------"); + ByteCodeDumper.dumpByteCode(bytes1); + + Class delegatorClazz = DefineClassUtils.defineClass(classLoader, JavaAssistUtils.jvmNameToJavaName(node.name), bytes1); + logger.debug("class:{}", delegatorClazz); + Object o = delegatorClazz.getDeclaredConstructor().newInstance(); + Method test = o.getClass().getMethod("test"); + Object invoke = test.invoke(o); + + Assert.assertEquals(DefineAnonymousClassDelegator.count, 1); + + + } + + private void renameClass(ClassReader reader, ClassVisitor classVisitor) { + String className = "com/navercorp/pinpoint/profiler/instrument/lambda/mock/UnsafeClassMock"; + Remapper remapper = new SimpleRemapper(className,className + "2"); + ClassRemapper classRemapper = new ClassRemapper(classVisitor, remapper); + reader.accept(classRemapper, 0); + } + +} diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/mock/DefineAnonymousClassDelegator.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/mock/DefineAnonymousClassDelegator.java new file mode 100644 index 000000000000..897bf03bbbcb --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/mock/DefineAnonymousClassDelegator.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda.mock; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefineAnonymousClassDelegator { + + private static final Logger logger = LoggerFactory.getLogger(DefineAnonymousClassDelegator.class.getName()); + public static int count; + + public static Class delegate(Class hostClass, byte[] data, Object[] cpPatches) { + logger.debug("invoke delegate"); + count++; + return null; + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/mock/UnsafeClassMock.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/mock/UnsafeClassMock.java new file mode 100644 index 000000000000..643825f9489d --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/mock/UnsafeClassMock.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda.mock; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class UnsafeClassMock { + public static final UnsafeMock UNSAFE = UnsafeMock.getUnsafe(); + + public static final int intField = 1; + + private String stringField = "ddd"; + + public UnsafeClassMock() { + } + + public void test() { + UNSAFE.defineAnonymousClass(null, null, null); + } + + public void test2() { + DefineAnonymousClassDelegator.delegate(null, null, null); + } + + public void test3() { + this.stringField.toCharArray(); + } + + +} \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/mock/UnsafeMock.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/mock/UnsafeMock.java new file mode 100644 index 000000000000..ee206990e140 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/pinpoint/profiler/instrument/lambda/mock/UnsafeMock.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda.mock; + +/** + * @author Woonduk Kang(emeroad) + */ +public class UnsafeMock { + private static final UnsafeMock UNSAFE = new UnsafeMock(); + + public static UnsafeMock getUnsafe() { + return UNSAFE; + } + + public Class defineAnonymousClass(Class var1, byte[] var2, Object[] var3) { + return null; + } +} \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/MethodInterface.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/MethodInterface.java new file mode 100644 index 000000000000..7c44aaaef3e4 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/MethodInterface.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.jdk8.interfaces; + +/** + * @author jaehong.kim + */ +public interface MethodInterface { + + static String currentTimeMillis() { + return System.currentTimeMillis() + "ms"; + } + + default String foo() { + return "foo"; + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/MethodInterfaceClass.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/MethodInterfaceClass.java new file mode 100644 index 000000000000..9a0c436c375c --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/MethodInterfaceClass.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.jdk8.interfaces; + +/** + * @author jaehong.kim + */ +public class MethodInterfaceClass implements MethodInterface { + + public String bar() { + return foo(); + } +} \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/MethodInterfaceTest.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/MethodInterfaceTest.java new file mode 100644 index 000000000000..e5dd508a5498 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/MethodInterfaceTest.java @@ -0,0 +1,286 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.jdk8.interfaces; + +import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; +import com.navercorp.pinpoint.profiler.instrument.ASMClass; +import com.navercorp.pinpoint.profiler.instrument.ASMClassNodeAdapter; +import com.navercorp.pinpoint.profiler.instrument.ASMClassWriter; +import com.navercorp.pinpoint.profiler.instrument.ASMFieldNodeAdapter; +import com.navercorp.pinpoint.profiler.instrument.ASMMethodNodeAdapter; +import com.navercorp.pinpoint.profiler.instrument.EngineComponent; +import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinition; +import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinitionFactory; +import com.navercorp.pinpoint.profiler.interceptor.registry.DefaultInterceptorRegistryBinder; +import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; +import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; +import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.util.CheckClassAdapter; +import org.objectweb.asm.util.TraceClassVisitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +/** + * @author jaehong.kim + */ +public class MethodInterfaceTest { + private final static InterceptorRegistryBinder interceptorRegistryBinder = new DefaultInterceptorRegistryBinder(); + private final static InstrumentContext pluginContext = mock(InstrumentContext.class); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final ApiMetaDataService apiMetaDataService = mock(ApiMetaDataService.class); + + private final ObjectBinderFactory objectBinderFactory = mock(ObjectBinderFactory.class); + + @BeforeClass + public static void beforeClass() { + interceptorRegistryBinder.bind(); + } + + @AfterClass + public static void afterClass() { + interceptorRegistryBinder.unbind(); + } + + @Test + public void addInterceptor() throws Exception { + final String targetInterfaceName = "com.navercorp.test.pinpoint.jdk8.interfaces.MethodInterface"; + final String targetClassName = "com.navercorp.test.pinpoint.jdk8.interfaces.MethodInterfaceClass"; + logger.debug("Add interceptor interface={}, class={}", targetInterfaceName, targetClassName); + + final int interceptorId = interceptorRegistryBinder.getInterceptorRegistryAdaptor().addInterceptor(new SimpleInterceptor()); + final InterceptorDefinition interceptorDefinition = new InterceptorDefinitionFactory().createInterceptorDefinition(SimpleInterceptor.class); + final List methodNameList = Arrays.asList("currentTimeMillis", "foo"); + TestClassLoader classLoader = new TestClassLoader(); + classLoader.addTargetClassName(targetClassName); + classLoader.addTargetClassName(targetInterfaceName); + classLoader.setCallbackHandler(new CallbackHandler() { + @Override + public void handle(ClassNode classNode) { + List methodNodes = classNode.methods; + for (MethodNode methodNode : methodNodes) { + logger.debug("Handle class={}, method={}", classNode.name, methodNode.name); + if (methodNode.name.equals("")) { + continue; + } + + ASMMethodNodeAdapter methodNodeAdapter = new ASMMethodNodeAdapter(classNode.name, methodNode); + if (methodNodeAdapter.isAbstract() || methodNodeAdapter.isNative()) { + continue; + } + + if (!methodNameList.contains(methodNode.name)) { + continue; + } + methodNodeAdapter.addBeforeInterceptor(interceptorId, interceptorDefinition, 99); + logger.debug("Add before interceptor in method={}", methodNode.name); + methodNodeAdapter.addAfterInterceptor(interceptorId, interceptorDefinition, 99); + logger.debug("Add after interceptor in method={}", methodNode.name); + } + } + }); + + // static method + Assert.assertFalse(SimpleInterceptor.before); + logger.debug("Interface static method"); + Class clazz = classLoader.loadClass(targetInterfaceName); + Method method = clazz.getDeclaredMethod("currentTimeMillis"); + method.invoke(null); + assertTrue(SimpleInterceptor.before); + + // reset + SimpleInterceptor.before = false; + + // default method + Assert.assertFalse(SimpleInterceptor.before); + logger.debug("Interface default method"); + clazz = classLoader.loadClass(targetClassName); + method = clazz.getDeclaredMethod("bar"); + method.invoke(clazz.newInstance()); + assertTrue(SimpleInterceptor.before); + } + + @Test(expected = ClassFormatError.class) + public void addField() throws Exception { + final String targetInterfaceName = "com.navercorp.test.pinpoint.jdk8.interfaces.MethodInterface"; + final String targetClassName = "com.navercorp.test.pinpoint.jdk8.interfaces.MethodInterfaceClass"; + final String accessorClassName = "com.navercorp.test.pinpoint.jdk8.interfaces.SimpleAccessor"; + TestClassLoader classLoader = new TestClassLoader(); + classLoader.addTargetClassName(targetClassName); + classLoader.addTargetClassName(targetInterfaceName); + classLoader.setTrace(false); + classLoader.setCallbackHandler(new CallbackHandler() { + @Override + public void handle(ClassNode classNode) { + logger.debug("Add field class={}", classNode.name); + ASMClassNodeAdapter classNodeAdapter = new ASMClassNodeAdapter(pluginContext, null, classNode); + classNodeAdapter.addField("_$PINPOINT$_" + JavaAssistUtils.javaClassNameToVariableName(accessorClassName), Type.getDescriptor(int.class)); + classNodeAdapter.addInterface(accessorClassName); + ASMFieldNodeAdapter fieldNodeAdapter = classNodeAdapter.getField("_$PINPOINT$_" + JavaAssistUtils.javaClassNameToVariableName(accessorClassName), null); + classNodeAdapter.addGetterMethod("_$PINPOINT$_getTraceInt", fieldNodeAdapter); + classNodeAdapter.addSetterMethod("_$PINPOINT$_setTraceInt", fieldNodeAdapter); + } + }); + logger.debug("Interface static method"); + Class clazz = classLoader.loadClass(targetInterfaceName); + Method method = clazz.getDeclaredMethod("currentTimeMillis"); + method.invoke(null); + } + + @Test + public void addMethod() throws Exception { + final MethodNode methodNode = TestClassLoader.get("com.navercorp.test.pinpoint.jdk8.interfaces.SimpleClass", "welcome"); + final ASMMethodNodeAdapter methodNodeAdapter = new ASMMethodNodeAdapter("com/navercorp/test/pinpoint/jdk8/interfaces/SimpleClass", methodNode); + + final String targetInterfaceName = "com.navercorp.test.pinpoint.jdk8.interfaces.MethodInterface"; + TestClassLoader classLoader = new TestClassLoader(); + classLoader.addTargetClassName(targetInterfaceName); + classLoader.setTrace(false); + classLoader.setCallbackHandler(new CallbackHandler() { + @Override + public void handle(ClassNode classNode) { + logger.debug("Add method class={}", classNode.name); + ASMClassNodeAdapter classNodeAdapter = new ASMClassNodeAdapter(pluginContext, null, classNode); + classNodeAdapter.copyMethod(methodNodeAdapter); + } + }); + logger.debug("Interface static method"); + Class clazz = classLoader.loadClass(targetInterfaceName); + Method method = clazz.getDeclaredMethod("welcome"); + method.invoke(null); + } + + @Test + public void isInterceptable() throws Exception { + ClassNode classNode = TestClassLoader.get("com.navercorp.test.pinpoint.jdk8.interfaces.MethodInterface"); + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + EngineComponent engineComponent = mock(EngineComponent.class); + ASMClass clazz = new ASMClass(engineComponent, pluginContext, classLoader, classNode); + assertTrue(clazz.isInterceptable()); + } + + public static class TestClassLoader extends ClassLoader { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private List targetClassNameList = new ArrayList<>(); + private CallbackHandler callbackHandler; + private boolean trace; + private boolean verify; + + public void addTargetClassName(String targetClassName) { + this.targetClassNameList.add(targetClassName); + } + + public void setCallbackHandler(CallbackHandler callbackHandler) { + this.callbackHandler = callbackHandler; + } + + public void setTrace(boolean trace) { + this.trace = trace; + } + + public void setVerify(boolean verify) { + this.verify = verify; + } + + // only use for test. + public static ClassNode get(final String className) throws Exception { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + ClassReader cr = new ClassReader(classLoader.getResourceAsStream(JavaAssistUtils.javaNameToJvmName(className) + ".class")); + ClassNode classNode = new ClassNode(); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + + return classNode; + } + + public static MethodNode get(final String classInternalName, final String methodName) throws Exception { + ClassNode classNode = get(classInternalName); + List methodNodes = classNode.methods; + for (MethodNode methodNode : methodNodes) { + if (methodNode.name.equals(methodName)) { + return methodNode; + } + } + return null; + } + + @Override + public Class loadClass(final String name) throws ClassNotFoundException { + logger.debug("TestClassLoader.loadClass " + name); + if (targetClassNameList.contains(name)) { + try { + ClassNode classNode = get(JavaAssistUtils.javaNameToJvmName(name)); + final int majorVersion = classNode.version & 0xFFFF; + logger.debug("Version {}, {}", classNode.version, majorVersion); + //classNode.version = 50; + if (this.trace) { + logger.debug("Trace original #############################################################"); + ASMClassWriter cw = new ASMClassWriter(pluginContext, 0, null); + TraceClassVisitor tcv = new TraceClassVisitor(cw, new PrintWriter(System.out)); + classNode.accept(tcv); + } + + if (callbackHandler != null) { + callbackHandler.handle(classNode); + } + + ASMClassWriter cw = new ASMClassWriter(pluginContext, ClassWriter.COMPUTE_FRAMES, null); + if (this.trace) { + logger.debug("## Trace modified #############################################################"); + TraceClassVisitor tcv = new TraceClassVisitor(cw, new PrintWriter(System.out)); + classNode.accept(tcv); + } else { + classNode.accept(cw); + } + byte[] bytecode = cw.toByteArray(); + if (this.verify) { + CheckClassAdapter.verify(new ClassReader(bytecode), false, new PrintWriter(System.out)); + } + logger.debug("TestClassLoader.defineClass name={}, length={}", name, bytecode.length); + return super.defineClass(name, bytecode, 0, bytecode.length); + } catch (Exception ex) { + throw new ClassNotFoundException("Load error: " + ex.toString(), ex); + } + } + logger.debug("Super.loadClass " + name); + return super.loadClass(name); + } + } + + public interface CallbackHandler { + void handle(ClassNode classNode); + } +} \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleAccessor.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleAccessor.java new file mode 100644 index 000000000000..4cb7ec8f73ad --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleAccessor.java @@ -0,0 +1,25 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.jdk8.interfaces; + +/** + * @author jaehong.kim + */ +public interface SimpleAccessor { + void _$PINPOINT$_setTraceInt(int value); + int _$PINPOINT$_getTraceInt(); +} \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleClass.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleClass.java new file mode 100644 index 000000000000..2214b2557e8c --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleClass.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.jdk8.interfaces; + +/** + * @author jaehong.kim + */ +public class SimpleClass { + + public static void welcome() { + System.out.println("Welcome"); + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleInterceptor.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleInterceptor.java new file mode 100644 index 000000000000..53a1a0aa273f --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleInterceptor.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.jdk8.interfaces; + +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; + +import java.util.Arrays; + +/** + * @author jaehong.kim + */ +public class SimpleInterceptor implements AroundInterceptor { + + public static boolean before; + public static boolean after; + public static Object beforeTarget; + public static Object[] beforeArgs; + public static Object afterTarget; + public static Object[] afterArgs; + public static Object result; + public static Throwable throwable; + + public static void clear() { + before = false; + after = false; + beforeTarget = null; + beforeArgs = null; + afterTarget = null; + afterArgs = null; + result = null; + throwable = null; + } + + @Override + public void before(Object target, Object[] args) { + this.before = true; + this.beforeTarget = target; + this.beforeArgs = args; + System.out.println("before target=" + target + ", args=" + toArgs(args)); + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + this.after = true; + this.afterTarget = target; + this.afterArgs = args; + this.result = result; + this.throwable = throwable; + System.out.println("after target=" + target + ", args=" + toArgs(args) + ", result=" + result + ", throwable=" + throwable); + } + + private String toArgs(Object[] args) { + if (args == null) { + return "null"; + } + + return Arrays.asList(args).toString(); + } +} \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleInterface.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleInterface.java new file mode 100644 index 000000000000..ef2c9d198ed7 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleInterface.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.jdk8.interfaces; + +/** + * @author jaehong.kim + */ +public interface SimpleInterface { + String foo(); +} diff --git a/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleInterfaceClass.java b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleInterfaceClass.java new file mode 100644 index 000000000000..7f196c613721 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/java/com/navercorp/test/pinpoint/jdk8/interfaces/SimpleInterfaceClass.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.test.pinpoint.jdk8.interfaces; + +/** + * @author jaehong.kim + */ +public class SimpleInterfaceClass implements SimpleInterface { + @Override + public String foo() { + return "foo"; + } +} diff --git a/profiler-optional/profiler-optional-jdk8/src/test/resources/log4j.xml b/profiler-optional/profiler-optional-jdk8/src/test/resources/log4j.xml new file mode 100644 index 000000000000..e26c5cff1277 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk8/src/test/resources/log4j.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk9/.gitignore b/profiler-optional/profiler-optional-jdk9/.gitignore new file mode 100644 index 000000000000..31dc463a2a2b --- /dev/null +++ b/profiler-optional/profiler-optional-jdk9/.gitignore @@ -0,0 +1,5 @@ +/.settings/ +/*.iml +/.project +/target/ +/.classpath diff --git a/profiler-optional/profiler-optional-jdk9/pom.xml b/profiler-optional/profiler-optional-jdk9/pom.xml new file mode 100644 index 000000000000..164688df03dd --- /dev/null +++ b/profiler-optional/profiler-optional-jdk9/pom.xml @@ -0,0 +1,137 @@ + + + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint-profiler-optional-parent + ../profiler-optional-parent + 1.8.1-SNAPSHOT + + + pinpoint-profiler-optional-jdk9 + pinpoint-profiler-optional-jdk9 + jar + pinpoint profiler optional package for jdk 9 + + + 9 + ${env.JAVA_9_HOME} + + + + + com.navercorp.pinpoint + pinpoint-test + test + + + org.springframework + spring-test + test + + + org.springframework + spring-context + test + + + commons-io + commons-io + test + + + + + org.openclover + clover + 4.2.1 + test + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + ${plugin.animal-sniffer.version} + + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${jdk.version} + ${jdk.version} + true + true + true + ${encoding} + true + ${jdk.version} + ${jdk.home}/bin/javac + + --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${plugin.surefire.version} + + + **/Mock* + **/Abstract* + **/*Helper + **/*$* + + + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED + -Dfile.encoding=${encoding} + + ${test.jdk.home}/bin/java + once + + + + + + + org.openclover + clover-maven-plugin + + + + ${plugin.clover.version} + + true + + + + + + \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk9/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/Java9DefineClass.java b/profiler-optional/profiler-optional-jdk9/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/Java9DefineClass.java new file mode 100644 index 000000000000..42b662ca90b8 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk9/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/Java9DefineClass.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.classloading; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +final class Java9DefineClass implements DefineClass { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public final Class defineClass(ClassLoader classLoader, String name, byte[] bytes) { + if (logger.isDebugEnabled()) { + logger.debug("define class:{} cl:{}", name, classLoader); + } + return jdk.internal.misc.SharedSecrets.getJavaLangAccess().defineClass(classLoader, name, bytes, null, null); + } +} diff --git a/profiler-optional/profiler-optional-jdk9/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/Java9DefineClassTest.java b/profiler-optional/profiler-optional-jdk9/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/Java9DefineClassTest.java new file mode 100644 index 000000000000..0cbafa2dab5a --- /dev/null +++ b/profiler-optional/profiler-optional-jdk9/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/Java9DefineClassTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.classloading; + +import com.navercorp.pinpoint.common.util.CodeSourceUtils; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * @author Woonduk Kang(emeroad) + */ +public class Java9DefineClassTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void defineClass() throws ClassNotFoundException, IOException { + URL location = CodeSourceUtils.getCodeLocation(Logger.class); + logger.debug("location:{}", location); + + URL[] empty = {}; + URLClassLoader classLoader = new URLClassLoader(empty, null); + try { + classLoader.loadClass(Logger.class.getName()); + Assert.fail(); + } catch (ClassNotFoundException ignore) { + } + + String className = JavaAssistUtils.javaClassNameToJvmResourceName(Logger.class.getName()); + InputStream classStream = Logger.class.getClassLoader().getResourceAsStream(className); + byte[] bytes = IOUtils.readFully(classStream, classStream.available()); + + DefineClass defineClass = new Java9DefineClass(); + Class defineClassSlf4jLogger = defineClass.defineClass(classLoader, Logger.class.getName(), bytes); + Class slf4jLogger = classLoader.loadClass(Logger.class.getName()); + + Assert.assertSame(defineClassSlf4jLogger, slf4jLogger); + Assert.assertSame(slf4jLogger.getClassLoader(), classLoader); + + Assert.assertNotSame(slf4jLogger.getClassLoader(), Logger.class.getClassLoader()); + + } + +} \ No newline at end of file diff --git a/profiler-optional/profiler-optional-jdk9/src/test/resources/log4j.xml b/profiler-optional/profiler-optional-jdk9/src/test/resources/log4j.xml new file mode 100644 index 000000000000..e26c5cff1277 --- /dev/null +++ b/profiler-optional/profiler-optional-jdk9/src/test/resources/log4j.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/profiler-optional/profiler-optional-parent/clover.license b/profiler-optional/profiler-optional-parent/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/profiler-optional/profiler-optional-parent/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkFcom.navercorp.pinpoint pinpoint ../.. - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-profiler-optional-parent diff --git a/profiler-test/clover.license b/profiler-test/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/profiler-test/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-profiler-test @@ -15,27 +31,6 @@ com.navercorp.pinpoint pinpoint-commons - - - org.apache.thrift - libthrift - - - org.slf4j - slf4j-api - - - - - com.navercorp.pinpoint - pinpoint-commons-server - provided - - - com.navercorp.pinpoint - pinpoint-commons-hbase - - com.navercorp.pinpoint @@ -102,13 +97,22 @@ - org.javassist - javassist + org.ow2.asm + asm org.ow2.asm - asm-debug-all + asm-commons + + org.ow2.asm + asm-util + + + org.ow2.asm + asm-tree + + org.apache.thrift diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/CompressingStorageDecorator.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/CompressingStorageDecorator.java deleted file mode 100644 index 29cee0186598..000000000000 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/CompressingStorageDecorator.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.test; - -import com.navercorp.pinpoint.profiler.context.Span; -import com.navercorp.pinpoint.profiler.context.SpanEvent; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressor; -import com.navercorp.pinpoint.profiler.context.storage.Storage; - -import java.util.Collections; - -/** - * @author HyunGil Jeong - */ -public class CompressingStorageDecorator implements Storage { - - private final Storage delegate; - private final SpanEventCompressor spanEventCompressor; - - public CompressingStorageDecorator(Storage delegate, SpanEventCompressor spanEventCompressor) { - if (delegate == null) { - throw new NullPointerException("delegate must not be null"); - } - if (spanEventCompressor == null) { - throw new NullPointerException("spanEventCompressor must not be null"); - } - this.delegate = delegate; - this.spanEventCompressor = spanEventCompressor; - } - - @Override - public void store(SpanEvent spanEvent) { - if (spanEvent == null) { - throw new NullPointerException("spanEvent must not be null"); - } - long keyTime = spanEvent.getTraceRoot().getTraceStartTime(); - spanEventCompressor.compress(Collections.singletonList(spanEvent), keyTime); - delegate.store(spanEvent); - } - - @Override - public void store(Span span) { - if (span == null) { - throw new NullPointerException("span must not be null"); - } - delegate.store(span); - } - - @Override - public void flush() { - delegate.flush(); - } - - @Override - public void close() { - delegate.close(); - } -} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/EmptyListener.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/EmptyListener.java new file mode 100644 index 000000000000..3c19911e83a6 --- /dev/null +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/EmptyListener.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test; + +/** + * @author Woonduk Kang(emeroad) + */ +public class EmptyListener implements ListenableDataSender.Listener { + @Override + public boolean handleSend(T data) { + return true; + } + + @Override + public String toString() { + return "EMPTY_LISTENER"; + } +}; \ No newline at end of file diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/InterceptorRegistryModule.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/InterceptorRegistryModule.java new file mode 100644 index 000000000000..66dc5848001b --- /dev/null +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/InterceptorRegistryModule.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test; + +import com.google.inject.AbstractModule; +import com.google.inject.Module; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; + +/** + * @author Woonduk Kang(emeroad) + */ +public class InterceptorRegistryModule extends AbstractModule { + private final InterceptorRegistryBinder interceptorRegistryBinder; + + public static Module wrap(InterceptorRegistryBinder interceptorRegistryBinder) { + return new InterceptorRegistryModule(interceptorRegistryBinder); + } + + private InterceptorRegistryModule(InterceptorRegistryBinder interceptorRegistryBinder) { + this.interceptorRegistryBinder = Assert.requireNonNull(interceptorRegistryBinder, "interceptorRegistryBinder must not be null"); + } + + @Override + protected void configure() { + bind(InterceptorRegistryBinder.class).toInstance(interceptorRegistryBinder); + } +} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/Item.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/Item.java new file mode 100644 index 000000000000..00c399e97247 --- /dev/null +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/Item.java @@ -0,0 +1,138 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test; + +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; + +/** + * @author Woonduk Kang(emeroad) + */ +public class Item implements Comparable { + + private final Object value; + private final long time; + private final long spanId; + private final int sequence; + private final int asyncId; + private final int asyncSequence; + private final TraceRoot traceRoot; + + public Item(Object value, long time, TraceRoot traceRoot, int sequence) { + this(value, time, traceRoot, sequence, OrderedSpanRecorder.ASYNC_ID_NOT_SET, OrderedSpanRecorder.ASYNC_SEQUENCE_NOT_SET); + } + + public Item(Object value, long time, TraceRoot traceRoot, int sequence, int asyncId, int asyncSequence) { + this.value = value; + this.time = time; + this.traceRoot = traceRoot; + this.spanId = traceRoot.getTraceId().getSpanId(); + this.sequence = sequence; + this.asyncId = asyncId; + this.asyncSequence = asyncSequence; + } + + public Object getValue() { + return value; + } + + public long getSpanId() { + return spanId; + } + + public TraceRoot getTraceRoot() { + return traceRoot; + } + + @Override + public int compareTo(Item o) { + if (this.asyncId == OrderedSpanRecorder.ASYNC_ID_NOT_SET && o.asyncId == OrderedSpanRecorder.ASYNC_ID_NOT_SET) { + return compareItems(this, o); + } else if (this.asyncId != OrderedSpanRecorder.ASYNC_ID_NOT_SET && o.asyncId != OrderedSpanRecorder.ASYNC_ID_NOT_SET) { + return compareAsyncItems(this, o); + } else { + if (this.asyncId == OrderedSpanRecorder.ASYNC_ID_NOT_SET) { + return -1; + } else { + return 1; + } + } + } + + private static int compareItems(Item lhs, Item rhs) { + if (lhs.time < rhs.time) { + return -1; + } else if (lhs.time > rhs.time) { + return 1; + } else { + if (lhs.spanId < rhs.spanId) { + return -1; + } else if (lhs.spanId > rhs.spanId) { + return 1; + } else { + if (lhs.sequence < rhs.sequence) { + return -1; + } else if (lhs.sequence > rhs.sequence) { + return 1; + } else { + return compareHashes(lhs, rhs); + } + } + } + } + + private static int compareAsyncItems(Item lhs, Item rhs) { + if (lhs.asyncId < rhs.asyncId) { + return -1; + } else if (lhs.asyncId > rhs.asyncId) { + return 1; + } else { + if (lhs.asyncSequence < rhs.asyncSequence) { + return -1; + } else if (lhs.asyncSequence > rhs.asyncSequence) { + return 1; + } else { + if (lhs.sequence < rhs.sequence) { + return -1; + } else if (lhs.sequence > rhs.sequence) { + return 1; + } else { + return compareHashes(lhs, rhs); + } + } + } + } + + private static int compareHashes(Item lhs, Item rhs) { + int h1 = System.identityHashCode(lhs.value); + int h2 = System.identityHashCode(rhs.value); + + return h1 < h2 ? -1 : (h1 > h2 ? 1 : 0); + } + + @Override + public String toString() { + return "Item{" + + "value=" + value + + ", time=" + time + + ", spanId=" + spanId + + ", sequence=" + sequence + + ", asyncId=" + asyncId + + ", asyncSequence=" + asyncSequence + + ", traceRoot=" + traceRoot + + '}'; + } +} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/ListenableDataSender.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/ListenableDataSender.java index da9c149a897f..90bdfe101aae 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/ListenableDataSender.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/ListenableDataSender.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,27 +17,14 @@ package com.navercorp.pinpoint.test; import com.navercorp.pinpoint.profiler.sender.DataSender; -import org.apache.thrift.TBase; /** * @author emeroad */ -public class ListenableDataSender> implements DataSender { - - private static final Listener DEFAULT_LISTENER = new Listener() { - @Override - public boolean handleSend(TBase data) { - return true; - } - - @Override - public String toString() { - return "EMPTY_LISTENER"; - } - }; +public class ListenableDataSender implements DataSender { private final String name; - private volatile Listener listener = DEFAULT_LISTENER; + private volatile Listener listener = new EmptyListener(); public ListenableDataSender(String name) { this.name = name; @@ -48,7 +35,7 @@ public void setListener(Listener listener) { } @Override - public boolean send(TBase data) { + public boolean send(T data) { return listener.handleSend(data); } @@ -60,8 +47,8 @@ public Listener getListener() { public void stop() { } - public interface Listener { - boolean handleSend(TBase data); + public interface Listener { + boolean handleSend(T data); } @Override diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContext.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContext.java deleted file mode 100644 index f78a92461b2f..000000000000 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContext.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.test; - - -import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; - -import com.navercorp.pinpoint.bootstrap.AgentOption; -import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; - -/** - * @author emeroad - * @author koo.taejin - * @author hyungil.jeong - */ -public class MockApplicationContext extends DefaultApplicationContext { - private final InterceptorRegistryBinder interceptorRegistryBinder; - - - public MockApplicationContext(AgentOption agentOption, InterceptorRegistryBinder binder, ModuleFactory moduleFactory) { - super(agentOption, binder, moduleFactory); - - if (binder == null) { - throw new NullPointerException("binder must not be null"); - } - this.interceptorRegistryBinder = binder; - } - - @Override - public void close() { - super.close(); - - if (this.interceptorRegistryBinder != null) { - interceptorRegistryBinder.unbind(); - } - } -} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContextFactory.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContextFactory.java index 01792ea2c6fb..512726380b9e 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContextFactory.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContextFactory.java @@ -17,23 +17,19 @@ package com.navercorp.pinpoint.test; import com.google.inject.Module; -import com.google.inject.util.Modules; import com.navercorp.pinpoint.bootstrap.AgentOption; import com.navercorp.pinpoint.bootstrap.DefaultAgentOption; import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; -import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.profiler.context.module.ApplicationContextModule; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; import java.io.IOException; import java.lang.instrument.Instrumentation; import java.net.URL; +import java.util.Collections; /** * @author Woonduk Kang(emeroad) @@ -43,9 +39,9 @@ public class MockApplicationContextFactory { public MockApplicationContextFactory() { } - public MockApplicationContext of(String configPath) { - ProfilerConfig profilerConfig = readProfilerConfig(configPath, MockApplicationContext.class.getClassLoader()); - return of(profilerConfig); + public DefaultApplicationContext build(String configPath) { + ProfilerConfig profilerConfig = readProfilerConfig(configPath, this.getClass().getClassLoader()); + return build(profilerConfig); } private ProfilerConfig readProfilerConfig(String configPath, ClassLoader classLoader) { @@ -72,38 +68,28 @@ private String getFilePath(ClassLoader classLoader, String configPath) { return resource.getPath(); } - public MockApplicationContext of(ProfilerConfig config) { - InterceptorRegistryBinder binder = new TestInterceptorRegistryBinder(); - binder.bind(); - return of(config, binder, newModuleFactory()); + public DefaultApplicationContext build(ProfilerConfig config) { + DefaultApplicationContext context = build(config, newModuleFactory()); + return context; } - public MockApplicationContext of(ProfilerConfig config, InterceptorRegistryBinder binder, ModuleFactory moduleFactory) { + public DefaultApplicationContext build(ProfilerConfig config, ModuleFactory moduleFactory) { Instrumentation instrumentation = new DummyInstrumentation(); String mockAgent = "mockAgent"; String mockApplicationName = "mockApplicationName"; - ServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(); - AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(); - - AgentOption agentOption = new DefaultAgentOption(instrumentation, mockAgent, mockApplicationName, config, new URL[0], - null, serviceTypeRegistryService, annotationKeyRegistryService); - return new MockApplicationContext(agentOption, binder, moduleFactory); + AgentOption agentOption = new DefaultAgentOption(instrumentation, mockAgent, mockApplicationName, false, config, Collections.emptyList(), + null); + return new DefaultApplicationContext(agentOption, moduleFactory); } - public ModuleFactory newModuleFactory() { - - ModuleFactory moduleFactory = new ModuleFactory() { - @Override - public Module newModule(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) { + private ModuleFactory newModuleFactory() { + Module pluginModule = new MockApplicationContextModule(); - Module module = new ApplicationContextModule(agentOption, interceptorRegistryBinder); - Module pluginModule = new MockApplicationContextModule(); - - return Modules.override(module).with(pluginModule); - } - }; + InterceptorRegistryBinder binder = new TestInterceptorRegistryBinder(); + Module interceptorRegistryModule = InterceptorRegistryModule.wrap(binder); + ModuleFactory moduleFactory = new OverrideModuleFactory(pluginModule, interceptorRegistryModule); return moduleFactory; } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContextModule.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContextModule.java index 51bec0edd182..93852e4b32be 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContextModule.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockApplicationContextModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,14 @@ import com.google.inject.AbstractModule; import com.google.inject.Scopes; +import com.google.inject.TypeLiteral; import com.google.inject.util.Providers; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.common.plugin.ServerPluginLoader; +import com.navercorp.pinpoint.common.util.ClassLoaderUtils; import com.navercorp.pinpoint.profiler.context.DefaultServerMetaDataRegistryService; import com.navercorp.pinpoint.profiler.context.ServerMetaDataRegistryService; +import com.navercorp.pinpoint.profiler.context.TraceDataFormatVersion; import com.navercorp.pinpoint.profiler.context.module.SpanDataSender; import com.navercorp.pinpoint.profiler.context.module.StatDataSender; import com.navercorp.pinpoint.profiler.context.storage.StorageFactory; @@ -49,55 +54,36 @@ public MockApplicationContextModule() { @Override protected void configure() { - final DataSender spanDataSender = newUdpSpanDataSender(); + final DataSender spanDataSender = new ListenableDataSender>("SpanDataSender"); logger.debug("spanDataSender:{}", spanDataSender); bind(DataSender.class).annotatedWith(SpanDataSender.class).toInstance(spanDataSender); - final DataSender statDataSender = newUdpStatDataSender(); + final DataSender statDataSender = new ListenableDataSender>("StatDataSender"); logger.debug("statDataSender:{}", statDataSender); bind(DataSender.class).annotatedWith(StatDataSender.class).toInstance(statDataSender); - StorageFactory storageFactory = newStorageFactory(spanDataSender); - logger.debug("spanFactory:{}", spanDataSender); - bind(StorageFactory.class).toInstance(storageFactory); + bind(TraceDataFormatVersion.class).toInstance(TraceDataFormatVersion.V1); + bind(StorageFactory.class).to(TestSpanStorageFactory.class); bind(PinpointClientFactory.class).toProvider(Providers.of((PinpointClientFactory)null)); - EnhancedDataSender enhancedDataSender = newTcpDataSender(); + EnhancedDataSender enhancedDataSender = new TestTcpDataSender(); logger.debug("enhancedDataSender:{}", enhancedDataSender); - bind(EnhancedDataSender.class).toInstance(enhancedDataSender); + TypeLiteral> dataSenderTypeLiteral = new TypeLiteral>() {}; + bind(dataSenderTypeLiteral).toInstance(enhancedDataSender); ServerMetaDataRegistryService serverMetaDataRegistryService = newServerMetaDataRegistryService(); bind(ServerMetaDataRegistryService.class).toInstance(serverMetaDataRegistryService); + bind(PluginLoader.class).toInstance(new ServerPluginLoader(ClassLoaderUtils.getDefaultClassLoader())); bind(PluginContextLoadResult.class).toProvider(MockPluginContextLoadResultProvider.class).in(Scopes.SINGLETON); } - protected DataSender newUdpStatDataSender() { - DataSender dataSender = new ListenableDataSender>("StatDataSender"); - return dataSender; - } - - - protected DataSender newUdpSpanDataSender() { - DataSender dataSender = new ListenableDataSender>("SpanDataSender"); - return dataSender; - } - - protected EnhancedDataSender newTcpDataSender() { - return new TestTcpDataSender(); - } - private ServerMetaDataRegistryService newServerMetaDataRegistryService() { List vmArgs = RuntimeMXBeanUtils.getVmArgs(); ServerMetaDataRegistryService serverMetaDataRegistryService = new DefaultServerMetaDataRegistryService(vmArgs); return serverMetaDataRegistryService; } - protected StorageFactory newStorageFactory(DataSender spanDataSender) { - logger.debug("newStorageFactory dataSender:{}", spanDataSender); - StorageFactory storageFactory = new SimpleSpanStorageFactory(spanDataSender); - return storageFactory; - } } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockPluginContextLoadResult.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockPluginContextLoadResult.java index 19568188ffc3..62c863bdce21 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockPluginContextLoadResult.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockPluginContextLoadResult.java @@ -18,6 +18,8 @@ import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; +import com.navercorp.pinpoint.common.plugin.Plugin; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; import com.navercorp.pinpoint.bootstrap.plugin.ApplicationTypeDetector; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; @@ -32,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.ServiceLoader; /** * @author Woonduk Kang(emeroad) @@ -40,23 +43,17 @@ public class MockPluginContextLoadResult implements PluginContextLoadResult { private final ProfilerConfig profilerConfig; private final InstrumentEngine instrumentEngine; private final DynamicTransformTrigger dynamicTransformTrigger; - + private final PluginLoader pluginLoader; private List lazy; - public MockPluginContextLoadResult(ProfilerConfig profilerConfig, InstrumentEngine instrumentEngine, DynamicTransformTrigger dynamicTransformTrigger) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (instrumentEngine == null) { - throw new NullPointerException("instrumentEngine must not be null"); - } - if (dynamicTransformTrigger == null) { - throw new NullPointerException("dynamicTransformTrigger must not be null"); - } - this.profilerConfig = profilerConfig; - this.instrumentEngine = instrumentEngine; - this.dynamicTransformTrigger = dynamicTransformTrigger; + public MockPluginContextLoadResult(ProfilerConfig profilerConfig, InstrumentEngine instrumentEngine, + DynamicTransformTrigger dynamicTransformTrigger, PluginLoader pluginLoader) { + + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.instrumentEngine = Assert.requireNonNull(instrumentEngine, "instrumentEngine must not be null"); + this.dynamicTransformTrigger = Assert.requireNonNull(dynamicTransformTrigger, "dynamicTransformTrigger must not be null"); + this.pluginLoader = Assert.requireNonNull(pluginLoader, "pluginLoader must not be null"); } private List getProfilerPluginContextList() { @@ -66,17 +63,17 @@ private List getProfilerPluginContextList() { return lazy; } - private List load() { - - List plugins = PluginLoader.load(ProfilerPlugin.class, ClassLoader.getSystemClassLoader()); + List> plugins = pluginLoader.load(ProfilerPlugin.class); List pluginContexts = new ArrayList(); ClassInjector classInjector = new TestProfilerPluginClassLoader(); PluginSetup pluginSetup = new MockPluginSetup(profilerConfig, instrumentEngine, dynamicTransformTrigger); - for (ProfilerPlugin plugin : plugins) { - SetupResult context = pluginSetup.setupPlugin(plugin, classInjector); - pluginContexts.add(context); + for (Plugin plugin : plugins) { + for (ProfilerPlugin profilerPlugin : plugin.getInstanceList()) { + SetupResult context = pluginSetup.setupPlugin(profilerPlugin, classInjector); + pluginContexts.add(context); + } } return pluginContexts; } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockPluginContextLoadResultProvider.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockPluginContextLoadResultProvider.java index db5f698e8d6f..60038542c140 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockPluginContextLoadResultProvider.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/MockPluginContextLoadResultProvider.java @@ -20,6 +20,8 @@ import com.google.inject.Provider; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; import com.navercorp.pinpoint.profiler.plugin.PluginContextLoadResult; @@ -31,26 +33,20 @@ public class MockPluginContextLoadResultProvider implements Provider> { - private static final int ROOT_SEQUENCE = -1; - private static final int ASYNC_ID_NOT_SET = -1; - private static final int ASYNC_SEQUENCE_NOT_SET = -1; +public class OrderedSpanRecorder implements ListenableDataSender.Listener, Iterable { + public static final int ROOT_SEQUENCE = -1; + public static final int ASYNC_ID_NOT_SET = -1; + public static final int ASYNC_SEQUENCE_NOT_SET = -1; private final List list = new ArrayList(); - private static final class Item implements Comparable { - - private final TBase value; - private final long time; - private final long spanId; - private final int sequence; - private final int asyncId; - private final int asyncSequence; - - public Item(TBase value, long time, long spanId, int sequence) { - this(value, time, spanId, sequence, ASYNC_ID_NOT_SET, ASYNC_SEQUENCE_NOT_SET); - } - - public Item(TBase value, long time, long spanId, int sequence, int asyncId, int asyncSequence) { - this.value = value; - this.time = time; - this.spanId = spanId; - this.sequence = sequence; - this.asyncId = asyncId; - this.asyncSequence = asyncSequence; - } - - @Override - public int compareTo(Item o) { - if (this.asyncId == ASYNC_ID_NOT_SET && o.asyncId == ASYNC_ID_NOT_SET) { - return compareItems(this, o); - } else if (this.asyncId != ASYNC_ID_NOT_SET && o.asyncId != ASYNC_ID_NOT_SET) { - return compareAsyncItems(this, o); - } else { - if (this.asyncId == ASYNC_ID_NOT_SET) { - return -1; - } else { - return 1; - } - } - } - - private static int compareItems(Item lhs, Item rhs) { - if (lhs.time < rhs.time) { - return -1; - } else if (lhs.time > rhs.time) { - return 1; - } else { - if (lhs.spanId < rhs.spanId) { - return -1; - } else if (lhs.spanId > rhs.spanId) { - return 1; - } else { - if (lhs.sequence < rhs.sequence) { - return -1; - } else if (lhs.sequence > rhs.sequence) { - return 1; - } else { - return compareHashes(lhs, rhs); - } - } - } - } - - private static int compareAsyncItems(Item lhs, Item rhs) { - if (lhs.asyncId < rhs.asyncId) { - return -1; - } else if (lhs.asyncId > rhs.asyncId) { - return 1; - } else { - if (lhs.asyncSequence < rhs.asyncSequence) { - return -1; - } else if (lhs.asyncSequence > rhs.asyncSequence) { - return 1; - } else { - if (lhs.sequence < rhs.sequence) { - return -1; - } else if (lhs.sequence > rhs.sequence) { - return 1; - } else { - return compareHashes(lhs, rhs); - } - } - } - } - - private static int compareHashes(Item lhs, Item rhs) { - int h1 = System.identityHashCode(lhs.value); - int h2 = System.identityHashCode(rhs.value); - - return h1 < h2 ? -1 : (h1 > h2 ? 1 : 0); - } + public OrderedSpanRecorder() { } + @Override - public synchronized boolean handleSend(TBase data) { + public synchronized boolean handleSend(Object data) { + if (data instanceof Span) { insertSpan((Span) data); return true; - } else if (data instanceof SpanEvent) { - handleSpanEvent((SpanEvent) data); + } + if (data instanceof SpanChunk) { + handleSpanEvent((SpanChunk) data); return true; } - +// throw new IllegalStateException("unknown data type:" + data); return false; } + private void insertSpan(Span span) { long startTime = span.getStartTime(); - long spanId = span.getSpanId(); + TraceRoot traceRoot = span.getTraceRoot(); - insertItem(new Item(span, startTime, spanId, ROOT_SEQUENCE)); + Item item = new Item(span, startTime, traceRoot, ROOT_SEQUENCE); + insertItem(item); } private void insertItem(Item item) { @@ -159,26 +78,46 @@ private void insertItem(Item item) { list.add(index, item); } - private void handleSpanEvent(SpanEvent event) { - TraceRoot span = event.getTraceRoot(); - int asyncId = event.isSetAsyncId() ? event.getAsyncId() : ASYNC_ID_NOT_SET; - TraceId traceId = span.getTraceId(); - int asyncSequence = event.isSetAsyncSequence() ? event.getAsyncSequence() : ASYNC_SEQUENCE_NOT_SET; - insertItem(new Item(event, span.getTraceStartTime() + event.getStartElapsed(), traceId.getSpanId(), event.getSequence(), asyncId, asyncSequence)); + private void handleSpanEvent(SpanChunk spanChunk) { + List spanEventList = spanChunk.getSpanEventList(); + for (SpanEvent event : spanEventList) { + final LocalAsyncId localAsyncId = event.getLocalAsyncId(); + int asyncId = ASYNC_ID_NOT_SET; + int asyncSequence = ASYNC_SEQUENCE_NOT_SET; + if (localAsyncId != null) { + asyncId = localAsyncId.getAsyncId(); + asyncSequence = localAsyncId.getSequence(); + } + + long startTime = event.getStartTime(); + Item item = new Item(event, startTime, spanChunk.getTraceRoot(), event.getSequence(), asyncId, asyncSequence); + insertItem(item); + } } - public synchronized TBase pop() { + public synchronized Object pop() { + final Item item = popItem(); + if (item == null) { + return null; + } + return item.getValue(); + } + + public synchronized Item popItem() { if (list.isEmpty()) { return null; } - return list.remove(0).value; + return list.remove(0); } public synchronized void print(PrintStream out) { out.println("TRACES(" + list.size() + "):"); - for (TBase obj : this) { + for (Item item : list) { + out.println(item); + } + for (Object obj : this) { out.println(obj); } } @@ -192,11 +131,11 @@ public synchronized int size() { } @Override - public synchronized Iterator> iterator() { + public synchronized Iterator iterator() { return new RecorderIterator(); } - private final class RecorderIterator implements Iterator> { + private final class RecorderIterator implements Iterator { private int current = -1; private int index = 0; @@ -208,11 +147,12 @@ public boolean hasNext() { } @Override - public TBase next() { + public Object next() { synchronized (OrderedSpanRecorder.this) { current = index; index++; - return list.get(current).value; + Item item = list.get(current); + return item.getValue(); } } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/OverrideModuleFactory.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/OverrideModuleFactory.java new file mode 100644 index 000000000000..76eef35c40d3 --- /dev/null +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/OverrideModuleFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test; + +import com.google.inject.Module; +import com.google.inject.util.Modules; +import com.navercorp.pinpoint.bootstrap.AgentOption; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.module.ApplicationContextModuleFactory; +import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class OverrideModuleFactory implements ModuleFactory { + private final Module[] overrideModule; + + public OverrideModuleFactory(Module... overrideModule) { + this.overrideModule = Assert.requireNonNull(overrideModule, "overrideModule must not be null"); + } + + @Override + public Module newModule(AgentOption agentOption) { + ModuleFactory moduleFactory = new ApplicationContextModuleFactory(); + Module module = moduleFactory.newModule(agentOption); + return Modules.override(module).with(overrideModule); + } +} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginApplicationContextModule.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginApplicationContextModule.java index d9fa237c8ac9..ed8eb8828de6 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginApplicationContextModule.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginApplicationContextModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,11 @@ package com.navercorp.pinpoint.test; import com.google.inject.AbstractModule; +import com.google.inject.TypeLiteral; import com.google.inject.util.Providers; -import com.navercorp.pinpoint.bootstrap.context.ServerMetaData; import com.navercorp.pinpoint.profiler.context.DefaultServerMetaDataRegistryService; import com.navercorp.pinpoint.profiler.context.ServerMetaDataRegistryService; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressor; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressorV1; +import com.navercorp.pinpoint.profiler.context.TraceDataFormatVersion; import com.navercorp.pinpoint.profiler.context.module.SpanDataSender; import com.navercorp.pinpoint.profiler.context.module.StatDataSender; import com.navercorp.pinpoint.profiler.context.storage.StorageFactory; @@ -43,10 +42,6 @@ public class PluginApplicationContextModule extends AbstractModule { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private TestTcpDataSender tcpDataSender; - private OrderedSpanRecorder orderedSpanRecorder; - private ServerMetaDataRegistryService serverMetaDataRegistryService; - public PluginApplicationContextModule() { } @@ -61,15 +56,15 @@ protected void configure() { logger.debug("statDataSender:{}", statDataSender); bind(DataSender.class).annotatedWith(StatDataSender.class).toInstance(statDataSender); - StorageFactory storageFactory = newStorageFactory(spanDataSender); - logger.debug("spanFactory:{}", spanDataSender); - bind(StorageFactory.class).toInstance(storageFactory); + bind(TraceDataFormatVersion.class).toInstance(TraceDataFormatVersion.V1); + bind(StorageFactory.class).to(TestSpanStorageFactory.class); bind(PinpointClientFactory.class).toProvider(Providers.of((PinpointClientFactory)null)); - EnhancedDataSender enhancedDataSender = newTcpDataSender(); + EnhancedDataSender enhancedDataSender = newTcpDataSender(); logger.debug("enhancedDataSender:{}", enhancedDataSender); - bind(EnhancedDataSender.class).toInstance(enhancedDataSender); + TypeLiteral> dataSenderTypeLiteral = new TypeLiteral>() {}; + bind(dataSenderTypeLiteral).toInstance(enhancedDataSender); ServerMetaDataRegistryService serverMetaDataRegistryService = newServerMetaDataRegistryService(); bind(ServerMetaDataRegistryService.class).toInstance(serverMetaDataRegistryService); @@ -85,39 +80,19 @@ private DataSender newUdpSpanDataSender() { ListenableDataSender> sender = new ListenableDataSender>("SpanDataSender"); OrderedSpanRecorder orderedSpanRecorder = new OrderedSpanRecorder(); sender.setListener(orderedSpanRecorder); - this.orderedSpanRecorder = orderedSpanRecorder; return sender; } - protected EnhancedDataSender newTcpDataSender() { + private EnhancedDataSender newTcpDataSender() { TestTcpDataSender tcpDataSender = new TestTcpDataSender(); - this.tcpDataSender = tcpDataSender; return tcpDataSender; } private ServerMetaDataRegistryService newServerMetaDataRegistryService() { List vmArgs = RuntimeMXBeanUtils.getVmArgs(); ServerMetaDataRegistryService serverMetaDataRegistryService = new DefaultServerMetaDataRegistryService(vmArgs); - this.serverMetaDataRegistryService = serverMetaDataRegistryService; return serverMetaDataRegistryService; } - protected StorageFactory newStorageFactory(DataSender spanDataSender) { - logger.debug("newStorageFactory dataSender:{}", spanDataSender); - SpanEventCompressor spanEventCompressor = new SpanEventCompressorV1(); - StorageFactory storageFactory = new SimpleSpanStorageFactory(spanDataSender, spanEventCompressor); - return storageFactory; - } - - public ServerMetaData getServerMetaData() { - return serverMetaDataRegistryService.getServerMetaData(); - } - - public TestTcpDataSender getTcpDataSender() { - return tcpDataSender; - } - public OrderedSpanRecorder getOrderedSpanRecorder() { - return orderedSpanRecorder; - } } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginTestAgent.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginTestAgent.java index d1dc028f2a0a..13feda28b2b5 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginTestAgent.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginTestAgent.java @@ -16,56 +16,13 @@ package com.navercorp.pinpoint.test; -import java.io.PrintStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; - -import com.google.inject.Module; -import com.google.inject.util.Modules; -import com.navercorp.pinpoint.bootstrap.context.ServerMetaData; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.common.util.AnnotationKeyUtils; -import com.navercorp.pinpoint.common.util.ArrayUtils; -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.profiler.context.id.Shared; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; import com.navercorp.pinpoint.profiler.context.module.ApplicationContext; -import com.navercorp.pinpoint.profiler.context.module.ApplicationContextModule; import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.google.common.base.Objects; import com.navercorp.pinpoint.bootstrap.AgentOption; -import com.navercorp.pinpoint.bootstrap.context.ServiceInfo; -import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; -import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedAnnotation; -import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedSql; -import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; -import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifierHolder; -import com.navercorp.pinpoint.bootstrap.plugin.test.TraceType; -import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.LoggingInfo; -import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.profiler.DefaultAgent; -import com.navercorp.pinpoint.profiler.context.Span; -import com.navercorp.pinpoint.profiler.context.SpanEvent; -import com.navercorp.pinpoint.profiler.interceptor.registry.DefaultInterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; -import com.navercorp.pinpoint.thrift.dto.TAnnotation; -import com.navercorp.pinpoint.thrift.dto.TIntStringStringValue; -import com.navercorp.pinpoint.thrift.dto.TIntStringValue; -import com.navercorp.pinpoint.thrift.dto.TSpan; -import com.navercorp.pinpoint.thrift.dto.TSpanEvent; /** * @author emeroad @@ -73,792 +30,29 @@ * @author hyungil.jeong * @author jaehong.kim */ -public class PluginTestAgent extends DefaultAgent implements PluginTestVerifier { - - - private AnnotationKeyRegistryService annotationKeyRegistryService; - - private final List ignoredServiceTypes = new ArrayList(); - - private PluginApplicationContextModule pluginApplicationContextModule; - +public class PluginTestAgent extends DefaultAgent { public PluginTestAgent(AgentOption agentOption) { - super(agentOption, new DefaultInterceptorRegistryBinder()); - this.annotationKeyRegistryService = agentOption.getAnnotationKeyRegistryService(); - PluginTestVerifierHolder.setInstance(this); - } - - @Override - protected ApplicationContext newApplicationContext(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) { - - this.pluginApplicationContextModule = new PluginApplicationContextModule(); - - final ModuleFactory moduleFactory = new ModuleFactory() { - @Override - public Module newModule(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) { - - Module module = new ApplicationContextModule(agentOption, interceptorRegistryBinder); - - return Modules.override(module).with(pluginApplicationContextModule); - } - }; - - ApplicationContext applicationContext = new DefaultApplicationContext(agentOption, interceptorRegistryBinder, moduleFactory); - return applicationContext; - - } - - @Override - public void verifyServerType(String serviceTypeName) { - final ApplicationContext applicationContext = getApplicationContext(); - - ServiceType expectedType = findServiceType(serviceTypeName); - ServiceType actualType = applicationContext.getAgentInformation().getServerType(); - - if (!expectedType.equals(actualType)) { - throw new AssertionError("ResolvedExpectedTrace server type: " + expectedType.getName() + "[" + expectedType.getCode() + "] but was " + actualType + "[" + actualType.getCode() + "]"); - } - } - - @Override - public void verifyServerInfo(String expected) { - String actualName = getServerMetaData().getServerInfo(); - - if (!actualName.equals(expected)) { - throw new AssertionError("ResolvedExpectedTrace server name [" + expected + "] but was [" + actualName + "]"); - } - } - - @Override - public void verifyConnector(String protocol, int port) { - Map connectorMap = getServerMetaData().getConnectors(); - String actualProtocol = connectorMap.get(port); - - if (actualProtocol == null || !actualProtocol.equals(protocol)) { - throw new AssertionError("ResolvedExpectedTrace protocol [" + protocol + "] at port [" + port + "] but was [" + actualProtocol + "]"); - } - } - - @Override - public void verifyService(String name, List libs) { - List serviceInfos = getServerMetaData().getServiceInfos(); - - for (ServiceInfo serviceInfo : serviceInfos) { - if (serviceInfo.getServiceName().equals(name)) { - List actualLibs = serviceInfo.getServiceLibs(); - - if (actualLibs.size() != libs.size()) { - throw new AssertionError("ResolvedExpectedTrace service [" + name + "] with libraries [" + libs + "] but was [" + actualLibs + "]"); - } - - for (String lib : libs) { - if (!actualLibs.contains(lib)) { - throw new AssertionError("ResolvedExpectedTrace service [" + name + "] with libraries [" + libs + "] but was [" + actualLibs + "]"); - } - } - - // OK - return; - } - } - - throw new AssertionError("ResolvedExpectedTrace service [" + name + "] with libraries [" + libs + "] but there is no such service"); - } - - private boolean isIgnored(Object obj) { - short serviceType = -1; - - if (obj instanceof TSpan) { - serviceType = ((TSpan) obj).getServiceType(); - } else if (obj instanceof TSpanEvent) { - serviceType = ((TSpanEvent) obj).getServiceType(); - } - - return ignoredServiceTypes.contains(serviceType); - } - - @Override - public void verifyTraceCount(int expected) { - int actual = 0; - - for (Object obj : getRecorder()) { - if (!isIgnored(obj)) { - actual++; - } - } - - if (expected != actual) { - throw new AssertionError("ResolvedExpectedTrace count: " + expected + ", actual: " + actual); - } - } - - private ServiceType findServiceType(String name) { - ServiceType serviceType = getServiceTypeRegistryService().findServiceTypeByName(name); - - if (serviceType == ServiceType.UNDEFINED) { - throw new AssertionError("No such service type: " + name); - } - - return serviceType; - } - - private Class resolveSpanClass(TraceType type) { - switch (type) { - case ROOT: - return Span.class; - case EVENT: - return SpanEvent.class; - } - - throw new IllegalArgumentException(type.toString()); - } - - @Override - public void verifyDiscreteTrace(ExpectedTrace... expectations) { - verifyDiscreteTraceBlock(expectations, null); - } - - public void verifyDiscreteTraceBlock(ExpectedTrace[] expectations, Integer asyncId) { - if (ArrayUtils.isEmpty(expectations)) { - throw new IllegalArgumentException("No expectations"); - } - - ExpectedTrace expected = expectations[0]; - ResolvedExpectedTrace resolved = resolveExpectedTrace(expected, asyncId); - - int i = 0; - Iterator iterator = getRecorder().iterator(); - - while (iterator.hasNext()) { - ActualTrace actual = wrap(iterator.next()); - - try { - verifySpan(resolved, actual); - } catch (AssertionError e) { - continue; - } - - iterator.remove(); - verifyAsyncTraces(expected, actual); - - if (++i == expectations.length) { - return; - } - - expected = expectations[i]; - resolved = resolveExpectedTrace(expected, asyncId); - } - - throw new AssertionError("Failed to match " + i + "th expectation: " + resolved); + super(agentOption); } @Override - public void verifyTrace(ExpectedTrace... expectations) { - if (ArrayUtils.isEmpty(expectations)) { - throw new IllegalArgumentException("No expectations"); - } + protected ApplicationContext newApplicationContext(AgentOption agentOption) { - for (ExpectedTrace expected : expectations) { - ResolvedExpectedTrace resolved = resolveExpectedTrace(expected, null); + PluginApplicationContextModule pluginApplicationContextModule = new PluginApplicationContextModule(); + ModuleFactory moduleFactory = new OverrideModuleFactory(pluginApplicationContextModule); + DefaultApplicationContext applicationContext = new DefaultApplicationContext(agentOption, moduleFactory); - final Object actual = popSpan(); - if (actual == null) { - throw new AssertionError("Expected a " + resolved.toString() + " but there is no trace"); - } + exportVerifier(applicationContext); - ActualTrace wrapped = wrap(actual); + return applicationContext ; - verifySpan(resolved, wrapped); - verifyAsyncTraces(expected, wrapped); - } } - private void verifyAsyncTraces(ExpectedTrace expected, ActualTrace wrapped) throws AssertionError { - ExpectedTrace[] asyncTraces = expected.getAsyncTraces(); - - if (asyncTraces != null && asyncTraces.length > 0) { - Integer asyncId = wrapped.getNextAsyncId(); - - if (asyncId == null) { - throw new AssertionError("Expected async traces triggered but nextAsyncId is not present: " + wrapped); - } - - verifyDiscreteTraceBlock(asyncTraces, asyncId); - } - } - - private ResolvedExpectedTrace resolveExpectedTrace(ExpectedTrace expected, Integer asyncId) throws AssertionError { - final ServiceType serviceType = findServiceType(expected.getServiceType()); - final Class spanClass = resolveSpanClass(expected.getType()); - final int apiId = getApiId(expected); - - return new ResolvedExpectedTrace(spanClass, serviceType, apiId, expected.getException(), expected.getRpc(), expected.getEndPoint(), expected.getRemoteAddr(), expected.getDestinationId(), expected.getAnnotations(), asyncId); + private void exportVerifier(DefaultApplicationContext applicationContext) { + PluginVerifierExternalAdaptor adaptor = new PluginVerifierExternalAdaptor(applicationContext); + PluginTestVerifierHolder.setInstance(adaptor); } - private int getApiId(ExpectedTrace expected) { - final Member method = expected.getMethod(); - if (method == null) { - if (expected.getMethodSignature() == null) { -// return null; - throw new RuntimeException("Method or MethodSignature is null"); - } else { - String methodSignature = expected.getMethodSignature(); - if (methodSignature.indexOf('(') != -1) { - methodSignature = MethodDescriptionUtils.toJavaMethodDescriptor(methodSignature); - } - return findApiId(methodSignature); - } - } else { - return findApiId(method); - } - } - - - @Override - public void ignoreServiceType(String... serviceTypes) { - for (String serviceType : serviceTypes) { - ServiceType t = findServiceType(serviceType); - ignoredServiceTypes.add(t.getCode()); - } - } - - private static void appendAnnotations(StringBuilder builder, List annotations) { - boolean first = true; - - if (annotations != null) { - for (TAnnotation a : annotations) { - if (first) { - first = false; - } else { - builder.append(", "); - } - - builder.append(toString(a)); - } - } - } - - private static String toString(TAnnotation a) { - return a.getKey() + "=" + a.getValue().getFieldValue(); - } - - private interface ActualTrace { - Short getServiceType(); - - Integer getApiId(); - - Integer getAsyncId(); - - Integer getNextAsyncId(); - - TIntStringValue getExceptionInfo(); - - String getRpc(); - - String getEndPoint(); - - String getRemoteAddr(); - - String getDestinationId(); - - List getAnnotations(); - - Class getType(); - } - - private static final class SpanFacade implements ActualTrace { - private final Span span; - - public SpanFacade(Span span) { - this.span = span; - } - - @Override - public Short getServiceType() { - return span.isSetServiceType() ? span.getServiceType() : null; - } - - @Override - public Integer getApiId() { - return span.isSetApiId() ? span.getApiId() : null; - } - - @Override - public Integer getAsyncId() { - return null; - } - - @Override - public Integer getNextAsyncId() { - return null; - } - - @Override - public TIntStringValue getExceptionInfo() { - return span.getExceptionInfo(); - } - - @Override - public String getRpc() { - return span.getRpc(); - } - - @Override - public String getEndPoint() { - return span.getEndPoint(); - } - - @Override - public String getRemoteAddr() { - return span.getRemoteAddr(); - } - - @Override - public String getDestinationId() { - return null; - } - - @Override - public List getAnnotations() { - return span.getAnnotations(); - } - - @Override - public Class getType() { - return Span.class; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("(serviceType: "); - builder.append(getServiceType()); - builder.append(", apiId: "); - builder.append(getApiId()); - builder.append(", exceptionInfo: "); - builder.append(getExceptionInfo()); - builder.append(", rpc: "); - builder.append(getRpc()); - builder.append(", endPoint: "); - builder.append(getEndPoint()); - builder.append(", remoteAddr: "); - builder.append(getRemoteAddr()); - builder.append(", ["); - appendAnnotations(builder, getAnnotations()); - builder.append("])"); - - return builder.toString(); - } - } - - private static final class SpanEventFacade implements ActualTrace { - private final SpanEvent span; - - public SpanEventFacade(SpanEvent span) { - this.span = span; - } - - @Override - public Short getServiceType() { - return span.isSetServiceType() ? span.getServiceType() : null; - } - - @Override - public Integer getApiId() { - return span.isSetApiId() ? span.getApiId() : null; - } - - @Override - public Integer getAsyncId() { - return span.isSetAsyncId() ? span.getAsyncId() : null; - } - - @Override - public Integer getNextAsyncId() { - return span.isSetNextAsyncId() ? span.getNextAsyncId() : null; - } - - @Override - public TIntStringValue getExceptionInfo() { - return span.getExceptionInfo(); - } - - @Override - public String getRpc() { - return span.getRpc(); - } - - @Override - public String getEndPoint() { - return span.getEndPoint(); - } - - @Override - public String getRemoteAddr() { - return null; - } - - @Override - public String getDestinationId() { - return span.getDestinationId(); - } - - @Override - public List getAnnotations() { - return span.getAnnotations(); - } - - @Override - public Class getType() { - return SpanEvent.class; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("(serviceType: "); - builder.append(getServiceType()); - builder.append(", apiId: "); - builder.append(getApiId()); - builder.append(", exceptionInfo: "); - builder.append(getExceptionInfo()); - builder.append(", rpc: "); - builder.append(getRpc()); - builder.append(", endPoint: "); - builder.append(getEndPoint()); - builder.append(", destinationId: "); - builder.append(getDestinationId()); - builder.append(", ["); - appendAnnotations(builder, getAnnotations()); - builder.append("], asyncId: "); - builder.append(getAsyncId()); - builder.append("nextAsyncId: "); - builder.append(getNextAsyncId()); - builder.append(')'); - - return builder.toString(); - } - } - - private static final class ResolvedExpectedTrace { - private final Class type; - private final ServiceType serviceType; - private final Integer asyncId; - private final Integer apiId; - private final Exception exception; - private final String rpc; - private final String endPoint; - private final String remoteAddr; - private final String destinationId; - private final ExpectedAnnotation[] annotations; - - public ResolvedExpectedTrace(Class type, ServiceType serviceType, Integer apiId, Exception exception, String rpc, String endPoint, String remoteAddr, String destinationId, ExpectedAnnotation[] annotations, Integer asyncId) { - this.type = type; - this.serviceType = serviceType; - this.apiId = apiId; - this.exception = exception; - this.rpc = rpc; - this.endPoint = endPoint; - this.remoteAddr = remoteAddr; - this.destinationId = destinationId; - this.annotations = annotations; - this.asyncId = asyncId; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - - builder.append(type.getSimpleName()); - builder.append("(serviceType: "); - builder.append(serviceType.getCode()); - builder.append(", apiId: "); - builder.append(apiId); - builder.append(", exception: "); - builder.append(exception); - builder.append(", rpc: "); - builder.append(rpc); - builder.append(", endPoint: "); - builder.append(endPoint); - builder.append(", remoteAddr: "); - builder.append(remoteAddr); - builder.append(", destinationId: "); - builder.append(destinationId); - builder.append(", annotations: "); - builder.append(Arrays.deepToString(annotations)); - builder.append(", asyncId: "); - builder.append(asyncId); - builder.append(")"); - - return builder.toString(); - } - } - - private ActualTrace wrap(Object obj) { - if (obj instanceof Span) { - return new SpanFacade((Span) obj); - } else if (obj instanceof SpanEvent) { - return new SpanEventFacade((SpanEvent) obj); - } - - throw new IllegalArgumentException("Unexpected type: " + obj.getClass()); - } - - private static boolean equals(Object expected, Object actual) { - // if expected is null, no need to compare. - return expected == null || (expected.equals(actual)); - } - - private void verifySpan(ResolvedExpectedTrace expected, ActualTrace actual) { - if (!expected.type.equals(actual.getType())) { - throw new AssertionError("Expected an instance of " + expected.type.getSimpleName() + " but was " + actual.getType().getName() + ". expected: " + expected + ", was: " + actual); - } - - if (!equals(expected.serviceType.getCode(), actual.getServiceType())) { - throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with serviceType[" + expected.serviceType.getCode() + "] but was [" + actual.getServiceType() + "]. expected: " + expected + ", was: " + actual); - } - - if (!equals(expected.apiId, actual.getApiId())) { - throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with apiId[" + expected.apiId + "] but was [" + actual.getApiId() + "]. expected: " + expected + ", was: " + actual); - } - - if (!equals(expected.rpc, actual.getRpc())) { - throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with rpc[" + expected.rpc + "] but was [" + actual.getRpc() + "]. expected: " + expected + ", was: " + actual); - } - - if (!equals(expected.endPoint, actual.getEndPoint())) { - throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with endPoint[" + expected.endPoint + "] but was [" + actual.getEndPoint() + "]. expected: " + expected + ", was: " + actual); - } - - if (!equals(expected.remoteAddr, actual.getRemoteAddr())) { - throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with remoteAddr[" + expected.remoteAddr + "] but was [" + actual.getRemoteAddr() + "]. expected: " + expected + ", was: " + actual); - } - - if (!equals(expected.destinationId, actual.getDestinationId())) { - throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with destinationId[" + expected.destinationId + "] but was [" + actual.getDestinationId() + "]. expected: " + expected + ", was: " + actual); - } - - if (!equals(expected.asyncId, actual.getAsyncId())) { - throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with asyncId[" + expected.asyncId + "] but was [" + actual.getAsyncId() + "]. expected: " + expected + ", was: " + actual); - } - - if (expected.exception != null) { - TIntStringValue actualExceptionInfo = actual.getExceptionInfo(); - if (actualExceptionInfo != null && actualExceptionInfo.isSetIntValue()) { - String actualExceptionClassName = getTestTcpDataSender().getString(actualExceptionInfo.getIntValue()); - String actualExceptionMessage = actualExceptionInfo.getStringValue(); - verifyException(expected.exception, actualExceptionClassName, actualExceptionMessage); - } else { - throw new AssertionError("Expected [" + expected.exception.getClass().getName() + "] but was none"); - } - } - - List actualAnnotations = actual.getAnnotations(); - - int len = expected.annotations == null ? 0 : expected.annotations.length; - int actualLen = actualAnnotations == null ? 0 : actualAnnotations.size(); - - if (actualLen != len) { - throw new AssertionError("Expected [" + len + "] annotations but was [" + actualLen + "], expected: " + expected + ", was: " + actual); - } - - for (int i = 0; i < len; i++) { - ExpectedAnnotation expect = expected.annotations[i]; - AnnotationKey expectedAnnotationKey = annotationKeyRegistryService.findAnnotationKeyByName(expect.getKeyName()); - TAnnotation actualAnnotation = actualAnnotations.get(i); - - if (expectedAnnotationKey.getCode() != actualAnnotation.getKey()) { - throw new AssertionError("Expected " + i + "th annotation [" + expectedAnnotationKey.getCode() + "=" + expect.getValue() + "] but was [" + toString(actualAnnotation) + "], expected: " + expected + ", was: " + actual); - } - - if (expectedAnnotationKey == AnnotationKey.SQL_ID && expect instanceof ExpectedSql) { - verifySql((ExpectedSql) expect, actualAnnotation); - } else { - Object expectedValue = expect.getValue(); - - if (expectedValue == Expectations.anyAnnotationValue()) { - continue; - } - - if (AnnotationKeyUtils.isCachedArgsKey(expectedAnnotationKey.getCode())) { - expectedValue = getTestTcpDataSender().getStringId(expectedValue.toString()); - } - - if (!Objects.equal(expectedValue, actualAnnotation.getValue().getFieldValue())) { - throw new AssertionError("Expected " + i + "th annotation [" + expectedAnnotationKey.getCode() + "=" + expect.getValue() + "] but was [" + toString(actualAnnotation) + "], expected: " + expected + ", was: " + actual); - } - } - } - } - - private void verifyException(Exception expectedException, String actualExceptionClassName, String actualExceptionMessage) { - String expectedExceptionClassName = expectedException.getClass().getName(); - String expectedExceptionMessage = StringUtils.abbreviate(expectedException.getMessage(), 256); - if (!Objects.equal(actualExceptionClassName, expectedExceptionClassName)) { - throw new AssertionError("Expected [" + expectedExceptionClassName + "] but was [" + actualExceptionClassName + "]"); - } - if (!Objects.equal(actualExceptionMessage, expectedExceptionMessage)) { - throw new AssertionError("Expected exception with message [" + expectedExceptionMessage + "] but was [" + actualExceptionMessage + "]"); - } - } - - private void verifySql(ExpectedSql expected, TAnnotation actual) { - int id = getTestTcpDataSender().getSqlId(expected.getQuery()); - TIntStringStringValue value = actual.getValue().getIntStringStringValue(); - - if (value.getIntValue() != id) { - String actualQuery = getTestTcpDataSender().getSql(value.getIntValue()); - throw new AssertionError("Expected sql [" + id + ": " + expected.getQuery() + "] but was [" + value.getIntValue() + ": " + actualQuery + "], expected: " + expected + ", was: " + actual); - } - - if (!Objects.equal(value.getStringValue1(), expected.getOutput())) { - throw new AssertionError("Expected sql with output [" + expected.getOutput() + "] but was [" + value.getStringValue1() + "], expected: " + expected + ", was: " + actual); - } - - if (!Objects.equal(value.getStringValue2(), expected.getBindValuesAsString())) { - throw new AssertionError("Expected sql with bindValues [" + expected.getBindValuesAsString() + "] but was [" + value.getStringValue2() + "], expected: " + expected + ", was: " + actual); - } - } - - private int findApiId(Member method) throws AssertionError { - final String desc = getMemberInfo(method); - return findApiId(desc); - } - - private String getMemberInfo(Member method) { - if (method instanceof Method) { - return getMethodInfo((Method) method); - } else if (method instanceof Constructor) { - return getConstructorInfo((Constructor) method); - } else { - throw new IllegalArgumentException("method: " + method); - } - } - - private String getMethodInfo(Method method) { - Class[] parameterTypes = method.getParameterTypes(); - String[] parameterTypeNames = JavaAssistUtils.toPinpointParameterType(parameterTypes); - return MethodDescriptionUtils.toJavaMethodDescriptor(method.getDeclaringClass().getName(), method.getName(), parameterTypeNames); - } - - private String getConstructorInfo(Constructor constructor) { - Class[] parameterTypes = constructor.getParameterTypes(); - String[] parameterTypeNames = JavaAssistUtils.getParameterType(parameterTypes); - - final String constructorSimpleName = MethodDescriptionUtils.getConstructorSimpleName(constructor); - return MethodDescriptionUtils.toJavaMethodDescriptor(constructor.getDeclaringClass().getName(), constructorSimpleName , parameterTypeNames); - } - - private int findApiId(String desc) throws AssertionError { - try { - return getTestTcpDataSender().getApiId(desc); - } catch (NoSuchElementException e) { - throw new AssertionError("Cannot find apiId of [" + desc + "]"); - } - } - - private TestTcpDataSender getTestTcpDataSender() { - return this.pluginApplicationContextModule.getTcpDataSender(); - } - - private OrderedSpanRecorder getRecorder() { - return this.pluginApplicationContextModule.getOrderedSpanRecorder(); - } - - private ServerMetaData getServerMetaData() { - return this.pluginApplicationContextModule.getServerMetaData(); - } - - private Object popSpan() { - while (true) { - OrderedSpanRecorder recorder = getRecorder(); - Object obj = recorder.pop(); - if (obj == null) { - return null; - } - - if (!isIgnored(obj)) { - return obj; - } - } - } - - @Override - public void printCache(PrintStream out) { - getRecorder().print(out); - getTestTcpDataSender().printDatas(out); - } - - @Override - public void printCache() { - printCache(System.out); - } - - @Override - public void initialize(boolean createTraceObject) { - if (createTraceObject) { - final TraceContext traceContext = getTraceContext(); - traceContext.newTraceObject(); - } - - getRecorder().clear(); - getTestTcpDataSender().clear(); - ignoredServiceTypes.clear(); - } - - @Override - public void cleanUp(boolean detachTraceObject) { - if (detachTraceObject) { - final TraceContext traceContext = getTraceContext(); - traceContext.removeTraceObject(); - } - - getRecorder().clear(); - getTestTcpDataSender().clear(); - ignoredServiceTypes.clear(); - } - - private TraceContext getTraceContext() { - ApplicationContext applicationContext = getApplicationContext(); - return applicationContext.getTraceContext(); - } - - @Override - public void verifyIsLoggingTransactionInfo(LoggingInfo loggingInfo) { - final Object actual = popSpan(); - - final TraceRoot traceRoot = getTraceRoot(actual); - final Shared shared = traceRoot.getShared(); - - if (shared.getLoggingInfo() != loggingInfo.getCode()) { - LoggingInfo loggingTransactionInfo = LoggingInfo.searchByCode(shared.getLoggingInfo()); - - if (loggingTransactionInfo != null) { - throw new AssertionError("Expected a Span isLoggingTransactionInfo value with [" + loggingInfo.getName() + "] but was [" + loggingTransactionInfo.getName() + "]. expected: " + loggingInfo.getName() + ", was: " + loggingTransactionInfo.getName()); - } else { - throw new AssertionError("Expected a Span isLoggingTransactionInfo value with [" + loggingInfo.getName() + "] but loggingTransactionInfo value invalid."); - } - - } - - } - - private TraceRoot getTraceRoot(Object actual) { - if (actual instanceof Span) { - return ((Span) actual).getTraceRoot(); - } else if (actual instanceof SpanEvent) { - return ((SpanEvent) actual).getTraceRoot(); - } else { - throw new IllegalArgumentException("Unexpected type: " + getActual(actual)); - } - } - - private String getActual(Object actual) { - if (actual == null) { - return "actual is null"; - } - return actual.getClass().getName(); - } } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginVerifierExternalAdaptor.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginVerifierExternalAdaptor.java new file mode 100644 index 000000000000..02e18a81d73c --- /dev/null +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/PluginVerifierExternalAdaptor.java @@ -0,0 +1,892 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test; + +import com.google.common.base.Objects; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.navercorp.pinpoint.bootstrap.context.ServerMetaData; +import com.navercorp.pinpoint.bootstrap.context.ServiceInfo; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.plugin.test.Expectations; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedAnnotation; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedSql; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTrace; +import com.navercorp.pinpoint.bootstrap.plugin.test.ExpectedTraceField; +import com.navercorp.pinpoint.bootstrap.plugin.test.PluginTestVerifier; +import com.navercorp.pinpoint.bootstrap.plugin.test.TraceType; +import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; +import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.LoggingInfo; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.AnnotationKeyUtils; +import com.navercorp.pinpoint.common.util.ArrayUtils; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.IntStringStringValue; +import com.navercorp.pinpoint.common.util.IntStringValue; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.profiler.context.Annotation; +import com.navercorp.pinpoint.profiler.context.DefaultLocalAsyncId; +import com.navercorp.pinpoint.profiler.context.LocalAsyncId; +import com.navercorp.pinpoint.profiler.context.ServerMetaDataRegistryService; +import com.navercorp.pinpoint.profiler.context.Span; +import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; +import com.navercorp.pinpoint.profiler.context.module.SpanDataSender; +import com.navercorp.pinpoint.profiler.sender.DataSender; +import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; + +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PluginVerifierExternalAdaptor implements PluginTestVerifier { + + private final List ignoredServiceTypes = new ArrayList(); + + private final DefaultApplicationContext applicationContext; + + public PluginVerifierExternalAdaptor(DefaultApplicationContext applicationContext) { + this.applicationContext = Assert.requireNonNull(applicationContext, "applicationContext must not be null"); + } + + public DefaultApplicationContext getApplicationContext() { + return applicationContext; + } + + @Override + public void verifyServerType(String serviceTypeName) { + final DefaultApplicationContext applicationContext = getApplicationContext(); + + ServiceType expectedType = findServiceType(serviceTypeName); + ServiceType actualType = applicationContext.getAgentInformation().getServerType(); + + if (!expectedType.equals(actualType)) { + throw new AssertionError("ResolvedExpectedTrace server type: " + expectedType.getName() + "[" + expectedType.getCode() + "] but was " + actualType + "[" + actualType.getCode() + "]"); + } + } + + @Override + public void verifyServerInfo(String expected) { + String actualName = getServerMetaData().getServerInfo(); + + if (!actualName.equals(expected)) { + throw new AssertionError("ResolvedExpectedTrace server name [" + expected + "] but was [" + actualName + "]"); + } + } + + @Override + public void verifyConnector(String protocol, int port) { + Map connectorMap = getServerMetaData().getConnectors(); + String actualProtocol = connectorMap.get(port); + + if (actualProtocol == null || !actualProtocol.equals(protocol)) { + throw new AssertionError("ResolvedExpectedTrace protocol [" + protocol + "] at port [" + port + "] but was [" + actualProtocol + "]"); + } + } + + @Override + public void verifyService(String name, List libs) { + List serviceInfos = getServerMetaData().getServiceInfos(); + + for (ServiceInfo serviceInfo : serviceInfos) { + if (serviceInfo.getServiceName().equals(name)) { + List actualLibs = serviceInfo.getServiceLibs(); + + if (actualLibs.size() != libs.size()) { + throw new AssertionError("ResolvedExpectedTrace service [" + name + "] with libraries [" + libs + "] but was [" + actualLibs + "]"); + } + + for (String lib : libs) { + if (!actualLibs.contains(lib)) { + throw new AssertionError("ResolvedExpectedTrace service [" + name + "] with libraries [" + libs + "] but was [" + actualLibs + "]"); + } + } + + // OK + return; + } + } + + throw new AssertionError("ResolvedExpectedTrace service [" + name + "] with libraries [" + libs + "] but there is no such service"); + } + + private boolean isIgnored(Object obj) { + short serviceType = -1; + + if (obj instanceof Span) { + serviceType = ((Span) obj).getServiceType(); + } else if (obj instanceof SpanEvent) { + serviceType = ((SpanEvent) obj).getServiceType(); + } + + return ignoredServiceTypes.contains(serviceType); + } + + @Override + public void verifyTraceCount(int expected) { + int actual = 0; + + for (Object obj : getRecorder()) { + if (!isIgnored(obj)) { + actual++; + } + } + + if (expected != actual) { + throw new AssertionError("ResolvedExpectedTrace count: " + expected + ", actual: " + actual); + } + } + + private ServiceType findServiceType(String name) { + ServiceTypeRegistryService serviceTypeRegistryService = getServiceTypeRegistry(); + ServiceType serviceType = serviceTypeRegistryService.findServiceTypeByName(name); + + if (serviceType == ServiceType.UNDEFINED) { + throw new AssertionError("No such service type: " + name); + } + + return serviceType; + } + + private Class resolveSpanClass(TraceType type) { + switch (type) { + case ROOT: + return Span.class; + case EVENT: + return SpanEvent.class; + } + + throw new IllegalArgumentException(type.toString()); + } + + @Override + public void verifyDiscreteTrace(ExpectedTrace... expectations) { + verifyDiscreteTraceBlock(expectations, null); + } + + public void verifyDiscreteTraceBlock(ExpectedTrace[] expectations, Integer asyncId) { + if (ArrayUtils.isEmpty(expectations)) { + throw new IllegalArgumentException("No expectations"); + } + + ExpectedTrace expected = expectations[0]; + ResolvedExpectedTrace resolved = resolveExpectedTrace(expected, asyncId); + + int i = 0; + Iterator iterator = getRecorder().iterator(); + + while (iterator.hasNext()) { + final Object next = iterator.next(); + ActualTrace actual = wrap(next); + + try { + verifySpan(resolved, actual); + } catch (AssertionError e) { + continue; + } + + iterator.remove(); + verifyAsyncTraces(expected, actual); + + if (++i == expectations.length) { + return; + } + + expected = expectations[i]; + resolved = resolveExpectedTrace(expected, asyncId); + } + + throw new AssertionError("Failed to match " + i + "th expectation: " + resolved); + } + + @Override + public void verifyTrace(ExpectedTrace... expectations) { + if (ArrayUtils.isEmpty(expectations)) { + throw new IllegalArgumentException("No expectations"); + } + + for (ExpectedTrace expected : expectations) { + ResolvedExpectedTrace resolved = resolveExpectedTrace(expected, null); + + final Item item = popItem(); + if (item == null) { + throw new AssertionError("Expected a " + resolved.toString() + " but there is no trace"); + } + final Object actual = item.getValue(); + + ActualTrace wrapped = wrap(actual); + + verifySpan(resolved, wrapped); + verifyAsyncTraces(expected, wrapped); + } + } + + private void verifyAsyncTraces(ExpectedTrace expected, ActualTrace wrapped) throws AssertionError { + final ExpectedTrace[] asyncTraces = expected.getAsyncTraces(); + + if (asyncTraces != null && asyncTraces.length > 0) { + Integer asyncId = wrapped.getNextAsyncId(); + + if (asyncId == null) { + throw new AssertionError("Expected async traces triggered but nextAsyncId is not present: " + wrapped); + } + + verifyDiscreteTraceBlock(asyncTraces, asyncId); + } + } + + private ResolvedExpectedTrace resolveExpectedTrace(ExpectedTrace expected, Integer asyncId) throws AssertionError { + final ServiceType serviceType = findServiceType(expected.getServiceType()); + final Class spanClass = resolveSpanClass(expected.getType()); + final int apiId = getApiId(expected); + + return new ResolvedExpectedTrace(spanClass, serviceType, apiId, expected.getException(), expected.getRpc(), expected.getEndPoint(), expected.getRemoteAddr(), expected.getDestinationId(), expected.getAnnotations(), asyncId); + } + + private int getApiId(ExpectedTrace expected) { + final Member method = expected.getMethod(); + if (method == null) { + if (expected.getMethodSignature() == null) { +// return null; + throw new RuntimeException("Method or MethodSignature is null"); + } else { + String methodSignature = expected.getMethodSignature(); + if (methodSignature.indexOf('(') != -1) { + methodSignature = MethodDescriptionUtils.toJavaMethodDescriptor(methodSignature); + } + return findApiId(methodSignature); + } + } else { + return findApiId(method); + } + } + + + @Override + public void ignoreServiceType(String... serviceTypes) { + for (String serviceType : serviceTypes) { + ServiceType t = findServiceType(serviceType); + ignoredServiceTypes.add(t.getCode()); + } + } + + private static void appendAnnotations(StringBuilder builder, List annotations) { + boolean first = true; + + if (annotations != null) { + for (Annotation annotation : annotations) { + if (first) { + first = false; + } else { + builder.append(", "); + } + + builder.append(toString(annotation)); + } + } + } + + private static String toString(Annotation a) { + return a.getAnnotationKey() + "=" + a.getValue(); + } + + private Injector getInjector() { + return this.applicationContext.getInjector(); + } + + private ServiceTypeRegistryService getServiceTypeRegistry() { + return getInjector().getInstance(ServiceTypeRegistryService.class); + } + + private AnnotationKeyRegistryService getAnnotationKeyRegistryService() { + Injector injector = getInjector(); + return injector.getInstance(AnnotationKeyRegistryService.class); + } + + private interface ActualTrace { + Short getServiceType(); + + Integer getApiId(); + + Integer getAsyncId(); + + Integer getNextAsyncId(); + + IntStringValue getExceptionInfo(); + + String getRpc(); + + String getEndPoint(); + + String getRemoteAddr(); + + String getDestinationId(); + + List getAnnotations(); + + Class getType(); + } + + private static final class SpanFacade implements ActualTrace { + private final Span span; + + public SpanFacade(Span span) { + this.span = span; + } + + @Override + public Short getServiceType() { + final short serviceType = span.getServiceType(); + if (serviceType == 0) { + return null; + } + return serviceType; + } + + @Override + public Integer getApiId() { + final int apiId = span.getApiId(); + if (apiId == 0) { + return null; + } + return apiId; + } + + @Override + public Integer getAsyncId() { + return null; + } + + @Override + public Integer getNextAsyncId() { + return null; + } + + @Override + public IntStringValue getExceptionInfo() { + return span.getExceptionInfo(); + } + + @Override + public String getRpc() { + return span.getTraceRoot().getShared().getRpcName(); + } + + @Override + public String getEndPoint() { + return span.getTraceRoot().getShared().getEndPoint(); + } + + @Override + public String getRemoteAddr() { + return span.getRemoteAddr(); + } + + @Override + public String getDestinationId() { + return null; + } + + @Override + public List getAnnotations() { + return span.getAnnotations(); + } + + @Override + public Class getType() { + return Span.class; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("(serviceType: "); + builder.append(getServiceType()); + builder.append(", apiId: "); + builder.append(getApiId()); + builder.append(", exceptionInfo: "); + builder.append(getExceptionInfo()); + builder.append(", rpc: "); + builder.append(getRpc()); + builder.append(", endPoint: "); + builder.append(getEndPoint()); + builder.append(", remoteAddr: "); + builder.append(getRemoteAddr()); + builder.append(", ["); + appendAnnotations(builder, getAnnotations()); + builder.append("])"); + + return builder.toString(); + } + } + + private static final class SpanEventFacade implements ActualTrace { + private final SpanEvent spanEvent; + + public SpanEventFacade(SpanEvent span) { + this.spanEvent = span; + } + + @Override + public Short getServiceType() { + return spanEvent.getServiceType(); + } + + @Override + public Integer getApiId() { + return spanEvent.getApiId(); + } + + @Override + public Integer getAsyncId() { + return spanEvent.getLocalAsyncId() != null ? spanEvent.getLocalAsyncId().getAsyncId() : null; + } + + @Override + public Integer getNextAsyncId() { + return spanEvent.getAsyncIdObject() != null ? spanEvent.getAsyncIdObject().getAsyncId() : null; + } + + @Override + public IntStringValue getExceptionInfo() { + return spanEvent.getExceptionInfo(); + } + + @Override + public String getRpc() { + return null; + } + + @Override + public String getEndPoint() { + return spanEvent.getEndPoint(); + } + + @Override + public String getRemoteAddr() { + return null; + } + + @Override + public String getDestinationId() { + return spanEvent.getDestinationId(); + } + + @Override + public List getAnnotations() { + return spanEvent.getAnnotations(); + } + + @Override + public Class getType() { + return SpanEvent.class; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("(serviceType: "); + builder.append(getServiceType()); + builder.append(", apiId: "); + builder.append(getApiId()); + builder.append(", exceptionInfo: "); + builder.append(getExceptionInfo()); + builder.append(", rpc: "); + builder.append(getRpc()); + builder.append(", endPoint: "); + builder.append(getEndPoint()); + builder.append(", destinationId: "); + builder.append(getDestinationId()); + builder.append(", ["); + appendAnnotations(builder, getAnnotations()); + builder.append("], asyncId: "); + builder.append(getAsyncId()); + builder.append("nextAsyncId: "); + builder.append(getNextAsyncId()); + builder.append(')'); + + return builder.toString(); + } + } + + private static final class ResolvedExpectedTrace { + private final Class type; + private final ServiceType serviceType; + private final LocalAsyncId localAsyncId; + private final Integer apiId; + private final Exception exception; + private final ExpectedTraceField rpc; + private final ExpectedTraceField endPoint; + private final ExpectedTraceField remoteAddr; + private final ExpectedTraceField destinationId; + private final ExpectedAnnotation[] annotations; + + public ResolvedExpectedTrace(Class type, ServiceType serviceType, Integer apiId, Exception exception, ExpectedTraceField rpc, ExpectedTraceField endPoint, ExpectedTraceField remoteAddr, ExpectedTraceField destinationId, ExpectedAnnotation[] annotations, Integer asyncId) { + this.type = type; + this.serviceType = serviceType; + this.apiId = apiId; + this.exception = exception; + this.rpc = rpc; + this.endPoint = endPoint; + this.remoteAddr = remoteAddr; + this.destinationId = destinationId; + this.annotations = annotations; + this.localAsyncId = newLocalAsyncId(asyncId); + } + + private LocalAsyncId newLocalAsyncId(Integer asyncId) { + if (asyncId == null) { + return null; + } + return new DefaultLocalAsyncId(asyncId, (short) 0); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + builder.append(type.getSimpleName()); + builder.append("(serviceType: "); + builder.append(serviceType.getCode()); + builder.append(", apiId: "); + builder.append(apiId); + builder.append(", exception: "); + builder.append(exception); + builder.append(", rpc: "); + builder.append(rpc); + builder.append(", endPoint: "); + builder.append(endPoint); + builder.append(", remoteAddr: "); + builder.append(remoteAddr); + builder.append(", destinationId: "); + builder.append(destinationId); + builder.append(", annotations: "); + builder.append(Arrays.deepToString(annotations)); + builder.append(", localAsyncId: "); + builder.append(localAsyncId); + builder.append(")"); + + return builder.toString(); + } + } + + private ActualTrace wrap(Object obj) { + if (obj instanceof Span) { + final Span span = (Span) obj; + return new SpanFacade(span); + } else if (obj instanceof SpanEvent) { + final SpanEvent spanEvent = (SpanEvent) obj; + return new SpanEventFacade(spanEvent); + } + + throw new IllegalArgumentException("Unexpected type: " + obj.getClass()); + } + + private static boolean equals(Object expected, Object actual) { + // if expected is null, no need to compare. + return expected == null || (expected.equals(actual)); + } + + private static boolean equals(Object expected, String actual) { + if (expected instanceof ExpectedTraceField) { + return ((ExpectedTraceField) expected).isEquals(actual); + } + + // if expected is null, no need to compare. + return expected == null || (expected.equals(actual)); + } + + private void verifySpan(ResolvedExpectedTrace expected, ActualTrace actual) { + if (!expected.type.equals(actual.getType())) { + throw new AssertionError("Expected an instance of " + expected.type.getSimpleName() + " but was " + actual.getType().getName() + ". expected: " + expected + ", was: " + actual); + } + + if (!equals(expected.serviceType.getCode(), actual.getServiceType())) { + throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with serviceType[" + expected.serviceType.getCode() + "] but was [" + actual.getServiceType() + "]. expected: " + expected + ", was: " + actual); + } + + if (!equals(expected.apiId, actual.getApiId())) { + throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with apiId[" + expected.apiId + "] but was [" + actual.getApiId() + "]. expected: " + expected + ", was: " + actual); + } + + if (!equals(expected.rpc, actual.getRpc())) { + throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with rpc[" + expected.rpc + "] but was [" + actual.getRpc() + "]. expected: " + expected + ", was: " + actual); + } + + if (!equals(expected.endPoint, actual.getEndPoint())) { + throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with endPoint[" + expected.endPoint + "] but was [" + actual.getEndPoint() + "]. expected: " + expected + ", was: " + actual); + } + + if (!equals(expected.remoteAddr, actual.getRemoteAddr())) { + throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with remoteAddr[" + expected.remoteAddr + "] but was [" + actual.getRemoteAddr() + "]. expected: " + expected + ", was: " + actual); + } + + if (!equals(expected.destinationId, actual.getDestinationId())) { + throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with destinationId[" + expected.destinationId + "] but was [" + actual.getDestinationId() + "]. expected: " + expected + ", was: " + actual); + } + + if (!equals(getAsyncId(expected), actual.getAsyncId())) { + throw new AssertionError("Expected a " + expected.type.getSimpleName() + " with asyncId[" + expected.localAsyncId + "] but was [" + actual.getAsyncId() + "]. expected: " + expected + ", was: " + actual); + } + + if (expected.exception != null) { + final IntStringValue actualExceptionInfo = actual.getExceptionInfo(); + if (actualExceptionInfo != null) { + String actualExceptionClassName = getTestTcpDataSender().getString(actualExceptionInfo.getIntValue()); + String actualExceptionMessage = actualExceptionInfo.getStringValue(); + verifyException(expected.exception, actualExceptionClassName, actualExceptionMessage); + } else { + throw new AssertionError("Expected [" + expected.exception.getClass().getName() + "] but was none"); + } + } + + List actualAnnotations = actual.getAnnotations(); + + int len = expected.annotations == null ? 0 : expected.annotations.length; + int actualLen = actualAnnotations == null ? 0 : actualAnnotations.size(); + + if (actualLen != len) { + throw new AssertionError("Expected [" + len + "] annotations but was [" + actualLen + "], expected: " + expected + ", was: " + actual); + } + + for (int i = 0; i < len; i++) { + ExpectedAnnotation expect = expected.annotations[i]; + AnnotationKey expectedAnnotationKey = getAnnotationKeyRegistryService().findAnnotationKeyByName(expect.getKeyName()); + Annotation actualAnnotation = actualAnnotations.get(i); + + if (expectedAnnotationKey.getCode() != actualAnnotation.getAnnotationKey()) { + throw new AssertionError("Code Different, Expected " + i + "th annotation [" + expectedAnnotationKey.getCode() + "=" + expect.getValue() + "] but was [" + toString(actualAnnotation) + "], expected: " + expected + ", was: " + actual); + } + + if (expectedAnnotationKey == AnnotationKey.SQL_ID && expect instanceof ExpectedSql) { + verifySql((ExpectedSql) expect, actualAnnotation); + } else { + Object expectedValue = expect.getValue(); + + if (expectedValue == Expectations.anyAnnotationValue()) { + continue; + } + + if (AnnotationKeyUtils.isCachedArgsKey(expectedAnnotationKey.getCode())) { + expectedValue = getTestTcpDataSender().getStringId(expectedValue.toString()); + } + + if (!Objects.equal(expectedValue, actualAnnotation.getValue())) { + + throw new AssertionError("Value Different, Expected " + i + "th annotation [" + expectedAnnotationKey.getCode() + "=" + expect.getValue() + "] but was [" + toString(actualAnnotation) + "], expected: " + expected + ", was: " + actual); + } + } + } + } + + private Integer getAsyncId(ResolvedExpectedTrace expected) { + if (expected.localAsyncId == null) { + return null; + } + return expected.localAsyncId.getAsyncId(); + } + + private void verifyException(Exception expectedException, String actualExceptionClassName, String actualExceptionMessage) { + String expectedExceptionClassName = expectedException.getClass().getName(); + String expectedExceptionMessage = StringUtils.abbreviate(expectedException.getMessage(), 256); + if (!Objects.equal(actualExceptionClassName, expectedExceptionClassName)) { + throw new AssertionError("Expected [" + expectedExceptionClassName + "] but was [" + actualExceptionClassName + "]"); + } + if (!Objects.equal(actualExceptionMessage, expectedExceptionMessage)) { + throw new AssertionError("Expected exception with message [" + expectedExceptionMessage + "] but was [" + actualExceptionMessage + "]"); + } + } + + private void verifySql(ExpectedSql expected, Annotation actual) { + int id = getTestTcpDataSender().getSqlId(expected.getQuery()); + IntStringStringValue value = (IntStringStringValue) actual.getValue(); + + if (value.getIntValue() != id) { + String actualQuery = getTestTcpDataSender().getSql(value.getIntValue()); + throw new AssertionError("Expected sql [" + id + ": " + expected.getQuery() + "] but was [" + value.getIntValue() + ": " + actualQuery + "], expected: " + expected + ", was: " + actual); + } + + if (!Objects.equal(value.getStringValue1(), expected.getOutput())) { + throw new AssertionError("Expected sql with output [" + expected.getOutput() + "] but was [" + value.getStringValue1() + "], expected: " + expected + ", was: " + actual); + } + + if (!Objects.equal(value.getStringValue2(), expected.getBindValuesAsString())) { + throw new AssertionError("Expected sql with bindValues [" + expected.getBindValuesAsString() + "] but was [" + value.getStringValue2() + "], expected: " + expected + ", was: " + actual); + } + } + + private int findApiId(Member method) throws AssertionError { + final String desc = getMemberInfo(method); + return findApiId(desc); + } + + private String getMemberInfo(Member method) { + if (method instanceof Method) { + return getMethodInfo((Method) method); + } else if (method instanceof Constructor) { + return getConstructorInfo((Constructor) method); + } else { + throw new IllegalArgumentException("method: " + method); + } + } + + private String getMethodInfo(Method method) { + Class[] parameterTypes = method.getParameterTypes(); + String[] parameterTypeNames = JavaAssistUtils.toPinpointParameterType(parameterTypes); + return MethodDescriptionUtils.toJavaMethodDescriptor(method.getDeclaringClass().getName(), method.getName(), parameterTypeNames); + } + + private String getConstructorInfo(Constructor constructor) { + Class[] parameterTypes = constructor.getParameterTypes(); + String[] parameterTypeNames = JavaAssistUtils.toPinpointParameterType(parameterTypes); + + final String constructorSimpleName = MethodDescriptionUtils.getConstructorSimpleName(constructor); + return MethodDescriptionUtils.toJavaMethodDescriptor(constructor.getDeclaringClass().getName(), constructorSimpleName, parameterTypeNames); + } + + private int findApiId(String desc) throws AssertionError { + try { + return getTestTcpDataSender().getApiId(desc); + } catch (NoSuchElementException e) { + throw new AssertionError("Cannot find apiId of [" + desc + "]"); + } + } + + private TestTcpDataSender getTestTcpDataSender() { + Injector injector = getInjector(); + TypeLiteral> dataSenderTypeLiteral = new TypeLiteral>() { + }; + Key> dataSenderKey = Key.get(dataSenderTypeLiteral); + EnhancedDataSender dataSender = injector.getInstance(dataSenderKey); + if (dataSender instanceof TestTcpDataSender) { + return (TestTcpDataSender) dataSender; + } + throw new IllegalStateException("unexpected dataSender" + dataSender); + } + + private OrderedSpanRecorder getRecorder() { + Injector injector = getInjector(); + Key dataSenderKey = Key.get(DataSender.class, SpanDataSender.class); + DataSender dataSender = injector.getInstance(dataSenderKey); + if (dataSender instanceof ListenableDataSender) { + ListenableDataSender listenableDataSender = (ListenableDataSender) dataSender; + ListenableDataSender.Listener listener = listenableDataSender.getListener(); + if (listener instanceof OrderedSpanRecorder) { + return (OrderedSpanRecorder) listener; + } + } + + throw new IllegalStateException("unexpected datasender:" + dataSender); + } + + private ServerMetaData getServerMetaData() { + Injector injector = getInjector(); + return injector.getInstance(ServerMetaDataRegistryService.class).getServerMetaData(); + } + + private Item popItem() { + while (true) { + OrderedSpanRecorder recorder = getRecorder(); + Item item = recorder.popItem(); + if (item == null) { + return null; + } + + if (!isIgnored(item.getValue())) { + return item; + } + } + } + + @Override + public void printCache(PrintStream out) { + getRecorder().print(out); + getTestTcpDataSender().printDatas(out); + } + + @Override + public void printCache() { + printCache(System.out); + } + + @Override + public void initialize(boolean createTraceObject) { + if (createTraceObject) { + final TraceContext traceContext = getTraceContext(); + traceContext.newTraceObject(); + } + + getRecorder().clear(); + getTestTcpDataSender().clear(); + ignoredServiceTypes.clear(); + } + + @Override + public void cleanUp(boolean detachTraceObject) { + if (detachTraceObject) { + final TraceContext traceContext = getTraceContext(); + traceContext.removeTraceObject(); + } + + getRecorder().clear(); + getTestTcpDataSender().clear(); + ignoredServiceTypes.clear(); + } + + private TraceContext getTraceContext() { + DefaultApplicationContext applicationContext = getApplicationContext(); + return applicationContext.getTraceContext(); + } + + @Override + public void verifyIsLoggingTransactionInfo(LoggingInfo loggingInfo) { + final Item item = popItem(); + if (item == null) { + throw new AssertionError("Expected a Span isLoggingTransactionInfo value with [" + loggingInfo.getName() + "]" + + " but loggingTransactionInfo value invalid."); + } + + final TraceRoot traceRoot = item.getTraceRoot(); + final byte loggingTransactionInfo = traceRoot.getShared().getLoggingInfo(); + if (loggingTransactionInfo != loggingInfo.getCode()) { + LoggingInfo code = LoggingInfo.searchByCode(loggingTransactionInfo); + if (code != null) { + throw new AssertionError("Expected a Span isLoggingTransactionInfo value with [" + loggingInfo.getName() + "]" + + " but was [" + code.getName() + "]. expected: " + loggingInfo.getName() + ", was: " + code.getName()); + } else { + throw new AssertionError("Expected a Span isLoggingTransactionInfo value with [" + loggingInfo.getName() + "]" + + " but loggingTransactionInfo value invalid."); + } + + } + } +} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/ProjectPathResolver.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/ProjectPathResolver.java index 1dae26bf0a12..2c4361d311b9 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/ProjectPathResolver.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/ProjectPathResolver.java @@ -49,7 +49,7 @@ private String getTestClassPath(Class testClass) { logger.debug("testClass:{}", testClass); final ClassLoader classLoader = getDefaultClassLoader(testClass); - final String testClassName = JavaAssistUtils.javaNameToJvmName(testClass.getName()) + ".class"; + final String testClassName = JavaAssistUtils.javaClassNameToJvmResourceName(testClass.getName()); final URL testClassResource = classLoader.getResource(testClassName); if (testClassResource == null) { throw new IllegalArgumentException("testClassName not found." + testClassName); diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/SimpleSpanStorage.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/SimpleSpanStorage.java deleted file mode 100644 index d2a1b69a2c08..000000000000 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/SimpleSpanStorage.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.test; - -import com.navercorp.pinpoint.profiler.sender.DataSender; - -import com.navercorp.pinpoint.profiler.context.Span; -import com.navercorp.pinpoint.profiler.context.SpanEvent; -import com.navercorp.pinpoint.profiler.context.storage.Storage; - -/** - * @author hyungil.jeong - * @author emeroad - */ -public final class SimpleSpanStorage implements Storage { - - private final DataSender dataSender; - - public SimpleSpanStorage(DataSender dataSender) { - if (dataSender == null) { - throw new NullPointerException("dataSender must not be null"); - } - this.dataSender = dataSender; - } - - @Override - public void store(SpanEvent spanEvent) { - if (spanEvent == null) { - throw new NullPointerException("spanEvent must not be null"); - } - this.dataSender.send(spanEvent); - } - - @Override - public void store(Span span) { - if (span == null) { - throw new NullPointerException("span must not be null"); - } - this.dataSender.send(span); - } - - @Override - public void flush() { - } - - @Override - public void close() { - } -} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/SimpleSpanStorageFactory.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/SimpleSpanStorageFactory.java deleted file mode 100644 index 4fa31f91a406..000000000000 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/SimpleSpanStorageFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.test; - -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressor; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.profiler.context.storage.Storage; -import com.navercorp.pinpoint.profiler.context.storage.StorageFactory; -import com.navercorp.pinpoint.profiler.sender.DataSender; - -/** - * @author hyungil.jeong - * @author emeroad - */ -public class SimpleSpanStorageFactory implements StorageFactory { - - private final DataSender dataSender; - private final SpanEventCompressor spanEventCompressor; - - public SimpleSpanStorageFactory(DataSender dataSender) { - this(dataSender, null); - } - - public SimpleSpanStorageFactory(DataSender dataSender, SpanEventCompressor spanEventCompressor) { - if (dataSender == null) { - throw new NullPointerException("dataSender must not be null"); - } - this.dataSender = dataSender; - this.spanEventCompressor = spanEventCompressor; - } - - @Override - public Storage createStorage(TraceRoot traceRoot) { - if (spanEventCompressor == null) { - return new SimpleSpanStorage(this.dataSender); - } else { - Storage storage = new SimpleSpanStorage(this.dataSender); - return new CompressingStorageDecorator(storage, spanEventCompressor); - } - } -} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TBaseRecorder.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TBaseRecorder.java index f768eb03baac..ab1d754175b5 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TBaseRecorder.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TBaseRecorder.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -25,7 +25,7 @@ /** * @author hyungil.jeong */ -public class TBaseRecorder> implements Iterable { +public class TBaseRecorder implements Iterable { private final Queue queue = new ConcurrentLinkedQueue(); diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TBaseRecorderAdaptor.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TBaseRecorderAdaptor.java index e01f8adad2f4..16f8e46006e5 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TBaseRecorderAdaptor.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TBaseRecorderAdaptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,24 +21,24 @@ /** * @author emeroad */ -public class TBaseRecorderAdaptor> implements ListenableDataSender.Listener { +public class TBaseRecorderAdaptor implements ListenableDataSender.Listener { - private final TBaseRecorder> recorder; + private final TBaseRecorder recorder; public TBaseRecorderAdaptor() { - this.recorder = new TBaseRecorder>(); + this.recorder = new TBaseRecorder(); } - public TBaseRecorderAdaptor(TBaseRecorder> recorder) { + public TBaseRecorderAdaptor(TBaseRecorder recorder) { this.recorder = recorder; } @Override - public boolean handleSend(TBase data) { + public boolean handleSend(T data) { return recorder.add(data); } - public TBaseRecorder> getRecorder() { + public TBaseRecorder getRecorder() { return recorder; } } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestAgentInformation.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestAgentInformation.java index a560d44d745c..96cb0a85fc7c 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestAgentInformation.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestAgentInformation.java @@ -29,6 +29,7 @@ public class TestAgentInformation extends DefaultAgentInformation { private static final String AGENT_ID = "test-agent"; private static final String APPLICATION_NAME = "TEST_APPLICATION"; + private static final boolean IS_CONTAINER = false; private static final int PID = 10; private static final String MACHINE_NAME = "test-machine"; private static final String HOST_IP = "127.0.0.1"; @@ -37,6 +38,6 @@ public class TestAgentInformation extends DefaultAgentInformation { private static final String AGENT_VERSION = Version.VERSION; public TestAgentInformation() { - super(AGENT_ID, APPLICATION_NAME, System.currentTimeMillis(), PID, MACHINE_NAME, HOST_IP, SERVICE_TYPE, JVM_VERSION, AGENT_VERSION); + super(AGENT_ID, APPLICATION_NAME, IS_CONTAINER, System.currentTimeMillis(), PID, MACHINE_NAME, HOST_IP, SERVICE_TYPE, JVM_VERSION, AGENT_VERSION); } } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestProfilerPluginClassLoader.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestProfilerPluginClassLoader.java index 9f5f92f82380..45de3ba59061 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestProfilerPluginClassLoader.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestProfilerPluginClassLoader.java @@ -29,16 +29,16 @@ public class TestProfilerPluginClassLoader implements ClassInjector { @Override public Class injectClass(ClassLoader targetClassLoader, String className) { try { - return (Class) targetClassLoader.loadClass(className); + return (Class) Class.forName(className, false, targetClassLoader); } catch (ClassNotFoundException e) { throw new PinpointException("Cannot find class: " + className, e); } } @Override - public InputStream getResourceAsStream(ClassLoader targetClassLoader, String classPath) { + public InputStream getResourceAsStream(ClassLoader targetClassLoader, String internalName) { targetClassLoader = getClassLoader(targetClassLoader); - return targetClassLoader.getResourceAsStream(classPath); + return targetClassLoader.getResourceAsStream(internalName); } private static ClassLoader getClassLoader(ClassLoader classLoader) { diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestSpanStorageFactory.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestSpanStorageFactory.java new file mode 100644 index 000000000000..0e1477420382 --- /dev/null +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestSpanStorageFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test; + +import com.google.inject.Inject; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.module.SpanDataSender; +import com.navercorp.pinpoint.profiler.context.storage.BufferedStorage; +import com.navercorp.pinpoint.profiler.context.storage.Storage; +import com.navercorp.pinpoint.profiler.context.storage.StorageFactory; +import com.navercorp.pinpoint.profiler.sender.DataSender; + + +/** + * @author hyungil.jeong + * @author emeroad + */ +public class TestSpanStorageFactory implements StorageFactory { + + private final DataSender dataSender; + + @Inject + public TestSpanStorageFactory(@SpanDataSender DataSender dataSender) { + this.dataSender = Assert.requireNonNull(dataSender, "dataSender must not be null"); + } + + @Override + public Storage createStorage(TraceRoot traceRoot) { + return new BufferedStorage(traceRoot, this.dataSender, 1); + } + +} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestTcpDataSender.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestTcpDataSender.java index fa2f81d4b799..b56b673fec5c 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestTcpDataSender.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/TestTcpDataSender.java @@ -1,10 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,14 +18,13 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Maps; +import com.navercorp.pinpoint.profiler.metadata.ApiMetaData; +import com.navercorp.pinpoint.profiler.metadata.SqlMetaData; +import com.navercorp.pinpoint.profiler.metadata.StringMetaData; import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; import com.navercorp.pinpoint.rpc.FutureListener; import com.navercorp.pinpoint.rpc.ResponseMessage; import com.navercorp.pinpoint.rpc.client.PinpointClientReconnectEventListener; -import com.navercorp.pinpoint.thrift.dto.TApiMetaData; -import com.navercorp.pinpoint.thrift.dto.TSqlMetaData; -import com.navercorp.pinpoint.thrift.dto.TStringMetaData; -import org.apache.thrift.TBase; import java.io.PrintStream; import java.util.ArrayList; @@ -39,9 +39,9 @@ * @author Jongho Moon * @author jaehong.kim */ -public class TestTcpDataSender implements EnhancedDataSender { +public class TestTcpDataSender implements EnhancedDataSender { - private final List> datas = Collections.synchronizedList(new ArrayList>()); + private final List datas = Collections.synchronizedList(new ArrayList()); private final BiMap apiIdMap = newSynchronizedBiMap(); @@ -65,27 +65,27 @@ private BiMap newSynchronizedBiMap() { @Override - public boolean send(TBase data) { + public boolean send(Object data) { addData(data); return false; } - private void addData(TBase data) { - if (data instanceof TApiMetaData) { - TApiMetaData md = (TApiMetaData)data; + private void addData(Object data) { + if (data instanceof ApiMetaData) { + ApiMetaData md = (ApiMetaData)data; final String javaMethodDescriptor = toJavaMethodDescriptor(md); apiIdMap.put(md.getApiId(), javaMethodDescriptor); - } else if (data instanceof TSqlMetaData) { - TSqlMetaData md = (TSqlMetaData)data; + } else if (data instanceof SqlMetaData) { + SqlMetaData md = (SqlMetaData)data; int id = md.getSqlId(); String sql = md.getSql(); sqlIdMap.put(id, sql); - } else if (data instanceof TStringMetaData) { - TStringMetaData md = (TStringMetaData)data; + } else if (data instanceof StringMetaData) { + StringMetaData md = (StringMetaData)data; int id = md.getStringId(); String string = md.getStringValue(); @@ -96,7 +96,7 @@ private void addData(TBase data) { datas.add(data); } - private String toJavaMethodDescriptor(TApiMetaData apiMetaData) { + private String toJavaMethodDescriptor(ApiMetaData apiMetaData) { // 1st method type check // int type = apiMetaData.getType(); // if (type != MethodType.DEFAULT) { @@ -119,19 +119,19 @@ public void stop() { } @Override - public boolean request(TBase data) { + public boolean request(Object data) { addData(data); return true; } @Override - public boolean request(TBase data, int retry) { + public boolean request(Object data, int retry) { addData(data); return true; } @Override - public boolean request(TBase data, FutureListener listener) { + public boolean request(Object data, FutureListener listener) { addData(data); return true; } @@ -191,7 +191,7 @@ public int getSqlId(String sql) { return id; } - public List> getDatas() { + public List getDatas() { return datas; } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/DefaultTranslator.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/DefaultTranslator.java index 93b0fed7d94b..72c07af2e663 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/DefaultTranslator.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/DefaultTranslator.java @@ -20,13 +20,13 @@ import com.navercorp.pinpoint.bootstrap.instrument.matcher.ClassNameMatcher; import com.navercorp.pinpoint.bootstrap.instrument.matcher.Matcher; import com.navercorp.pinpoint.bootstrap.instrument.matcher.MultiClassNameMatcher; -import com.navercorp.pinpoint.profiler.ClassFileTransformerDispatcher; import com.navercorp.pinpoint.profiler.plugin.MatchableClassFileTransformer; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import com.navercorp.pinpoint.test.util.BytecodeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -42,9 +42,9 @@ public class DefaultTranslator implements Translator { private final ConcurrentMap transformerMap = new ConcurrentHashMap(); private final ClassLoader loader; - private final ClassFileTransformerDispatcher dispatcher; + private final ClassFileTransformer dispatcher; - public DefaultTranslator(ClassLoader loader, ClassFileTransformerDispatcher defaultTransformer) { + public DefaultTranslator(ClassLoader loader, ClassFileTransformer defaultTransformer) { if (defaultTransformer == null) { throw new NullPointerException("dispatcher must not be null"); } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/JavassistTranslator.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/JavassistTranslator.java deleted file mode 100644 index 19bebc380e6c..000000000000 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/JavassistTranslator.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.navercorp.pinpoint.test.classloader; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.lang.instrument.IllegalClassFormatException; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import com.navercorp.pinpoint.profiler.ClassFileTransformerDispatcher; -import javassist.ClassPool; -import javassist.CtClass; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.bootstrap.instrument.matcher.ClassNameMatcher; -import com.navercorp.pinpoint.bootstrap.instrument.matcher.Matcher; -import com.navercorp.pinpoint.bootstrap.instrument.matcher.MultiClassNameMatcher; -import com.navercorp.pinpoint.profiler.plugin.MatchableClassFileTransformer; -import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; - -/** - * @author emeroad - */ -public class JavassistTranslator implements Translator { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final ConcurrentMap transformerMap = new ConcurrentHashMap(); - - private final ClassLoader loader; - private final ClassFileTransformerDispatcher dispatcher; - private final ClassPool classPool; - - public JavassistTranslator(ClassLoader loader, ClassPool classPool, ClassFileTransformerDispatcher defaultTransformer) { - if (defaultTransformer == null) { - throw new NullPointerException("dispatcher must not be null"); - } - if (classPool == null) { - throw new NullPointerException("classPool must not be null"); - } - - this.loader = loader; - this.dispatcher = defaultTransformer; - this.classPool = classPool; - } - - public void addTransformer(MatchableClassFileTransformer transformer) { - // TODO extract matcher process - final Matcher matcher = transformer.getMatcher(); - if (matcher instanceof ClassNameMatcher) { - ClassNameMatcher classNameMatcher = (ClassNameMatcher) matcher; - String className = classNameMatcher.getClassName(); - addTransformer0(transformer, className); - } else if (matcher instanceof MultiClassNameMatcher) { - final MultiClassNameMatcher classNameMatcher = (MultiClassNameMatcher) matcher; - List classNameList = classNameMatcher.getClassNames(); - for (String className : classNameList) { - addTransformer0(transformer, className); - } - } else { - throw new IllegalArgumentException("unsupported Matcher " + matcher); - } - - } - - private void addTransformer0(MatchableClassFileTransformer transformer, String className) { - final String checkClassInternalName = JavaAssistUtils.javaNameToJvmName(className); - MatchableClassFileTransformer old = transformerMap.put(checkClassInternalName, transformer); - if (old != null) { - throw new IllegalStateException("Modifier already exist new:" + transformer.getClass() + " old:" + old.getMatcher()); - } - } - - @Override - public void start() { - - } - - @Override - public byte[] transform(String className) throws ClassNotFoundException { - logger.debug("loading className:{}", className); - - final String classInternalName = JavaAssistUtils.javaNameToJvmName(className); - try { - // Find Modifier from agent and try transforming - final byte[] transformBytes = dispatcher.transform(this.loader, classInternalName, null, null, null); - if (transformBytes != null) { - logger.debug(classInternalName + " find in dispatcher"); - makeClass(classPool, transformBytes, classInternalName); - return transformBytes; - } - - final byte[] customTransformBytes = customTransformer(classPool, classInternalName); - if (customTransformBytes != null) { - logger.debug(classInternalName + " find in transformerMap"); - return customTransformBytes; - } - - final CtClass ctClass = this.classPool.get(className); - return ctClass.toBytecode(); - } catch (Throwable th) { - throw new RuntimeException(className + " transform fail" , th); - } - - } - - private byte[] customTransformer(ClassPool pool, String jvmClassName) { - logger.info("Modify find classname:{}, loader:{}", jvmClassName, loader); - MatchableClassFileTransformer transformer = transformerMap.get(jvmClassName); - if (transformer == null) { - return null; - } - logger.info("Modify jvmClassName:{}, modifier{}, loader:{}", jvmClassName, transformer, loader); - - - final Thread thread = Thread.currentThread(); - final ClassLoader beforeClassLoader = thread.getContextClassLoader(); - thread.setContextClassLoader(loader); - try { - String javaClassName = JavaAssistUtils.jvmNameToJavaName(jvmClassName); - byte[] transformBytes = transformer.transform(loader, javaClassName, null, null, null); - makeClass(pool, transformBytes, jvmClassName); - return transformBytes; - } catch (IllegalClassFormatException e) { - throw new RuntimeException(jvmClassName + " transform fail" , e); - } finally { - thread.setContextClassLoader(beforeClassLoader); - } - } - - private CtClass makeClass(ClassPool pool, byte[] transform, String jvmClassName) { - try { - if (logger.isDebugEnabled()) { - logger.debug("{} makeClass.", jvmClassName); - } - return pool.makeClass(new ByteArrayInputStream(transform)); - } catch (IOException ex) { - throw new RuntimeException("Class make fail. jvmClass:" + jvmClassName + " Caused by:" + ex.getMessage(), ex); - } - } - -} diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TestClassLoader.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TestClassLoader.java index dfa95e9f9a3a..21287c896785 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TestClassLoader.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TestClassLoader.java @@ -22,18 +22,15 @@ import java.util.logging.Level; import java.util.logging.Logger; -import com.google.inject.Injector; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; import com.navercorp.pinpoint.profiler.instrument.ASMEngine; import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjector; import com.navercorp.pinpoint.profiler.instrument.classloading.DebugTransformerClassInjector; -import com.navercorp.pinpoint.profiler.instrument.JavassistEngine; import com.navercorp.pinpoint.profiler.plugin.ClassFileTransformerLoader; import com.navercorp.pinpoint.profiler.plugin.MatchableClassFileTransformerGuardDelegate; import com.navercorp.pinpoint.profiler.plugin.PluginInstrumentContext; -import com.navercorp.pinpoint.test.MockApplicationContext; -import javassist.ClassPool; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.instrument.matcher.Matcher; @@ -50,19 +47,18 @@ public class TestClassLoader extends TransformClassLoader { private final Logger logger = Logger.getLogger(TestClassLoader.class.getName()); - private final MockApplicationContext applicationContext; + private final DefaultApplicationContext applicationContext; private Translator instrumentTranslator; private final List delegateClass; private final ClassFileTransformerLoader classFileTransformerLoader; private final InstrumentContext instrumentContext; - public TestClassLoader(MockApplicationContext applicationContext) { + public TestClassLoader(DefaultApplicationContext applicationContext) { Assert.requireNonNull(applicationContext, "applicationContext must not be null"); this.applicationContext = applicationContext; this.classFileTransformerLoader = new ClassFileTransformerLoader(applicationContext.getProfilerConfig(), applicationContext.getDynamicTransformTrigger()); -// ClassInjector classInjector = new LegacyProfilerPluginClassInjector(getClass().getClassLoader()); ClassInjector classInjector = new DebugTransformerClassInjector(); this.instrumentContext = new PluginInstrumentContext(applicationContext.getProfilerConfig(), applicationContext.getInstrumentEngine(), applicationContext.getDynamicTransformTrigger(), classInjector, classFileTransformerLoader); @@ -129,26 +125,20 @@ protected Class loadClassByDelegation(String name) throws ClassNotFoundExcept } public void addTranslator() { - final InstrumentEngine instrumentEngine = applicationContext.getInstrumentEngine(); - if (instrumentEngine instanceof JavassistEngine) { - - logger.info("JAVASSIST BCI engine"); - ClassPool classPool = ((JavassistEngine) instrumentEngine).getClassPool(this); - this.instrumentTranslator = new JavassistTranslator(this, classPool, applicationContext.getClassFileTransformerDispatcher()); - this.addTranslator(instrumentTranslator); - - } else if (instrumentEngine instanceof ASMEngine) { + this.instrumentTranslator = newTranslator(); + addTranslator(instrumentTranslator); + } + private Translator newTranslator() { + final InstrumentEngine instrumentEngine = applicationContext.getInstrumentEngine(); + if (instrumentEngine instanceof ASMEngine) { logger.info("ASM BCI engine"); - this.instrumentTranslator = new DefaultTranslator(this, applicationContext.getClassFileTransformerDispatcher()); - this.addTranslator(instrumentTranslator); - - } else { + return new DefaultTranslator(this, applicationContext.getClassFileTransformer()); + } - logger.info("Unknown BCI engine"); - this.instrumentTranslator = new DefaultTranslator(this, applicationContext.getClassFileTransformerDispatcher()); - this.addTranslator(instrumentTranslator); - } + logger.info("Unknown BCI engine"); + return new DefaultTranslator(this, applicationContext.getClassFileTransformer()); } + } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TestClassLoaderFactory.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TestClassLoaderFactory.java index 5813c42fd068..3af7e8330d56 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TestClassLoaderFactory.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TestClassLoaderFactory.java @@ -17,12 +17,11 @@ package com.navercorp.pinpoint.test.classloader; -import com.navercorp.pinpoint.test.MockApplicationContext; +import com.navercorp.pinpoint.common.util.ClassUtils; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.navercorp.pinpoint.common.util.ClassUtils; - /** * @author hyungil.jeong */ @@ -35,7 +34,7 @@ public class TestClassLoaderFactory { private static final String ATLASSIAN_CLOVER = "com_atlassian_clover.Clover"; - public static TestClassLoader createTestClassLoader(MockApplicationContext applicationContext) { + public static TestClassLoader createTestClassLoader(DefaultApplicationContext applicationContext) { final TestClassLoader testClassLoader = new TestClassLoader(applicationContext); addCloverPackage(testClassLoader, CENQUA_CLOVER); addCloverPackage(testClassLoader, ATLASSIAN_CLOVER); diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TransformClassLoader.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TransformClassLoader.java index be2f40edc554..b188a21cef17 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TransformClassLoader.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/classloader/TransformClassLoader.java @@ -17,8 +17,8 @@ package com.navercorp.pinpoint.test.classloader; +import com.navercorp.pinpoint.common.util.IOUtils; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; -import com.navercorp.pinpoint.test.util.BytecodeUtils; import java.io.InputStream; import java.security.ProtectionDomain; @@ -183,12 +183,12 @@ protected Class findClass(String name) throws ClassNotFoundException { return null; } } else { - String jarname = "/" + JavaAssistUtils.javaNameToJvmName(name) + ".class"; + String jarname = "/" + JavaAssistUtils.javaClassNameToJvmResourceName(name); InputStream in = this.getClass().getClassLoader().getResourceAsStream(jarname); if (in == null) { return null; } - classfile = BytecodeUtils.readClass(in, true); + classfile = IOUtils.toByteArray(in); } } catch (Exception e) { throw new ClassNotFoundException("caught an exception while obtaining a class file for " + name, e); diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/BasePinpointTest.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/BasePinpointTest.java index 9e893088e5a5..055808e78962 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/BasePinpointTest.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/BasePinpointTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,18 +19,15 @@ import java.util.ArrayList; import java.util.List; -import com.navercorp.pinpoint.common.server.bo.SpanFactory; import com.navercorp.pinpoint.profiler.context.ServerMetaDataRegistryService; +import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.profiler.sender.DataSender; import com.navercorp.pinpoint.test.ListenableDataSender; -import com.navercorp.pinpoint.test.MockApplicationContext; -import org.apache.thrift.TBase; import org.junit.runner.RunWith; import com.navercorp.pinpoint.bootstrap.context.ServerMetaData; -import com.navercorp.pinpoint.common.server.bo.SpanBo; -import com.navercorp.pinpoint.common.server.bo.SpanEventBo; import com.navercorp.pinpoint.profiler.context.Span; import com.navercorp.pinpoint.profiler.context.SpanEvent; import com.navercorp.pinpoint.test.TBaseRecorder; @@ -41,33 +38,34 @@ @RunWith(value = PinpointJUnit4ClassRunner.class) public abstract class BasePinpointTest { - private volatile TBaseRecorder> tBaseRecorder; + private volatile TBaseRecorder tBaseRecorder; private volatile ServerMetaDataRegistryService serverMetaDataRegistryService; - private final SpanFactory spanFactory = new SpanFactory(); - - protected List getCurrentSpanEvents() { - List spanEvents = new ArrayList(); - for (TBase span : this.tBaseRecorder) { - if (span instanceof SpanEvent) { - SpanEvent spanEvent = (SpanEvent)span; - SpanEventBo spanEventBo = spanFactory.buildSpanEventBo(spanEvent); - spanEvents.add(spanEventBo); + + protected List getCurrentSpanEvents() { + List spanEvents = new ArrayList(); + for (Object value : this.tBaseRecorder) { + if (value instanceof SpanChunk) { + final SpanChunk spanChunk = (SpanChunk) value; + for (SpanEvent tSpanEvent : spanChunk.getSpanEventList()) { + SpanEvent spanEvent = tSpanEvent; + spanEvents.add(spanEvent); + } } } return spanEvents; } - protected List getCurrentRootSpans() { - List rootSpans = new ArrayList(); - for (TBase span : this.tBaseRecorder) { - if (span instanceof Span) { - SpanBo spanBo = spanFactory.buildSpanBo((Span) span); - rootSpans.add(spanBo); + protected List getCurrentRootSpans() { + List rootSpans = new ArrayList(); + for (Object value : this.tBaseRecorder) { + if (value instanceof Span) { + Span span = (Span) value; + rootSpans.add(span); } } return rootSpans; } - + protected ServerMetaData getServerMetaData() { return this.serverMetaDataRegistryService.getServerMetaData(); } @@ -75,23 +73,23 @@ protected ServerMetaData getServerMetaData() { private void setTBaseRecorder(TBaseRecorder tBaseRecorder) { this.tBaseRecorder = tBaseRecorder; } - + private void setServerMetaDataRegistryService(ServerMetaDataRegistryService serverMetaDataRegistryService) { this.serverMetaDataRegistryService = serverMetaDataRegistryService; } public void setup(TestContext testContext) { - MockApplicationContext mockApplicationContext = testContext.getMockApplicationContext(); + DefaultApplicationContext mockApplicationContext = testContext.getDefaultApplicationContext(); DataSender spanDataSender = mockApplicationContext.getSpanDataSender(); if (spanDataSender instanceof ListenableDataSender) { ListenableDataSender listenableDataSender = (ListenableDataSender) spanDataSender; - final TBaseRecorder tBaseRecord = new TBaseRecorder(); + final TBaseRecorder tBaseRecord = new TBaseRecorder(); listenableDataSender.setListener(new ListenableDataSender.Listener() { @Override - public boolean handleSend(TBase data) { + public boolean handleSend(Object data) { return tBaseRecord.add(data); } }); diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/PinpointJUnit4ClassRunner.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/PinpointJUnit4ClassRunner.java index a3339cca42e6..40825dc8fe66 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/PinpointJUnit4ClassRunner.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/PinpointJUnit4ClassRunner.java @@ -19,7 +19,7 @@ import java.lang.reflect.Method; -import com.navercorp.pinpoint.test.MockApplicationContext; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import org.junit.internal.runners.model.EachTestNotifier; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; @@ -71,7 +71,7 @@ protected TestClass createTestClass(Class testClass) { } private TraceContext getTraceContext() { - MockApplicationContext mockApplicationContext = testContext.getMockApplicationContext(); + DefaultApplicationContext mockApplicationContext = testContext.getDefaultApplicationContext(); return mockApplicationContext.getTraceContext(); } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/TestContext.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/TestContext.java index 39452ca81780..9d9b4d1e403d 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/TestContext.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/junit4/TestContext.java @@ -19,6 +19,7 @@ import java.io.Closeable; import java.io.IOException; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.test.MockApplicationContextFactory; import com.navercorp.pinpoint.test.classloader.TestClassLoader; import com.navercorp.pinpoint.test.classloader.TestClassLoaderFactory; @@ -29,7 +30,6 @@ import com.navercorp.pinpoint.bootstrap.logging.PLoggerBinder; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.profiler.logging.Slf4jLoggerBinder; -import com.navercorp.pinpoint.test.MockApplicationContext; /** * @author hyungil.jeong @@ -43,13 +43,14 @@ public class TestContext implements Closeable { private final PLoggerBinder loggerBinder = new Slf4jLoggerBinder(); private final TestClassLoader classLoader; - private final MockApplicationContext mockApplicationContext; + private final DefaultApplicationContext mockApplicationContext; private final Class baseTestClass; public TestContext() { this.mockApplicationContext = createMockApplicationContext(); + this.mockApplicationContext.start(); this.classLoader = TestClassLoaderFactory.createTestClassLoader(mockApplicationContext); this.classLoader.initialize(); try { @@ -60,17 +61,17 @@ public TestContext() { } - private MockApplicationContext createMockApplicationContext() { + private DefaultApplicationContext createMockApplicationContext() { logger.trace("agent create"); MockApplicationContextFactory factory = new MockApplicationContextFactory(); - return factory.of("pinpoint.config"); + return factory.build("pinpoint.config"); } public ClassLoader getClassLoader() { return classLoader; } - public MockApplicationContext getMockApplicationContext() { + public DefaultApplicationContext getDefaultApplicationContext() { return mockApplicationContext; } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/util/BytecodeUtils.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/util/BytecodeUtils.java index 99eed7f4d189..d6e3b59fd369 100644 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/util/BytecodeUtils.java +++ b/profiler-test/src/main/java/com/navercorp/pinpoint/test/util/BytecodeUtils.java @@ -16,122 +16,35 @@ package com.navercorp.pinpoint.test.util; +import com.navercorp.pinpoint.common.util.IOUtils; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; -import java.io.Closeable; import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.Method; // TODO move package public final class BytecodeUtils { - private static final Method DEFINE_CLASS = getDefineClassMethod(); - private BytecodeUtils() { } - private static Method getDefineClassMethod() { - try { - final Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); - method.setAccessible(true); - return method; - } catch (NoSuchMethodException e) { - // link error - throw new RuntimeException("defineClass not found. Error:" + e.getMessage(), e); - } catch (SecurityException e) { - // link error - throw new RuntimeException("defineClass error. Error:" + e.getMessage(), e); - } - } - - public static Class defineClass(ClassLoader classLoader, String className, byte[] classFile) { - try { - return (Class) DEFINE_CLASS.invoke(classLoader, className, classFile, 0, classFile.length); - } catch (Exception ex) { - throw new RuntimeException("defineClass error. Caused:" + ex.getMessage(), ex); - } - } - public static byte[] getClassFile(ClassLoader classLoader, String className) { if (className == null) { throw new NullPointerException("className must not be null"); } classLoader = getClassLoader(classLoader); - final String classInternalName = JavaAssistUtils.javaNameToJvmName(className); - final InputStream is = classLoader.getResourceAsStream(classInternalName + ".class"); + final String classInternalName = JavaAssistUtils.javaClassNameToJvmResourceName(className); + final InputStream is = classLoader.getResourceAsStream(classInternalName); if (is == null) { throw new RuntimeException("No such class file: " + className); } try { - return readClass(is, false); + return IOUtils.toByteArray(is); } catch (IOException e) { - throw new RuntimeException(e); - } finally { - close(is); - } - } - - /** - * COPY ASM method. reference : org.objectweb.asm.ClassReader - * - * Reads the bytecode of a class. - * - * @param is - * an input stream from which to read the class. - * @param close - * true to close the input stream after reading. - * @return the bytecode read from the given input stream. - * @throws IOException - * if a problem occurs during reading. - */ - public static byte[] readClass(final InputStream is, boolean close) - throws IOException { - if (is == null) { - throw new IOException("Class not found"); - } - try { - byte[] b = new byte[is.available()]; - int len = 0; - while (true) { - int n = is.read(b, len, b.length - len); - if (n == -1) { - if (len < b.length) { - byte[] c = new byte[len]; - System.arraycopy(b, 0, c, 0, len); - b = c; - } - return b; - } - len += n; - if (len == b.length) { - int last = is.read(); - if (last < 0) { - return b; - } - byte[] c = new byte[b.length + 1000]; - System.arraycopy(b, 0, c, 0, len); - c[len++] = (byte) last; - b = c; - } - } - } finally { - if (close) { - close(is); - } - } - } - - private static void close(Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (IOException ignore) { - // skip - } + throw new RuntimeException("class read fail file: " + className, e); } } diff --git a/profiler-test/src/main/java/com/navercorp/pinpoint/test/util/LoaderUtils.java b/profiler-test/src/main/java/com/navercorp/pinpoint/test/util/LoaderUtils.java deleted file mode 100644 index 3749bfa680ad..000000000000 --- a/profiler-test/src/main/java/com/navercorp/pinpoint/test/util/LoaderUtils.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.test.util; - -import javassist.ClassPool; -import javassist.Loader; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -/** - * @author emeroad - */ -public final class LoaderUtils { - - private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); - - private LoaderUtils() { - } - - public static Loader createLoader(final ClassPool classPool) { - if (classPool == null) { - throw new NullPointerException("classPool must not be null"); - } - Loader loader; - if (SECURITY_MANAGER != null) { - loader = AccessController.doPrivileged(new LoaderCreateAction(classPool)); - } else { - loader = new Loader(classPool); - } - loader.delegateLoadingOf("org.apache.log4j."); - return loader; - } - - static class LoaderCreateAction implements PrivilegedAction { - private final ClassPool classPool; - - public LoaderCreateAction(final ClassPool classPool) { - if (classPool == null) { - throw new NullPointerException("classPool must not be null"); - } - this.classPool = classPool; - } - - public Loader run() { - return new Loader(classPool); - } - } - - -} diff --git a/profiler-test/src/test/java/com/navercorp/pinpoint/test/MockApplicationContextModuleTest.java b/profiler-test/src/test/java/com/navercorp/pinpoint/test/MockApplicationContextModuleTest.java index d1ee9c0fa006..5e5fef02b921 100644 --- a/profiler-test/src/test/java/com/navercorp/pinpoint/test/MockApplicationContextModuleTest.java +++ b/profiler-test/src/test/java/com/navercorp/pinpoint/test/MockApplicationContextModuleTest.java @@ -18,23 +18,24 @@ import com.google.inject.Injector; import com.google.inject.Module; -import com.google.inject.util.Modules; import com.navercorp.pinpoint.bootstrap.AgentOption; import com.navercorp.pinpoint.bootstrap.DefaultAgentOption; import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; import com.navercorp.pinpoint.profiler.AgentInfoSender; -import com.navercorp.pinpoint.profiler.ClassFileTransformerDispatcher; -import com.navercorp.pinpoint.profiler.context.module.ApplicationContextModule; import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; import org.junit.Assert; import org.junit.Test; +import org.mockito.Mockito; -import java.net.URL; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.Instrumentation; +import java.util.Collections; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; /** * @author Woonduk Kang(emeroad) @@ -43,40 +44,38 @@ public class MockApplicationContextModuleTest { @Test public void test() { - ProfilerConfig profilerConfig = new DefaultProfilerConfig(); + ProfilerConfig profilerConfig = spy(new DefaultProfilerConfig()); + when(profilerConfig.getStaticResourceCleanup()).thenReturn(true); + Instrumentation instrumentation = Mockito.mock(Instrumentation.class); - AgentOption agentOption = new DefaultAgentOption(new DummyInstrumentation(), - "mockAgent", "mockApplicationName", profilerConfig, new URL[0], - null, new DefaultServiceTypeRegistryService(), new DefaultAnnotationKeyRegistryService()); + AgentOption agentOption = new DefaultAgentOption(instrumentation, + "mockAgent", "mockApplicationName", false, profilerConfig, Collections.emptyList(), + null); PluginTestAgent pluginTestAgent = new PluginTestAgent(agentOption); try { pluginTestAgent.start(); } finally { - pluginTestAgent.stop(true); + pluginTestAgent.stop(); } } @Test public void testMockApplicationContext() { - ProfilerConfig profilerConfig = new DefaultProfilerConfig(); - InterceptorRegistryBinder binder = new TestInterceptorRegistryBinder(); - AgentOption agentOption = new DefaultAgentOption(new DummyInstrumentation(), - "mockAgent", "mockApplicationName", profilerConfig, new URL[0], - null, new DefaultServiceTypeRegistryService(), new DefaultAnnotationKeyRegistryService()); - - ModuleFactory moduleFactory = new ModuleFactory() { - @Override - public Module newModule(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) { + ProfilerConfig profilerConfig = spy(new DefaultProfilerConfig()); + when(profilerConfig.getStaticResourceCleanup()).thenReturn(true); + Instrumentation instrumentation = Mockito.mock(Instrumentation.class); - Module module = new ApplicationContextModule(agentOption, interceptorRegistryBinder); - Module pluginModule = new PluginApplicationContextModule(); + AgentOption agentOption = new DefaultAgentOption(instrumentation, + "mockAgent", "mockApplicationName", false, profilerConfig, Collections.emptyList(), + null); - return Modules.override(module).with(pluginModule); - } - }; + Module pluginModule = new PluginApplicationContextModule(); + InterceptorRegistryBinder interceptorRegistryBinder = new TestInterceptorRegistryBinder(); + Module testInterceptorRegistryModule = InterceptorRegistryModule.wrap(interceptorRegistryBinder); + ModuleFactory moduleFactory = new OverrideModuleFactory(pluginModule, testInterceptorRegistryModule); - DefaultApplicationContext applicationContext = new DefaultApplicationContext(agentOption, binder, moduleFactory); + DefaultApplicationContext applicationContext = new DefaultApplicationContext(agentOption, moduleFactory); Injector injector = applicationContext.getInjector(); // singleton check @@ -84,7 +83,9 @@ public Module newModule(AgentOption agentOption, InterceptorRegistryBinder inter AgentInfoSender instance2 = injector.getInstance(AgentInfoSender.class); Assert.assertSame(instance1, instance2); - ClassFileTransformerDispatcher instance4 = injector.getInstance(ClassFileTransformerDispatcher.class); + ClassFileTransformer instance4 = injector.getInstance(ClassFileTransformer.class); + + applicationContext.close(); } diff --git a/profiler-test/src/test/java/com/navercorp/pinpoint/test/OrderedSpanRecorderTest.java b/profiler-test/src/test/java/com/navercorp/pinpoint/test/OrderedSpanRecorderTest.java index 44c65ea6030d..9c4c2c4a5a18 100644 --- a/profiler-test/src/test/java/com/navercorp/pinpoint/test/OrderedSpanRecorderTest.java +++ b/profiler-test/src/test/java/com/navercorp/pinpoint/test/OrderedSpanRecorderTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2015 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -25,17 +25,20 @@ import java.util.List; import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.DefaultLocalAsyncId; +import com.navercorp.pinpoint.profiler.context.LocalAsyncId; +import com.navercorp.pinpoint.profiler.context.Span; +import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.SpanEvent; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import org.apache.thrift.TBase; import org.junit.After; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.navercorp.pinpoint.profiler.context.Span; -import com.navercorp.pinpoint.profiler.context.SpanEvent; /** * @author HyunGil Jeong @@ -59,22 +62,21 @@ public void tearDown() throws Exception { @Test public void testOrderingWithSameEventTime() { // given - final long startTime = System.currentTimeMillis(); + final long startTime = 100; final long spanId = 1L; TraceId traceId = new DefaultTraceId(agentId, startTime, 0,-1L, spanId, (short)0); final TraceRoot traceRoot = new DefaultTraceRoot(traceId, agentId, startTime, 0); - - Span span = createSpan(traceRoot, startTime, spanId); - SpanEvent event = createSpanEvent(traceRoot, 0, (short) 0); - SpanEvent event1 = createSpanEvent(traceRoot, 0, (short) 1); - SpanEvent event2 = createSpanEvent(traceRoot, 0, (short) 2); - SpanEvent asyncEvent1_1 = createAsyncSpanEvent(traceRoot, 0, (short) 0, 1, (short) 1); - SpanEvent asyncEvent1_2 = createAsyncSpanEvent(traceRoot, 0, (short) 1, 1, (short) 1); - SpanEvent asyncEvent2 = createAsyncSpanEvent(traceRoot, 0, (short) 0, 2, (short) 1); + Span span = createSpan(traceRoot, startTime); + SpanChunk event = wrapSpanChunk(traceRoot, createSpanEvent(traceRoot, 0, (short) 0)); + SpanChunk event1 = wrapSpanChunk(traceRoot, createSpanEvent(traceRoot, 0, (short) 1)); + SpanChunk event2 = wrapSpanChunk(traceRoot, createSpanEvent(traceRoot, 0, (short) 2)); + SpanChunk asyncEvent1_1 = wrapSpanChunk(traceRoot, createAsyncSpanEvent(traceRoot, 0, (short) 0, 1, (short) 1)); + SpanChunk asyncEvent1_2 = wrapSpanChunk(traceRoot, createAsyncSpanEvent(traceRoot, 0, (short) 1, 1, (short) 1)); + SpanChunk asyncEvent2 = wrapSpanChunk(traceRoot, createAsyncSpanEvent(traceRoot, 0, (short) 0, 2, (short) 1)); @SuppressWarnings("unchecked") - final List> expectedOrder = Arrays.asList( + final List expectedOrder = Arrays.asList( span, event, event1, @@ -85,19 +87,21 @@ public void testOrderingWithSameEventTime() { ); // when @SuppressWarnings("unchecked") - final List> listToBeHandled = Arrays.asList( + final List listToBeHandled = Arrays.asList( span, event, event1, event2, asyncEvent1_1, asyncEvent1_2, asyncEvent2 ); Collections.shuffle(listToBeHandled); - for (TBase base : listToBeHandled) { + for (Object base : listToBeHandled) { this.recorder.handleSend(base); } // then ByteArrayOutputStream baos = new ByteArrayOutputStream(); this.recorder.print(new PrintStream(baos)); this.logger.debug(baos.toString()); - for (TBase expectedBase : expectedOrder) { - TBase actualBase = this.recorder.pop(); + for (Object expectedBase : expectedOrder) { + expectedBase = unwrapSpanChunk(expectedBase); + + Object actualBase = this.recorder.pop(); assertSame(expectedBase, actualBase); } assertNull(this.recorder.pop()); @@ -106,7 +110,7 @@ public void testOrderingWithSameEventTime() { @Test public void testMultipleAsyncSpanEvents() { // given - final long startTime1 = System.currentTimeMillis(); + final long startTime1 = 100; final long spanId = 1L; TraceId traceId1 = new DefaultTraceId(agentId, startTime1, 0,-1L, spanId, (short)0); final TraceRoot traceRoot1 = new DefaultTraceRoot(traceId1, agentId, startTime1, 0); @@ -118,16 +122,17 @@ public void testMultipleAsyncSpanEvents() { final TraceRoot traceRoot2 = new DefaultTraceRoot(traceId2, agentId, startTime2, 0); - Span span = createSpan(traceRoot1, startTime1, spanId); - SpanEvent event1 = createSpanEvent(traceRoot1, 0, (short) 0); - SpanEvent asyncEvent1_1_1 = createAsyncSpanEvent(traceRoot1, 0, (short) 0, 1, (short) 1); - SpanEvent asyncEvent1_1_2 = createAsyncSpanEvent(traceRoot1, 0, (short) 1, 1, (short) 1); - SpanEvent asyncEvent1_2_1 = createAsyncSpanEvent(traceRoot1, 0, (short) 0, 1, (short) 2); - SpanEvent event2 = createSpanEvent(traceRoot2, 0, (short) 1); - SpanEvent asyncEvent2_1 = createAsyncSpanEvent(traceRoot2, 0, (short) 0, 2, (short) 1); - SpanEvent asyncEvent2_2 = createAsyncSpanEvent(traceRoot2, 0, (short) 0, 2, (short) 2); + Span span = createSpan(traceRoot1, startTime1); + SpanChunk event1 = wrapSpanChunk(traceRoot1, createSpanEvent(traceRoot1, 0, (short) 0)); + SpanChunk asyncEvent1_1_1 = wrapSpanChunk(traceRoot1, createAsyncSpanEvent(traceRoot1, 0, (short) 0, 1, (short) 1)); + SpanChunk asyncEvent1_1_2 = wrapSpanChunk(traceRoot1, createAsyncSpanEvent(traceRoot1, 0, (short) 1, 1, (short) 1)); + SpanChunk asyncEvent1_2_1 = wrapSpanChunk(traceRoot1, createAsyncSpanEvent(traceRoot1, 0, (short) 0, 1, (short) 2)); + + SpanChunk event2 = wrapSpanChunk(traceRoot2, createSpanEvent(traceRoot2, 0, (short) 1)); + SpanChunk asyncEvent2_1 = wrapSpanChunk(traceRoot2, createAsyncSpanEvent(traceRoot2, 0, (short) 0, 2, (short) 1)); + SpanChunk asyncEvent2_2 = wrapSpanChunk(traceRoot2, createAsyncSpanEvent(traceRoot2, 0, (short) 0, 2, (short) 2)); @SuppressWarnings("unchecked") - final List> expectedOrder = Arrays.asList( + final List expectedOrder = Arrays.asList( span, event1, event2, @@ -139,19 +144,21 @@ public void testMultipleAsyncSpanEvents() { ); // when @SuppressWarnings("unchecked") - final List> listToBeHandled = Arrays.asList( + final List listToBeHandled = Arrays.asList( span, event1, asyncEvent1_1_1, asyncEvent1_1_2, asyncEvent1_2_1, event2, asyncEvent2_1, asyncEvent2_2 ); Collections.shuffle(listToBeHandled); - for (TBase base : listToBeHandled) { + for (Object base : listToBeHandled) { this.recorder.handleSend(base); } // then ByteArrayOutputStream baos = new ByteArrayOutputStream(); this.recorder.print(new PrintStream(baos)); this.logger.debug(baos.toString()); - for (TBase expectedBase : expectedOrder) { - TBase actualBase = this.recorder.pop(); + for (Object expectedBase : expectedOrder) { + expectedBase = unwrapSpanChunk(expectedBase); + + Object actualBase = this.recorder.pop(); assertSame(expectedBase, actualBase); } assertNull(this.recorder.pop()); @@ -160,7 +167,7 @@ public void testMultipleAsyncSpanEvents() { @Test public void testMultipleSpanOrdering() { // given - final long startTime1 = System.currentTimeMillis(); + final long startTime1 = 100; final long spanId1 = 1L; final TraceId traceId1 = new DefaultTraceId(agentId, startTime1, 0,-1L, spanId1, (short)0); final TraceRoot traceRoot1 = new DefaultTraceRoot(traceId1, agentId, startTime1, 0); @@ -170,17 +177,18 @@ public void testMultipleSpanOrdering() { final TraceId traceId2 = new DefaultTraceId(agentId, startTime2, 0,-1L, spanId2, (short)0); final TraceRoot traceRoot2 = new DefaultTraceRoot(traceId2, agentId, startTime2, 0); - Span span1 = createSpan(traceRoot1, startTime1, spanId1); - SpanEvent event1_0 = createSpanEvent(traceRoot1, 1, (short) 0); - SpanEvent event1_1 = createSpanEvent(traceRoot1, 2, (short) 1); - SpanEvent asyncEvent1_0 = createAsyncSpanEvent(traceRoot1, 1, (short) 0, 1, (short) 1); - SpanEvent asyncEvent1_1 = createAsyncSpanEvent(traceRoot1, 2, (short) 1, 1, (short) 1); - Span span2 = createSpan(traceRoot2, startTime2, spanId2); - SpanEvent event2_0 = createSpanEvent(traceRoot2, 0, (short) 0); - SpanEvent event2_1 = createSpanEvent(traceRoot2, 1, (short) 1); - SpanEvent asyncEvent2_0 = createAsyncSpanEvent(traceRoot2, 0, (short) 0, 2, (short) 1); + Span span1 = createSpan(traceRoot1, startTime1); + SpanChunk event1_0 = wrapSpanChunk(traceRoot1, createSpanEvent(traceRoot1, 1, (short) 0)); + SpanChunk event1_1 = wrapSpanChunk(traceRoot1, createSpanEvent(traceRoot1,2, (short) 1)); + SpanChunk asyncEvent1_0 = wrapSpanChunk(traceRoot1, createAsyncSpanEvent(traceRoot1,1, (short) 0, 1, (short) 1)); + SpanChunk asyncEvent1_1 = wrapSpanChunk(traceRoot1, createAsyncSpanEvent(traceRoot1, 2, (short) 1, 1, (short) 1)); + + Span span2 = createSpan(traceRoot2, startTime2); + SpanChunk event2_0 = wrapSpanChunk(traceRoot2, createSpanEvent(traceRoot2, 0, (short) 0)); + SpanChunk event2_1 = wrapSpanChunk(traceRoot2, createSpanEvent(traceRoot2, 1, (short) 1)); + SpanChunk asyncEvent2_0 = wrapSpanChunk(traceRoot2, createAsyncSpanEvent(traceRoot2, 0, (short) 0, 2, (short) 1)); @SuppressWarnings("unchecked") - final List> expectedOrder = Arrays.asList( + final List expectedOrder = Arrays.asList( span1, event1_0, event1_1, @@ -193,54 +201,70 @@ public void testMultipleSpanOrdering() { ); // when @SuppressWarnings("unchecked") - final List> listToBeHandled = Arrays.asList( + final List listToBeHandled = Arrays.asList( span1, event1_0, event1_1, span2, event2_0, event2_1, asyncEvent1_0, asyncEvent1_1, asyncEvent2_0 ); Collections.shuffle(listToBeHandled); - for (TBase base : listToBeHandled) { + for (Object base : listToBeHandled) { this.recorder.handleSend(base); } // then ByteArrayOutputStream baos = new ByteArrayOutputStream(); this.recorder.print(new PrintStream(baos)); this.logger.debug(baos.toString()); - for (TBase expectedBase : expectedOrder) { - TBase actualBase = this.recorder.pop(); + for (Object expectedBase : expectedOrder) { + expectedBase = unwrapSpanChunk(expectedBase); + + Object actualBase = this.recorder.pop(); assertSame(expectedBase, actualBase); } assertNull(this.recorder.pop()); } - private SpanEvent createSpanEvent(TraceRoot traceRoot, int startElapsed, short sequence) { - return createAsyncSpanEvent(traceRoot, startElapsed, sequence, UNSET_ASYNC_ID, UNSET_ASYNC_SEQUENCE); + private SpanEvent createSpanEvent(TraceRoot traceRoot1, int startElapsed, short sequence) { + return createAsyncSpanEvent(traceRoot1, startElapsed, sequence, UNSET_ASYNC_ID, UNSET_ASYNC_SEQUENCE); } private SpanEvent createAsyncSpanEvent(TraceRoot traceRoot, int startElapsed, short sequence, int asyncId, short asyncSequence) { - if (traceRoot == null) { - throw new NullPointerException("associatedLocalTraceId must not be null"); - } + Assert.requireNonNull(traceRoot, "traceRoot must not be null"); if (startElapsed < 0) { throw new IllegalArgumentException("startElapsed cannot be less than 0"); } if (sequence < 0) { throw new IllegalArgumentException("sequence cannot be less than 0"); } - SpanEvent event = new SpanEvent(traceRoot); - event.setStartElapsed(startElapsed); + SpanEvent event = new SpanEvent(); + long startTime = traceRoot.getTraceStartTime() + startElapsed; + event.setStartTime(startTime); event.setSequence(sequence); - if (asyncId != UNSET_ASYNC_ID) { - event.setAsyncId(asyncId); - } - if (asyncSequence != UNSET_ASYNC_SEQUENCE) { - event.setAsyncSequence(asyncSequence); + if (asyncId != UNSET_ASYNC_ID && asyncSequence != UNSET_ASYNC_SEQUENCE) { + LocalAsyncId localAsyncId = new DefaultLocalAsyncId(asyncId, asyncSequence); + event.setLocalAsyncId(localAsyncId); } return event; } - private Span createSpan(TraceRoot traceRoot, long startTime, long spanId) { + + private Object unwrapSpanChunk(Object tBase) { + if (tBase instanceof SpanChunk) { + List spanEventList = ((SpanChunk) tBase).getSpanEventList(); + if (spanEventList.size() != 1) { + throw new IllegalStateException("spanEvent size must be 1 " + tBase); + } + return spanEventList.get(0); + } + return tBase; + } + + private SpanChunk wrapSpanChunk(TraceRoot traceRoot, SpanEvent event) { + SpanChunk spanChunk = new SpanChunk(traceRoot, Collections.singletonList(event)); + return spanChunk; + } + + + private Span createSpan(TraceRoot traceRoot, long startTime) { Span span = new Span(traceRoot); span.setStartTime(startTime); - span.setSpanId(spanId); return span; } diff --git a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavaAssistInterceptorTest.java b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavaAssistInterceptorTest.java deleted file mode 100644 index 2f61715e2d6e..000000000000 --- a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavaAssistInterceptorTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.test.javasssit; - - -import com.navercorp.pinpoint.test.util.LoaderUtils; -import javassist.*; -import javassist.expr.ExprEditor; -import javassist.expr.MethodCall; - -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.reflect.InvocationTargetException; - -/** - * @author emeroad - */ -@Deprecated -public class JavaAssistInterceptorTest { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - - @Test - public void afterCatch() throws NotFoundException, CannotCompileException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException { - ClassPool pool = new ClassPool(true); - Loader loader = getLoader(pool); - - CtClass ctClass = pool.get("com.navercorp.pinpoint.test.javasssit.mock.TestObject"); - CtClass object = pool.get("java.lang.String"); - - logger.debug("target:{}", ctClass); - - - CtMethod callA = ctClass.getDeclaredMethod("callA", null); - logger.debug("callA:{}", callA); -// callA.addLocalVariable("__test", object); - final String before = "{ java.lang.Throwable __throwable = null; java.lang.String __test = \"abc\"; System.out.println(\"BEFORE\" + __test);"; -// callA.insertBefore(); -// callA.insertAfter("System.out.println(\"AFTER\" + __test);"); -// final String AFTER = "finally {System.out.println(\"AFTER\" + __test);}}"; - final String after = "}"; -// callA.addCatch(); - -// callA.addCatch("System.out.println(\"AFTER\");", pool.get("java.lang.Throwable")); - callA.instrument(new ExprEditor() { - @Override - public void edit(MethodCall m) throws CannotCompileException { - logger.debug("edit class{}", m.getClassName()); - try { - logger.debug("edit method:{}", m.getMethod().toString()); - } catch (NotFoundException e) { - logger.warn("getMethod() fail. Caused:{}", e.getMessage(), e); - } - logger.debug(m.getMethodName()); - m.replace(before + " try {$_ = $proceed($$); System.out.println(\"end---\"+ $_);} catch (java.lang.Throwable ex) { __throwable = ex; System.out.println(\"catch\"); } " + after); - } - }); - - - Class aClass = loader.loadClass(ctClass.getName()); - java.lang.reflect.Method callA1 = aClass.getMethod("callA"); - Object target = aClass.newInstance(); - Object result = callA1.invoke(target); - logger.debug("result:{}", result); - } - - @Test - public void afterCatch2() throws NotFoundException, CannotCompileException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException { - ClassPool pool = new ClassPool(true); - Loader loader = getLoader(pool); - CtClass ctClass = pool.get("com.navercorp.pinpoint.test.javasssit.mock.TestObject"); - CtClass object = pool.get("java.lang.String"); - logger.debug("target:{}", ctClass); - - - CtMethod callA = ctClass.getDeclaredMethod("callA", null); - logger.debug("callA:{}", callA); - callA.addLocalVariable("__test", object); - callA.insertBefore("{ __test = \"abc\"; System.out.println(\"BEFORE\" + __test); }"); - callA.insertAfter("{ System.out.println(\"AFTER\"); }"); - callA.addCatch("{ System.out.println(\"catch\"); throw $e; }", pool.get("java.lang.Throwable")); - - Class aClass = loader.loadClass(ctClass.getName()); - java.lang.reflect.Method callA1 = aClass.getMethod("callA"); - Object target = aClass.newInstance(); - Object result = callA1.invoke(target); - logger.debug("result:{}", result); - - } - - @Test - public void around() throws NotFoundException, CannotCompileException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, ClassNotFoundException { - ClassPool pool = new ClassPool(true); - Loader loader = getLoader(pool); - - - CtClass ctClass = pool.get("com.navercorp.pinpoint.test.javasssit.mock.TestObject"); - CtClass object = pool.get("java.lang.String"); - logger.debug("target:{}", ctClass); - - CtMethod callA = ctClass.getDeclaredMethod("callA", null); - logger.debug("callA:{}", callA); - callA.addLocalVariable("__test", object); - String inti = "__test = \"abc\";"; -// callA.insertBefore("__test = \"abc\";); - callA.insertBefore("{com.navercorp.pinpoint.test.javasssit.mock.TestObject.before();}"); - callA.insertAfter("{com.navercorp.pinpoint.test.javasssit.mock.TestObject.after();}"); - callA.addCatch("{ com.navercorp.pinpoint.test.javasssit.mock.TestObject.callCatch(); throw $e; }", pool.get("java.lang.Throwable")); - - Class aClass = loader.loadClass(ctClass.getName()); - java.lang.reflect.Method callA1 = aClass.getMethod("callA"); - Object target = aClass.newInstance(); - Object result = callA1.invoke(target); - logger.debug("result:{}", result); - - } - - private Loader getLoader(ClassPool pool) { - return LoaderUtils.createLoader(pool); - } -} diff --git a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavaAssistTest.java b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavaAssistTest.java index cfab8d8b0076..f885df8628b9 100644 --- a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavaAssistTest.java +++ b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavaAssistTest.java @@ -16,18 +16,11 @@ package com.navercorp.pinpoint.test.javasssit; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.NotFoundException; -import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.reflect.Method; import java.net.URL; -import java.util.Arrays; /** * @author emeroad @@ -37,46 +30,10 @@ public class JavaAssistTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private ClassPool pool; - - @Before - public void setUp() throws Exception { - pool = new ClassPool(); - pool.appendSystemPath(); - } - - @Test - public void testAssist() throws NotFoundException, NoSuchMethodException { - - CtClass ctClass = pool.get(String.class.getName()); - logger.debug(ctClass.toString()); - String s = ""; -// ctClass.getMethod("valueOf", "(D)"); - - CtMethod[] methods = ctClass.getMethods(); -// for (CtMethod method : methods) { -// logger.debug("{} {}", method.getMethodInfo(), method.getSignature()); -// } - - CtMethod endsWith = ctClass.getMethod("endsWith", "(Ljava/lang/String;)Z"); - logger.debug(endsWith.getMethodInfo().toString()); - logger.debug(endsWith.getSignature()); - logger.debug(endsWith.getLongName()); - logger.debug(endsWith.toString()); - logger.debug(endsWith.getName()); - logger.debug(endsWith.getMethodInfo().getName()); - logger.debug(endsWith.getMethodInfo().getDescriptor()); - - Method endsWith1 = String.class.getMethod("endsWith", String.class); - logger.debug(endsWith1.toString()); - - } - @Test public void test() { - sout("/java/lang/String.class"); + sout("java/lang/String.class"); sout("java.lang.String.class"); - } private void sout(String str) { @@ -84,44 +41,5 @@ private void sout(String str) { logger.debug("{}", resource); } - @Test - public void genericTest() throws NotFoundException { - CtClass testClass = pool.get("com.navercorp.pinpoint.test.javasssit.TestClass"); -// CtMethod setb = testClass.getMethod("setb"); - CtMethod[] declaredMethods = testClass.getDeclaredMethods(); - for (CtMethod declaredMethod : declaredMethods) { - logger.debug(declaredMethod.toString()); - logger.debug(declaredMethod.getGenericSignature()); - logger.debug(declaredMethod.getSignature()); - logger.debug("paramTypes:{}", Arrays.toString(declaredMethod.getParameterTypes())); - logger.debug(declaredMethod.getMethodInfo2().getDescriptor()); - logger.debug(declaredMethod.getMethodInfo().getDescriptor()); -// logger.debug(declaredMethod.()); - } - - - CtMethod setb = testClass.getDeclaredMethod("setA", new CtClass[]{pool.get("int")}); - logger.debug(setb.toString()); - CtMethod setStringArray = testClass.getDeclaredMethod("setStringArray", new CtClass[]{pool.get("java.lang.String[]")}); - logger.debug(setStringArray.toString()); - - - } - - @Test - public void innerClass() throws NotFoundException { - CtClass testClass = pool.get("com.navercorp.pinpoint.test.javasssit.TestClass"); - logger.debug(testClass.toString()); - CtClass[] nestedClasses = testClass.getNestedClasses(); - for(CtClass nested : nestedClasses) { - logger.debug("nestedClass:{}", nested); - } - - CtClass innerClass = pool.get("com.navercorp.pinpoint.test.javasssit.TestClass$InnerClass"); - logger.debug("{}", innerClass); - - CtClass class1 = pool.get("com.navercorp.pinpoint.test.javasssit.TestClass$1"); - logger.debug("{}", class1); - } } diff --git a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavassistClassTest.java b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavassistClassTest.java index 0d80ba9bc23b..cda349b0d042 100644 --- a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavassistClassTest.java +++ b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/JavassistClassTest.java @@ -1,31 +1,23 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ package com.navercorp.pinpoint.test.javasssit; -import com.google.inject.Provider; -import com.google.inject.util.Providers; import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; - -import com.navercorp.pinpoint.bootstrap.instrument.ClassFilters; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; -import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; -import com.navercorp.pinpoint.common.util.ArrayUtils; -import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; import com.navercorp.pinpoint.bootstrap.instrument.Instrumentor; @@ -33,16 +25,11 @@ import com.navercorp.pinpoint.bootstrap.interceptor.Interceptor; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.profiler.instrument.JavassistEngine; -import com.navercorp.pinpoint.profiler.interceptor.registry.GlobalInterceptorRegistryBinder; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.profiler.logging.Slf4jLoggerBinder; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; -import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; -import com.navercorp.pinpoint.test.MockApplicationContext; import com.navercorp.pinpoint.test.MockApplicationContextFactory; import com.navercorp.pinpoint.test.classloader.TestClassLoader; -import com.navercorp.pinpoint.test.util.BytecodeUtils; -import javassist.bytecode.Descriptor; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; @@ -50,109 +37,45 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.instrument.Instrumentation; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.ProtectionDomain; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; /** * @author emeroad */ -@Deprecated +//@Deprecated public class JavassistClassTest { private Logger logger = LoggerFactory.getLogger(JavassistClassTest.class.getName()); + private DefaultApplicationContext applicationContext; + Slf4jLoggerBinder loggerBinder = new Slf4jLoggerBinder(); + @Before - public void clear() { + public void setUp() throws Exception { TestInterceptors.clear(); - } - - private byte[] readByteCode(String className) { - final ClassLoader classLoader = ClassLoader.getSystemClassLoader(); - return BytecodeUtils.getClassFile(classLoader, className); - } - - @Test - public void testClassHierarchy() throws InstrumentException { - InstrumentEngine engine = newJavassistEngine(); + PLoggerFactory.initialize(loggerBinder); - InstrumentContext instrumentContext = mock(InstrumentContext.class); - String testObjectName = "com.navercorp.pinpoint.test.javasssit.mock.TestObject"; - - byte[] testObjectByteCode = readByteCode(testObjectName); - InstrumentClass testObject = engine.getClass(instrumentContext, null, testObjectName, testObjectByteCode); - - Assert.assertEquals(testObject.getName(), testObjectName); - - String testObjectSuperClass = testObject.getSuperClass(); - Assert.assertEquals("java.lang.Object", testObjectSuperClass); - - String[] testObjectSuperClassInterfaces = testObject.getInterfaces(); - Assert.assertEquals(testObjectSuperClassInterfaces.length, 0); - - final String classHierarchyTestMockName = "com.navercorp.pinpoint.test.javasssit.mock.ClassHierarchyTestMock"; - byte[] classHierarchyTestMockByteCode = readByteCode(classHierarchyTestMockName); - InstrumentClass classHierarchyObject = engine.getClass(instrumentContext, null, classHierarchyTestMockName, classHierarchyTestMockByteCode); - String hierarchySuperClass = classHierarchyObject.getSuperClass(); - Assert.assertEquals("java.util.HashMap", hierarchySuperClass); + DefaultProfilerConfig profilerConfig = new DefaultProfilerConfig(); + profilerConfig.setApplicationServerType(ServiceType.TEST_STAND_ALONE.getName()); + profilerConfig.setStaticResourceCleanup(true); - String[] hierarchyInterfaces = classHierarchyObject.getInterfaces(); - Assert.assertEquals(hierarchyInterfaces.length, 2); - Assert.assertEquals(hierarchyInterfaces[0], "java.lang.Runnable"); - Assert.assertEquals(hierarchyInterfaces[1], "java.lang.Comparable"); + MockApplicationContextFactory factory = new MockApplicationContextFactory(); + this.applicationContext = factory.build(profilerConfig); + this.applicationContext.start(); } - private InstrumentEngine newJavassistEngine() { - Instrumentation instrumentation = mock(Instrumentation.class); - ObjectBinderFactory objectBinderFactory = mock(ObjectBinderFactory.class); - Provider apiMetaDataService = Providers.of(mock(ApiMetaDataService.class)); - - return new JavassistEngine(instrumentation, objectBinderFactory, new GlobalInterceptorRegistryBinder(), apiMetaDataService, null); + @After + public void tearDown() throws Exception { + PLoggerFactory.unregister(loggerBinder); + if (this.applicationContext != null) { + this.applicationContext.close(); + } } - @Test - public void testDeclaredMethod() throws InstrumentException { - - InstrumentEngine engine = newJavassistEngine(); - - InstrumentContext instrumentContext = mock(InstrumentContext.class); - String testObjectName = "com.navercorp.pinpoint.test.javasssit.mock.TestObject"; - byte[] testObjectByteCode = readByteCode(testObjectName); - InstrumentClass testObject = engine.getClass(instrumentContext, null, testObjectName, testObjectByteCode); - - Assert.assertEquals(testObject.getName(), testObjectName); - InstrumentMethod declaredMethod = testObject.getDeclaredMethod("callA"); - Assert.assertNotNull(declaredMethod); - - } - - @Test - public void testDeclaredMethods() throws InstrumentException { - InstrumentEngine engine = newJavassistEngine(); - - InstrumentContext instrumentContext = mock(InstrumentContext.class); - String testObjectName = "com.navercorp.pinpoint.test.javasssit.mock.TestObject"; - byte[] testObjectByteCode = readByteCode(testObjectName); - InstrumentClass testObject = engine.getClass(instrumentContext, null, testObjectName, testObjectByteCode); - Assert.assertEquals(testObject.getName(), testObjectName); - - int findMethodCount = 0; - for (InstrumentMethod methodInfo : testObject.getDeclaredMethods()) { - if (!methodInfo.getName().equals("callA")) { - continue; - } - String[] parameterTypes = methodInfo.getParameterTypes(); - if (ArrayUtils.isEmpty(parameterTypes)) { - findMethodCount++; - } - } - Assert.assertEquals(findMethodCount, 1); - } @Test public void testBeforeAddInterceptor() throws Exception { @@ -206,26 +129,18 @@ private Interceptor getInterceptor(final TestClassLoader loader, int index) thro } private TestClassLoader getTestClassLoader() { - PLoggerFactory.initialize(new Slf4jLoggerBinder()); - - DefaultProfilerConfig profilerConfig = new DefaultProfilerConfig(); - profilerConfig.setApplicationServerType(ServiceType.TEST_STAND_ALONE.getName()); - - MockApplicationContextFactory factory = new MockApplicationContextFactory(); - MockApplicationContext applicationContext = factory.of(profilerConfig); - TestClassLoader testClassLoader = new TestClassLoader(applicationContext); testClassLoader.initialize(); return testClassLoader; } - public void assertEqualsIntField(Object target, String fieldName, int value) throws NoSuchFieldException, IllegalAccessException { + private void assertEqualsIntField(Object target, String fieldName, int value) throws NoSuchFieldException, IllegalAccessException { Field field = target.getClass().getField(fieldName); int anInt = field.getInt(target); Assert.assertEquals(anInt, value); } - public void assertEqualsObjectField(Object target, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException { + private void assertEqualsObjectField(Object target, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException { Field field = target.getClass().getField(fieldName); Object obj = field.get(target); Assert.assertEquals(value, obj); @@ -291,55 +206,5 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, } - @Test - public void nullDescriptor() { - String nullDescriptor = Descriptor.ofParameters(null); - logger.debug("Descriptor null:{}", nullDescriptor); - } - - - - @Test - public void getNestedClasses() throws Exception { - - InstrumentEngine engine = newJavassistEngine(); - - InstrumentContext instrumentContext = mock(InstrumentContext.class); - String testObjectName = "com.navercorp.pinpoint.test.javasssit.mock.TestObjectNestedClass"; - - byte[] testObjectByteCode = readByteCode(testObjectName); - InstrumentClass testObject = engine.getClass(instrumentContext, null, testObjectName, testObjectByteCode); - Assert.assertEquals(testObject.getName(), testObjectName); - - // find class name condition. - final String targetClassName = "com.navercorp.pinpoint.profiler.interceptor.bci.TestObjectNestedClass$InstanceInner"; - for (InstrumentClass c : testObject.getNestedClasses(ClassFilters.name(targetClassName))) { - assertEquals(targetClassName, c.getName()); - } - - // find enclosing method condition. - assertEquals(2, testObject.getNestedClasses(ClassFilters.enclosingMethod("annonymousInnerClass")).size()); - - // find interface condition. - assertEquals(2, testObject.getNestedClasses(ClassFilters.interfaze("java.util.concurrent.Callable")).size()); - - // find enclosing method & interface condition. - assertEquals(1, testObject.getNestedClasses(ClassFilters.chain(ClassFilters.enclosingMethod("annonymousInnerClass"), ClassFilters.interfaze("java.util.concurrent.Callable"))).size()); - } - - @Test - public void hasEnclodingMethod() throws Exception { - - InstrumentEngine engine = newJavassistEngine(); - InstrumentContext instrumentContext = mock(InstrumentContext.class); - String testObjectName = "com.navercorp.pinpoint.test.javasssit.mock.TestObjectNestedClass"; - - byte[] testObjectByteCode = readByteCode(testObjectName); - InstrumentClass testObject = engine.getClass(instrumentContext, null, testObjectName, testObjectByteCode); - Assert.assertEquals(testObject.getName(), testObjectName); - - assertEquals(1, testObject.getNestedClasses(ClassFilters.enclosingMethod("enclosingMethod", "java.lang.String", "int")).size()); - assertEquals(0, testObject.getNestedClasses(ClassFilters.enclosingMethod("enclosingMethod", "int")).size()); - } } diff --git a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/TestBeforeInterceptor.java b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/TestBeforeInterceptor.java index ca1fd95ddacc..091d04b5cfa4 100644 --- a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/TestBeforeInterceptor.java +++ b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/TestBeforeInterceptor.java @@ -1,18 +1,17 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ package com.navercorp.pinpoint.test.javasssit; @@ -41,7 +40,7 @@ public class TestBeforeInterceptor implements StaticAroundInterceptor { @Override public void before(Object target, String className, String methodName, String parameterDescription, Object[] args) { - logger.info("BEFORE target:" + target + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args)); + logger.info("BEFORE target:" + toClassName(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args)); this.target = target; this.className = className; this.methodName = methodName; @@ -51,6 +50,13 @@ public void before(Object target, String className, String methodName, String pa TestInterceptors.add(this); } + private String toClassName(Object target) { + if (target == null) { + return "null"; + } + return target.getClass().getName(); + } + @Override public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result, Throwable throwable) { diff --git a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/TestBootstrapClass.java b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/TestBootstrapClass.java index 8dc2e3216d6d..4b0016ff3e0c 100644 --- a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/TestBootstrapClass.java +++ b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/TestBootstrapClass.java @@ -22,12 +22,6 @@ import java.net.URL; import java.net.URLClassLoader; -import com.navercorp.pinpoint.test.util.BytecodeUtils; -import javassist.CannotCompileException; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.LoaderClassPath; - import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,23 +37,16 @@ public class TestBootstrapClass { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Test - public void test() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, CannotCompileException { - - URLClassLoader classLoader = new URLClassLoader(new URL[]{}); - LoaderClassPath loaderClassPath = new LoaderClassPath(classLoader); - - ClassPool cp = new ClassPool(); - cp.appendClassPath(loaderClassPath); - - CtClass ctClass = cp.makeClass(TEST_CLASS_NAME); - byte[] bytes = ctClass.toBytecode(); - logger.debug(classLoader.getClass().getName()); - Class aClass = BytecodeUtils.defineClass(classLoader, TEST_CLASS_NAME, bytes); + private class TestClassLoader extends URLClassLoader { + public TestClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } - logger.debug("{}", aClass.getName()); + final Class defineClass(String name, byte[] b) throws ClassFormatError { + return super.defineClass(name, b, 0, b.length); + } } diff --git a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/accessor/AccessorInjectionTest.java b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/accessor/AccessorInjectionTest.java index 043561732494..9c89349de109 100644 --- a/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/accessor/AccessorInjectionTest.java +++ b/profiler-test/src/test/java/com/navercorp/pinpoint/test/javasssit/accessor/AccessorInjectionTest.java @@ -26,11 +26,12 @@ import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo; import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.profiler.logging.Slf4jLoggerBinder; -import com.navercorp.pinpoint.test.MockApplicationContext; import com.navercorp.pinpoint.test.MockApplicationContextFactory; import com.navercorp.pinpoint.test.classloader.TestClassLoader; import com.navercorp.pinpoint.test.javasssit.JavassistClassTest; +import org.junit.After; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; @@ -45,7 +46,9 @@ @Deprecated public class AccessorInjectionTest { - private Logger logger = LoggerFactory.getLogger(JavassistClassTest.class.getName()); + private final Logger logger = LoggerFactory.getLogger(JavassistClassTest.class.getName()); + + private DefaultApplicationContext applicationContext; private TestClassLoader getTestClassLoader() { PLoggerFactory.initialize(new Slf4jLoggerBinder()); @@ -54,13 +57,21 @@ private TestClassLoader getTestClassLoader() { profilerConfig.setApplicationServerType(ServiceType.TEST_STAND_ALONE.getName()); MockApplicationContextFactory factory = new MockApplicationContextFactory(); - MockApplicationContext applicationContext = factory.of(profilerConfig); + this.applicationContext = factory.build(profilerConfig); + this.applicationContext.start(); TestClassLoader testClassLoader = new TestClassLoader(applicationContext); testClassLoader.initialize(); return testClassLoader; } + @After + public void tearDown() throws Exception { + if (applicationContext != null) { + applicationContext.close(); + } + } + @Test public void addTraceValue() throws Exception { final TestClassLoader loader = getTestClassLoader(); diff --git a/profiler-test/src/test/java/com/navercorp/pinpoint/test/plugin/DefaultClassEditorBuilderTest.java b/profiler-test/src/test/java/com/navercorp/pinpoint/test/plugin/DefaultClassEditorBuilderTest.java index 64948582c879..92e885cfa685 100644 --- a/profiler-test/src/test/java/com/navercorp/pinpoint/test/plugin/DefaultClassEditorBuilderTest.java +++ b/profiler-test/src/test/java/com/navercorp/pinpoint/test/plugin/DefaultClassEditorBuilderTest.java @@ -18,12 +18,10 @@ package com.navercorp.pinpoint.test.plugin; import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; -import com.navercorp.pinpoint.profiler.context.module.ApplicationContext; import com.navercorp.pinpoint.profiler.util.TypeUtils; import org.junit.Test; @@ -36,11 +34,9 @@ public class DefaultClassEditorBuilderTest { @Test public void test() throws Exception { InstrumentEngine instrumentEngine = mock(InstrumentEngine.class); - TraceContext traceContext = mock(TraceContext.class); InstrumentClass aClass = mock(InstrumentClass.class); InstrumentMethod aMethod = mock(InstrumentMethod.class); MethodDescriptor aDescriptor = mock(MethodDescriptor.class); - ApplicationContext applicationContext = mock(ApplicationContext.class); InstrumentContext context = mock(InstrumentContext.class); ClassLoader classLoader = getClass().getClassLoader(); @@ -50,9 +46,7 @@ public void test() throws Exception { Class[] parameterTypes = new Class[] { String.class }; String[] parameterTypeNames = TypeUtils.toClassNames(parameterTypes); - when(applicationContext.getInstrumentEngine()).thenReturn(instrumentEngine); - when(applicationContext.getTraceContext()).thenReturn(traceContext); - when(instrumentEngine.getClass(context, classLoader, className, classFileBuffer)).thenReturn(aClass); + when(instrumentEngine.getClass(context, classLoader, className, null, classFileBuffer)).thenReturn(aClass); when(aClass.getDeclaredMethod(methodName, parameterTypeNames)).thenReturn(aMethod); when(aMethod.getName()).thenReturn(methodName); when(aMethod.getParameterTypes()).thenReturn(parameterTypeNames); diff --git a/profiler/clover.license b/profiler/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/profiler/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-profiler @@ -19,16 +35,6 @@ com.navercorp.pinpoint pinpoint-commons - - - org.apache.thrift - libthrift - - - org.slf4j - slf4j-api - - com.navercorp.pinpoint @@ -44,6 +50,10 @@ + + com.navercorp.pinpoint + pinpoint-grpc + com.navercorp.pinpoint pinpoint-bootstrap-core @@ -97,17 +107,34 @@ commons-lang3 test - + + com.navercorp.pinpoint + pinpoint-rpc + ${project.version} + test-jar + test + - - org.javassist - javassist + org.ow2.asm + asm org.ow2.asm - asm-debug-all + asm-commons + + + org.ow2.asm + asm-util + + + org.ow2.asm + asm-tree + + + org.ow2.asm + asm-analysis @@ -153,6 +180,19 @@ log4j log4j + + + junit diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInfoSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInfoSender.java index c177fcf06447..ff6c0189cb25 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInfoSender.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInfoSender.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,6 +20,8 @@ import java.util.TimerTask; import java.util.concurrent.atomic.AtomicInteger; +import com.navercorp.pinpoint.io.request.EmptyMessage; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.profiler.util.AgentInfoFactory; import com.navercorp.pinpoint.rpc.DefaultFuture; import com.navercorp.pinpoint.rpc.ResponseMessage; @@ -173,7 +175,7 @@ private boolean sendAgentInfo() { final DefaultFuture future = new DefaultFuture(); logger.info("Sending AgentInfo {}", agentInfo); - dataSender.request(agentInfo, new AgentInfoSenderListener(future)); + dataSender.request(agentInfo, new ResponseMessageFutureListener(future)); if (!future.await()) { logger.warn("request timed out while waiting for response."); return false; @@ -196,12 +198,13 @@ private boolean sendAgentInfo() { } private boolean getResult(ResponseMessage responseMessage) { - byte[] message = responseMessage.getMessage(); - TBase tbase = SerializationUtils.deserialize(message, HeaderTBaseDeserializerFactory.DEFAULT_FACTORY, null); - if (tbase == null) { - logger.warn("tbase is null"); + byte[] byteMessage = responseMessage.getMessage(); + Message> message = SerializationUtils.deserialize(byteMessage, HeaderTBaseDeserializerFactory.DEFAULT_FACTORY, null); + if (message == null) { + logger.warn("message is null"); return false; } + final TBase tbase = message.getData(); if (!(tbase instanceof TResult)) { logger.warn("Invalid response : {}", tbase.getClass()); return false; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInfoSenderListener.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInfoSenderListener.java deleted file mode 100644 index 81c78e80622a..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInfoSenderListener.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler; - -import com.navercorp.pinpoint.rpc.DefaultFuture; -import com.navercorp.pinpoint.rpc.Future; -import com.navercorp.pinpoint.rpc.FutureListener; -import com.navercorp.pinpoint.rpc.ResponseMessage; - -public class AgentInfoSenderListener implements FutureListener { - - private final DefaultFuture future; - - public AgentInfoSenderListener(DefaultFuture future) { - this.future = future; - } - - @Override - public void onComplete(Future future) { - if (future == null) { - this.future.setFailure(new IllegalStateException("ResponseMessage future is null")); - return; - } - if (!future.isReady()) { - this.future.setFailure(new IllegalStateException("ResponseMessage future is not complete")); - return; - } - - if (future.isSuccess()) { - ResponseMessage responseMessage = future.getResult(); - this.future.setResult(responseMessage); - } else { - Throwable cause = future.getCause(); - this.future.setFailure(cause); - } - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInformation.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInformation.java index d11c21d6b8e7..f3732cba6879 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInformation.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/AgentInformation.java @@ -26,6 +26,8 @@ public interface AgentInformation { String getApplicationName(); + boolean isContainer(); + long getStartTime(); int getPid(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/BaseClassFileTransformer.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/BaseClassFileTransformer.java index 9c09b8e46a73..5de629a6e5c4 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/BaseClassFileTransformer.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/BaseClassFileTransformer.java @@ -16,11 +16,13 @@ package com.navercorp.pinpoint.profiler; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.instrument.ClassFileTransformer; +import java.net.URL; import java.security.ProtectionDomain; /** @@ -29,7 +31,6 @@ */ public class BaseClassFileTransformer { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); private final ClassLoader agentClassLoader; @@ -40,12 +41,11 @@ public BaseClassFileTransformer(ClassLoader agentClassLoader) { public byte[] transform(ClassLoader classLoader, String classInternalName, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classFileBuffer, ClassFileTransformer transformer) { final String className = JavaAssistUtils.jvmNameToJavaName(classInternalName); - if (isDebug) { - if (classBeingRedefined == null) { - logger.debug("[transform] classLoader:{} className:{} transformer:{}", classLoader, className, transformer.getClass().getName()); - } else { - logger.debug("[retransform] classLoader:{} className:{} transformer:{}", classLoader, className, transformer.getClass().getName()); - } + if (logger.isDebugEnabled()) { + final URL codeLocation = CodeSourceUtils.getCodeLocation(protectionDomain); + final String transform = getTransformState(classBeingRedefined); + logger.debug("[{}] classLoader:{} className:{} transformer:{} codeSource:{}", + transform, classLoader, className, transformer.getClass().getName(), codeLocation); } try { @@ -59,19 +59,27 @@ public byte[] transform(ClassLoader classLoader, String classInternalName, Class thread.setContextClassLoader(before); } } catch (Throwable e) { - logger.error("Transformer:{} threw an exception. cl:{} ctxCl:{} agentCl:{} Cause:{}", - transformer.getClass().getName(), classLoader, Thread.currentThread().getContextClassLoader(), agentClassLoader, e.getMessage(), e); + final URL codeLocation = CodeSourceUtils.getCodeLocation(protectionDomain); + logger.error("Transformer:{} threw an exception. codeLocation:{} cl:{} ctxCl:{} agentCl:{} Cause:{}", + transformer.getClass().getName(), codeLocation, classLoader, Thread.currentThread().getContextClassLoader(), agentClassLoader, e.getMessage(), e); return null; } } + private String getTransformState(Class classBeingRedefined) { + if (classBeingRedefined == null) { + return "transform"; + } + return "retransform"; + } + private ClassLoader getContextClassLoader(Thread thread) throws Throwable { try { return thread.getContextClassLoader(); } catch (SecurityException se) { throw se; } catch (Throwable th) { - if (isDebug) { + if (logger.isDebugEnabled()) { logger.debug("getContextClassLoader(). Caused:{}", th.getMessage(), th); } throw th; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java index 9187fa6f0578..d6185768d094 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java @@ -20,16 +20,17 @@ import com.navercorp.pinpoint.bootstrap.Agent; import com.navercorp.pinpoint.bootstrap.AgentOption; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.bootstrap.interceptor.InterceptorInvokerHelper; import com.navercorp.pinpoint.bootstrap.logging.PLogger; import com.navercorp.pinpoint.bootstrap.logging.PLoggerBinder; import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; -import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; +import com.navercorp.pinpoint.bootstrap.plugin.util.SocketAddressUtils; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.module.ApplicationContext; import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; +import com.navercorp.pinpoint.profiler.context.module.DefaultModuleFactoryResolver; +import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; +import com.navercorp.pinpoint.profiler.context.module.ModuleFactoryResolver; import com.navercorp.pinpoint.profiler.util.SystemPropertyDumper; -import com.navercorp.pinpoint.profiler.interceptor.registry.DefaultInterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.logging.Slf4jLoggerBinder; import com.navercorp.pinpoint.rpc.ClassPreLoader; @@ -56,9 +57,6 @@ public class DefaultAgent implements Agent { private final Object agentStatusLock = new Object(); private volatile AgentStatus agentStatus; - private final InterceptorRegistryBinder interceptorRegistryBinder; - private final ServiceTypeRegistryService serviceTypeRegistryService; - static { // Preload classes related to pinpoint-rpc module. @@ -66,23 +64,6 @@ public class DefaultAgent implements Agent { } public DefaultAgent(AgentOption agentOption) { - this(agentOption, createInterceptorRegistry(agentOption)); - } - - public static InterceptorRegistryBinder createInterceptorRegistry(AgentOption agentOption) { - final int interceptorSize = getInterceptorSize(agentOption); - return new DefaultInterceptorRegistryBinder(interceptorSize); - } - - private static int getInterceptorSize(AgentOption agentOption) { - if (agentOption == null) { - return DefaultInterceptorRegistryBinder.DEFAULT_MAX; - } - final ProfilerConfig profilerConfig = agentOption.getProfilerConfig(); - return profilerConfig.getInterceptorRegistrySize(); - } - - public DefaultAgent(AgentOption agentOption, final InterceptorRegistryBinder interceptorRegistryBinder) { if (agentOption == null) { throw new NullPointerException("agentOption must not be null"); } @@ -92,39 +73,33 @@ public DefaultAgent(AgentOption agentOption, final InterceptorRegistryBinder int if (agentOption.getProfilerConfig() == null) { throw new NullPointerException("profilerConfig must not be null"); } - if (agentOption.getServiceTypeRegistryService() == null) { - throw new NullPointerException("serviceTypeRegistryService must not be null"); - } - if (interceptorRegistryBinder == null) { - throw new NullPointerException("interceptorRegistryBinder must not be null"); - } logger.info("AgentOption:{}", agentOption); this.binder = new Slf4jLoggerBinder(); bindPLoggerFactory(this.binder); - this.interceptorRegistryBinder = interceptorRegistryBinder; - interceptorRegistryBinder.bind(); - this.serviceTypeRegistryService = agentOption.getServiceTypeRegistryService(); - dumpSystemProperties(); dumpConfig(agentOption.getProfilerConfig()); changeStatus(AgentStatus.INITIALIZING); + preloadOnStartup(); + this.profilerConfig = agentOption.getProfilerConfig(); - this.applicationContext = newApplicationContext(agentOption, interceptorRegistryBinder); + this.applicationContext = newApplicationContext(agentOption); - - InterceptorInvokerHelper.setPropagateException(profilerConfig.isPropagateInterceptorException()); } - protected ApplicationContext newApplicationContext(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) { - return new DefaultApplicationContext(agentOption, interceptorRegistryBinder); - } + protected ApplicationContext newApplicationContext(AgentOption agentOption) { + Assert.requireNonNull(agentOption, "agentOption must not be null"); + ProfilerConfig profilerConfig = Assert.requireNonNull(agentOption.getProfilerConfig(), "profilerConfig must not be null"); + ModuleFactoryResolver moduleFactoryResolver = new DefaultModuleFactoryResolver(profilerConfig.getInjectionModuleFactoryClazzName()); + ModuleFactory moduleFactory = moduleFactoryResolver.resolve(); + return new DefaultApplicationContext(agentOption, moduleFactory); + } protected ApplicationContext getApplicationContext() { return applicationContext; @@ -158,11 +133,12 @@ private void bindPLoggerFactory(PLoggerBinder binder) { PLoggerFactory.initialize(binder); } - - public ServiceTypeRegistryService getServiceTypeRegistryService() { - return serviceTypeRegistryService; + private void preloadOnStartup() { + // Preload to fail fast on startup. This won't be necessary once JDK 6 support ends + // and reflective method handle is not needed. + SocketAddressUtils.getHostNameFirst(null); } - + @Override public void start() { synchronized (agentStatusLock) { @@ -180,10 +156,6 @@ public void start() { @Override public void stop() { - stop(false); - } - - public void stop(boolean staticResourceCleanup) { synchronized (agentStatusLock) { if (this.agentStatus == AgentStatus.RUNNING) { changeStatus(AgentStatus.STOPPED); @@ -196,9 +168,8 @@ public void stop(boolean staticResourceCleanup) { this.applicationContext.close(); // for testcase - if (staticResourceCleanup) { + if (profilerConfig.getStaticResourceCleanup()) { PLoggerFactory.unregister(this.binder); - this.interceptorRegistryBinder.unbind(); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgentInformation.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgentInformation.java index e120a9ff6cc7..72343779b44d 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgentInformation.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgentInformation.java @@ -26,6 +26,7 @@ public class DefaultAgentInformation implements AgentInformation { private final String agentId; private final String applicationName; + private final boolean isContainer; private final long startTime; private final int pid; private final String machineName; @@ -37,6 +38,7 @@ public class DefaultAgentInformation implements AgentInformation { public DefaultAgentInformation( String agentId, String applicationName, + boolean isContainer, long startTime, int pid, String machineName, @@ -58,6 +60,7 @@ public DefaultAgentInformation( } this.agentId = agentId; this.applicationName = applicationName; + this.isContainer = isContainer; this.startTime = startTime; this.pid = pid; this.machineName = machineName; @@ -77,6 +80,11 @@ public String getApplicationName() { return applicationName; } + @Override + public boolean isContainer() { + return isContainer; + } + @Override public long getStartTime() { return startTime; @@ -112,12 +120,12 @@ public String getAgentVersion() { return agentVersion; } - @Override public String toString() { - final StringBuilder sb = new StringBuilder("AgentInformation{"); + final StringBuilder sb = new StringBuilder("DefaultAgentInformation{"); sb.append("agentId='").append(agentId).append('\''); sb.append(", applicationName='").append(applicationName).append('\''); + sb.append(", isContainer=").append(isContainer); sb.append(", startTime=").append(startTime); sb.append(", pid=").append(pid); sb.append(", machineName='").append(machineName).append('\''); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultClassFileTransformerDispatcher.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultClassFileTransformerDispatcher.java index 7cd8f73bc95d..c12c83b61a2b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultClassFileTransformerDispatcher.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultClassFileTransformerDispatcher.java @@ -19,21 +19,13 @@ import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; -import com.google.inject.Inject; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; -import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; -import com.navercorp.pinpoint.profiler.instrument.classreading.InternalClassMetadata; -import com.navercorp.pinpoint.profiler.instrument.classreading.InternalClassMetadataReader; -import com.navercorp.pinpoint.profiler.instrument.transformer.DefaultTransformerRegistry; -import com.navercorp.pinpoint.profiler.instrument.transformer.DebugTransformerRegistry; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.instrument.transformer.LambdaClassFileResolver; import com.navercorp.pinpoint.profiler.instrument.transformer.TransformerRegistry; -import com.navercorp.pinpoint.profiler.plugin.PluginContextLoadResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.navercorp.pinpoint.profiler.plugin.MatchableClassFileTransformer; /** * @author emeroad @@ -41,10 +33,6 @@ * @author jaehong.kim */ public class DefaultClassFileTransformerDispatcher implements ClassFileTransformerDispatcher { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - - private final ClassLoader agentClassLoader = this.getClass().getClassLoader(); private final BaseClassFileTransformer baseClassFileTransformer; private final TransformerRegistry transformerRegistry; @@ -56,35 +44,21 @@ public class DefaultClassFileTransformerDispatcher implements ClassFileTransform private final ClassFileFilter pinpointClassFilter; private final ClassFileFilter unmodifiableFilter; - private final boolean supportLambdaExpressions; + private final LambdaClassFileResolver lambdaClassFileResolver; - @Inject - public DefaultClassFileTransformerDispatcher(ProfilerConfig profilerConfig, PluginContextLoadResult pluginContextLoadResult, InstrumentEngine instrumentEngine, - DynamicTransformTrigger dynamicTransformTrigger, DynamicTransformerRegistry dynamicTransformerRegistry) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (pluginContextLoadResult == null) { - throw new NullPointerException("pluginContexts must not be null"); - } - if (instrumentEngine == null) { - throw new NullPointerException("instrumentEngine must not be null"); - } - if (dynamicTransformerRegistry == null) { - throw new NullPointerException("dynamicTransformerRegistry must not be null"); - } + public DefaultClassFileTransformerDispatcher(TransformerRegistry transformerRegistry, TransformerRegistry debugTransformerRegistry, + DynamicTransformerRegistry dynamicTransformerRegistry, LambdaClassFileResolver lambdaClassFileResolver) { - this.baseClassFileTransformer = new BaseClassFileTransformer(agentClassLoader); - this.debugTransformerRegistry = new DebugTransformerRegistry(profilerConfig, instrumentEngine, dynamicTransformTrigger); + this.baseClassFileTransformer = new BaseClassFileTransformer(this.getClass().getClassLoader()); + this.debugTransformerRegistry = Assert.requireNonNull(debugTransformerRegistry, "debugTransformerRegistry must not be null"); - this.classLoaderFilter = new PinpointClassLoaderFilter(agentClassLoader); + this.classLoaderFilter = new PinpointClassLoaderFilter(this.getClass().getClassLoader()); this.pinpointClassFilter = new PinpointClassFilter(); this.unmodifiableFilter = new UnmodifiableClassFilter(); - this.transformerRegistry = createTransformerRegistry(pluginContextLoadResult); - this.dynamicTransformerRegistry = dynamicTransformerRegistry; - - this.supportLambdaExpressions = profilerConfig.isSupportLambdaExpressions(); + this.transformerRegistry = Assert.requireNonNull(transformerRegistry, "transformerRegistry must not be null"); + this.dynamicTransformerRegistry = Assert.requireNonNull(dynamicTransformerRegistry, "dynamicTransformerRegistry must not be null"); + this.lambdaClassFileResolver = Assert.requireNonNull(lambdaClassFileResolver, "lambdaClassFileResolver must not be null"); } @Override @@ -93,26 +67,7 @@ public byte[] transform(ClassLoader classLoader, String classInternalName, Class return null; } - String internalName = classInternalName; - if (internalName == null) { - if (this.supportLambdaExpressions) { - // proxy-like class specific for lambda expressions. - // e.g. Example$$Lambda$1/1072591677 - try { - final InternalClassMetadata classMetadata = InternalClassMetadataReader.readInternalClassMetadata(classFileBuffer); - internalName = classMetadata.getClassInternalName(); - } catch (Exception e) { - if (logger.isInfoEnabled()) { - logger.info("Failed to read metadata of lambda expressions. classLoader={}", classLoader, e); - } - return null; - } - } else { - // unsupported lambda expressions. - return null; - } - } - + final String internalName = lambdaClassFileResolver.resolve(classLoader, classInternalName, protectionDomain, classFileBuffer); if (internalName == null) { return null; } @@ -143,28 +98,4 @@ public byte[] transform(ClassLoader classLoader, String classInternalName, Class return baseClassFileTransformer.transform(classLoader, internalName, classBeingRedefined, protectionDomain, classFileBuffer, transformer); } - private TransformerRegistry createTransformerRegistry(PluginContextLoadResult pluginContexts) { - final DefaultTransformerRegistry registry = new DefaultTransformerRegistry(); - for (ClassFileTransformer transformer : pluginContexts.getClassFileTransformer()) { - if (transformer instanceof MatchableClassFileTransformer) { - MatchableClassFileTransformer t = (MatchableClassFileTransformer) transformer; - if (logger.isInfoEnabled()) { - logger.info("Registering class file transformer {} for {} ", t, t.getMatcher()); - } - try { - registry.addTransformer(t.getMatcher(), t); - } catch (Exception e) { - if (logger.isWarnEnabled()) { - logger.warn("Failed to add transformer {}", transformer, e); - } - } - } else { - if (logger.isWarnEnabled()) { - logger.warn("Ignore class file transformer {}", transformer); - } - } - } - - return registry; - } } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultDynamicTransformerRegistry.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultDynamicTransformerRegistry.java index 4f4b593fa201..5f1c464b0841 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultDynamicTransformerRegistry.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultDynamicTransformerRegistry.java @@ -58,11 +58,7 @@ public RequestHandle onRetransformRequest(Class target, final ClassFileTransf @Override public void onTransformRequest(ClassLoader classLoader, String targetClassName, ClassFileTransformer transformer) { - // TODO fix classLoader null case -// if (classLoader== null) { -// boot? ext? system? -// classLoader = ClassLoader.getSystemClassLoader(); -// } + final TransformerKey transformKey = createTransformKey(classLoader, targetClassName); add(transformKey, transformer); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/MatchableClassFileTransformerDispatcher.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/MatchableClassFileTransformerDispatcher.java deleted file mode 100644 index 2cf6ef146384..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/MatchableClassFileTransformerDispatcher.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler; - -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; -import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; -import com.navercorp.pinpoint.profiler.instrument.classreading.InternalClassMetadata; -import com.navercorp.pinpoint.profiler.instrument.classreading.InternalClassMetadataReader; -import com.navercorp.pinpoint.profiler.instrument.transformer.DebugTransformerRegistry; -import com.navercorp.pinpoint.profiler.instrument.transformer.MatchableTransformerRegistry; -import com.navercorp.pinpoint.profiler.instrument.transformer.TransformerRegistry; -import com.navercorp.pinpoint.profiler.plugin.MatchableClassFileTransformer; -import com.navercorp.pinpoint.profiler.plugin.PluginContextLoadResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.IllegalClassFormatException; -import java.security.ProtectionDomain; - -/** - * @author jaehong.kim - */ -public class MatchableClassFileTransformerDispatcher implements ClassFileTransformerDispatcher { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - - private final ClassLoader agentClassLoader = this.getClass().getClassLoader(); - - private final BaseClassFileTransformer baseClassFileTransformer; - private final TransformerRegistry transformerRegistry; - private final DynamicTransformerRegistry dynamicTransformerRegistry; - private final TransformerRegistry debugTransformerRegistry; - - private final ClassFileFilter classLoaderFilter; - private final ClassFileFilter pinpointClassFilter; - private final ClassFileFilter unmodifiableFilter; - - private final boolean supportLambdaExpressions; - - public MatchableClassFileTransformerDispatcher(ProfilerConfig profilerConfig, PluginContextLoadResult pluginContextLoadResult, InstrumentEngine instrumentEngine, - DynamicTransformTrigger dynamicTransformTrigger, DynamicTransformerRegistry dynamicTransformerRegistry) { - Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); - Assert.requireNonNull(pluginContextLoadResult, "pluginContexts must not be null"); - Assert.requireNonNull(instrumentEngine, "instrumentEngine must not be null"); - Assert.requireNonNull(dynamicTransformerRegistry, "dynamicTransformerRegistry must not be null"); - - this.baseClassFileTransformer = new BaseClassFileTransformer(agentClassLoader); - this.debugTransformerRegistry = new DebugTransformerRegistry(profilerConfig, instrumentEngine, dynamicTransformTrigger); - this.transformerRegistry = createTransformerRegistry(pluginContextLoadResult, profilerConfig); - this.dynamicTransformerRegistry = dynamicTransformerRegistry; - - this.classLoaderFilter = new PinpointClassLoaderFilter(agentClassLoader); - this.pinpointClassFilter = new PinpointClassFilter(); - this.unmodifiableFilter = new UnmodifiableClassFilter(); - - this.supportLambdaExpressions = profilerConfig.isSupportLambdaExpressions(); - } - - @Override - public byte[] transform(ClassLoader classLoader, String classInternalName, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classFileBuffer) throws IllegalClassFormatException { - if (!classLoaderFilter.accept(classLoader, classInternalName, classBeingRedefined, protectionDomain, classFileBuffer)) { - return null; - } - - InternalClassMetadata classMetadata = null; - String internalName = classInternalName; - if (internalName == null) { - if (this.supportLambdaExpressions) { - // proxy-like class specific for lambda expressions. - // e.g. Example$$Lambda$1/1072591677 - try { - classMetadata = InternalClassMetadataReader.readInternalClassMetadata(classFileBuffer); - internalName = classMetadata.getClassInternalName(); - } catch (Exception e) { - if (logger.isInfoEnabled()) { - logger.info("Failed to read metadata of lambda expressions. classLoader={}", classLoader, e); - } - return null; - } - } else { - // unsupported lambda expressions. - return null; - } - } - - if (internalName == null) { - return null; - } - - if (!pinpointClassFilter.accept(classLoader, internalName, classBeingRedefined, protectionDomain, classFileBuffer)) { - return null; - } - - final ClassFileTransformer dynamicTransformer = dynamicTransformerRegistry.getTransformer(classLoader, internalName); - if (dynamicTransformer != null) { - return baseClassFileTransformer.transform(classLoader, internalName, classBeingRedefined, protectionDomain, classFileBuffer, dynamicTransformer); - } - - if (!unmodifiableFilter.accept(classLoader, internalName, classBeingRedefined, protectionDomain, classFileBuffer)) { - return null; - } - - ClassFileTransformer transformer = this.transformerRegistry.findTransformer(classLoader, internalName, classFileBuffer, classMetadata); - if (transformer == null) { - // For debug - // TODO What if a modifier is duplicated? - transformer = this.debugTransformerRegistry.findTransformer(classLoader, internalName, classFileBuffer); - if (transformer == null) { - return null; - } - } - - return baseClassFileTransformer.transform(classLoader, internalName, classBeingRedefined, protectionDomain, classFileBuffer, transformer); - } - - private TransformerRegistry createTransformerRegistry(PluginContextLoadResult pluginContexts, final ProfilerConfig profilerConfig) { - final MatchableTransformerRegistry registry = new MatchableTransformerRegistry(profilerConfig); - for (ClassFileTransformer transformer : pluginContexts.getClassFileTransformer()) { - if (transformer instanceof MatchableClassFileTransformer) { - MatchableClassFileTransformer t = (MatchableClassFileTransformer) transformer; - if (logger.isInfoEnabled()) { - logger.info("Registering class file transformer {} for {} ", t, t.getMatcher()); - } - try { - registry.addTransformer(t.getMatcher(), t); - } catch (Exception e) { - if (logger.isWarnEnabled()) { - logger.warn("Failed to add transformer {}", transformer, e); - } - } - } else { - if (logger.isWarnEnabled()) { - logger.warn("Ignore class file transformer {}", transformer); - } - } - } - - return registry; - } -} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/ResponseMessageFutureListener.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/ResponseMessageFutureListener.java new file mode 100644 index 000000000000..4f44bf590a52 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/ResponseMessageFutureListener.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler; + +import com.navercorp.pinpoint.rpc.DefaultFuture; +import com.navercorp.pinpoint.rpc.Future; +import com.navercorp.pinpoint.rpc.FutureListener; +import com.navercorp.pinpoint.rpc.ResponseMessage; + +public class ResponseMessageFutureListener implements FutureListener { + + private final DefaultFuture future; + + public ResponseMessageFutureListener(DefaultFuture future) { + this.future = future; + } + + @Override + public void onComplete(Future future) { + if (future == null) { + this.future.setFailure(new IllegalStateException("ResponseMessage future is null")); + return; + } + if (!future.isReady()) { + this.future.setFailure(new IllegalStateException("ResponseMessage future is not complete")); + return; + } + + if (future.isSuccess()) { + ResponseMessage responseMessage = future.getResult(); + this.future.setResult(responseMessage); + } else { + Throwable cause = future.getCause(); + this.future.setFailure(cause); + } + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/Annotation.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/Annotation.java index 357ddbc5262d..a92cb0fa8082 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/Annotation.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/Annotation.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,55 +16,72 @@ package com.navercorp.pinpoint.profiler.context; +import com.navercorp.pinpoint.common.util.IntStringStringValue; +import com.navercorp.pinpoint.common.util.IntStringValue; +import com.navercorp.pinpoint.common.util.LongIntIntByteByteStringValue; +import com.navercorp.pinpoint.common.util.StringStringValue; import com.navercorp.pinpoint.profiler.util.AnnotationValueMapper; -import com.navercorp.pinpoint.thrift.dto.TAnnotation; -import com.navercorp.pinpoint.thrift.dto.TAnnotationValue; -import com.navercorp.pinpoint.thrift.dto.TIntStringStringValue; -import com.navercorp.pinpoint.thrift.dto.TIntStringValue; -import com.navercorp.pinpoint.thrift.dto.TLongIntIntByteByteStringValue; /** * @author netspider * @author emeroad */ -public class Annotation extends TAnnotation { +public class Annotation { + + private int key; + private Object value; public Annotation(int key) { - super(key); + this.key = key; } public Annotation(int key, Object value) { - super(key); - AnnotationValueMapper.mappingValue(this, value); + this.key = key; + this.value = AnnotationValueMapper.checkValueType(value); + } + + + public Annotation(int key, IntStringValue value) { + this.key = key; + this.value = value; } - public Annotation(int key, TIntStringValue value) { - super(key); - this.setValue(TAnnotationValue.intStringValue(value)); + public Annotation(int key, IntStringStringValue value) { + this.key = key; + this.value = value; } - public Annotation(int key, TIntStringStringValue value) { - super(key); - this.setValue(TAnnotationValue.intStringStringValue(value)); + public Annotation(int key, StringStringValue value) { + this.key = key; + this.value = value; } public Annotation(int key, String value) { - super(key); - this.setValue(TAnnotationValue.stringValue(value)); + this.key = key; + this.value = value; } + public Annotation(int key, int value) { - super(key); - this.setValue(TAnnotationValue.intValue(value)); + this.key = key; + this.value = value; + } + + public Annotation(int key, long value) { + this.key = key; + this.value = value; } - public Annotation(int key, TLongIntIntByteByteStringValue value) { - super(key); - this.setValue(TAnnotationValue.longIntIntByteByteStringValue(value)); + public Annotation(int key, LongIntIntByteByteStringValue value) { + this.key = key; + this.value = value; } public int getAnnotationKey() { - return this.getKey(); + return key; } + public Object getValue() { + return value; + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncChildTrace.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncChildTrace.java index 10c48f15541d..d11b6c8531b3 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncChildTrace.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncChildTrace.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ public class AsyncChildTrace implements Trace { private final boolean sampling; - private final CallStack callStack; + private final CallStack callStack; private final Storage storage; @@ -50,11 +50,10 @@ public class AsyncChildTrace implements Trace { private final DefaultTraceScopePool scopePool = new DefaultTraceScopePool(); - private final int asyncId; - private final short asyncSequence; + private final LocalAsyncId localAsyncId; - public AsyncChildTrace(final TraceRoot traceRoot, CallStack callStack, Storage storage, AsyncContextFactory asyncContextFactory, boolean sampling, - SpanRecorder spanRecorder, WrappedSpanEventRecorder wrappedSpanEventRecorder, final int asyncId, final short asyncSequence) { + public AsyncChildTrace(final TraceRoot traceRoot, CallStack callStack, Storage storage, AsyncContextFactory asyncContextFactory, boolean sampling, + SpanRecorder spanRecorder, WrappedSpanEventRecorder wrappedSpanEventRecorder, final LocalAsyncId localAsyncId) { this.traceRoot = Assert.requireNonNull(traceRoot, "traceRoot must not be null"); this.callStack = Assert.requireNonNull(callStack, "callStack must not be null"); @@ -63,9 +62,7 @@ public AsyncChildTrace(final TraceRoot traceRoot, CallStack callStack, Storage s this.sampling = sampling; this.spanRecorder = Assert.requireNonNull(spanRecorder, "spanRecorder must not be null"); this.wrappedSpanEventRecorder = Assert.requireNonNull(wrappedSpanEventRecorder, "wrappedSpanEventRecorder must not be null"); - this.asyncId = asyncId; - this.asyncSequence = asyncSequence; - + this.localAsyncId = Assert.requireNonNull(localAsyncId, "localAsyncId must not be null"); traceBlockBegin(ASYNC_BEGIN_STACK_ID); } @@ -130,7 +127,7 @@ public SpanEvent traceBlockBegin0(final int stackId) { } private SpanEvent newSpanEvent(int stackId) { - final SpanEvent spanEvent = new SpanEvent(traceRoot); + final SpanEvent spanEvent = new SpanEvent(); spanEvent.markStartTime(); spanEvent.setStackId(stackId); return spanEvent; @@ -144,8 +141,8 @@ private void stackDump(String caused) { @Override public SpanEventRecorder traceBlockBegin(int stackId) { final SpanEvent spanEvent = traceBlockBegin0(stackId); - spanEvent.setAsyncId(asyncId); - spanEvent.setAsyncSequence(asyncSequence); + + spanEvent.setLocalAsyncId(localAsyncId); return wrappedSpanEventRecorder(wrappedSpanEventRecorder, spanEvent); } @@ -267,7 +264,7 @@ public SpanEventRecorder currentSpanEventRecorder() { stackDump("call stack is empty"); } // make dummy. - spanEvent = new SpanEvent(traceRoot); + spanEvent = new SpanEvent(); } return wrappedSpanEventRecorder(this.wrappedSpanEventRecorder, spanEvent); @@ -297,8 +294,7 @@ public TraceScope addScope(String name) { public String toString() { return "AsyncChildTrace{" + "traceRoot=" + traceRoot + - ", asyncId=" + asyncId + - ", asyncSequence=" + asyncSequence + + ", localAsyncId=" + localAsyncId + '}'; } } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncId.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncId.java index 1d512c01957c..cd8860e50730 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncId.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncId.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,4 +24,6 @@ public interface AsyncId { int getAsyncId(); short nextAsyncSequence(); + + LocalAsyncId nextLocalAsyncId(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncTraceContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncTraceContext.java index 9edf7261dad6..4c1f382f8721 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncTraceContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/AsyncTraceContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,9 +28,9 @@ public interface AsyncTraceContext { // Reference continueAsyncTraceObject(TraceRoot traceRoot, int asyncId, short asyncSequence); - Reference continueAsyncTraceObject(TraceRoot traceRoot, int asyncId, short asyncSequence); + Reference continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId); - Trace newAsyncTraceObject(TraceRoot traceRoot, int asyncId, short asyncSequence); + Trace newAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId); Reference continueAsyncTraceObject(AsyncTraceId asyncTraceId, int asyncId, long startTime); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/BaseTraceFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/BaseTraceFactory.java index 8bd6ecaa6754..74fd41f6e9f2 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/BaseTraceFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/BaseTraceFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -34,7 +34,7 @@ public interface BaseTraceFactory { @InterfaceAudience.LimitedPrivate("vert.x") Trace continueAsyncTraceObject(TraceId traceId); - Trace continueAsyncTraceObject(TraceRoot traceRoot, int asyncId, short asyncSequence); + Trace continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId); Trace newTraceObject(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStack.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStack.java index 344e7b57f84a..58aa49250a76 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStack.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStack.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,18 +19,30 @@ /** * @author Woonduk Kang(emeroad) */ -public interface CallStack { +public interface CallStack { int getIndex(); - int push(SpanEvent spanEvent); + int push(T element); - SpanEvent pop(); + T pop(); - SpanEvent peek(); + T peek(); boolean empty(); - SpanEvent[] copyStackFrame(); + T[] copyStackFrame(); int getMaxDepth(); + + Factory getFactory(); + + interface Factory { + Class getType(); + + T newInstance(); + + void markDepth(T element, int index); + + void setSequence(T element, short sequence); + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactory.java index 17dd1d8c0583..615ad20826d3 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,10 @@ package com.navercorp.pinpoint.profiler.context; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; /** * @author Woonduk Kang(emeroad) */ -public interface CallStackFactory { - CallStack newCallStack(TraceRoot traceRoot); +public interface CallStackFactory { + CallStack newCallStack(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV1.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV1.java index b890687937ca..bbb40ced133d 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV1.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV1.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,12 @@ package com.navercorp.pinpoint.profiler.context; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; - /** * @author Woonduk Kang(emeroad) */ -public class CallStackFactoryV1 implements CallStackFactory { +public class CallStackFactoryV1 implements CallStackFactory { + private final CallStack.Factory factory = new SpanEventFactory(); private final int maxDepth; public CallStackFactoryV1(int maxDepth) { @@ -30,7 +29,7 @@ public CallStackFactoryV1(int maxDepth) { } @Override - public CallStack newCallStack(TraceRoot traceRoot) { - return new DepthCompressCallStack(traceRoot, maxDepth); + public CallStack newCallStack() { + return new DepthCompressCallStack(factory, maxDepth); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV2.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV2.java index 1300ca5f264c..ab01370f5199 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV2.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/CallStackFactoryV2.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,12 @@ package com.navercorp.pinpoint.profiler.context; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; - /** * @author Woonduk Kang(emeroad) */ -public class CallStackFactoryV2 implements CallStackFactory { +public class CallStackFactoryV2 implements CallStackFactory { + private final CallStack.Factory factory = new SpanEventFactory(); private final int maxDepth; public CallStackFactoryV2(int maxDepth) { @@ -30,7 +29,7 @@ public CallStackFactoryV2(int maxDepth) { } @Override - public CallStack newCallStack(TraceRoot traceRoot) { - return new DefaultCallStack(traceRoot, maxDepth); + public CallStack newCallStack() { + return new DefaultCallStack(factory, maxDepth); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContext.java index dd70982fbc0c..84917b882bb1 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,9 +73,10 @@ public Trace continueAsyncTraceObject() { } private Trace newAsyncTrace(Reference reference) { - final int asyncId = this.asyncId.getAsyncId(); - final short asyncSequence = this.asyncId.nextAsyncSequence(); - final Trace asyncTrace = asyncTraceContext.newAsyncTraceObject(traceRoot, asyncId, asyncSequence); +// final int asyncId = this.asyncId.getAsyncId(); +// final short asyncSequence = this.asyncId.nextAsyncSequence(); + final LocalAsyncId localAsyncId = this.asyncId.nextLocalAsyncId(); + final Trace asyncTrace = asyncTraceContext.newAsyncTraceObject(traceRoot, localAsyncId); bind(reference, asyncTrace); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncId.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncId.java index e4d64a1bcac9..09282828fd82 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncId.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncId.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,12 +24,12 @@ public class DefaultAsyncId implements AsyncId { private static final AtomicIntegerFieldUpdater ASYNC_SEQUENCE_UPDATER - = AtomicIntegerFieldUpdater.newUpdater(DefaultAsyncId.class, "asyncSequence"); + = AtomicIntegerFieldUpdater.newUpdater(DefaultAsyncId.class, "sequence"); private final int asyncId; @SuppressWarnings("unused") - private volatile int asyncSequence = 0; + private volatile int sequence = 0; public DefaultAsyncId(int asyncId) { this.asyncId = asyncId; @@ -45,11 +45,18 @@ public short nextAsyncSequence() { return (short) ASYNC_SEQUENCE_UPDATER.incrementAndGet(this); } + @Override + public LocalAsyncId nextLocalAsyncId() { + final int asyncId = getAsyncId(); + final short sequence = nextAsyncSequence(); + return new DefaultLocalAsyncId(asyncId, sequence); + } + @Override public String toString() { return "DefaultAsyncId{" + "asyncId=" + asyncId + - ", asyncSequence=" + asyncSequence + + ", sequence=" + sequence + '}'; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContext.java index 83c3ea9694cf..289c432ef4d6 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultAsyncTraceContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,20 +48,20 @@ public DefaultAsyncTraceContext(Provider baseTraceFactoryProvi } @Override - public Reference continueAsyncTraceObject(TraceRoot traceRoot, int asyncId, short asyncSequence) { + public Reference continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId) { final Reference reference = checkAndGet(); final BaseTraceFactory baseTraceFactory = baseTraceFactoryProvider.get(); - final Trace trace = baseTraceFactory.continueAsyncTraceObject(traceRoot, asyncId, asyncSequence); + final Trace trace = baseTraceFactory.continueAsyncTraceObject(traceRoot, localAsyncId); bind(reference, trace); return reference; } @Override - public Trace newAsyncTraceObject(TraceRoot traceRoot, int asyncId, short asyncSequence) { + public Trace newAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId) { final BaseTraceFactory baseTraceFactory = baseTraceFactoryProvider.get(); - return baseTraceFactory.continueAsyncTraceObject(traceRoot, asyncId, asyncSequence); + return baseTraceFactory.continueAsyncTraceObject(traceRoot, localAsyncId); } @@ -71,8 +71,9 @@ public Reference continueAsyncTraceObject(AsyncTraceId asyncTraceId, int final TraceRoot traceRoot = getTraceRoot(asyncTraceId, startTime); final short asyncSequence = asyncTraceId.nextAsyncSequence(); + final LocalAsyncId localAsyncId = new DefaultLocalAsyncId(asyncId, asyncSequence); - return this.continueAsyncTraceObject(traceRoot, asyncId, asyncSequence); + return this.continueAsyncTraceObject(traceRoot, localAsyncId); } @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultBaseTraceFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultBaseTraceFactory.java index 56c3035b4fb7..727fc416de24 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultBaseTraceFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultBaseTraceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,7 @@ */ public class DefaultBaseTraceFactory implements BaseTraceFactory { - private final CallStackFactory callStackFactory; + private final CallStackFactory callStackFactory; private final StorageFactory storageFactory; private final Sampler sampler; @@ -57,7 +57,7 @@ public class DefaultBaseTraceFactory implements BaseTraceFactory { private final ActiveTraceRepository activeTraceRepository; - public DefaultBaseTraceFactory(TraceRootFactory traceRootFactory, CallStackFactory callStackFactory, StorageFactory storageFactory, + public DefaultBaseTraceFactory(TraceRootFactory traceRootFactory, CallStackFactory callStackFactory, StorageFactory storageFactory, Sampler sampler, IdGenerator idGenerator, AsyncContextFactory asyncContextFactory, SpanFactory spanFactory, RecorderFactory recorderFactory, ActiveTraceRepository activeTraceRepository) { @@ -84,11 +84,11 @@ public Trace continueTraceObject(final TraceId traceId) { final Span span = spanFactory.newSpan(traceRoot); final Storage storage = storageFactory.createStorage(traceRoot); - final CallStack callStack = callStackFactory.newCallStack(traceRoot); + final CallStack callStack = callStackFactory.newCallStack(); final boolean samplingEnable = true; final SpanRecorder spanRecorder = recorderFactory.newSpanRecorder(span, traceId.isRoot(), samplingEnable); - final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(); + final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(traceRoot); final ActiveTraceHandle handle = registerActiveTrace(traceRoot); final DefaultTrace trace = new DefaultTrace(span, callStack, storage, asyncContextFactory, samplingEnable, spanRecorder, wrappedSpanEventRecorder, handle); @@ -115,11 +115,11 @@ public Trace newTraceObject() { final Span span = spanFactory.newSpan(traceRoot); final Storage storage = storageFactory.createStorage(traceRoot); - final CallStack callStack = callStackFactory.newCallStack(traceRoot); + final CallStack callStack = callStackFactory.newCallStack(); final TraceId traceId = traceRoot.getTraceId(); final SpanRecorder spanRecorder = recorderFactory.newSpanRecorder(span, traceId.isRoot(), sampling); - final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(); + final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(traceRoot); final ActiveTraceHandle handle = registerActiveTrace(traceRoot); final DefaultTrace trace = new DefaultTrace(span, callStack, storage, asyncContextFactory, sampling, spanRecorder, wrappedSpanEventRecorder, handle); @@ -133,18 +133,18 @@ public Trace newTraceObject() { // internal async trace. @Override - public Trace continueAsyncTraceObject(TraceRoot traceRoot, int asyncId, short asyncSequence) { + public Trace continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId) { final Storage storage = storageFactory.createStorage(traceRoot); - final CallStack callStack = callStackFactory.newCallStack(traceRoot); + final CallStack callStack = callStackFactory.newCallStack(); final boolean samplingEnable = true; final SpanRecorder spanRecorder = recorderFactory.newTraceRootSpanRecorder(traceRoot, samplingEnable); - final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(); + final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(traceRoot); - final Trace asyncTrace = new AsyncChildTrace(traceRoot, callStack, storage, asyncContextFactory, samplingEnable, spanRecorder, wrappedSpanEventRecorder, asyncId, asyncSequence); + final Trace asyncTrace = new AsyncChildTrace(traceRoot, callStack, storage, asyncContextFactory, samplingEnable, spanRecorder, wrappedSpanEventRecorder, localAsyncId); return asyncTrace; } @@ -167,14 +167,14 @@ public Trace continueAsyncTraceObject(final TraceId traceId) { final TraceRoot traceRoot = traceRootFactory.continueTraceRoot(traceId); final Span span = spanFactory.newSpan(traceRoot); final Storage storage = storageFactory.createStorage(traceRoot); - final CallStack callStack = callStackFactory.newCallStack(traceRoot); + final CallStack callStack = callStackFactory.newCallStack(); final ActiveTraceHandle handle = registerActiveTrace(traceRoot); final SpanAsyncStateListener asyncStateListener = new SpanAsyncStateListener(span, storageFactory); final AsyncState asyncState = new ListenableAsyncState(asyncStateListener, handle); final SpanRecorder spanRecorder = recorderFactory.newSpanRecorder(span, traceId.isRoot(), sampling); - final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(asyncState); + final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(traceRoot, asyncState); final DefaultTrace trace = new DefaultTrace(span, callStack, storage, asyncContextFactory, sampling, spanRecorder, wrappedSpanEventRecorder, ActiveTraceHandle.EMPTY_HANDLE); @@ -196,7 +196,7 @@ public Trace newAsyncTraceObject() { final Span span = spanFactory.newSpan(traceRoot); final Storage storage = storageFactory.createStorage(traceRoot); - final CallStack callStack = callStackFactory.newCallStack(traceRoot); + final CallStack callStack = callStackFactory.newCallStack(); final ActiveTraceHandle handle = registerActiveTrace(traceRoot); final SpanAsyncStateListener asyncStateListener = new SpanAsyncStateListener(span, storageFactory); @@ -205,7 +205,7 @@ public Trace newAsyncTraceObject() { final TraceId traceId = traceRoot.getTraceId(); final SpanRecorder spanRecorder = recorderFactory.newSpanRecorder(span, traceId.isRoot(), sampling); - final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(asyncState); + final WrappedSpanEventRecorder wrappedSpanEventRecorder = recorderFactory.newWrappedSpanEventRecorder(traceRoot, asyncState); final DefaultTrace trace = new DefaultTrace(span, callStack, storage, asyncContextFactory, sampling, spanRecorder, wrappedSpanEventRecorder, ActiveTraceHandle.EMPTY_HANDLE); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultCallStack.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultCallStack.java index d982bff34029..c3775cc0c5bc 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultCallStack.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultCallStack.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,8 @@ package com.navercorp.pinpoint.profiler.context; import com.navercorp.pinpoint.common.annotations.VisibleForTesting; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import java.lang.reflect.Array; import java.util.Arrays; /** @@ -26,25 +26,34 @@ * @author Woonduk Kang(emeroad) * @author jaehong.kim */ -public class DefaultCallStack implements CallStack { +public class DefaultCallStack implements CallStack { + protected static final int STACK_SIZE = 8; protected static final int DEFAULT_INDEX = 0; - protected SpanEvent[] stack = new SpanEvent[STACK_SIZE]; + protected final Factory factory; + protected T[] stack; - protected final TraceRoot traceRoot; protected final int maxDepth; protected int index = DEFAULT_INDEX; protected int overflowIndex = 0; protected short sequence; - public DefaultCallStack(TraceRoot traceRoot) { - this(traceRoot, -1); + public DefaultCallStack(Factory factory) { + this(factory, -1); } - public DefaultCallStack(TraceRoot traceRoot, int maxDepth) { - this.traceRoot = traceRoot; + @SuppressWarnings("unchecked") + public DefaultCallStack(Factory factory, int maxDepth) { + this.factory = factory; this.maxDepth = maxDepth; + + this.stack = newStack(factory.getType(), STACK_SIZE); + } + + @SuppressWarnings("unchecked") + private T[] newStack(Class type, int size) { + return (T[]) Array.newInstance(type, size); } @@ -58,63 +67,58 @@ public int getIndex() { } @Override - public int push(final SpanEvent spanEvent) { + public int push(final T element) { if (isOverflow()) { overflowIndex++; return index + overflowIndex; } checkExtend(index + 1); - spanEvent.setSequence(sequence++); - stack[index++] = spanEvent; - markDepth(spanEvent, index); + factory.setSequence(element, sequence++); + stack[index++] = element; + markDepth(element, index); return index; } - protected void markDepth(SpanEvent spanEvent, int index) { - spanEvent.setDepth(index); + protected void markDepth(T element, int index) { + factory.markDepth(element, index); } - protected void checkExtend(final int size) { - final SpanEvent[] originalStack = this.stack; + + private void checkExtend(final int size) { + final T[] originalStack = this.stack; if (size >= originalStack.length) { final int copyStackSize = originalStack.length << 1; - final SpanEvent[] copyStack = new SpanEvent[copyStackSize]; + final T[] copyStack = newStack(factory.getType(), copyStackSize); System.arraycopy(originalStack, 0, copyStack, 0, originalStack.length); this.stack = copyStack; } } @Override - public SpanEvent pop() { + public T pop() { if (isOverflow() && overflowIndex > 0) { overflowIndex--; - return newDummySpanEvent(); + return factory.newInstance(); } - final SpanEvent spanEvent = peek(); + final T spanEvent = peek(); if (spanEvent != null) { stack[index - 1] = null; index--; } - return spanEvent; } - private SpanEvent newDummySpanEvent() { - return new SpanEvent(traceRoot); - } - @Override - public SpanEvent peek() { + public T peek() { if (index == DEFAULT_INDEX) { return null; } if (isOverflow() && overflowIndex > 0) { - return newDummySpanEvent(); + return factory.newInstance(); } - return stack[index - 1]; } @@ -124,10 +128,10 @@ public boolean empty() { } @Override - public SpanEvent[] copyStackFrame() { + public T[] copyStackFrame() { // without synchronization arraycopy, last index is null reference - final SpanEvent[] currentStack = this.stack; - final SpanEvent[] copyStack = new SpanEvent[currentStack.length]; + final T[] currentStack = this.stack; + final T[] copyStack = newStack(factory.getType(), currentStack.length); System.arraycopy(currentStack, 0, copyStack, 0, currentStack.length); return copyStack; } @@ -142,6 +146,11 @@ boolean isOverflow() { return maxDepth != -1 && maxDepth < index; } + @Override + public Factory getFactory() { + return factory; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -149,6 +158,8 @@ public String toString() { builder.append(Arrays.toString(stack)); builder.append(", index="); builder.append(index); + builder.append(", factory="); + builder.append(factory); builder.append("}"); return builder.toString(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultFrameAttachment.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultFrameAttachment.java new file mode 100644 index 000000000000..9ba1e1622fc5 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultFrameAttachment.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context; + +import com.navercorp.pinpoint.bootstrap.context.FrameAttachment; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultFrameAttachment implements FrameAttachment { + + private Object frameObject; + + @Override + public Object attachFrameObject(Object attachObject) { + final Object before = this.frameObject; + this.frameObject = attachObject; + return before; + } + + @Override + public Object getFrameObject() { + return this.frameObject; + } + + @Override + public Object detachFrameObject() { + final Object delete = this.frameObject; + this.frameObject = null; + return delete; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultLocalAsyncId.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultLocalAsyncId.java new file mode 100644 index 000000000000..ab2f01e6e34c --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultLocalAsyncId.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultLocalAsyncId implements LocalAsyncId { + private final int asyncId; + private final short sequence; + + public DefaultLocalAsyncId(int asyncId, short sequence) { + this.asyncId = asyncId; + this.sequence = sequence; + } + + @Override + public int getAsyncId() { + return asyncId; + } + + @Override + public short getSequence() { + return sequence; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof DefaultLocalAsyncId)) return false; + + DefaultLocalAsyncId that = (DefaultLocalAsyncId) o; + + if (asyncId != that.asyncId) return false; + return sequence == that.sequence; + } + + @Override + public int hashCode() { + int result = asyncId; + result = 31 * result + (int) sequence; + return result; + } + + @Override + public String toString() { + return "DefaultLocalAsyncId{" + + "asyncId=" + asyncId + + ", sequence=" + sequence + + '}'; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultSpanFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultSpanFactory.java index 96930e1ed5b9..68286524ab0e 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultSpanFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultSpanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,15 +17,9 @@ package com.navercorp.pinpoint.profiler.context; import com.google.inject.Inject; -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; -import com.navercorp.pinpoint.profiler.context.module.AgentId; -import com.navercorp.pinpoint.profiler.context.module.AgentStartTime; -import com.navercorp.pinpoint.profiler.context.module.ApplicationName; -import com.navercorp.pinpoint.profiler.context.module.ApplicationServerType; + import java.nio.ByteBuffer; @@ -34,21 +28,9 @@ */ public class DefaultSpanFactory implements SpanFactory { - private final String applicationName; - private final String agentId; - private final long agentStartTime; - private final ServiceType applicationServiceType; - private final TransactionIdEncoder transactionIdEncoder; @Inject - public DefaultSpanFactory(@ApplicationName String applicationName, @AgentId String agentId, @AgentStartTime long agentStartTime, - @ApplicationServerType ServiceType applicationServiceType, TransactionIdEncoder transactionIdEncoder) { - this.applicationName = Assert.requireNonNull(applicationName, "applicationName must not be null"); - this.agentId = Assert.requireNonNull(agentId, "agentId must not be null"); - this.agentStartTime = agentStartTime; - this.applicationServiceType = Assert.requireNonNull(applicationServiceType, "applicationServiceType must not be null"); - this.transactionIdEncoder = Assert.requireNonNull(transactionIdEncoder, "transactionIdEncoder must not be null"); - + public DefaultSpanFactory() { } @Override @@ -57,14 +39,6 @@ public Span newSpan(TraceRoot traceRoot) { final Span span = new Span(traceRoot); - final TraceId traceId = traceRoot.getTraceId(); - final ByteBuffer transactionId = transactionIdEncoder.encodeTransactionId(traceId); - span.setTransactionId(transactionId); - - span.setAgentId(agentId); - span.setApplicationName(applicationName); - span.setAgentStartTime(agentStartTime); - span.setApplicationServiceType(applicationServiceType.getCode()); span.markBeforeTime(); return span; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java index a7b0b6f2eead..8c50fbddba10 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -42,7 +42,7 @@ public final class DefaultTrace implements Trace, TraceRootSupport { private final boolean sampling; - private final CallStack callStack; + private final CallStack callStack; private final Storage storage; @@ -59,13 +59,13 @@ public final class DefaultTrace implements Trace, TraceRootSupport { private final DefaultTraceScopePool scopePool = new DefaultTraceScopePool(); - public DefaultTrace(Span span, CallStack callStack, Storage storage, AsyncContextFactory asyncContextFactory, boolean sampling, + public DefaultTrace(Span span, CallStack callStack, Storage storage, AsyncContextFactory asyncContextFactory, boolean sampling, SpanRecorder spanRecorder, WrappedSpanEventRecorder wrappedSpanEventRecorder, ActiveTraceHandle activeTraceHandle) { this.span = Assert.requireNonNull(span, "span must not be null"); this.callStack = Assert.requireNonNull(callStack, "callStack must not be null"); this.storage = Assert.requireNonNull(storage, "storage must not be null"); - this.sampling = Assert.requireNonNull(sampling, "sampling must not be null"); + this.sampling = sampling; this.asyncContextFactory = Assert.requireNonNull(asyncContextFactory, "asyncContextFactory must not be null"); this.spanRecorder = Assert.requireNonNull(spanRecorder, "spanRecorder must not be null"); @@ -107,7 +107,7 @@ public SpanEventRecorder traceBlockBegin(final int stackId) { } private SpanEvent newSpanEvent(int stackId) { - final SpanEvent spanEvent = new SpanEvent(getTraceRoot()); + final SpanEvent spanEvent = newSpanEvent(); spanEvent.markStartTime(); spanEvent.setStackId(stackId); return spanEvent; @@ -282,12 +282,16 @@ public SpanEventRecorder currentSpanEventRecorder() { stackDump("call stack is empty"); } // make dummy. - spanEvent = new SpanEvent(getTraceRoot()); + spanEvent = newSpanEvent(); } return wrappedSpanEventRecorder(this.wrappedSpanEventRecorder, spanEvent); } + private SpanEvent newSpanEvent() { + return callStack.getFactory().newInstance(); + } + @Override public int getCallStackFrameId() { final SpanEvent spanEvent = callStack.peek(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTraceContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTraceContext.java index a5fb7bb2d67a..9c0b2ec34662 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTraceContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTraceContext.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -28,7 +28,6 @@ import com.navercorp.pinpoint.common.annotations.InterfaceAudience; import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.AgentInformation; - import com.navercorp.pinpoint.profiler.context.id.TraceIdFactory; import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; import com.navercorp.pinpoint.profiler.metadata.SqlMetaDataService; @@ -151,7 +150,8 @@ public Trace continueAsyncTraceObject(final TraceId traceId) { @Override public Trace continueAsyncTraceObject(AsyncTraceId asyncTraceId, int asyncId, long startTime) { - return asyncTraceContext.continueAsyncTraceObject(asyncTraceId, asyncId, startTime).get(); + final Reference traceReference = asyncTraceContext.continueAsyncTraceObject(asyncTraceId, asyncId, startTime); + return traceReference.get(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DepthCompressCallStack.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DepthCompressCallStack.java index b87c415b8699..2c76b7cacc7d 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DepthCompressCallStack.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DepthCompressCallStack.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,29 +16,27 @@ package com.navercorp.pinpoint.profiler.context; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; - /** * @author Woonduk Kang(emeroad) */ -public class DepthCompressCallStack extends DefaultCallStack { +public class DepthCompressCallStack extends DefaultCallStack { private int latestStackIndex = 0; - public DepthCompressCallStack(TraceRoot traceRoot) { - this(traceRoot, -1); + public DepthCompressCallStack(Factory factory) { + this(factory, -1); } - public DepthCompressCallStack(TraceRoot traceRoot, int maxDepth) { - super(traceRoot, maxDepth); + public DepthCompressCallStack(Factory factory, int maxDepth) { + super(factory, maxDepth); } @Override - protected void markDepth(SpanEvent spanEvent, int depth) { + protected void markDepth(T element, int depth) { // compact same depth if (latestStackIndex != index) { latestStackIndex = index; - spanEvent.setDepth(latestStackIndex); + this.factory.markDepth(element, latestStackIndex); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LocalAsyncId.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LocalAsyncId.java new file mode 100644 index 000000000000..45360ca3352a --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LocalAsyncId.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface LocalAsyncId { +// private int asyncId; // optional +// private short asyncSequence; // optional + int getAsyncId(); + short getSequence(); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LoggingBaseTraceFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LoggingBaseTraceFactory.java index 197f584eec28..8febf418d385 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LoggingBaseTraceFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/LoggingBaseTraceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,12 +76,12 @@ public Trace continueAsyncTraceObject(TraceId traceId) { } @Override - public Trace continueAsyncTraceObject(TraceRoot traceRoot, int asyncId, short asyncSequence) { + public Trace continueAsyncTraceObject(TraceRoot traceRoot, LocalAsyncId localAsyncId) { if (logger.isDebugEnabled()) { - logger.debug("continueAsyncTraceObject(traceRoot:{}, asyncId:{}, asyncSequence:{})", traceRoot, asyncId, asyncSequence); + logger.debug("continueAsyncTraceObject(traceRoot:{}, localAsyncId:{})", traceRoot, localAsyncId); } - return baseTraceFactory.continueAsyncTraceObject(traceRoot, asyncId, asyncSequence); + return baseTraceFactory.continueAsyncTraceObject(traceRoot, localAsyncId); } @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/Span.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/Span.java index 51dd2ac1316d..f6e4ba04c8ac 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/Span.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/Span.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,15 +16,13 @@ package com.navercorp.pinpoint.profiler.context; -import com.navercorp.pinpoint.bootstrap.context.FrameAttachment; -import com.navercorp.pinpoint.bootstrap.context.SpanId; -import com.navercorp.pinpoint.bootstrap.context.TraceId; import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.util.IntStringValue; import com.navercorp.pinpoint.profiler.context.id.Shared; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.thrift.dto.TIntStringValue; -import com.navercorp.pinpoint.thrift.dto.TSpan; + +import java.util.ArrayList; +import java.util.List; /** * Span represent RPC @@ -32,115 +30,190 @@ * @author netspider * @author emeroad */ -public class Span extends TSpan implements FrameAttachment { +public class Span extends DefaultFrameAttachment { private boolean timeRecording = true; - private Object frameObject; private final TraceRoot traceRoot; + private long startTime; // required + private int elapsedTime; // optional + + private int apiId; // optional + private short serviceType; // required + + private List annotations; // optional + private List spanEventList; // optional + + private String remoteAddr; // optional + + private String parentApplicationName; // optional + private short parentApplicationType; // optional + private String acceptorHost; // optional + + private IntStringValue exceptionInfo; // optional + + public Span(final TraceRoot traceRoot) { if (traceRoot == null) { throw new NullPointerException("traceRoot must not be null"); } this.traceRoot = traceRoot; - - final TraceId traceId = traceRoot.getTraceId(); - this.setSpanId(traceId.getSpanId()); - final long parentSpanId = traceId.getParentSpanId(); - if (parentSpanId != SpanId.NULL) { - this.setParentSpanId(parentSpanId); - } - this.setFlag(traceId.getFlags()); } public TraceRoot getTraceRoot() { return traceRoot; } - public void markBeforeTime() { - final long spanStartTime = traceRoot.getTraceStartTime(); - this.setStartTime(spanStartTime); + + public long getStartTime() { + return startTime; } - public void markAfterTime() { - markAfterTime(System.currentTimeMillis()); + public int getElapsedTime() { + return elapsedTime; } - public void markAfterTime(long currentTime) { - final int after = (int)(currentTime - this.getStartTime()); + public void setElapsedTime(int elapsedTime) { + this.elapsedTime = elapsedTime; + } - // TODO have to change int to long - if (after != 0) { - this.setElapsed(after); - } + public short getServiceType() { + return serviceType; } - public long getAfterTime() { - return this.getStartTime() + this.getElapsed(); + public void setServiceType(short serviceType) { + this.serviceType = serviceType; } + public String getRemoteAddr() { + return remoteAddr; + } - public void addAnnotation(Annotation annotation) { - this.addToAnnotations(annotation); + public void setRemoteAddr(String remoteAddr) { + this.remoteAddr = remoteAddr; } - public void setExceptionInfo(int exceptionClassId, String exceptionMessage) { - final TIntStringValue exceptionInfo = new TIntStringValue(exceptionClassId); - if (StringUtils.hasLength(exceptionMessage)) { - exceptionInfo.setStringValue(exceptionMessage); - } - super.setExceptionInfo(exceptionInfo); + public List getAnnotations() { + return annotations; } - public boolean isSetErrCode() { - return isSetErr(); + + public List getSpanEventList() { + return spanEventList; } - public int getErrCode() { - return getErr(); + public void setSpanEventList(List spanEventList) { + this.spanEventList = spanEventList; } - public void setErrCode(int exception) { - super.setErr(exception); + public String getParentApplicationName() { + return parentApplicationName; } - public boolean isTimeRecording() { - return timeRecording; + public void setParentApplicationName(String parentApplicationName) { + this.parentApplicationName = parentApplicationName; } - public void setTimeRecording(boolean timeRecording) { - this.timeRecording = timeRecording; + public short getParentApplicationType() { + return parentApplicationType; } - @Override - public Object attachFrameObject(Object attachObject) { - final Object before = this.frameObject; - this.frameObject = attachObject; - return before; + public void setParentApplicationType(short parentApplicationType) { + this.parentApplicationType = parentApplicationType; } - @Override - public Object getFrameObject() { - return this.frameObject; + public String getAcceptorHost() { + return acceptorHost; } - @Override - public Object detachFrameObject() { - final Object delete = this.frameObject; - this.frameObject = null; - return delete; + public void setAcceptorHost(String acceptorHost) { + this.acceptorHost = acceptorHost; + } + + public int getApiId() { + return apiId; + } + + public void setApiId(int apiId) { + this.apiId = apiId; + } + + public IntStringValue getExceptionInfo() { + return exceptionInfo; + } + + public void setExceptionInfo(IntStringValue exceptionInfo) { + this.exceptionInfo = exceptionInfo; + } + + public void markBeforeTime() { + final long spanStartTime = traceRoot.getTraceStartTime(); + this.setStartTime(spanStartTime); + } + + public void setStartTime(long spanStartTime) { + this.startTime = spanStartTime; + } + + public void markAfterTime() { + markAfterTime(System.currentTimeMillis()); + } + + public void markAfterTime(long currentTime) { + final int after = (int)(currentTime - this.getStartTime()); + this.setElapsedTime(after); + } + + public void addAnnotation(Annotation annotation) { + if (this.annotations == null) { + this.annotations = new ArrayList(); + } + this.annotations.add(annotation); + } + + public void setExceptionInfo(int exceptionClassId, String exceptionMessage) { + final IntStringValue exceptionInfo = new IntStringValue(exceptionClassId, exceptionMessage); + this.setExceptionInfo(exceptionInfo); + } + + + public boolean isTimeRecording() { + return timeRecording; + } + + public void setTimeRecording(boolean timeRecording) { + this.timeRecording = timeRecording; } public void finish() { // snapshot last image final Shared shared = traceRoot.getShared(); - final int errorCode = shared.getErrorCode(); - this.setErrCode(errorCode); if (shared.getStatusCode() != 0) { - this.addAnnotation(new Annotation(AnnotationKey.HTTP_STATUS_CODE.getCode(), shared.getStatusCode())); + Annotation annotation = new Annotation(AnnotationKey.HTTP_STATUS_CODE.getCode(), shared.getStatusCode()); + this.addAnnotation(annotation); } + } - final byte loggingInfo = shared.getLoggingInfo(); - this.setLoggingTransactionInfo(loggingInfo); + public void clear() { + + } + + @Override + public String toString() { + return "Span{" + + "timeRecording=" + timeRecording + + ", traceRoot=" + traceRoot + + ", startTime=" + startTime + + ", elapsed=" + elapsedTime + + ", serviceType=" + serviceType + + ", remoteAddr='" + remoteAddr + '\'' + + ", annotations=" + annotations + + ", spanEventList=" + spanEventList + + ", parentApplicationName='" + parentApplicationName + '\'' + + ", parentApplicationType=" + parentApplicationType + + ", acceptorHost='" + acceptorHost + '\'' + + ", apiId=" + apiId + + ", exceptionInfo=" + exceptionInfo + + "} " + super.toString(); } } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunk.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunk.java index 4625d878af95..dae3adc834ba 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunk.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunk.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,34 +17,35 @@ package com.navercorp.pinpoint.profiler.context; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; + import java.util.List; -import com.navercorp.pinpoint.thrift.dto.TSpanChunk; /** * @author emeroad */ -public class SpanChunk extends TSpanChunk { +public class SpanChunk { - public SpanChunk(List spanEventList) { - if (spanEventList == null) { - throw new NullPointerException("spanEventList must not be null"); - } - setSpanEventList((List) spanEventList); - } + private final TraceRoot traceRoot; + + private final List spanEventList; // required - @Override - public void setServiceType(short serviceType) { - super.setServiceType(serviceType); + + public SpanChunk(TraceRoot traceRoot, List spanEventList) { + this.traceRoot = Assert.requireNonNull(traceRoot, "traceRoot must not be null"); + this.spanEventList = Assert.requireNonNull(spanEventList, "spanEventList must not be null"); } - @Override - public void setServiceTypeIsSet(boolean value) { - super.setServiceTypeIsSet(value); + public TraceRoot getTraceRoot() { + return traceRoot; } - @Override - public short getServiceType() { - return super.getServiceType(); + + public List getSpanEventList() { + return spanEventList; } + } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactory.java deleted file mode 100644 index edcae67505fc..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context; - -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; - -import java.util.List; - -/** - * @author emeroad - */ -public interface SpanChunkFactory { - - SpanChunk create(TraceRoot traceRoot, final List flushData); -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactoryV1.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactoryV1.java deleted file mode 100644 index e207bddd3171..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactoryV1.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context; - -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.common.util.CollectionUtils; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressor; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressorV1; -import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; - -import java.nio.ByteBuffer; -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public class SpanChunkFactoryV1 implements SpanChunkFactory { - -// private static final TraceDataFormatVersion V1 = TraceDataFormatVersion.V1; - - private final String applicationName; - private final String agentId; - private final long agentStartTime; - private final ServiceType applicationServiceType; - private final TransactionIdEncoder transactionIdEncoder; - - private final SpanEventCompressor spanEventCompressor = new SpanEventCompressorV1(); - - - public SpanChunkFactoryV1(String applicationName, String agentId, long agentStartTime, ServiceType applicationServiceType, TransactionIdEncoder transactionIdEncoder) { - - this.applicationName = Assert.requireNonNull(applicationName, "applicationName must not be null"); - this.agentId = Assert.requireNonNull(agentId, "agentId must not be null"); - this.agentStartTime = agentStartTime; - this.applicationServiceType = Assert.requireNonNull(applicationServiceType, "applicationServiceType must not be null"); - this.transactionIdEncoder = Assert.requireNonNull(transactionIdEncoder, "transactionIdEncoder must not be null"); - - } - - @Override - public SpanChunk create(TraceRoot traceRoot, final List spanEventList) { - if (CollectionUtils.isEmpty(spanEventList)) { - throw new IllegalArgumentException("spanEventList is empty."); - } - - - final SpanEvent first = spanEventList.get(0); - if (first == null) { - throw new IllegalStateException("first SpanEvent is null"); - } - - final SpanChunk spanChunk = new SpanChunk(spanEventList); -// skip default version -// spanChunk.setVersion(V1.getVersion()); - - spanChunk.setAgentId(agentId); - spanChunk.setApplicationName(applicationName); - spanChunk.setAgentStartTime(agentStartTime); - spanChunk.setApplicationServiceType(applicationServiceType.getCode()); - - - spanEventCompressor.compress(spanEventList, traceRoot.getTraceStartTime()); - - final TraceId traceId = traceRoot.getTraceId(); - final ByteBuffer transactionId = transactionIdEncoder.encodeTransactionId(traceId); - spanChunk.setTransactionId(transactionId); - - spanChunk.setSpanId(traceId.getSpanId()); - - spanChunk.setEndPoint(traceRoot.getShared().getEndPoint()); - return spanChunk; - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactoryV2.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactoryV2.java deleted file mode 100644 index 60acce479c59..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactoryV2.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context; - -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.common.util.CollectionUtils; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressor; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressorV2; -import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; - -import java.nio.ByteBuffer; -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public class SpanChunkFactoryV2 implements SpanChunkFactory { - - private static final TraceDataFormatVersion V2 = TraceDataFormatVersion.V2; - - private final String applicationName; - private final String agentId; - private final long agentStartTime; - private final ServiceType applicationServiceType; - private final TransactionIdEncoder transactionIdEncoder; - - private final SpanEventCompressor spanEventCompressor = new SpanEventCompressorV2(); - - - public SpanChunkFactoryV2(String applicationName, String agentId, long agentStartTime, ServiceType applicationServiceType, TransactionIdEncoder transactionIdEncoder) { - - this.applicationName = Assert.requireNonNull(applicationName, "applicationName must not be null"); - this.agentId = Assert.requireNonNull(agentId, "agentId must not be null"); - this.agentStartTime = agentStartTime; - this.applicationServiceType = Assert.requireNonNull(applicationServiceType, "applicationServiceType must not be null"); - this.transactionIdEncoder = Assert.requireNonNull(transactionIdEncoder, "transactionIdEncoder must not be null"); - - } - - - @Override - public SpanChunk create(TraceRoot traceRoot, final List spanEventList) { - if (CollectionUtils.isEmpty(spanEventList)) { - throw new IllegalArgumentException("spanEventList is empty."); - } - - final SpanEvent first = spanEventList.get(0); - if (first == null) { - throw new IllegalStateException("first SpanEvent is null"); - } - - - final SpanChunk spanChunk = new SpanChunk(spanEventList); - spanChunk.setVersion(V2.getVersion()); - - spanChunk.setAgentId(agentId); - spanChunk.setApplicationName(applicationName); - spanChunk.setAgentStartTime(agentStartTime); - spanChunk.setApplicationServiceType(applicationServiceType.getCode()); - - - final long keyTime = first.getStartTime(); - spanChunk.setKeyTime(keyTime); - // TODO change data compression timing to another thread eg: DataSender thread - spanEventCompressor.compress(spanEventList, keyTime); - - final TraceId traceId = traceRoot.getTraceId(); - final ByteBuffer transactionId = transactionIdEncoder.encodeTransactionId(traceId); - spanChunk.setTransactionId(transactionId); - - spanChunk.setSpanId(traceId.getSpanId()); - spanChunk.setEndPoint(traceRoot.getShared().getEndPoint()); - - return spanChunk; - } - -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEvent.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEvent.java index ab0ba9c0779d..045452dcde1d 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEvent.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEvent.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,12 +16,10 @@ package com.navercorp.pinpoint.profiler.context; -import com.navercorp.pinpoint.bootstrap.context.FrameAttachment; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.common.util.IntStringValue; -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.thrift.dto.TIntStringValue; -import com.navercorp.pinpoint.thrift.dto.TSpanEvent; +import java.util.ArrayList; +import java.util.List; /** * Span represent RPC @@ -29,42 +27,53 @@ * @author netspider * @author emeroad */ -public class SpanEvent extends TSpanEvent implements FrameAttachment { +public class SpanEvent extends DefaultFrameAttachment { - private final TraceRoot traceRoot; - private int stackId; private boolean timeRecording = true; - private Object frameObject; + private int stackId; + private long startTime; - private long afterTime; + private int elapsedTime; - private AsyncId asyncIdObject; + private short sequence; // required - public SpanEvent(TraceRoot traceRoot) { - if (traceRoot == null) { - throw new NullPointerException("traceRoot must not be null"); - } - this.traceRoot = traceRoot; - } +// private String rpc; // optional + private short serviceType; // required + private String endPoint; // optional + + private List annotations; // optional + private int depth = -1; // optional + + private long nextSpanId = -1; // optional + private String destinationId; // optional + + private int apiId; // optional + private IntStringValue exceptionInfo; // optional - public TraceRoot getTraceRoot() { - return traceRoot; + private AsyncId asyncIdObject; + private LocalAsyncId localAsyncId; + + public SpanEvent() { } public void addAnnotation(Annotation annotation) { - this.addToAnnotations(annotation); + if (this.annotations == null) { + this.annotations = new ArrayList(); + } + this.annotations.add(annotation); } public void setExceptionInfo(int exceptionClassId, String exceptionMessage) { - final TIntStringValue exceptionInfo = new TIntStringValue(exceptionClassId); - if (StringUtils.hasLength(exceptionMessage)) { - exceptionInfo.setStringValue(exceptionMessage); - } - super.setExceptionInfo(exceptionInfo); + final IntStringValue exceptionInfo = new IntStringValue(exceptionClassId, exceptionMessage); + this.exceptionInfo = exceptionInfo; } public void markStartTime() { - this.startTime = System.currentTimeMillis(); + setStartTime(System.currentTimeMillis()); + } + + public void setStartTime(long startTime) { + this.startTime = startTime; } public long getStartTime() { @@ -72,11 +81,24 @@ public long getStartTime() { } public void markAfterTime() { - this.afterTime = System.currentTimeMillis(); + checkStartTime(); + setAfterTime(System.currentTimeMillis()); + } + + + public void setAfterTime(long afterTime) { + checkStartTime(); + this.elapsedTime = (int) (afterTime - startTime); + } + + private void checkStartTime() { + if (startTime == 0) { + throw new IllegalStateException("startTime not recorded"); + } } public long getAfterTime() { - return afterTime; + return startTime + elapsedTime; } public int getStackId() { @@ -95,23 +117,101 @@ public void setTimeRecording(boolean timeRecording) { this.timeRecording = timeRecording; } - @Override - public Object attachFrameObject(Object attachObject) { - final Object before = this.frameObject; - this.frameObject = attachObject; - return before; + public short getSequence() { + return sequence; } - @Override - public Object getFrameObject() { - return this.frameObject; + public void setSequence(short sequence) { + this.sequence = sequence; } - @Override - public Object detachFrameObject() { - final Object delete = this.frameObject; - this.frameObject = null; - return delete; + public int getElapsedTime() { + return elapsedTime; + } + + public void setElapsedTime(int elapsedTime) { + this.elapsedTime = elapsedTime; + } + + @Deprecated + public String getRpc() { + return null; + } + + @Deprecated + public void setRpc(String rpc) { + } + + public short getServiceType() { + return serviceType; + } + + public void setServiceType(short serviceType) { + this.serviceType = serviceType; + } + + public String getEndPoint() { + return endPoint; + } + + public void setEndPoint(String endPoint) { + this.endPoint = endPoint; + } + + public List getAnnotations() { + return annotations; + } + + public void setAnnotations(List annotations) { + this.annotations = annotations; + } + + public int getDepth() { + return depth; + } + + public void setDepth(int depth) { + this.depth = depth; + } + + public long getNextSpanId() { + return nextSpanId; + } + + public void setNextSpanId(long nextSpanId) { + this.nextSpanId = nextSpanId; + } + + public String getDestinationId() { + return destinationId; + } + + public void setDestinationId(String destinationId) { + this.destinationId = destinationId; + } + + public int getApiId() { + return apiId; + } + + public void setApiId(int apiId) { + this.apiId = apiId; + } + + public IntStringValue getExceptionInfo() { + return exceptionInfo; + } + + public void setExceptionInfo(IntStringValue exceptionInfo) { + this.exceptionInfo = exceptionInfo; + } + + public LocalAsyncId getLocalAsyncId() { + return localAsyncId; + } + + public void setLocalAsyncId(LocalAsyncId localAsyncId) { + this.localAsyncId = localAsyncId; } public void setAsyncIdObject(AsyncId asyncIdObject) { @@ -121,4 +221,25 @@ public void setAsyncIdObject(AsyncId asyncIdObject) { public AsyncId getAsyncIdObject() { return asyncIdObject; } + + @Override + public String toString() { + return "SpanEvent{" + + "stackId=" + stackId + + ", timeRecording=" + timeRecording + + ", startTime=" + startTime + + ", elapsedTime=" + elapsedTime + + ", asyncIdObject=" + asyncIdObject + + ", sequence=" + sequence + + ", serviceType=" + serviceType + + ", endPoint='" + endPoint + '\'' + + ", annotations=" + annotations + + ", depth=" + depth + + ", nextSpanId=" + nextSpanId + + ", destinationId='" + destinationId + '\'' + + ", apiId=" + apiId + + ", exceptionInfo=" + exceptionInfo + + ", localAsyncId=" + localAsyncId + + "} "; + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventFactory.java new file mode 100644 index 000000000000..2c66a8f6db39 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanEventFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context; + +/** + * @author Woonduk Kang(emeroad) + */ +public class SpanEventFactory implements CallStack.Factory { + @Override + public Class getType() { + return SpanEvent.class; + } + + @Override + public SpanEvent newInstance() { + return new SpanEvent(); + } + + @Override + public void markDepth(SpanEvent element, int index) { + element.setDepth(index); + } + + @Override + public void setSequence(SpanEvent element, short sequence) { + element.setSequence(sequence); + } + + @Override + public String toString() { + return "SpanEventFactory{}"; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanPostProcessor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanPostProcessor.java deleted file mode 100644 index ff66a822c8e4..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanPostProcessor.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context; - -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public interface SpanPostProcessor { - Span postProcess(Span span, List spanEventList); -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanPostProcessorV1.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanPostProcessorV1.java deleted file mode 100644 index 37d1e3c0d9a0..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanPostProcessorV1.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context; - -import com.navercorp.pinpoint.common.util.CollectionUtils; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressor; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressorV1; - -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public class SpanPostProcessorV1 implements SpanPostProcessor { - -// private static final TraceDataFormatVersion V1 = TraceDataFormatVersion.V1; - private final SpanEventCompressor spanEventCompressor = new SpanEventCompressorV1(); - - @Override - public Span postProcess(Span span, List spanEventList) { -// skip default version -// span.setVersion(V1.getVersion()); - span.finish(); - if (CollectionUtils.hasLength(spanEventList)) { - final long spanStartTime = span.getStartTime(); - spanEventCompressor.compress(spanEventList, spanStartTime); - span.setSpanEventList((List) spanEventList); - } - return span; - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanPostProcessorV2.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanPostProcessorV2.java deleted file mode 100644 index 3928724f2aa9..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/SpanPostProcessorV2.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context; - -import com.navercorp.pinpoint.common.util.CollectionUtils; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressor; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressorV2; - -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public class SpanPostProcessorV2 implements SpanPostProcessor { - - private static final TraceDataFormatVersion V2 = TraceDataFormatVersion.V2; - - // TODO refactor injector - private final SpanEventCompressor spanEventCompressor = new SpanEventCompressorV2(); - - @Override - public Span postProcess(Span span, List spanEventList) { - span.setVersion(V2.getVersion()); - span.finish(); - if (CollectionUtils.hasLength(spanEventList)) { - long spanStartTime = span.getStartTime(); - spanEventCompressor.compress(spanEventList, spanStartTime); - span.setSpanEventList((List) spanEventList); - } - return span; - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/Context.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/Context.java new file mode 100644 index 000000000000..c02aa22c8afd --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/Context.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.compress; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface Context { + long keyTime(); + + void next(); + + void finish(); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/ContextV1.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/ContextV1.java new file mode 100644 index 000000000000..37ebb72666b9 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/ContextV1.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.compress; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ContextV1 implements Context { + private long keyTime; + + public ContextV1(long keyTime) { + this.keyTime = keyTime; + } + + @Override + public long keyTime() { + return keyTime; + } + + + @Override + public void next() { + } + + @Override + public void finish() { + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/ContextV2.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/ContextV2.java new file mode 100644 index 000000000000..3b002732dd2d --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/ContextV2.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.compress; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ContextV2 implements Context { + private long keyTime; + private int index = 0; + private int prevDepth = 0; + + ContextV2(long keyTime) { + this.keyTime = keyTime; + } + + @Override + public long keyTime() { + return keyTime; + } + + void setKeyTime(long keyTime) { + this.keyTime = keyTime; + } + + int getPrevDepth() { + return prevDepth; + } + + void setPrevDepth(int prevDepth) { + this.prevDepth = prevDepth; + } + + int getIndex() { + return index; + } + + @Override + public void next() { + index++; + } + + @Override + public void finish() { + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanEventCompressor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanEventCompressor.java deleted file mode 100644 index dd4e0f715d65..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanEventCompressor.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context.compress; - -import com.navercorp.pinpoint.profiler.context.SpanEvent; - -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public interface SpanEventCompressor { - void compress(List spanEventList, T context); -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanEventCompressorV1.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanEventCompressorV1.java deleted file mode 100644 index 47c938ca1759..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanEventCompressorV1.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context.compress; - -import com.navercorp.pinpoint.profiler.context.SpanEvent; - -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public class SpanEventCompressorV1 implements SpanEventCompressor { - - @Override - public void compress(List spanEventList, final Long keyTime) { - - final long prevKeyTime = keyTime; - for (final SpanEvent spanEvent : spanEventList) { - final long startTime = spanEvent.getStartTime(); - final long startElapsedTime = startTime - prevKeyTime; - spanEvent.setStartElapsed((int) startElapsedTime); - - - final long endElapsedTime = spanEvent.getAfterTime() - startTime; - if (endElapsedTime != 0) { - spanEvent.setEndElapsed((int) endElapsedTime); - } - } - - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanEventCompressorV2.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanEventCompressorV2.java deleted file mode 100644 index d4444df52d19..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanEventCompressorV2.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context.compress; - -import com.navercorp.pinpoint.profiler.context.SpanEvent; - -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -/** - * @author Woonduk Kang(emeroad) - */ -public class SpanEventCompressorV2 implements SpanEventCompressor { - - private final static Comparator SEQUENCE_COMPARATOR = SpanEventSequenceComparator.INSTANCE; - - @Override - public void compress(List spanEventList, final Long keyTime) { - // sort list for data compression - Collections.sort(spanEventList, SEQUENCE_COMPARATOR); - - compressTime(spanEventList, keyTime); - compressDepth(spanEventList); - } - - private void compressTime(List spanEventList, Long keyTime) { - long prevKeyTime = keyTime; - - - final int size = spanEventList.size(); - for (int i = 0; i < size; i++) { - final SpanEvent spanEvent = spanEventList.get(i); - - final long startTime = spanEvent.getStartTime(); - final long startElapsedTime = startTime - prevKeyTime; - spanEvent.setStartElapsed((int) startElapsedTime); - - - final long endElapsedTime = spanEvent.getAfterTime() - startTime; - if (endElapsedTime != 0) { - spanEvent.setEndElapsed((int) endElapsedTime); - } - - // save next KeyFrame; - prevKeyTime = startTime; - } - } - - - /** - * Skip depth to Span or SpanChunk scope - * @param spanEventList - */ - private void compressDepth(List spanEventList) { - boolean first = true; - int prevDepth = 0; - - final int size = spanEventList.size(); - for (int i = 0; i < size; i++) { - final SpanEvent spanEvent = spanEventList.get(i); - - if (first) { - first = false; - prevDepth = spanEvent.getDepth(); - } else { - final int currentDepth = spanEvent.getDepth(); - if (currentDepth == prevDepth) { - // skip - spanEvent.unsetDepth(); - } - prevDepth = currentDepth; - } - - } - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessor.java new file mode 100644 index 000000000000..14d4173b99a1 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessor.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.compress; + +import com.navercorp.pinpoint.profiler.context.Span; +import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; +import com.navercorp.pinpoint.thrift.dto.TSpanEvent; + + +/** + * @author Woonduk Kang(emeroad) + */ +public interface SpanPostProcessor { + + C newContext(Span span, TSpan tSpan); + + C newContext(SpanChunk spanChunk, TSpanChunk tSpanChunk); + + void postProcess(C context, SpanEvent spanEvent, TSpanEvent tSpanEvent); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessorV1.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessorV1.java new file mode 100644 index 000000000000..1ac256562045 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessorV1.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.compress; + +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.profiler.context.Span; +import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.profiler.context.TraceDataFormatVersion; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; +import com.navercorp.pinpoint.thrift.dto.TSpanEvent; + +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class SpanPostProcessorV1 implements SpanPostProcessor { + + private static final byte V1 = TraceDataFormatVersion.V1.getVersion(); + + @Override + public Context newContext(Span span, TSpan tSpan) { + if (tSpan.getVersion() == V1) { + tSpan.setVersion(V1); + } + + final long startTime = span.getStartTime(); + return new ContextV1(startTime); + } + + @Override + public Context newContext(SpanChunk spanChunk, TSpanChunk tSpanChunk) { + if (tSpanChunk.getVersion() == V1) { + tSpanChunk.setVersion(V1); + } + + final List spanEventList = spanChunk.getSpanEventList(); + if (CollectionUtils.isEmpty(spanEventList)) { + throw new IllegalStateException("spanEventList is empty"); + } +// skip default version +// tSpanChunk.setVersion(V1.getVersion()); + + final TraceRoot traceRoot = spanChunk.getTraceRoot(); + final long traceStartTime = traceRoot.getTraceStartTime(); + return new ContextV1(traceStartTime); + } + + @Override + public void postProcess(Context context, SpanEvent spanEvent, TSpanEvent tSpanEvent) { + final long startTime = spanEvent.getStartTime(); + final long keyTime = context.keyTime(); + final long startElapsedTime = startTime - keyTime; + tSpanEvent.setStartElapsed((int) startElapsedTime); + } + + + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessorV2.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessorV2.java new file mode 100644 index 000000000000..1d4f61005a61 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessorV2.java @@ -0,0 +1,110 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.compress; + +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.profiler.context.Span; +import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.profiler.context.TraceDataFormatVersion; +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; +import com.navercorp.pinpoint.thrift.dto.TSpanEvent; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class SpanPostProcessorV2 implements SpanPostProcessor { + + private static final byte V2 = TraceDataFormatVersion.V2.getVersion(); + + // TODO refactor injector + private final static Comparator SEQUENCE_COMPARATOR = SpanEventSequenceComparator.INSTANCE; + + public SpanPostProcessorV2() { + } + + @Override + public Context newContext(Span span, TSpan tSpan) { + tSpan.setVersion(V2); + + final List spanEventList = span.getSpanEventList(); + Collections.sort(spanEventList, SEQUENCE_COMPARATOR); + + final long keyTime = getKeyTime(spanEventList); + return new ContextV2(keyTime); + } + + @Override + public Context newContext(SpanChunk spanChunk, TSpanChunk tSpanChunk) { + tSpanChunk.setVersion(V2); + + final List spanEventList = spanChunk.getSpanEventList(); + Collections.sort(spanEventList, SEQUENCE_COMPARATOR); + + final long keyTime = getKeyTime(spanEventList); + + tSpanChunk.setKeyTime(keyTime); + return new ContextV2(keyTime); + } + + @Override + public void postProcess(Context context, SpanEvent spanEvent, TSpanEvent tSpanEvent) { + final ContextV2 context2 = (ContextV2) context; + + final long startTime = spanEvent.getStartTime(); + final long keyTime = context.keyTime(); + final long startElapsedTime = startTime - keyTime; + tSpanEvent.setStartElapsed((int) startElapsedTime); + context2.setKeyTime(startTime); + + if (context2.getIndex() == 0) { + int depth = spanEvent.getDepth(); + context2.setPrevDepth(depth); + tSpanEvent.setDepth(depth); + } else { + int currentDepth = spanEvent.getDepth(); + int prevDepth = context2.getPrevDepth(); + if (currentDepth == prevDepth) { + // skip + tSpanEvent.setDepth(0); + } else { + tSpanEvent.setDepth(currentDepth); + } + context2.setPrevDepth(currentDepth); + } + + } + + + private long getKeyTime(List spanEventList) { + if (CollectionUtils.isEmpty(spanEventList)) { + throw new IllegalArgumentException("spanEventList is empty."); + } + final SpanEvent first = spanEventList.get(0); + if (first == null) { + throw new IllegalStateException("first SpanEvent is null"); + } + + return first.getStartTime(); + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/javamodule/ClassFileTransformerModuleHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/javamodule/ClassFileTransformerModuleHandler.java new file mode 100644 index 000000000000..d79e63de17a0 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/javamodule/ClassFileTransformerModuleHandler.java @@ -0,0 +1,118 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.javamodule; + +import com.navercorp.pinpoint.bootstrap.module.ClassFileTransformModuleAdaptor; +import com.navercorp.pinpoint.bootstrap.module.JavaModule; +import com.navercorp.pinpoint.bootstrap.module.JavaModuleFactory; +import com.navercorp.pinpoint.common.util.ClassUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClassFileTransformerModuleHandler implements ClassFileTransformModuleAdaptor { + + private final ClassFileTransformer delegate; + private final JavaModuleFactory javaModuleFactory; + private final JavaModule bootstrapModule; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + + public ClassFileTransformerModuleHandler(Instrumentation instrumentation, ClassFileTransformer delegate, JavaModuleFactory javaModuleFactory) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + if (delegate == null) { + throw new NullPointerException("delegate must not be null"); + } + if (javaModuleFactory == null) { + throw new NullPointerException("javaModuleFactory must not be null"); + } + this.delegate = delegate; + this.javaModuleFactory = javaModuleFactory; + this.bootstrapModule = javaModuleFactory.wrapFromClass(JavaModuleFactory.class); + } + + @Override + public byte[] transform(Object transformedModuleObject, ClassLoader loader, String className, Class classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + + final byte[] transform = delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + if (transformedModuleObject == null) { + return transform; + } + if (transform != null && transform != classfileBuffer) { + if (!javaModuleFactory.isNamedModule(transformedModuleObject)) { + return transform; + } + // bootstrap-core permission + final JavaModule transformedModule = javaModuleFactory.wrapFromModule(transformedModuleObject); + addModulePermission(transformedModule, className, bootstrapModule); + + + if (loader != Object.class.getClassLoader()) { + // plugin permission + final Object pluginModuleObject = getPluginModule(loader); + final JavaModule pluginModule = javaModuleFactory.wrapFromModule(pluginModuleObject); + + addModulePermission(transformedModule, className, pluginModule); + } + } + return transform; + } + + private Object getPluginModule(ClassLoader loader) { + // current internal implementation + // The plugin.jar is loaded into the unnamed module + return javaModuleFactory.getUnnamedModule(loader); + } + + private void addModulePermission(JavaModule transformedModule, String className, JavaModule targetModule) { + if (!transformedModule.canRead(targetModule)) { + if (logger.isInfoEnabled()) { + logger.info("addReads module:{} target:{}", transformedModule, targetModule); + } + transformedModule.addReads(targetModule); + } + + final String packageName = getPackageName(className); + if (packageName != null) { + if (!transformedModule.isExported(packageName, targetModule)) { + if (logger.isInfoEnabled()) { + logger.info("addExports module:{} pkg:{} target:{}", transformedModule, packageName, targetModule); + } + transformedModule.addExports(packageName, targetModule); + } + // need open? + } + } + + private String getPackageName(String className) { + final String packageName = ClassUtils.getPackageName(className, '/', null); + if (packageName == null) { + return null; + } + return PackageUtils.getPackageNameFromInternalName(className); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/javamodule/JavaModuleFactoryFinder.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/javamodule/JavaModuleFactoryFinder.java new file mode 100644 index 000000000000..73cc0d113e95 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/javamodule/JavaModuleFactoryFinder.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.javamodule; + +import com.navercorp.pinpoint.bootstrap.module.JavaModule; +import com.navercorp.pinpoint.bootstrap.module.JavaModuleFactory; + +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Constructor; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class JavaModuleFactoryFinder { + private JavaModuleFactoryFinder() { + } + + public static JavaModuleFactory lookup(Instrumentation instrumentation) { + if (instrumentation == null) { + throw new NullPointerException("instrumentation must not be null"); + } + + final Class javaModuleFactory = getJavaModuleFactory(); + try { + Constructor constructor = javaModuleFactory.getDeclaredConstructor(Instrumentation.class); + return constructor.newInstance(instrumentation); + } catch (Exception e) { + throw new IllegalStateException("JavaModuleFactory() invoke fail Caused by:" + e.getMessage(), e); + } + } + + private static Class getJavaModuleFactory() { + final String factoryName = "com.navercorp.pinpoint.bootstrap.java9.module.DefaultJavaModuleFactory"; + try { + return (Class) Class.forName(factoryName, false, JavaModule.class.getClassLoader()); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(factoryName + " not found"); + } + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/javamodule/PackageUtils.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/javamodule/PackageUtils.java new file mode 100644 index 000000000000..76523bfacba3 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/javamodule/PackageUtils.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.javamodule; + +import com.navercorp.pinpoint.common.util.ClassUtils; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; + +/** + * @author Woonduk Kang(emeroad) + */ +final class PackageUtils { + + static String getPackageNameFromInternalName(String className) { + if (className == null) { + throw new NullPointerException("className must not be null"); + } + final String jvmPackageName = ClassUtils.getPackageName(className, '/', null); + if (jvmPackageName == null) { + return null; + } + + return JavaAssistUtils.jvmNameToJavaName(jvmPackageName); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContext.java index 1d42aa0b24af..16e61a034df6 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContext.java @@ -16,33 +16,11 @@ package com.navercorp.pinpoint.profiler.context.module; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.bootstrap.context.TraceContext; -import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; -import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; -import com.navercorp.pinpoint.profiler.AgentInformation; -import com.navercorp.pinpoint.profiler.ClassFileTransformerDispatcher; - /** * @author Woonduk Kang(emeroad) */ public interface ApplicationContext { - ProfilerConfig getProfilerConfig(); - - TraceContext getTraceContext(); - - InstrumentEngine getInstrumentEngine(); - - - DynamicTransformTrigger getDynamicTransformTrigger(); - - ClassFileTransformerDispatcher getClassFileTransformerDispatcher(); - - AgentInformation getAgentInformation(); - - - void start(); void close(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContextModule.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContextModule.java index 76bb99d2d8da..2d625843e36b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContextModule.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContextModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,21 +19,16 @@ import com.google.inject.AbstractModule; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; -import com.google.inject.name.Names; -import com.navercorp.pinpoint.bootstrap.AgentOption; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.context.ServerMetaDataHolder; import com.navercorp.pinpoint.bootstrap.context.Trace; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; import com.navercorp.pinpoint.bootstrap.plugin.jdbc.JdbcContext; import com.navercorp.pinpoint.bootstrap.sampler.Sampler; -import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; +import com.navercorp.pinpoint.common.plugin.PluginLoader; import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.AgentInfoSender; import com.navercorp.pinpoint.profiler.AgentInformation; -import com.navercorp.pinpoint.profiler.ClassFileTransformerDispatcher; import com.navercorp.pinpoint.profiler.DefaultDynamicTransformerRegistry; import com.navercorp.pinpoint.profiler.DynamicTransformerRegistry; import com.navercorp.pinpoint.profiler.JvmInformation; @@ -44,12 +39,13 @@ import com.navercorp.pinpoint.profiler.context.CallStackFactory; import com.navercorp.pinpoint.profiler.context.DefaultSpanFactory; import com.navercorp.pinpoint.profiler.context.ServerMetaDataRegistryService; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactory; +import com.navercorp.pinpoint.profiler.context.SpanEvent; import com.navercorp.pinpoint.profiler.context.SpanFactory; -import com.navercorp.pinpoint.profiler.context.SpanPostProcessor; import com.navercorp.pinpoint.profiler.context.ThreadLocalBinder; import com.navercorp.pinpoint.profiler.context.TraceFactory; import com.navercorp.pinpoint.profiler.context.active.ActiveTraceRepository; +import com.navercorp.pinpoint.profiler.context.compress.Context; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; import com.navercorp.pinpoint.profiler.context.id.AsyncIdGenerator; import com.navercorp.pinpoint.profiler.context.id.AtomicIdGenerator; import com.navercorp.pinpoint.profiler.context.id.DefaultAsyncIdGenerator; @@ -71,59 +67,36 @@ import com.navercorp.pinpoint.profiler.context.provider.AgentInfoFactoryProvider; import com.navercorp.pinpoint.profiler.context.provider.AgentInfoSenderProvider; import com.navercorp.pinpoint.profiler.context.provider.AgentInformationProvider; -import com.navercorp.pinpoint.profiler.context.provider.AgentStartTimeProvider; import com.navercorp.pinpoint.profiler.context.provider.ApiMetaDataServiceProvider; import com.navercorp.pinpoint.profiler.context.provider.ApplicationServerTypeProvider; import com.navercorp.pinpoint.profiler.context.provider.AsyncContextFactoryProvider; import com.navercorp.pinpoint.profiler.context.provider.AsyncTraceContextProvider; import com.navercorp.pinpoint.profiler.context.provider.BaseTraceFactoryProvider; import com.navercorp.pinpoint.profiler.context.provider.CallStackFactoryProvider; -import com.navercorp.pinpoint.profiler.context.provider.ClassFileTransformerDispatcherProvider; -import com.navercorp.pinpoint.profiler.context.provider.CommandDispatcherProvider; +import com.navercorp.pinpoint.profiler.context.provider.ClassFileTransformerProvider; import com.navercorp.pinpoint.profiler.context.provider.DataSourceMonitorRegistryServiceProvider; import com.navercorp.pinpoint.profiler.context.provider.DeadlockMonitorProvider; import com.navercorp.pinpoint.profiler.context.provider.DeadlockThreadRegistryProvider; import com.navercorp.pinpoint.profiler.context.provider.DynamicTransformTriggerProvider; +import com.navercorp.pinpoint.profiler.context.provider.ExceptionHandlerFactoryProvider; import com.navercorp.pinpoint.profiler.context.provider.InstrumentEngineProvider; import com.navercorp.pinpoint.profiler.context.provider.JdbcUrlParsingServiceProvider; import com.navercorp.pinpoint.profiler.context.provider.JvmInformationProvider; import com.navercorp.pinpoint.profiler.context.provider.ObjectBinderFactoryProvider; -import com.navercorp.pinpoint.profiler.context.provider.PinpointClientFactoryProvider; import com.navercorp.pinpoint.profiler.context.provider.PluginContextLoadResultProvider; import com.navercorp.pinpoint.profiler.context.provider.SamplerProvider; import com.navercorp.pinpoint.profiler.context.provider.ServerMetaDataHolderProvider; import com.navercorp.pinpoint.profiler.context.provider.ServerMetaDataRegistryServiceProvider; -import com.navercorp.pinpoint.profiler.context.provider.SpanChunkFactoryProvider; -import com.navercorp.pinpoint.profiler.context.provider.SpanDataSenderProvider; import com.navercorp.pinpoint.profiler.context.provider.SpanPostProcessorProvider; -import com.navercorp.pinpoint.profiler.context.provider.SpanStatClientFactoryProvider; -import com.navercorp.pinpoint.profiler.context.provider.StatDataSenderProvider; import com.navercorp.pinpoint.profiler.context.provider.StorageFactoryProvider; -import com.navercorp.pinpoint.profiler.context.provider.TcpDataSenderProvider; import com.navercorp.pinpoint.profiler.context.provider.TraceContextProvider; import com.navercorp.pinpoint.profiler.context.provider.TraceFactoryProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.activethread.ActiveTraceMetricCollectorProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.activethread.ActiveTraceMetricProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.cpu.CpuLoadMetricCollectorProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.cpu.CpuLoadMetricProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.datasource.DataSourceMetricCollectorProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.datasource.DataSourceMetricProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.deadlock.DeadlockMetricCollectorProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.deadlock.DeadlockMetricProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.DetailedGarbageCollectorMetricProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.DetailedMemoryMetricProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.GarbageCollectorMetricProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.JvmGcMetricCollectorProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.MemoryMetricProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.response.ResponseTimeMetricCollectorProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.response.ResponseTimeMetricProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.transaction.TransactionMetricCollectorProvider; -import com.navercorp.pinpoint.profiler.context.provider.stat.transaction.TransactionMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.plugin.PluginLoaderProvider; import com.navercorp.pinpoint.profiler.context.recorder.DefaultRecorderFactory; import com.navercorp.pinpoint.profiler.context.recorder.RecorderFactory; import com.navercorp.pinpoint.profiler.context.storage.StorageFactory; import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; +import com.navercorp.pinpoint.profiler.interceptor.factory.ExceptionHandlerFactory; import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; import com.navercorp.pinpoint.profiler.metadata.DefaultSqlMetaDataService; import com.navercorp.pinpoint.profiler.metadata.DefaultStringMetaDataService; @@ -133,55 +106,21 @@ import com.navercorp.pinpoint.profiler.monitor.DeadlockMonitor; import com.navercorp.pinpoint.profiler.monitor.DeadlockThreadRegistry; import com.navercorp.pinpoint.profiler.monitor.DefaultAgentStatMonitor; -import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.activethread.ActiveTraceMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.cpu.CpuLoadMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.datasource.DataSourceMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.deadlock.DeadlockMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.jvmgc.JvmGcMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.response.ResponseTimeMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.transaction.TransactionMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.metric.activethread.ActiveTraceMetric; -import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetric; -import com.navercorp.pinpoint.profiler.monitor.metric.datasource.DataSourceMetric; -import com.navercorp.pinpoint.profiler.monitor.metric.deadlock.DeadlockMetric; -import com.navercorp.pinpoint.profiler.monitor.metric.gc.DetailedGarbageCollectorMetric; -import com.navercorp.pinpoint.profiler.monitor.metric.gc.GarbageCollectorMetric; -import com.navercorp.pinpoint.profiler.monitor.metric.memory.DetailedMemoryMetric; -import com.navercorp.pinpoint.profiler.monitor.metric.memory.MemoryMetric; import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeCollector; -import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeMetric; import com.navercorp.pinpoint.profiler.monitor.metric.response.ReuseResponseTimeCollector; -import com.navercorp.pinpoint.profiler.monitor.metric.transaction.TransactionMetric; import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; import com.navercorp.pinpoint.profiler.plugin.PluginContextLoadResult; -import com.navercorp.pinpoint.profiler.receiver.CommandDispatcher; -import com.navercorp.pinpoint.profiler.sender.DataSender; -import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; import com.navercorp.pinpoint.profiler.util.AgentInfoFactory; -import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; -import com.navercorp.pinpoint.thrift.dto.TAgentStat; -import java.lang.instrument.Instrumentation; -import java.net.URL; -import java.util.List; +import java.lang.instrument.ClassFileTransformer; /** * @author Woonduk Kang(emeroad) */ public class ApplicationContextModule extends AbstractModule { - private final ProfilerConfig profilerConfig; - private final ServiceTypeRegistryService serviceTypeRegistryService; - private final AgentOption agentOption; - private final InterceptorRegistryBinder interceptorRegistryBinder; - - public ApplicationContextModule(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) { - this.agentOption = Assert.requireNonNull(agentOption, "agentOption must not be null"); - this.profilerConfig = Assert.requireNonNull(agentOption.getProfilerConfig(), "agentOption.getProfilerConfig() must not be null"); - this.serviceTypeRegistryService = Assert.requireNonNull(agentOption.getServiceTypeRegistryService(), "agentOption.getServiceTypeRegistryService() must not be null"); - this.interceptorRegistryBinder = interceptorRegistryBinder; + + public ApplicationContextModule() { } @Override @@ -190,20 +129,7 @@ protected void configure() { binder().requireAtInjectOnConstructors(); binder().disableCircularProxies(); - bind(ProfilerConfig.class).toInstance(profilerConfig); - bind(ServiceTypeRegistryService.class).toInstance(serviceTypeRegistryService); - bind(AgentOption.class).toInstance(agentOption); - bind(Instrumentation.class).toInstance(agentOption.getInstrumentation()); - bind(InterceptorRegistryBinder.class).toInstance(interceptorRegistryBinder); - - bind(URL[].class).annotatedWith(PluginJars.class).toInstance(agentOption.getPluginJars()); - - TypeLiteral> listString = new TypeLiteral>() {}; - bind(listString).annotatedWith(BootstrapJarPaths.class).toInstance(agentOption.getBootstrapJarPaths()); - - bindAgentInformation(agentOption.getAgentId(), agentOption.getApplicationName()); - - bindDataTransferComponent(); + bind(ServiceType.class).annotatedWith(ApplicationServerType.class).toProvider(ApplicationServerTypeProvider.class).in(Scopes.SINGLETON); bind(ServerMetaDataRegistryService.class).toProvider(ServerMetaDataRegistryServiceProvider.class).in(Scopes.SINGLETON); bind(ServerMetaDataHolder.class).toProvider(ServerMetaDataHolderProvider.class).in(Scopes.SINGLETON); @@ -236,6 +162,7 @@ protected void configure() { bind(ActiveTraceRepository.class).toProvider(ActiveTraceRepositoryProvider.class).in(Scopes.SINGLETON); bind(PluginContextLoadResult.class).toProvider(PluginContextLoadResultProvider.class).in(Scopes.SINGLETON); + bind(PluginLoader.class).toProvider(PluginLoaderProvider.class).in(Scopes.SINGLETON); bind(JdbcContext.class).to(DefaultJdbcContext.class).in(Scopes.SINGLETON); bind(JdbcUrlParsingService.class).toProvider(JdbcUrlParsingServiceProvider.class).in(Scopes.SINGLETON); @@ -243,14 +170,13 @@ protected void configure() { bind(AgentInformation.class).toProvider(AgentInformationProvider.class).in(Scopes.SINGLETON); bind(InstrumentEngine.class).toProvider(InstrumentEngineProvider.class).in(Scopes.SINGLETON); + bind(ExceptionHandlerFactory.class).toProvider(ExceptionHandlerFactoryProvider.class).in(Scopes.SINGLETON); bind(ObjectBinderFactory.class).toProvider(ObjectBinderFactoryProvider.class).in(Scopes.SINGLETON); - bind(ClassFileTransformerDispatcher.class).toProvider(ClassFileTransformerDispatcherProvider.class).in(Scopes.SINGLETON); + bind(ClassFileTransformer.class).toProvider(ClassFileTransformerProvider.class).in(Scopes.SINGLETON); bind(DynamicTransformerRegistry.class).to(DefaultDynamicTransformerRegistry.class).in(Scopes.SINGLETON); bind(DynamicTransformTrigger.class).toProvider(DynamicTransformTriggerProvider.class).in(Scopes.SINGLETON); // bind(ClassFileTransformer.class).toProvider(ClassFileTransformerWrapProvider.class).in(Scopes.SINGLETON); - bindAgentStatComponent(); - bind(JvmInformation.class).toProvider(JvmInformationProvider.class).in(Scopes.SINGLETON); bind(AgentInfoFactory.class).toProvider(AgentInfoFactoryProvider.class).in(Scopes.SINGLETON); bind(DeadlockMonitor.class).toProvider(DeadlockMonitorProvider.class).in(Scopes.SINGLETON); @@ -261,33 +187,21 @@ protected void configure() { private void bindTraceComponent() { bind(TraceRootFactory.class).to(DefaultTraceRootFactory.class).in(Scopes.SINGLETON); bind(TraceIdFactory.class).to(DefaultTraceIdFactory.class).in(Scopes.SINGLETON); - bind(CallStackFactory.class).toProvider(CallStackFactoryProvider.class).in(Scopes.SINGLETON); + + TypeLiteral> callStackFactoryKey = new TypeLiteral>() {}; + bind(callStackFactoryKey).toProvider(CallStackFactoryProvider.class).in(Scopes.SINGLETON); bind(SpanFactory.class).to(DefaultSpanFactory.class).in(Scopes.SINGLETON); - bind(SpanPostProcessor.class).toProvider(SpanPostProcessorProvider.class).in(Scopes.SINGLETON); - bind(SpanChunkFactory.class).toProvider(SpanChunkFactoryProvider.class).in(Scopes.SINGLETON); + + TypeLiteral> spanPostProcessorType = new TypeLiteral>() {}; + bind(spanPostProcessorType).toProvider(SpanPostProcessorProvider.class).in(Scopes.SINGLETON); bind(RecorderFactory.class).to(DefaultRecorderFactory.class).in(Scopes.SINGLETON); - bind(BaseTraceFactory.class).toProvider(BaseTraceFactoryProvider.class).in(Scopes.SINGLETON);; + bind(BaseTraceFactory.class).toProvider(BaseTraceFactoryProvider.class).in(Scopes.SINGLETON); bind(TraceFactory.class).toProvider(TraceFactoryProvider.class).in(Scopes.SINGLETON); } - private void bindDataTransferComponent() { - // create tcp channel - - bind(CommandDispatcher.class).toProvider(CommandDispatcherProvider.class).in(Scopes.SINGLETON); - bind(PinpointClientFactory.class).annotatedWith(DefaultClientFactory.class). - toProvider(PinpointClientFactoryProvider.class).in(Scopes.SINGLETON); - bind(EnhancedDataSender.class).toProvider(TcpDataSenderProvider.class).in(Scopes.SINGLETON); - - bind(PinpointClientFactory.class).annotatedWith(SpanStatClientFactory.class). - toProvider(SpanStatClientFactoryProvider.class).in(Scopes.SINGLETON); - bind(DataSender.class).annotatedWith(SpanDataSender.class) - .toProvider(SpanDataSenderProvider.class).in(Scopes.SINGLETON); - bind(DataSender.class).annotatedWith(StatDataSender.class) - .toProvider(StatDataSenderProvider.class).in(Scopes.SINGLETON); - } private void bindServiceComponent() { @@ -297,41 +211,5 @@ private void bindServiceComponent() { bind(PredefinedMethodDescriptorRegistry.class).to(DefaultPredefinedMethodDescriptorRegistry.class).in(Scopes.SINGLETON); } - private void bindAgentInformation(String agentId, String applicationName) { - bind(String.class).annotatedWith(AgentId.class).toInstance(agentId); - bind(String.class).annotatedWith(ApplicationName.class).toInstance(applicationName); - bind(Long.class).annotatedWith(AgentStartTime.class).toProvider(AgentStartTimeProvider.class).in(Scopes.SINGLETON); - bind(ServiceType.class).annotatedWith(ApplicationServerType.class).toProvider(ApplicationServerTypeProvider.class).in(Scopes.SINGLETON); - } - - private void bindAgentStatComponent() { - bind(MemoryMetric.class).toProvider(MemoryMetricProvider.class).in(Scopes.SINGLETON); - bind(DetailedMemoryMetric.class).toProvider(DetailedMemoryMetricProvider.class).in(Scopes.SINGLETON); - bind(GarbageCollectorMetric.class).toProvider(GarbageCollectorMetricProvider.class).in(Scopes.SINGLETON); - bind(DetailedGarbageCollectorMetric.class).toProvider(DetailedGarbageCollectorMetricProvider.class).in(Scopes.SINGLETON); - bind(JvmGcMetricCollector.class).toProvider(JvmGcMetricCollectorProvider.class).in(Scopes.SINGLETON); - - bind(CpuLoadMetric.class).toProvider(CpuLoadMetricProvider.class).in(Scopes.SINGLETON); - bind(CpuLoadMetricCollector.class).toProvider(CpuLoadMetricCollectorProvider.class).in(Scopes.SINGLETON); - - bind(TransactionMetric.class).toProvider(TransactionMetricProvider.class).in(Scopes.SINGLETON); - bind(TransactionMetricCollector.class).toProvider(TransactionMetricCollectorProvider.class).in(Scopes.SINGLETON); - - bind(ActiveTraceMetric.class).toProvider(ActiveTraceMetricProvider.class).in(Scopes.SINGLETON); - bind(ActiveTraceMetricCollector.class).toProvider(ActiveTraceMetricCollectorProvider.class).in(Scopes.SINGLETON); - - bind(ResponseTimeMetric.class).toProvider(ResponseTimeMetricProvider.class).in(Scopes.SINGLETON); - bind(ResponseTimeMetricCollector.class).toProvider(ResponseTimeMetricCollectorProvider.class).in(Scopes.SINGLETON); - - bind(DataSourceMetric.class).toProvider(DataSourceMetricProvider.class).in(Scopes.SINGLETON); - bind(DataSourceMetricCollector.class).toProvider(DataSourceMetricCollectorProvider.class).in(Scopes.SINGLETON); - - bind(DeadlockMetric.class).toProvider(DeadlockMetricProvider.class).in(Scopes.SINGLETON); - bind(DeadlockMetricCollector.class).toProvider(DeadlockMetricCollectorProvider.class).in(Scopes.SINGLETON); - - bind(new TypeLiteral>() {}) - .annotatedWith(Names.named("AgentStatCollector")) - .to(AgentStatCollector.class).in(Scopes.SINGLETON); - } } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContextModuleFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContextModuleFactory.java index 724820ac1cf4..98d5643ea1e5 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContextModuleFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ApplicationContextModuleFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,16 +17,24 @@ package com.navercorp.pinpoint.profiler.context.module; import com.google.inject.Module; +import com.google.inject.util.Modules; import com.navercorp.pinpoint.bootstrap.AgentOption; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; +import com.navercorp.pinpoint.profiler.context.module.config.ConfigModule; /** * @author Woonduk Kang(emeroad) */ public class ApplicationContextModuleFactory implements ModuleFactory { + @Override - public Module newModule(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) { + public Module newModule(AgentOption agentOption) { + final Module config = new ConfigModule(agentOption); + final Module pluginModule = new PluginModule(); + final Module applicationContextModule = new ApplicationContextModule(); + final Module rpcModule = new RpcModule(); + final Module statsModule = new StatsModule(); + final Module thriftStatsModule = new ThriftStatsModule(); - return new ApplicationContextModule(agentOption, interceptorRegistryBinder); + return Modules.combine(config, pluginModule, applicationContextModule, rpcModule, statsModule, thriftStatsModule); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/Container.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/Container.java new file mode 100644 index 000000000000..ad69af38c4e1 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/Container.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * @author HyunGil Jeong + */ +@BindingAnnotation +@Target(PARAMETER) +@Retention(RUNTIME) +public @interface Container { +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContext.java index 5fc22c309ddc..11fd1e4dcf5f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,19 +21,25 @@ import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.Stage; +import com.google.inject.TypeLiteral; import com.navercorp.pinpoint.bootstrap.AgentOption; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; -import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; +import com.navercorp.pinpoint.bootstrap.module.ClassFileTransformModuleAdaptor; +import com.navercorp.pinpoint.bootstrap.module.JavaModuleFactory; import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.JvmVersion; import com.navercorp.pinpoint.profiler.AgentInfoSender; import com.navercorp.pinpoint.profiler.AgentInformation; -import com.navercorp.pinpoint.profiler.ClassFileTransformerDispatcher; import com.navercorp.pinpoint.profiler.context.ServerMetaDataRegistryService; +import com.navercorp.pinpoint.profiler.context.javamodule.ClassFileTransformerModuleHandler; +import com.navercorp.pinpoint.profiler.context.javamodule.JavaModuleFactoryFinder; import com.navercorp.pinpoint.profiler.instrument.ASMBytecodeDumpService; import com.navercorp.pinpoint.profiler.instrument.BytecodeDumpTransformer; import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; +import com.navercorp.pinpoint.profiler.instrument.lambda.LambdaTransformBootloader; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.monitor.AgentStatMonitor; import com.navercorp.pinpoint.profiler.monitor.DeadlockMonitor; @@ -45,6 +51,7 @@ import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; +import java.lang.reflect.Constructor; /** * @author Woonduk Kang(emeroad) @@ -69,45 +76,48 @@ public class DefaultApplicationContext implements ApplicationContext { private final DataSender statDataSender; private final AgentInformation agentInformation; - private final AgentOption agentOption; private final ServerMetaDataRegistryService serverMetaDataRegistryService; - private final ServiceTypeRegistryService serviceTypeRegistryService; + private final ClassFileTransformer classFileTransformer; - private final ClassFileTransformerDispatcher classFileDispatcher; - - private final Instrumentation instrumentation; private final InstrumentEngine instrumentEngine; private final DynamicTransformTrigger dynamicTransformTrigger; + private final InterceptorRegistryBinder interceptorRegistryBinder; private final Injector injector; - public DefaultApplicationContext(AgentOption agentOption, final InterceptorRegistryBinder interceptorRegistryBinder) { - this(agentOption, interceptorRegistryBinder, new ApplicationContextModuleFactory()); - } - - public DefaultApplicationContext(AgentOption agentOption, final InterceptorRegistryBinder interceptorRegistryBinder, ModuleFactory moduleFactory) { - this.agentOption = Assert.requireNonNull(agentOption, "agentOption must not be null"); - this.profilerConfig = Assert.requireNonNull(agentOption.getProfilerConfig(), "profilerConfig must not be null"); + public DefaultApplicationContext(AgentOption agentOption, ModuleFactory moduleFactory) { + Assert.requireNonNull(agentOption, "agentOption must not be null"); Assert.requireNonNull(moduleFactory, "moduleFactory must not be null"); + Assert.requireNonNull(agentOption.getProfilerConfig(), "profilerConfig must not be null"); - this.instrumentation = agentOption.getInstrumentation(); - this.serviceTypeRegistryService = agentOption.getServiceTypeRegistryService(); - + final Instrumentation instrumentation = agentOption.getInstrumentation(); if (logger.isInfoEnabled()) { logger.info("DefaultAgent classLoader:{}", this.getClass().getClassLoader()); } - final Module applicationContextModule = moduleFactory.newModule(agentOption, interceptorRegistryBinder); + final Module applicationContextModule = moduleFactory.newModule(agentOption); this.injector = Guice.createInjector(Stage.PRODUCTION, applicationContextModule); + this.profilerConfig = injector.getInstance(ProfilerConfig.class); + this.interceptorRegistryBinder = injector.getInstance(InterceptorRegistryBinder.class); + this.instrumentEngine = injector.getInstance(InstrumentEngine.class); - this.classFileDispatcher = injector.getInstance(ClassFileTransformerDispatcher.class); + this.classFileTransformer = injector.getInstance(ClassFileTransformer.class); this.dynamicTransformTrigger = injector.getInstance(DynamicTransformTrigger.class); -// ClassFileTransformer classFileTransformer = injector.getInstance(ClassFileTransformer.class); - ClassFileTransformer classFileTransformer = wrap(classFileDispatcher); - instrumentation.addTransformer(classFileTransformer, true); + + ClassFileTransformer classFileTransformer = wrap(this.classFileTransformer); + final JvmVersion version = JvmUtils.getVersion(); + if (version.onOrAfter(JvmVersion.JAVA_9)) { + final JavaModuleFactory javaModuleFactory = JavaModuleFactoryFinder.lookup(instrumentation); + ClassFileTransformModuleAdaptor classFileTransformModuleAdaptor = new ClassFileTransformerModuleHandler(instrumentation, classFileTransformer, javaModuleFactory); + classFileTransformer = wrapJava9ClassFileTransformer(classFileTransformModuleAdaptor); + lambdaFactorySetup(instrumentation, classFileTransformModuleAdaptor, javaModuleFactory); + instrumentation.addTransformer(classFileTransformer, true); + } else { + instrumentation.addTransformer(classFileTransformer, true); + } this.spanStatClientFactory = injector.getInstance(Key.get(PinpointClientFactory.class, SpanStatClientFactory.class)); logger.info("spanStatClientFactory:{}", spanStatClientFactory); @@ -121,7 +131,9 @@ public DefaultApplicationContext(AgentOption agentOption, final InterceptorRegis this.clientFactory = injector.getInstance(Key.get(PinpointClientFactory.class, DefaultClientFactory.class)); logger.info("clientFactory:{}", clientFactory); - this.tcpDataSender = injector.getInstance(EnhancedDataSender.class); + TypeLiteral> enhancedDataSenderLiteral = new TypeLiteral>(){}; + Key> enhancedDataSenderKey = Key.get(enhancedDataSenderLiteral); + this.tcpDataSender = injector.getInstance(enhancedDataSenderKey); logger.info("tcpDataSender:{}", tcpDataSender); this.traceContext = injector.getInstance(TraceContext.class); @@ -135,17 +147,42 @@ public DefaultApplicationContext(AgentOption agentOption, final InterceptorRegis this.agentStatMonitor = injector.getInstance(AgentStatMonitor.class); } - public ClassFileTransformer wrap(ClassFileTransformerDispatcher classFileTransformerDispatcher) { + private void lambdaFactorySetup(Instrumentation instrumentation, ClassFileTransformModuleAdaptor classFileTransformer, JavaModuleFactory javaModuleFactory) { + final JvmVersion version = JvmUtils.getVersion(); +// TODO version.onOrAfter(JvmVersion.JAVA_8) + if (version.onOrAfter(JvmVersion.JAVA_9)) { + LambdaTransformBootloader lambdaTransformBootloader = new LambdaTransformBootloader(); + lambdaTransformBootloader.transformLambdaFactory(instrumentation, classFileTransformer, javaModuleFactory); + } + } + + private ClassFileTransformer wrapJava9ClassFileTransformer(ClassFileTransformModuleAdaptor classFileTransformer) { + logger.info("initialize Java9ClassFileTransformer"); + String moduleWrap = "com.navercorp.pinpoint.bootstrap.java9.module.ClassFileTransformerModuleWrap"; + try { + Class cftClass = (Class) forName(moduleWrap, Object.class.getClassLoader()); + Constructor constructor = cftClass.getDeclaredConstructor(ClassFileTransformModuleAdaptor.class); + return constructor.newInstance(classFileTransformer); + } catch (Exception e) { + throw new IllegalStateException(moduleWrap + " load fail Caused by:" + e.getMessage(), e); + } + } + + private Class forName(String className, ClassLoader classLoader) { + try { + return Class.forName(className, false, classLoader); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(className + " not found"); + } + } + + private ClassFileTransformer wrap(ClassFileTransformer classFileTransformer) { final boolean enableBytecodeDump = profilerConfig.readBoolean(ASMBytecodeDumpService.ENABLE_BYTECODE_DUMP, ASMBytecodeDumpService.ENABLE_BYTECODE_DUMP_DEFAULT_VALUE); if (enableBytecodeDump) { logger.info("wrapBytecodeDumpTransformer"); - return BytecodeDumpTransformer.wrap(classFileTransformerDispatcher, profilerConfig); + return BytecodeDumpTransformer.wrap(classFileTransformer, profilerConfig); } - return classFileTransformerDispatcher; - } - - protected Module newApplicationContextModule(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) { - return new ApplicationContextModule(agentOption, interceptorRegistryBinder); + return classFileTransformer; } private DataSender newUdpStatDataSender() { @@ -158,7 +195,6 @@ private DataSender newUdpSpanDataSender() { return injector.getInstance(spanDataSenderKey); } - @Override public ProfilerConfig getProfilerConfig() { return profilerConfig; } @@ -167,7 +203,6 @@ public Injector getInjector() { return injector; } - @Override public TraceContext getTraceContext() { return traceContext; } @@ -181,18 +216,15 @@ public InstrumentEngine getInstrumentEngine() { } - @Override public DynamicTransformTrigger getDynamicTransformTrigger() { return dynamicTransformTrigger; } - @Override - public ClassFileTransformerDispatcher getClassFileTransformerDispatcher() { - return classFileDispatcher; + public ClassFileTransformer getClassFileTransformer() { + return classFileTransformer; } - @Override public AgentInformation getAgentInformation() { return this.agentInformation; } @@ -201,8 +233,11 @@ public ServerMetaDataRegistryService getServerMetaDataRegistryService() { return this.serverMetaDataRegistryService; } + @Override public void start() { + this.interceptorRegistryBinder.bind(); + this.deadlockMonitor.start(); this.agentInfoSender.start(); this.agentStatMonitor.start(); @@ -222,6 +257,10 @@ public void close() { } closeTcpDataSender(); + + if (profilerConfig.getStaticResourceCleanup()) { + this.interceptorRegistryBinder.unbind(); + } } private void closeTcpDataSender() { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/DefaultModuleFactoryResolver.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/DefaultModuleFactoryResolver.java new file mode 100644 index 000000000000..54e9100dcd25 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/DefaultModuleFactoryResolver.java @@ -0,0 +1,87 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.exception.PinpointException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Constructor; + +/** + * @author Taejin Koo + */ +public class DefaultModuleFactoryResolver implements ModuleFactoryResolver { + + private static final String DEFAULT_MODULE_FACTORY = ApplicationContextModuleFactory.class.getName(); + private final Logger logger = LoggerFactory.getLogger(DefaultModuleFactoryResolver.class); + + private final String moduleFactoryClazzName; + + + + public DefaultModuleFactoryResolver() { + this(DEFAULT_MODULE_FACTORY); + } + + public DefaultModuleFactoryResolver(String moduleFactoryClazzName) { + this.moduleFactoryClazzName = getDefaultModuleFactoryClassName(moduleFactoryClazzName); + } + + private String getDefaultModuleFactoryClassName(String moduleFactoryClazzName) { + if (StringUtils.isEmpty(moduleFactoryClazzName)) { + return DEFAULT_MODULE_FACTORY; + } + return moduleFactoryClazzName; + } + + private boolean isDefaultModuleFactory(String moduleFactoryClazzName) { + if (StringUtils.isEmpty(moduleFactoryClazzName)) { + return true; + } + if (DEFAULT_MODULE_FACTORY.equals(moduleFactoryClazzName)) { + return true; + } + return false; + } + + @Override + public ModuleFactory resolve() { + logger.info("{} ModuleFactory lookup", moduleFactoryClazzName); + if (isDefaultModuleFactory(moduleFactoryClazzName)) { + return new ApplicationContextModuleFactory(); + } + + ClassLoader classLoader = getClassLoader(DefaultModuleFactoryResolver.class.getClassLoader()); + try { + final Class moduleFactoryClass = + (Class) Class.forName(moduleFactoryClazzName, true, classLoader); + Constructor constructor = moduleFactoryClass.getConstructor(); + return constructor.newInstance(); + } catch (Exception ex) { + logger.warn("{} ModuleFactory initialize fail", moduleFactoryClazzName, ex); + throw new PinpointException(moduleFactoryClazzName + " ModuleFactory initialize fail", ex); + } + } + + private ClassLoader getClassLoader(ClassLoader classLoader) { + return Assert.requireNonNull(classLoader, "can't find classLoader"); + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/MetadataConverter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/MetadataConverter.java new file mode 100644 index 000000000000..a532dafe636c --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/MetadataConverter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * @author Woonduk Kang(emeroad) + */ +@BindingAnnotation +@Target(PARAMETER) +@Retention(RUNTIME) +public @interface MetadataConverter { +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactory.java index 5b039648822b..6506d999897f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactory.java @@ -18,11 +18,10 @@ import com.google.inject.Module; import com.navercorp.pinpoint.bootstrap.AgentOption; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; /** * @author Woonduk Kang(emeroad) */ public interface ModuleFactory { - Module newModule(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder); + Module newModule(AgentOption agentOption); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactoryResolver.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactoryResolver.java new file mode 100644 index 000000000000..93f490a4b32e --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactoryResolver.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +/** + * @author Taejin Koo + */ +public interface ModuleFactoryResolver { + + ModuleFactory resolve(); + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/PluginModule.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/PluginModule.java new file mode 100644 index 000000000000..bb3180b6518f --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/PluginModule.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.PrivateModule; +import com.google.inject.Scopes; +import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; +import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; +import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; +import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; +import com.navercorp.pinpoint.profiler.context.provider.plugin.AnnotationKeyRegistryServiceProvider; +import com.navercorp.pinpoint.profiler.context.provider.plugin.ServiceTypeRegistryServiceProvider; +import com.navercorp.pinpoint.profiler.context.provider.plugin.Slf4jCommonLoggerFactory; +import com.navercorp.pinpoint.profiler.context.provider.plugin.TraceMetadataLoaderServiceProvider; + +/** + * @author Woonduk Kang(emeroad) + */ + +public class PluginModule extends PrivateModule { + + @Override + protected void configure() { + binder().requireExplicitBindings(); + binder().requireAtInjectOnConstructors(); + binder().disableCircularProxies(); + + bind(CommonLoggerFactory.class).toInstance(new Slf4jCommonLoggerFactory()); + bind(TraceMetadataLoaderService.class).toProvider(TraceMetadataLoaderServiceProvider.class).in(Scopes.SINGLETON); + + bind(ServiceTypeRegistryService.class).toProvider(ServiceTypeRegistryServiceProvider.class).in(Scopes.SINGLETON); + expose(ServiceTypeRegistryService.class); + + bind(AnnotationKeyRegistryService.class).toProvider(AnnotationKeyRegistryServiceProvider.class).in(Scopes.SINGLETON); + expose(AnnotationKeyRegistryService.class); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/RpcModule.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/RpcModule.java new file mode 100644 index 000000000000..afd357f4adab --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/RpcModule.java @@ -0,0 +1,87 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.Key; +import com.google.inject.PrivateModule; +import com.google.inject.Scopes; +import com.google.inject.TypeLiteral; +import com.navercorp.pinpoint.profiler.context.provider.CommandDispatcherProvider; +import com.navercorp.pinpoint.profiler.context.provider.ConnectionFactoryProviderProvider; +import com.navercorp.pinpoint.profiler.context.provider.HeaderTBaseSerializerProvider; +import com.navercorp.pinpoint.profiler.context.provider.MetadataMessageConverterProvider; +import com.navercorp.pinpoint.profiler.context.provider.PinpointClientFactoryProvider; +import com.navercorp.pinpoint.profiler.context.provider.SpanDataSenderProvider; +import com.navercorp.pinpoint.profiler.context.provider.SpanStatClientFactoryProvider; +import com.navercorp.pinpoint.profiler.context.provider.StatDataSenderProvider; +import com.navercorp.pinpoint.profiler.context.provider.TcpDataSenderProvider; +import com.navercorp.pinpoint.profiler.context.provider.SpanThriftMessageConverterProvider; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import com.navercorp.pinpoint.profiler.receiver.CommandDispatcher; +import com.navercorp.pinpoint.profiler.sender.DataSender; +import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; +import com.navercorp.pinpoint.rpc.client.ConnectionFactoryProvider; +import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; +import org.apache.thrift.TBase; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RpcModule extends PrivateModule { + @Override + protected void configure() { + bind(CommandDispatcher.class).toProvider(CommandDispatcherProvider.class).in(Scopes.SINGLETON); + + bind(ConnectionFactoryProvider.class).toProvider(ConnectionFactoryProviderProvider.class).in(Scopes.SINGLETON); + + Key pinpointClientFactory = Key.get(PinpointClientFactory.class, DefaultClientFactory.class); + bind(pinpointClientFactory).toProvider(PinpointClientFactoryProvider.class).in(Scopes.SINGLETON); + expose(pinpointClientFactory); + + bind(HeaderTBaseSerializer.class).toProvider(HeaderTBaseSerializerProvider.class).in(Scopes.SINGLETON); + + TypeLiteral> dataSenderTypeLiteral = new TypeLiteral>() {}; + bind(dataSenderTypeLiteral).toProvider(TcpDataSenderProvider.class).in(Scopes.SINGLETON); + expose(dataSenderTypeLiteral); + + Key pinpointStatClientFactory = Key.get(PinpointClientFactory.class, SpanStatClientFactory.class); + bind(pinpointStatClientFactory).toProvider(SpanStatClientFactoryProvider.class).in(Scopes.SINGLETON); + expose(pinpointStatClientFactory); + + + TypeLiteral>> thriftMessageConverter = new TypeLiteral>>() {}; + Key>> spanMessageConverterKey = Key.get(thriftMessageConverter, SpanConverter.class); + bind(spanMessageConverterKey).toProvider(SpanThriftMessageConverterProvider.class ).in(Scopes.SINGLETON); + expose(spanMessageConverterKey); + + Key>> metadataMessageConverterKey = Key.get(thriftMessageConverter, MetadataConverter.class); + bind(metadataMessageConverterKey).toProvider(MetadataMessageConverterProvider.class ).in(Scopes.SINGLETON); + expose(metadataMessageConverterKey); + + + Key spanDataSender = Key.get(DataSender.class, SpanDataSender.class); + bind(spanDataSender).toProvider(SpanDataSenderProvider.class).in(Scopes.SINGLETON); + expose(spanDataSender); + + Key statDataSender = Key.get(DataSender.class, StatDataSender.class); + bind(DataSender.class).annotatedWith(StatDataSender.class) + .toProvider(StatDataSenderProvider.class).in(Scopes.SINGLETON); + expose(statDataSender); + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/SpanConverter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/SpanConverter.java new file mode 100644 index 000000000000..b9a03a3c0531 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/SpanConverter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * @author Woonduk Kang(emeroad) + */ +@BindingAnnotation +@Target(PARAMETER) +@Retention(RUNTIME) +public @interface SpanConverter { +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/StatsModule.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/StatsModule.java new file mode 100644 index 000000000000..e3c8c6a1c604 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/StatsModule.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.AbstractModule; +import com.google.inject.Scopes; +import com.navercorp.pinpoint.profiler.context.provider.stat.activethread.ActiveTraceMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.cpu.CpuLoadMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.datasource.DataSourceMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.deadlock.DeadlockMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.buffer.BufferMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.filedescriptor.FileDescriptorMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.DetailedGarbageCollectorMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.DetailedMemoryMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.GarbageCollectorMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.MemoryMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.response.ResponseTimeMetricProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.transaction.TransactionMetricProvider; +import com.navercorp.pinpoint.profiler.monitor.metric.activethread.ActiveTraceMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.datasource.DataSourceMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.deadlock.DeadlockMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.buffer.BufferMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.FileDescriptorMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.gc.DetailedGarbageCollectorMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.gc.GarbageCollectorMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.memory.DetailedMemoryMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.memory.MemoryMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.transaction.TransactionMetric; + +/** + * @author Woonduk Kang(emeroad) + */ +public class StatsModule extends AbstractModule { + + @Override + protected void configure() { + binder().requireExplicitBindings(); + binder().requireAtInjectOnConstructors(); + binder().disableCircularProxies(); + + // gc + bind(MemoryMetric.class).toProvider(MemoryMetricProvider.class).in(Scopes.SINGLETON); + bind(DetailedMemoryMetric.class).toProvider(DetailedMemoryMetricProvider.class).in(Scopes.SINGLETON); + bind(GarbageCollectorMetric.class).toProvider(GarbageCollectorMetricProvider.class).in(Scopes.SINGLETON); + bind(DetailedGarbageCollectorMetric.class).toProvider(DetailedGarbageCollectorMetricProvider.class).in(Scopes.SINGLETON); + + // cpu + bind(CpuLoadMetric.class).toProvider(CpuLoadMetricProvider.class).in(Scopes.SINGLETON); + + // FD + bind(FileDescriptorMetric.class).toProvider(FileDescriptorMetricProvider.class).in(Scopes.SINGLETON); + + // buffer + bind(BufferMetric.class).toProvider(BufferMetricProvider.class).in(Scopes.SINGLETON); + + // transaction + bind(TransactionMetric.class).toProvider(TransactionMetricProvider.class).in(Scopes.SINGLETON); + + // activeTrace + bind(ActiveTraceMetric.class).toProvider(ActiveTraceMetricProvider.class).in(Scopes.SINGLETON); + + // responseTime + bind(ResponseTimeMetric.class).toProvider(ResponseTimeMetricProvider.class).in(Scopes.SINGLETON); + + // datasource + bind(DataSourceMetric.class).toProvider(DataSourceMetricProvider.class).in(Scopes.SINGLETON); + + // deadlock + bind(DeadlockMetric.class).toProvider(DeadlockMetricProvider.class).in(Scopes.SINGLETON); + + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ThriftStatsModule.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ThriftStatsModule.java new file mode 100644 index 000000000000..f3ce68dda8d4 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/ThriftStatsModule.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.AbstractModule; +import com.google.inject.Scopes; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; +import com.navercorp.pinpoint.profiler.context.provider.stat.activethread.ActiveTraceMetricCollectorProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.buffer.BufferMetricCollectorProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.cpu.CpuLoadMetricCollectorProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.datasource.DataSourceMetricCollectorProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.deadlock.DeadlockMetricCollectorProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.filedescriptor.FileDescriptorMetricCollectorProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.jvmgc.JvmGcMetricCollectorProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.response.ResponseTimeMetricCollectorProvider; +import com.navercorp.pinpoint.profiler.context.provider.stat.transaction.TransactionMetricCollectorProvider; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.thrift.dto.TActiveTrace; +import com.navercorp.pinpoint.thrift.dto.TAgentStat; +import com.navercorp.pinpoint.thrift.dto.TCpuLoad; +import com.navercorp.pinpoint.thrift.dto.TDataSourceList; +import com.navercorp.pinpoint.thrift.dto.TDeadlock; +import com.navercorp.pinpoint.thrift.dto.TDirectBuffer; +import com.navercorp.pinpoint.thrift.dto.TFileDescriptor; +import com.navercorp.pinpoint.thrift.dto.TJvmGc; +import com.navercorp.pinpoint.thrift.dto.TResponseTime; +import com.navercorp.pinpoint.thrift.dto.TTransaction; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ThriftStatsModule extends AbstractModule { + + @Override + protected void configure() { + binder().requireExplicitBindings(); + binder().requireAtInjectOnConstructors(); + binder().disableCircularProxies(); + + // gc + TypeLiteral> jvmGcCollector = new TypeLiteral>() {}; + bind(jvmGcCollector).toProvider(JvmGcMetricCollectorProvider.class).in(Scopes.SINGLETON); + + // cpu + TypeLiteral> cpuLoadCollector = new TypeLiteral>() {}; + bind(cpuLoadCollector).toProvider(CpuLoadMetricCollectorProvider.class).in(Scopes.SINGLETON); + + // FD + TypeLiteral> fdCollector = new TypeLiteral>() {}; + bind(fdCollector).toProvider(FileDescriptorMetricCollectorProvider.class).in(Scopes.SINGLETON); + + // buffer + TypeLiteral> bufferCollector = new TypeLiteral>() {}; + bind(bufferCollector).toProvider(BufferMetricCollectorProvider.class).in(Scopes.SINGLETON); + + // transaction + TypeLiteral> transactionCollector = new TypeLiteral>() {}; + bind(transactionCollector).toProvider(TransactionMetricCollectorProvider.class).in(Scopes.SINGLETON); + + // activeTrace + TypeLiteral> activeTraceCollector = new TypeLiteral>() {}; + bind(activeTraceCollector).toProvider(ActiveTraceMetricCollectorProvider.class).in(Scopes.SINGLETON); + + // responseTime + TypeLiteral> responseTimeCollector = new TypeLiteral>() {}; + bind(responseTimeCollector).toProvider(ResponseTimeMetricCollectorProvider.class).in(Scopes.SINGLETON); + + // datasource + TypeLiteral> datasourceCollector = new TypeLiteral>() {}; + bind(datasourceCollector).toProvider(DataSourceMetricCollectorProvider.class).in(Scopes.SINGLETON); + + // deadlock + TypeLiteral> deadlockCollector = new TypeLiteral>() {}; + bind(deadlockCollector).toProvider(DeadlockMetricCollectorProvider.class).in(Scopes.SINGLETON); + + // stat + TypeLiteral> statMetric = new TypeLiteral>() {}; + bind(statMetric).annotatedWith(Names.named("AgentStatCollector")) + .to(AgentStatCollector.class).in(Scopes.SINGLETON); + } + +} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/ConfigModule.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/ConfigModule.java new file mode 100644 index 000000000000..5f96bbe20182 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/ConfigModule.java @@ -0,0 +1,115 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module.config; + +import com.google.inject.AbstractModule; +import com.google.inject.Scopes; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Named; +import com.google.inject.name.Names; +import com.navercorp.pinpoint.bootstrap.AgentOption; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.TraceDataFormatVersion; +import com.navercorp.pinpoint.profiler.context.module.AgentId; +import com.navercorp.pinpoint.profiler.context.module.AgentStartTime; +import com.navercorp.pinpoint.profiler.context.module.ApplicationName; +import com.navercorp.pinpoint.profiler.context.module.BootstrapJarPaths; +import com.navercorp.pinpoint.profiler.context.module.Container; +import com.navercorp.pinpoint.profiler.context.module.PluginJars; +import com.navercorp.pinpoint.profiler.context.provider.AgentStartTimeProvider; +import com.navercorp.pinpoint.profiler.context.provider.InterceptorRegistryBinderProvider; +import com.navercorp.pinpoint.profiler.instrument.classloading.BootstrapCore; +import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.instrument.Instrumentation; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ConfigModule extends AbstractModule { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final AgentOption agentOption; + + public ConfigModule(AgentOption agentOption) { + this.agentOption = Assert.requireNonNull(agentOption, "profilerConfig must not be null"); + Assert.requireNonNull(agentOption.getProfilerConfig(), "profilerConfig must not be null"); + } + + @Override + protected void configure() { + binder().requireExplicitBindings(); + binder().requireAtInjectOnConstructors(); + binder().disableCircularProxies(); + + ProfilerConfig profilerConfig = agentOption.getProfilerConfig(); + + bind(ProfilerConfig.class).toInstance(profilerConfig); + + bindConstants(profilerConfig); + + + bind(Instrumentation.class).toInstance(agentOption.getInstrumentation()); + + bind(InterceptorRegistryBinder.class).toProvider(InterceptorRegistryBinderProvider.class).in(Scopes.SINGLETON); + + TypeLiteral> pluginJarFile = new TypeLiteral>() {}; + bind(pluginJarFile).annotatedWith(PluginJars.class).toInstance(agentOption.getPluginJars()); + + + bindBootstrapCoreInformation(); + + bindAgentInformation(agentOption.getAgentId(), agentOption.getApplicationName(), agentOption.isContainer()); + } + + private void bindBootstrapCoreInformation() { + List bootstrapJarPaths = agentOption.getBootstrapJarPaths(); + + TypeLiteral> bootstrapJarFIle = new TypeLiteral>() {}; + bind(bootstrapJarFIle).annotatedWith(BootstrapJarPaths.class).toInstance(bootstrapJarPaths); + + BootstrapCore bootstrapCore = new BootstrapCore(bootstrapJarPaths); + bind(BootstrapCore.class).toInstance(bootstrapCore); + } + + private void bindConstants(ProfilerConfig profilerConfig) { + + final TraceDataFormatVersion version = TraceDataFormatVersion.getTraceDataFormatVersion(profilerConfig); + logger.info("TraceDataFormatVersion:{}", version); + bind(TraceDataFormatVersion.class).toInstance(version); + + Named callstackMaxDepth = Names.named("profiler.callstack.max.depth"); + bindConstant().annotatedWith(callstackMaxDepth).to(profilerConfig.getCallStackMaxDepth()); + + bindConstant().annotatedWith(TraceAgentActiveThread.class).to(profilerConfig.isTraceAgentActiveThread()); + + bindConstant().annotatedWith(DeadlockMonitorEnable.class).to(profilerConfig.isDeadlockMonitorEnable()); + bindConstant().annotatedWith(DeadlockMonitorInterval.class).to(profilerConfig.getDeadlockMonitorInterval()); + } + + private void bindAgentInformation(String agentId, String applicationName, boolean isContainer) { + + bind(String.class).annotatedWith(AgentId.class).toInstance(agentId); + bind(String.class).annotatedWith(ApplicationName.class).toInstance(applicationName); + bind(Boolean.class).annotatedWith(Container.class).toInstance(isContainer); + bind(Long.class).annotatedWith(AgentStartTime.class).toProvider(AgentStartTimeProvider.class).in(Scopes.SINGLETON); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/DeadlockMonitorEnable.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/DeadlockMonitorEnable.java new file mode 100644 index 000000000000..95aefb6e5a7e --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/DeadlockMonitorEnable.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module.config; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * @author Woonduk Kang(emeroad) + */ +@BindingAnnotation +@Target(PARAMETER) +@Retention(RUNTIME) +public @interface DeadlockMonitorEnable { +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/DeadlockMonitorInterval.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/DeadlockMonitorInterval.java new file mode 100644 index 000000000000..5e2db1dee522 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/DeadlockMonitorInterval.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module.config; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * @author Woonduk Kang(emeroad) + */ +@BindingAnnotation +@Target(PARAMETER) +@Retention(RUNTIME) +public @interface DeadlockMonitorInterval { +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/TraceAgentActiveThread.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/TraceAgentActiveThread.java new file mode 100644 index 000000000000..7747590ee42c --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/module/config/TraceAgentActiveThread.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module.config; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * @author Woonduk Kang(emeroad) + */ +@BindingAnnotation +@Target(PARAMETER) +@Retention(RUNTIME) +public @interface TraceAgentActiveThread { +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/monitor/DefaultJdbcContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/monitor/DefaultJdbcContext.java index 25aedb6e4eaf..c3290557df59 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/monitor/DefaultJdbcContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/monitor/DefaultJdbcContext.java @@ -20,7 +20,6 @@ import com.navercorp.pinpoint.bootstrap.context.DatabaseInfo; import com.navercorp.pinpoint.bootstrap.plugin.jdbc.JdbcContext; import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.profiler.context.monitor.JdbcUrlParsingService; /** diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ActiveTraceRepositoryProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ActiveTraceRepositoryProvider.java index 525c62bfa6bb..38468c4c35fd 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ActiveTraceRepositoryProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ActiveTraceRepositoryProvider.java @@ -20,11 +20,11 @@ import com.google.inject.Provider; import com.google.inject.Inject; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.active.ActiveTraceRepository; import com.navercorp.pinpoint.profiler.context.active.DefaultActiveTraceRepository; import com.navercorp.pinpoint.profiler.context.active.EmptyActiveTraceRepository; +import com.navercorp.pinpoint.profiler.context.module.config.TraceAgentActiveThread; import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeCollector; @@ -33,18 +33,18 @@ */ public class ActiveTraceRepositoryProvider implements Provider { - private final ProfilerConfig profilerConfig; + private boolean isTraceAgentActiveThread; private final ResponseTimeCollector responseTimeCollector; @Inject - public ActiveTraceRepositoryProvider(ProfilerConfig profilerConfig, ResponseTimeCollector responseTimeCollector) { - this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + public ActiveTraceRepositoryProvider(@TraceAgentActiveThread boolean isTraceAgentActiveThread, ResponseTimeCollector responseTimeCollector) { + this.isTraceAgentActiveThread = isTraceAgentActiveThread; this.responseTimeCollector = Assert.requireNonNull(responseTimeCollector, "responseTimeCollector must not be null"); } public ActiveTraceRepository get() { - if (profilerConfig.isTraceAgentActiveThread()) { + if (isTraceAgentActiveThread) { return new DefaultActiveTraceRepository(responseTimeCollector); } ActiveTraceRepository emptyActiveTraceRepository = new EmptyActiveTraceRepository(responseTimeCollector); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/AgentInfoSenderProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/AgentInfoSenderProvider.java index 443c53b44c2e..6fd408ad1e91 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/AgentInfoSenderProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/AgentInfoSenderProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,14 +32,14 @@ public class AgentInfoSenderProvider implements Provider { private final ProfilerConfig profilerConfig; - private final Provider enhancedDataSenderProvider; + private final Provider> enhancedDataSenderProvider; private final Provider agentInfoFactoryProvider; private final ServerMetaDataRegistryService serverMetaDataRegistryService; @Inject public AgentInfoSenderProvider( ProfilerConfig profilerConfig, - Provider enhancedDataSenderProvider, + Provider> enhancedDataSenderProvider, Provider agentInfoFactoryProvider, ServerMetaDataRegistryService serverMetaDataRegistryService) { this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/AgentInformationProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/AgentInformationProvider.java index c443375aa2f1..231bfdc4d8b1 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/AgentInformationProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/AgentInformationProvider.java @@ -30,6 +30,7 @@ import com.navercorp.pinpoint.profiler.context.module.ApplicationServerType; import com.navercorp.pinpoint.profiler.context.module.AgentStartTime; import com.navercorp.pinpoint.profiler.context.module.ApplicationName; +import com.navercorp.pinpoint.profiler.context.module.Container; import com.navercorp.pinpoint.profiler.util.RuntimeMXBeanUtils; /** @@ -39,11 +40,12 @@ public class AgentInformationProvider implements Provider { private final String agentId; private final String applicationName; + private final boolean isContainer; private final long agentStartTime; private final ServiceType serverType; @Inject - public AgentInformationProvider(@AgentId String agentId, @ApplicationName String applicationName, @AgentStartTime long agentStartTime, @ApplicationServerType ServiceType serverType) { + public AgentInformationProvider(@AgentId String agentId, @ApplicationName String applicationName, @Container boolean isContainer, @AgentStartTime long agentStartTime, @ApplicationServerType ServiceType serverType) { if (agentId == null) { throw new NullPointerException("agentId must not be null"); } @@ -56,6 +58,7 @@ public AgentInformationProvider(@AgentId String agentId, @ApplicationName String this.agentId = checkId("agentId", agentId); this.applicationName = checkId("applicationName", applicationName); + this.isContainer = isContainer; this.agentStartTime = agentStartTime; this.serverType = serverType; @@ -72,7 +75,7 @@ public AgentInformation createAgentInformation() { final int pid = RuntimeMXBeanUtils.getPid(); final String jvmVersion = JvmUtils.getSystemProperty(SystemPropertyKey.JAVA_VERSION); - return new DefaultAgentInformation(agentId, applicationName, agentStartTime, pid, machineName, hostIp, serverType, jvmVersion, Version.VERSION); + return new DefaultAgentInformation(agentId, applicationName, isContainer, agentStartTime, pid, machineName, hostIp, serverType, jvmVersion, Version.VERSION); } private String checkId(String keyName,String id) { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ApiMetaDataServiceProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ApiMetaDataServiceProvider.java index 76d5bc082b54..e38b49cc3c4b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ApiMetaDataServiceProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ApiMetaDataServiceProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,23 +28,20 @@ * @author Woonduk Kang(emeroad) */ public class ApiMetaDataServiceProvider implements Provider { - private final String agentId; - private final long agentStartTime; - private final Provider enhancedDataSenderProvider; + + private final Provider> enhancedDataSenderProvider; @Inject - public ApiMetaDataServiceProvider(@AgentId String agentId, @AgentStartTime long agentStartTime, Provider enhancedDataSenderProvider) { + public ApiMetaDataServiceProvider(Provider> enhancedDataSenderProvider) { if (enhancedDataSenderProvider == null) { throw new NullPointerException("enhancedDataSenderProvider must not be null"); } - this.agentId = agentId; - this.agentStartTime = agentStartTime; this.enhancedDataSenderProvider = enhancedDataSenderProvider; } @Override public ApiMetaDataService get() { - final EnhancedDataSender enhancedDataSender = this.enhancedDataSenderProvider.get(); - return new DefaultApiMetaDataService(agentId, agentStartTime, enhancedDataSender); + final EnhancedDataSender enhancedDataSender = this.enhancedDataSenderProvider.get(); + return new DefaultApiMetaDataService(enhancedDataSender); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/BaseTraceFactoryProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/BaseTraceFactoryProvider.java index 02133ce40b5c..6dd8ae951f21 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/BaseTraceFactoryProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/BaseTraceFactoryProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import com.navercorp.pinpoint.profiler.context.CallStackFactory; import com.navercorp.pinpoint.profiler.context.DefaultBaseTraceFactory; import com.navercorp.pinpoint.profiler.context.LoggingBaseTraceFactory; +import com.navercorp.pinpoint.profiler.context.SpanEvent; import com.navercorp.pinpoint.profiler.context.SpanFactory; import com.navercorp.pinpoint.profiler.context.active.ActiveTraceRepository; import com.navercorp.pinpoint.profiler.context.id.IdGenerator; @@ -47,7 +48,7 @@ public class BaseTraceFactoryProvider implements Provider { private final Provider asyncContextFactoryProvider; - private final CallStackFactory callStackFactory; + private final CallStackFactory callStackFactory; private final SpanFactory spanFactory; private final RecorderFactory recorderFactory; @@ -56,7 +57,7 @@ public class BaseTraceFactoryProvider implements Provider { @Inject public BaseTraceFactoryProvider(TraceRootFactory traceRootFactory, StorageFactory storageFactory, Sampler sampler, IdGenerator idGenerator, Provider asyncContextFactoryProvider, - CallStackFactory callStackFactory, SpanFactory spanFactory, RecorderFactory recorderFactory, ActiveTraceRepository activeTraceRepository) { + CallStackFactory callStackFactory, SpanFactory spanFactory, RecorderFactory recorderFactory, ActiveTraceRepository activeTraceRepository) { this.traceRootFactory = Assert.requireNonNull(traceRootFactory, "traceRootFactory must not be null"); this.callStackFactory = Assert.requireNonNull(callStackFactory, "callStackFactory must not be null"); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/CallStackFactoryProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/CallStackFactoryProvider.java index e7ccc3a70caf..9d23f4320c8a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/CallStackFactoryProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/CallStackFactoryProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,36 +18,36 @@ import com.google.inject.Inject; import com.google.inject.Provider; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.google.inject.name.Named; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.CallStackFactory; import com.navercorp.pinpoint.profiler.context.CallStackFactoryV1; import com.navercorp.pinpoint.profiler.context.CallStackFactoryV2; +import com.navercorp.pinpoint.profiler.context.SpanEvent; import com.navercorp.pinpoint.profiler.context.TraceDataFormatVersion; /** * @author Woonduk Kang(emeroad) */ -public class CallStackFactoryProvider implements Provider { +public class CallStackFactoryProvider implements Provider> { private final TraceDataFormatVersion version; private final int callStackMaxDepth; @Inject - public CallStackFactoryProvider(ProfilerConfig profilerConfig) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - this.version = TraceDataFormatVersion.getTraceDataFormatVersion(profilerConfig); - this.callStackMaxDepth = profilerConfig.getCallStackMaxDepth(); + public CallStackFactoryProvider(@Named("profiler.callstack.max.depth") int callStackMaxDepth, + TraceDataFormatVersion version) { + this.version = Assert.requireNonNull(version, "version must not be null"); + this.callStackMaxDepth = callStackMaxDepth; } @Override - public CallStackFactory get() { + public CallStackFactory get() { if (version == TraceDataFormatVersion.V2) { return new CallStackFactoryV2(callStackMaxDepth); } - if(version == TraceDataFormatVersion.V1) { + if (version == TraceDataFormatVersion.V1) { return new CallStackFactoryV1(callStackMaxDepth); } throw new UnsupportedOperationException("unknown version :" + version); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ClassFileTransformerDispatcherProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ClassFileTransformerDispatcherProvider.java deleted file mode 100644 index d10465a7dcb7..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ClassFileTransformerDispatcherProvider.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context.provider; - -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; -import com.navercorp.pinpoint.profiler.MatchableClassFileTransformerDispatcher; -import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; -import com.navercorp.pinpoint.profiler.ClassFileTransformerDispatcher; -import com.navercorp.pinpoint.profiler.DefaultClassFileTransformerDispatcher; -import com.navercorp.pinpoint.profiler.DynamicTransformerRegistry; -import com.navercorp.pinpoint.profiler.plugin.PluginContextLoadResult; - -/** - * @author Woonduk Kang(emeroad) - */ -public class ClassFileTransformerDispatcherProvider implements Provider { - - private final ProfilerConfig profilerConfig; - private final PluginContextLoadResult pluginContextLoadResult; - private final InstrumentEngine instrumentEngine; - private final DynamicTransformTrigger dynamicTransformTrigger; - private final DynamicTransformerRegistry dynamicTransformerRegistry; - - @Inject - public ClassFileTransformerDispatcherProvider(ProfilerConfig profilerConfig, InstrumentEngine instrumentEngine, PluginContextLoadResult pluginContextLoadResult, - DynamicTransformTrigger dynamicTransformTrigger, DynamicTransformerRegistry dynamicTransformerRegistry) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (instrumentEngine == null) { - throw new NullPointerException("instrumentEngine must not be null"); - } - if (pluginContextLoadResult == null) { - throw new NullPointerException("pluginContextLoadResult must not be null"); - } - if (dynamicTransformTrigger == null) { - throw new NullPointerException("dynamicTransformTrigger must not be null"); - } - if (dynamicTransformerRegistry == null) { - throw new NullPointerException("dynamicTransformerRegistry must not be null"); - } - this.profilerConfig = profilerConfig; - this.instrumentEngine = instrumentEngine; - this.pluginContextLoadResult = pluginContextLoadResult; - this.dynamicTransformTrigger = dynamicTransformTrigger; - this.dynamicTransformerRegistry = dynamicTransformerRegistry; - } - - @Override - public ClassFileTransformerDispatcher get() { - if(this.profilerConfig.isInstrumentMatcherEnable()) { - return new MatchableClassFileTransformerDispatcher(profilerConfig, pluginContextLoadResult, instrumentEngine, dynamicTransformTrigger, dynamicTransformerRegistry); - } - return new DefaultClassFileTransformerDispatcher(profilerConfig, pluginContextLoadResult, instrumentEngine, dynamicTransformTrigger, dynamicTransformerRegistry); - } -} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ClassFileTransformerProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ClassFileTransformerProvider.java new file mode 100644 index 000000000000..4180274f10bb --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ClassFileTransformerProvider.java @@ -0,0 +1,115 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; +import com.navercorp.pinpoint.profiler.DefaultClassFileTransformerDispatcher; +import com.navercorp.pinpoint.profiler.DynamicTransformerRegistry; +import com.navercorp.pinpoint.profiler.instrument.transformer.BaseTransformerRegistry; +import com.navercorp.pinpoint.profiler.instrument.transformer.BypassLambdaClassFileResolver; +import com.navercorp.pinpoint.profiler.instrument.transformer.DebugTransformerRegistry; +import com.navercorp.pinpoint.profiler.instrument.transformer.DefaultLambdaClassFileResolver; +import com.navercorp.pinpoint.profiler.instrument.transformer.DefaultTransformerRegistry; +import com.navercorp.pinpoint.profiler.instrument.transformer.LambdaClassFileResolver; +import com.navercorp.pinpoint.profiler.instrument.transformer.MatchableTransformerRegistry; +import com.navercorp.pinpoint.profiler.instrument.transformer.TransformerRegistry; +import com.navercorp.pinpoint.profiler.plugin.MatchableClassFileTransformer; +import com.navercorp.pinpoint.profiler.plugin.PluginContextLoadResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.instrument.ClassFileTransformer; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClassFileTransformerProvider implements Provider { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final ProfilerConfig profilerConfig; + private final PluginContextLoadResult pluginContextLoadResult; + private final InstrumentEngine instrumentEngine; + private final DynamicTransformTrigger dynamicTransformTrigger; + private final DynamicTransformerRegistry dynamicTransformerRegistry; + + @Inject + public ClassFileTransformerProvider(ProfilerConfig profilerConfig, InstrumentEngine instrumentEngine, PluginContextLoadResult pluginContextLoadResult, + DynamicTransformTrigger dynamicTransformTrigger, DynamicTransformerRegistry dynamicTransformerRegistry) { + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.instrumentEngine = Assert.requireNonNull(instrumentEngine, "instrumentEngine must not be null"); + this.pluginContextLoadResult = Assert.requireNonNull(pluginContextLoadResult, "pluginContextLoadResult must not be null"); + this.dynamicTransformTrigger = Assert.requireNonNull(dynamicTransformTrigger, "dynamicTransformTrigger must not be null"); + this.dynamicTransformerRegistry = Assert.requireNonNull(dynamicTransformerRegistry, "dynamicTransformerRegistry must not be null"); + } + + @Override + public ClassFileTransformer get() { + final LambdaClassFileResolver lambdaClassFileResolver = newLambdaClassFileResolver(); + final BaseTransformerRegistry baseTransformerRegistry = newDefaultTransformerRegistry(); + final TransformerRegistry transformerRegistry = setupTransformerRegistry(baseTransformerRegistry, pluginContextLoadResult); + final TransformerRegistry debugTransformerRegistry = new DebugTransformerRegistry(profilerConfig, instrumentEngine, dynamicTransformTrigger); + return new DefaultClassFileTransformerDispatcher(transformerRegistry, debugTransformerRegistry, dynamicTransformerRegistry, lambdaClassFileResolver); + } + + private LambdaClassFileResolver newLambdaClassFileResolver() { + if (profilerConfig.isSupportLambdaExpressions()) { + return new DefaultLambdaClassFileResolver(); + } + return new BypassLambdaClassFileResolver(); + } + + private BaseTransformerRegistry newDefaultTransformerRegistry() { + if (this.profilerConfig.isInstrumentMatcherEnable()) { + return new MatchableTransformerRegistry(profilerConfig); + } + return new DefaultTransformerRegistry(); + } + + private TransformerRegistry setupTransformerRegistry(BaseTransformerRegistry registry, PluginContextLoadResult pluginContexts) { + Assert.requireNonNull(registry, "registry must not be null"); + Assert.requireNonNull(pluginContexts, "pluginContexts must not be null"); + + for (ClassFileTransformer transformer : pluginContexts.getClassFileTransformer()) { + if (transformer instanceof MatchableClassFileTransformer) { + MatchableClassFileTransformer t = (MatchableClassFileTransformer) transformer; + if (logger.isInfoEnabled()) { + logger.info("Registering class file transformer {} for {} ", t, t.getMatcher()); + } + try { + registry.addTransformer(t.getMatcher(), t); + } catch (Exception e) { + if (logger.isWarnEnabled()) { + logger.warn("Failed to add transformer {}", transformer, e); + } + } + } else { + if (logger.isWarnEnabled()) { + logger.warn("Ignore class file transformer {}", transformer); + } + } + } + + return registry; + } + +} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ConnectionFactoryProviderProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ConnectionFactoryProviderProvider.java new file mode 100644 index 000000000000..b7f05a13e303 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ConnectionFactoryProviderProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.rpc.client.ClientCodecPipelineFactory; +import com.navercorp.pinpoint.rpc.client.ConnectionFactoryProvider; +import com.navercorp.pinpoint.rpc.client.DefaultConnectionFactoryProvider; + +/** + * @author Taejin Koo + */ +public class ConnectionFactoryProviderProvider implements Provider { + + @Inject + public ConnectionFactoryProviderProvider() { + } + + @Override + public ConnectionFactoryProvider get() { + return new DefaultConnectionFactoryProvider(new ClientCodecPipelineFactory()); + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/DeadlockMonitorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/DeadlockMonitorProvider.java index 7bde244f587d..63788c65bdd6 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/DeadlockMonitorProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/DeadlockMonitorProvider.java @@ -18,7 +18,8 @@ import com.google.inject.Inject; import com.google.inject.Provider; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.profiler.context.module.config.DeadlockMonitorEnable; +import com.navercorp.pinpoint.profiler.context.module.config.DeadlockMonitorInterval; import com.navercorp.pinpoint.profiler.monitor.DeadlockMonitor; import com.navercorp.pinpoint.profiler.monitor.DeadlockThreadRegistry; import com.navercorp.pinpoint.profiler.monitor.DefaultDeadlockMonitor; @@ -29,19 +30,23 @@ */ public class DeadlockMonitorProvider implements Provider { - private final ProfilerConfig profilerConfig; + private final boolean deadlockMonitorEnable; private final DeadlockThreadRegistry deadlockThreadRegistry; + private final long deadlockMonitorInterval; @Inject - public DeadlockMonitorProvider(ProfilerConfig profilerConfig, DeadlockThreadRegistry deadlockThreadRegistry) { - this.profilerConfig = profilerConfig; + public DeadlockMonitorProvider(@DeadlockMonitorEnable boolean deadlockMonitorEnable, + @DeadlockMonitorInterval long deadlockMonitorInterval, + DeadlockThreadRegistry deadlockThreadRegistry) { + this.deadlockMonitorEnable = deadlockMonitorEnable; this.deadlockThreadRegistry = deadlockThreadRegistry; + this.deadlockMonitorInterval = deadlockMonitorInterval; } @Override public DeadlockMonitor get() { - if (profilerConfig.isDeadlockMonitorEnable()) { - return new DefaultDeadlockMonitor(deadlockThreadRegistry, profilerConfig.getDeadlockMonitorInterval()); + if (deadlockMonitorEnable) { + return new DefaultDeadlockMonitor(deadlockThreadRegistry, deadlockMonitorInterval); } else { return new DisabledDeadlockMonitor(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ExceptionHandlerFactoryProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ExceptionHandlerFactoryProvider.java new file mode 100644 index 000000000000..f99758e1383a --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ExceptionHandlerFactoryProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.interceptor.factory.ExceptionHandlerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ExceptionHandlerFactoryProvider implements Provider { + private final ProfilerConfig profilerConfig; + + @Inject + public ExceptionHandlerFactoryProvider(ProfilerConfig profilerConfig) { + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + } + + @Override + public ExceptionHandlerFactory get() { + boolean exceptionGuard = !profilerConfig.isPropagateInterceptorException(); + return new ExceptionHandlerFactory(exceptionGuard); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/HeaderTBaseSerializerProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/HeaderTBaseSerializerProvider.java new file mode 100644 index 000000000000..d351bac75bbd --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/HeaderTBaseSerializerProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; + +/** + * @author Taejin Koo + */ +public class HeaderTBaseSerializerProvider implements Provider { + + private final HeaderTBaseSerializerFactory serializerFactory = new HeaderTBaseSerializerFactory(); + + @Inject + public HeaderTBaseSerializerProvider() { + } + + @Override + public HeaderTBaseSerializer get() { + return serializerFactory.createSerializer(); + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/InstrumentEngineProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/InstrumentEngineProvider.java index d9fbafe2eced..a67d7530cde3 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/InstrumentEngineProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/InstrumentEngineProvider.java @@ -18,13 +18,16 @@ import com.google.inject.Inject; import com.google.inject.Provider; -import com.navercorp.pinpoint.bootstrap.AgentOption; import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.instrument.DefaultEngineComponent; +import com.navercorp.pinpoint.profiler.instrument.EngineComponent; import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; import com.navercorp.pinpoint.profiler.instrument.ASMEngine; -import com.navercorp.pinpoint.profiler.instrument.JavassistEngine; +import com.navercorp.pinpoint.profiler.instrument.ScopeFactory; +import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinitionFactory; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; @@ -41,50 +44,37 @@ public class InstrumentEngineProvider implements Provider { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final ProfilerConfig profilerConfig; - private final AgentOption agentOption; private final InterceptorRegistryBinder interceptorRegistryBinder; private final Provider apiMetaDataServiceProvider; private final ObjectBinderFactory objectBinderFactory; private final Instrumentation instrumentation; @Inject - public InstrumentEngineProvider(ProfilerConfig profilerConfig, Instrumentation instrumentation, ObjectBinderFactory objectBinderFactory, AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder, Provider apiMetaDataServiceProvider) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (instrumentation == null) { - throw new NullPointerException("instrumentation must not be null"); - } - if (objectBinderFactory == null) { - throw new NullPointerException("objectBinderFactory must not be null"); - } - if (agentOption == null) { - throw new NullPointerException("agentOption must not be null"); - } - if (interceptorRegistryBinder == null) { - throw new NullPointerException("interceptorRegistryBinder must not be null"); - } - if (apiMetaDataServiceProvider == null) { - throw new NullPointerException("apiMetaDataServiceProvider must not be null"); - } + public InstrumentEngineProvider(ProfilerConfig profilerConfig, + Instrumentation instrumentation, + ObjectBinderFactory objectBinderFactory, + InterceptorRegistryBinder interceptorRegistryBinder, + Provider apiMetaDataServiceProvider) { - this.profilerConfig = profilerConfig; - this.instrumentation = instrumentation; - this.objectBinderFactory = objectBinderFactory; - this.agentOption = agentOption; - this.interceptorRegistryBinder = interceptorRegistryBinder; - this.apiMetaDataServiceProvider = apiMetaDataServiceProvider; + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.instrumentation = Assert.requireNonNull(instrumentation, "instrumentation must not be null"); + this.objectBinderFactory = Assert.requireNonNull(objectBinderFactory, "objectBinderFactory must not be null"); + this.interceptorRegistryBinder = Assert.requireNonNull(interceptorRegistryBinder, "interceptorRegistryBinder must not be null"); + this.apiMetaDataServiceProvider = Assert.requireNonNull(apiMetaDataServiceProvider, "apiMetaDataServiceProvider must not be null"); } public InstrumentEngine get() { final String instrumentEngine = profilerConfig.getProfileInstrumentEngine().toUpperCase(); if (DefaultProfilerConfig.INSTRUMENT_ENGINE_ASM.equals(instrumentEngine)) { - logger.info("ASM InstrumentEngine."); - return new ASMEngine(instrumentation, objectBinderFactory, interceptorRegistryBinder, apiMetaDataServiceProvider, agentOption.getBootstrapJarPaths()); + logger.info("ASM InstrumentEngine"); + + // WARNING must be singleton + final InterceptorDefinitionFactory interceptorDefinitionFactory = new InterceptorDefinitionFactory(); + // WARNING must be singleton + final ScopeFactory scopeFactory = new ScopeFactory(); + EngineComponent engineComponent = new DefaultEngineComponent(objectBinderFactory, interceptorRegistryBinder, interceptorDefinitionFactory, apiMetaDataServiceProvider, scopeFactory); + return new ASMEngine(instrumentation, engineComponent); - } else if (DefaultProfilerConfig.INSTRUMENT_ENGINE_JAVASSIST.equals(instrumentEngine)) { - logger.info("JAVASSIST InstrumentEngine."); - return new JavassistEngine(instrumentation, objectBinderFactory, interceptorRegistryBinder, apiMetaDataServiceProvider, agentOption.getBootstrapJarPaths()); } else { logger.warn("Unknown InstrumentEngine:{}", instrumentEngine); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/InterceptorRegistryBinderProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/InterceptorRegistryBinderProvider.java new file mode 100644 index 000000000000..940d03349068 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/InterceptorRegistryBinderProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider; + + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.interceptor.registry.DefaultInterceptorRegistryBinder; +import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; + +/** + * @author Woonduk Kang(emeroad) + */ +public class InterceptorRegistryBinderProvider implements Provider { + + private final InterceptorRegistryBinder interceptorRegistryBinder; + + @Inject + public InterceptorRegistryBinderProvider(ProfilerConfig profilerConfig) { + this(getInterceptorRegistrySize(profilerConfig)); + } + + private static int getInterceptorRegistrySize(ProfilerConfig profilerConfig) { + Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + return profilerConfig.getInterceptorRegistrySize(); + } + + public InterceptorRegistryBinderProvider(int interceptorSize) { + this.interceptorRegistryBinder = new DefaultInterceptorRegistryBinder(interceptorSize); + } + + @Override + public InterceptorRegistryBinder get() { + return interceptorRegistryBinder; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/JvmInformationProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/JvmInformationProvider.java index e2e77188c082..5b4b9767c9e7 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/JvmInformationProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/JvmInformationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,8 @@ import com.navercorp.pinpoint.common.util.SystemPropertyKey; import com.navercorp.pinpoint.profiler.JvmInformation; import com.navercorp.pinpoint.profiler.monitor.metric.gc.GarbageCollectorMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.gc.JvmGcType; import com.navercorp.pinpoint.profiler.monitor.metric.gc.UnknownGarbageCollectorMetric; -import com.navercorp.pinpoint.thrift.dto.TJvmGcType; /** * @author HyunGil Jeong @@ -45,7 +45,7 @@ public JvmInformationProvider() { } public JvmInformation get() { - TJvmGcType gcType = garbageCollectorMetric.getGcType(); + JvmGcType gcType = garbageCollectorMetric.getGcType(); return new JvmInformation(jvmVersion, gcType.getValue()); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/MetadataMessageConverterProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/MetadataMessageConverterProvider.java new file mode 100644 index 000000000000..17413bf8d48d --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/MetadataMessageConverterProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.module.AgentId; +import com.navercorp.pinpoint.profiler.context.module.AgentStartTime; +import com.navercorp.pinpoint.profiler.context.module.ApplicationName; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import com.navercorp.pinpoint.profiler.context.thrift.MetadataMessageConverter; +import org.apache.thrift.TBase; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class MetadataMessageConverterProvider implements Provider>> { + + private final String applicationName; + private final String agentId; + private final long agentStartTime; + + @Inject + public MetadataMessageConverterProvider(@ApplicationName String applicationName, @AgentId String agentId, @AgentStartTime long agentStartTime) { + this.applicationName = Assert.requireNonNull(applicationName, "applicationName must not be null"); + this.agentId = Assert.requireNonNull(agentId, "agentId must not be null"); + this.agentStartTime = agentStartTime; + } + + + @Override + public MessageConverter> get() { + MessageConverter> messageConverter = new MetadataMessageConverter(applicationName, agentId, agentStartTime); + return messageConverter; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ObjectBinderFactoryProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ObjectBinderFactoryProvider.java index 5d190b1d5889..8520e1afb5b7 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ObjectBinderFactoryProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/ObjectBinderFactoryProvider.java @@ -20,7 +20,9 @@ import com.google.inject.Provider; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.monitor.DataSourceMonitorRegistryService; +import com.navercorp.pinpoint.profiler.interceptor.factory.ExceptionHandlerFactory; import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; @@ -33,30 +35,25 @@ public class ObjectBinderFactoryProvider implements Provider traceContextProvider; private final DataSourceMonitorRegistryService dataSourceMonitorRegistryService; private final Provider apiMetaDataServiceProvider; + private final ExceptionHandlerFactory exceptionHandlerFactory; + @Inject - public ObjectBinderFactoryProvider(ProfilerConfig profilerConfig, Provider traceContextProvider, DataSourceMonitorRegistryService dataSourceMonitorRegistryService, Provider apiMetaDataServiceProvider) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (traceContextProvider == null) { - throw new NullPointerException("traceContextProvider must not be null"); - } - if (dataSourceMonitorRegistryService == null) { - throw new NullPointerException("dataSourceMonitorRegistryService must not be null"); - } - if (apiMetaDataServiceProvider == null) { - throw new NullPointerException("apiMetaDataServiceProvider must not be null"); - } - this.profilerConfig = profilerConfig; - this.traceContextProvider = traceContextProvider; - this.dataSourceMonitorRegistryService = dataSourceMonitorRegistryService; - this.apiMetaDataServiceProvider = apiMetaDataServiceProvider; + public ObjectBinderFactoryProvider(ProfilerConfig profilerConfig, + Provider traceContextProvider, + DataSourceMonitorRegistryService dataSourceMonitorRegistryService, + Provider apiMetaDataServiceProvider, + ExceptionHandlerFactory exceptionHandlerFactory) { + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.traceContextProvider = Assert.requireNonNull(traceContextProvider, "traceContextProvider must not be null"); + this.dataSourceMonitorRegistryService = Assert.requireNonNull(dataSourceMonitorRegistryService, "dataSourceMonitorRegistryService must not be null"); + this.apiMetaDataServiceProvider = Assert.requireNonNull(apiMetaDataServiceProvider, "apiMetaDataServiceProvider must not be null"); + this.exceptionHandlerFactory = Assert.requireNonNull(exceptionHandlerFactory, "exceptionHandlerFactory must not be null"); } @Override public ObjectBinderFactory get() { - return new ObjectBinderFactory(profilerConfig, traceContextProvider, dataSourceMonitorRegistryService, apiMetaDataServiceProvider); + return new ObjectBinderFactory(profilerConfig, traceContextProvider, dataSourceMonitorRegistryService, apiMetaDataServiceProvider, exceptionHandlerFactory); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/PinpointClientFactoryProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/PinpointClientFactoryProvider.java index af2e0af3a5bd..6d423254bfb4 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/PinpointClientFactoryProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/PinpointClientFactoryProvider.java @@ -21,6 +21,7 @@ import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.profiler.AgentInformation; import com.navercorp.pinpoint.profiler.receiver.CommandDispatcher; +import com.navercorp.pinpoint.rpc.client.ConnectionFactoryProvider; import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; @@ -35,10 +36,11 @@ public class PinpointClientFactoryProvider implements Provider agentInformation; + private final Provider connectionFactoryProvider; private final CommandDispatcher commandDispatcher; @Inject - public PinpointClientFactoryProvider(ProfilerConfig profilerConfig, Provider agentInformation, CommandDispatcher commandDispatcher) { + public PinpointClientFactoryProvider(ProfilerConfig profilerConfig, Provider agentInformation, CommandDispatcher commandDispatcher, Provider connectionFactoryProvider) { if (profilerConfig == null) { throw new NullPointerException("profilerConfig must not be null"); } @@ -48,14 +50,22 @@ public PinpointClientFactoryProvider(ProfilerConfig profilerConfig, Provider properties = toMap(agentInformation); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/PluginContextLoadResultProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/PluginContextLoadResultProvider.java index 18e26d135a71..617c12bf481d 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/PluginContextLoadResultProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/PluginContextLoadResultProvider.java @@ -20,8 +20,11 @@ import com.google.inject.Provider; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; -import com.navercorp.pinpoint.profiler.context.module.PluginJars; +import com.navercorp.pinpoint.profiler.instrument.classloading.BootstrapCore; +import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjectorFactory; import com.navercorp.pinpoint.profiler.plugin.DefaultPluginContextLoadResult; import com.navercorp.pinpoint.profiler.plugin.PluginContextLoadResult; @@ -34,35 +37,23 @@ public class PluginContextLoadResultProvider implements Provider { - - private final String applicationName; - private final String agentId; - private final long agentStartTime; - private final ServiceType applicationServiceType; - private final TraceDataFormatVersion version; - private final TransactionIdEncoder transactionIdEncoder; - - - @Inject - public SpanChunkFactoryProvider(ProfilerConfig profilerConfig, @ApplicationName String applicationName, @AgentId String agentId, @AgentStartTime long agentStartTime, - @ApplicationServerType ServiceType applicationServiceType, TransactionIdEncoder transactionIdEncoder) { - - this.applicationName = Assert.requireNonNull(applicationName, "applicationName must not be null"); - this.agentId = Assert.requireNonNull(agentId, "agentId must not be null"); - - this.agentStartTime = agentStartTime; - this.applicationServiceType = Assert.requireNonNull(applicationServiceType, "applicationServiceType must not be null"); - this.transactionIdEncoder = Assert.requireNonNull(transactionIdEncoder, "transactionIdEncoder must not be null"); - - - this.version = TraceDataFormatVersion.getTraceDataFormatVersion(profilerConfig); - } - - - @Override - public SpanChunkFactory get() { - if (this.version == TraceDataFormatVersion.V2) { - return new SpanChunkFactoryV2(applicationName, agentId, agentStartTime, applicationServiceType, transactionIdEncoder); - } - if (this.version == TraceDataFormatVersion.V1) { - return new SpanChunkFactoryV1(applicationName, agentId, agentStartTime, applicationServiceType, transactionIdEncoder); - } - throw new UnsupportedOperationException("unknown version :" + version); - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanDataSenderProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanDataSenderProvider.java index 375860f9b4f7..d487bfdcfb05 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanDataSenderProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanDataSenderProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,16 +19,18 @@ import com.google.inject.Inject; import com.google.inject.Provider; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.module.SpanConverter; import com.navercorp.pinpoint.profiler.context.module.SpanStatClientFactory; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; import com.navercorp.pinpoint.profiler.sender.DataSender; import com.navercorp.pinpoint.profiler.sender.TcpDataSender; import com.navercorp.pinpoint.profiler.sender.UdpDataSenderFactory; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; +import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; - /** * @author Taejin Koo */ @@ -47,17 +49,13 @@ public class SpanDataSenderProvider implements Provider { private final int sendBufferSize; private final String ioType; private final String transportType; + private final MessageConverter> messageConverter; @Inject - public SpanDataSenderProvider(ProfilerConfig profilerConfig, @SpanStatClientFactory Provider clientFactoryProvider) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (clientFactoryProvider == null) { - throw new NullPointerException("clientFactoryProvider must not be null"); - } - - this.clientFactoryProvider = clientFactoryProvider; + public SpanDataSenderProvider(ProfilerConfig profilerConfig, @SpanStatClientFactory Provider clientFactoryProvider, + @SpanConverter MessageConverter> messageConverter) { + Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.clientFactoryProvider = Assert.requireNonNull(clientFactoryProvider, "clientFactoryProvider must not be null"); this.ip = profilerConfig.getCollectorSpanServerIp(); this.port = profilerConfig.getCollectorSpanServerPort(); @@ -66,6 +64,7 @@ public SpanDataSenderProvider(ProfilerConfig profilerConfig, @SpanStatClientFact this.sendBufferSize = profilerConfig.getSpanDataSenderSocketSendBufferSize(); this.ioType = profilerConfig.getSpanDataSenderSocketType(); this.transportType = profilerConfig.getSpanDataSenderTransportType(); + this.messageConverter = Assert.requireNonNull(messageConverter, "messageConverter must not be null"); } @Override @@ -76,10 +75,9 @@ public DataSender get() { } PinpointClientFactory pinpointClientFactory = clientFactoryProvider.get(); - InetSocketAddress address = new InetSocketAddress(ip, port); - return new TcpDataSender("SpanDataSender", address, pinpointClientFactory); + return new TcpDataSender("SpanDataSender", ip, port, pinpointClientFactory); } else { - UdpDataSenderFactory factory = new UdpDataSenderFactory(ip, port, UDP_EXECUTOR_NAME, writeQueueSize, timeout, sendBufferSize); + UdpDataSenderFactory factory = new UdpDataSenderFactory(ip, port, UDP_EXECUTOR_NAME, writeQueueSize, timeout, sendBufferSize, messageConverter); return factory.create(ioType); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanPostProcessorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanPostProcessorProvider.java index a872c8d3ef7c..9903dbd6f4f1 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanPostProcessorProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanPostProcessorProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,30 +18,27 @@ import com.google.inject.Inject; import com.google.inject.Provider; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.profiler.context.SpanPostProcessor; -import com.navercorp.pinpoint.profiler.context.SpanPostProcessorV1; -import com.navercorp.pinpoint.profiler.context.SpanPostProcessorV2; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.compress.Context; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessorV1; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessorV2; import com.navercorp.pinpoint.profiler.context.TraceDataFormatVersion; /** * @author Woonduk Kang(emeroad) */ -public class SpanPostProcessorProvider implements Provider { +public class SpanPostProcessorProvider implements Provider> { private final TraceDataFormatVersion version; @Inject - public SpanPostProcessorProvider(ProfilerConfig profilerConfig) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - - this.version = TraceDataFormatVersion.getTraceDataFormatVersion(profilerConfig); + public SpanPostProcessorProvider(TraceDataFormatVersion version) { + this.version = Assert.requireNonNull(version, "version must not be null"); } @Override - public SpanPostProcessor get() { + public SpanPostProcessor get() { if (version == TraceDataFormatVersion.V2) { return new SpanPostProcessorV2(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanStatClientFactoryProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanStatClientFactoryProvider.java index 63866c6ba00e..959424861859 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanStatClientFactoryProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanStatClientFactoryProvider.java @@ -52,7 +52,8 @@ public PinpointClientFactory get() { return null; } else { PinpointClientFactory pinpointClientFactory = new DefaultPinpointClientFactory(1, workerCount); - pinpointClientFactory.setTimeoutMillis(1000 * 5); + pinpointClientFactory.setWriteTimeoutMillis(1000 * 3); + pinpointClientFactory.setRequestTimeoutMillis(1000 * 5); return pinpointClientFactory; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanThriftMessageConverterProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanThriftMessageConverterProvider.java new file mode 100644 index 000000000000..588f3524d15c --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/SpanThriftMessageConverterProvider.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.compress.Context; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; +import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.module.AgentId; +import com.navercorp.pinpoint.profiler.context.module.AgentStartTime; +import com.navercorp.pinpoint.profiler.context.module.ApplicationName; +import com.navercorp.pinpoint.profiler.context.module.ApplicationServerType; +import com.navercorp.pinpoint.profiler.context.thrift.SpanThriftMessageConverter; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import org.apache.thrift.TBase; + +import javax.inject.Inject; +import javax.inject.Provider; + +/** + * @author Woonduk Kang(emeroad) + */ +public class SpanThriftMessageConverterProvider implements Provider>> { + + private final String applicationName; + private final String agentId; + private final long agentStartTime; + private final ServiceType applicationServiceType; + private final TransactionIdEncoder transactionIdEncoder; + private final SpanPostProcessor spanPostProcessor; + + @Inject + public SpanThriftMessageConverterProvider(@ApplicationName String applicationName, @AgentId String agentId, @AgentStartTime long agentStartTime, + @ApplicationServerType ServiceType applicationServiceType, + TransactionIdEncoder transactionIdEncoder, SpanPostProcessor spanPostProcessor) { + this.applicationName = Assert.requireNonNull(applicationName, "applicationName must not be null"); + this.agentId = Assert.requireNonNull(agentId, "agentId must not be null"); + this.agentStartTime = agentStartTime; + this.applicationServiceType = Assert.requireNonNull(applicationServiceType, "applicationServiceType must not be null"); + this.transactionIdEncoder = Assert.requireNonNull(transactionIdEncoder, "transactionIdEncoder must not be null"); + this.spanPostProcessor = Assert.requireNonNull(spanPostProcessor, "spanPostProcessor must not be null"); + } + + @Override + public MessageConverter> get() { + return new SpanThriftMessageConverter(applicationName, agentId, agentStartTime, applicationServiceType.getCode(), transactionIdEncoder, spanPostProcessor); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/StatDataSenderProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/StatDataSenderProvider.java index be60905e2e87..aab1c5993830 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/StatDataSenderProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/StatDataSenderProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,16 +19,18 @@ import com.google.inject.Inject; import com.google.inject.Provider; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.module.SpanStatClientFactory; +import com.navercorp.pinpoint.profiler.context.thrift.BypassMessageConverter; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; import com.navercorp.pinpoint.profiler.sender.DataSender; import com.navercorp.pinpoint.profiler.sender.TcpDataSender; import com.navercorp.pinpoint.profiler.sender.UdpDataSenderFactory; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; +import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; - /** * @author Taejin Koo */ @@ -48,16 +50,13 @@ public class StatDataSenderProvider implements Provider { private final String ioType; private final String transportType; + private final MessageConverter> messageConverter; + @Inject public StatDataSenderProvider(ProfilerConfig profilerConfig, @SpanStatClientFactory Provider clientFactoryProvider) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (clientFactoryProvider == null) { - throw new NullPointerException("clientFactoryProvider must not be null"); - } + Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); - this.clientFactoryProvider = clientFactoryProvider; + this.clientFactoryProvider = Assert.requireNonNull(clientFactoryProvider, "clientFactoryProvider must not be null"); this.ip = profilerConfig.getCollectorStatServerIp(); this.port = profilerConfig.getCollectorStatServerPort(); @@ -66,6 +65,8 @@ public StatDataSenderProvider(ProfilerConfig profilerConfig, @SpanStatClientFact this.sendBufferSize = profilerConfig.getStatDataSenderSocketSendBufferSize(); this.ioType = profilerConfig.getStatDataSenderSocketType(); this.transportType = profilerConfig.getStatDataSenderTransportType(); + + this.messageConverter = new BypassMessageConverter>(); } @Override @@ -76,10 +77,9 @@ public DataSender get() { } PinpointClientFactory pinpointClientFactory = clientFactoryProvider.get(); - InetSocketAddress address = new InetSocketAddress(ip, port); - return new TcpDataSender("StatDataSender", address, pinpointClientFactory); + return new TcpDataSender("StatDataSender", ip, port, pinpointClientFactory); } else { - UdpDataSenderFactory factory = new UdpDataSenderFactory(ip, port, UDP_EXECUTOR_NAME, writeQueueSize, timeout, sendBufferSize); + UdpDataSenderFactory factory = new UdpDataSenderFactory(ip, port, UDP_EXECUTOR_NAME, writeQueueSize, timeout, sendBufferSize, messageConverter); return factory.create(ioType); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/StorageFactoryProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/StorageFactoryProvider.java index 8d0bc224c129..a7c5a9f1cf0d 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/StorageFactoryProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/StorageFactoryProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,9 @@ import com.google.inject.Inject; import com.google.inject.Provider; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactory; -import com.navercorp.pinpoint.profiler.context.SpanPostProcessor; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.module.SpanDataSender; import com.navercorp.pinpoint.profiler.context.storage.BufferedStorageFactory; -import com.navercorp.pinpoint.profiler.context.storage.SpanStorageFactory; import com.navercorp.pinpoint.profiler.context.storage.StorageFactory; import com.navercorp.pinpoint.profiler.context.storage.TraceLogDelegateStorage; import com.navercorp.pinpoint.profiler.context.storage.TraceLogDelegateStorageFactory; @@ -38,25 +36,11 @@ public class StorageFactoryProvider implements Provider { private final ProfilerConfig profilerConfig; private final DataSender spanDataSender; - private final SpanPostProcessor spanPostProcessor; - private final SpanChunkFactory spanChunkFactory; @Inject - public StorageFactoryProvider(ProfilerConfig profilerConfig, @SpanDataSender DataSender spanDataSender, SpanPostProcessor spanPostProcessor, SpanChunkFactory spanChunkFactory) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (spanDataSender == null) { - throw new NullPointerException("spanDataSender must not be null"); - } - if (spanChunkFactory == null) { - throw new NullPointerException("spanChunkFactory must not be null"); - } - - this.profilerConfig = profilerConfig; - this.spanDataSender = spanDataSender; - this.spanPostProcessor = spanPostProcessor; - this.spanChunkFactory = spanChunkFactory; + public StorageFactoryProvider(ProfilerConfig profilerConfig, @SpanDataSender DataSender spanDataSender) { + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.spanDataSender = Assert.requireNonNull(spanDataSender, "spanDataSender must not be null"); } @Override @@ -71,9 +55,9 @@ public StorageFactory get() { private StorageFactory newStorageFactory() { if (profilerConfig.isIoBufferingEnable()) { int ioBufferingBufferSize = this.profilerConfig.getIoBufferingBufferSize(); - return new BufferedStorageFactory(ioBufferingBufferSize, this.spanDataSender, this.spanPostProcessor, this.spanChunkFactory); + return new BufferedStorageFactory(ioBufferingBufferSize, this.spanDataSender); } else { - return new SpanStorageFactory(spanDataSender); + return new BufferedStorageFactory(Integer.MAX_VALUE, this.spanDataSender); } } @@ -82,7 +66,6 @@ public String toString() { return "StorageFactoryProvider{" + "profilerConfig=" + profilerConfig + ", spanDataSender=" + spanDataSender + - ", spanChunkFactory=" + spanChunkFactory + '}'; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/TcpDataSenderProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/TcpDataSenderProvider.java index c1a5684bbeb3..4607f2a4d1db 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/TcpDataSenderProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/TcpDataSenderProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,38 +19,44 @@ import com.google.inject.Inject; import com.google.inject.Provider; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.module.DefaultClientFactory; +import com.navercorp.pinpoint.profiler.context.module.MetadataConverter; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; +import com.navercorp.pinpoint.profiler.sender.MessageSerializer; import com.navercorp.pinpoint.profiler.sender.TcpDataSender; +import com.navercorp.pinpoint.profiler.sender.ThriftMessageSerializer; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; - -import java.net.InetSocketAddress; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; +import org.apache.thrift.TBase; /** * @author Woonduk Kang(emeroad) */ -public class TcpDataSenderProvider implements Provider { +public class TcpDataSenderProvider implements Provider> { private final ProfilerConfig profilerConfig; private final Provider clientFactoryProvider; + private final Provider tBaseSerializerProvider; + private final MessageConverter> messageConverter; @Inject - public TcpDataSenderProvider(ProfilerConfig profilerConfig, @DefaultClientFactory Provider clientFactoryProvider) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (clientFactoryProvider == null) { - throw new NullPointerException("clientFactoryProvider must not be null"); - } - - this.profilerConfig = profilerConfig; - this.clientFactoryProvider = clientFactoryProvider; - + public TcpDataSenderProvider(ProfilerConfig profilerConfig, @DefaultClientFactory Provider clientFactoryProvider, + Provider tBaseSerializerProvider, + @MetadataConverter MessageConverter> messageConverter) { + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.clientFactoryProvider = Assert.requireNonNull(clientFactoryProvider, "clientFactoryProvider must not be null"); + this.tBaseSerializerProvider = Assert.requireNonNull(tBaseSerializerProvider, "tBaseSerializerProvider must not be null"); + this.messageConverter = Assert.requireNonNull(messageConverter, "messageConverter must not be null"); } @Override - public EnhancedDataSender get() { + public EnhancedDataSender get() { PinpointClientFactory clientFactory = clientFactoryProvider.get(); - InetSocketAddress address = new InetSocketAddress(profilerConfig.getCollectorTcpServerIp(), profilerConfig.getCollectorTcpServerPort()); - return new TcpDataSender("Default", address, clientFactory); + String collectorTcpServerIp = profilerConfig.getCollectorTcpServerIp(); + int collectorTcpServerPort = profilerConfig.getCollectorTcpServerPort(); + HeaderTBaseSerializer headerTBaseSerializer = tBaseSerializerProvider.get(); + MessageSerializer messageSerializer = new ThriftMessageSerializer(messageConverter, headerTBaseSerializer); + return new TcpDataSender("Default", collectorTcpServerIp, collectorTcpServerPort, clientFactory, messageSerializer); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/AnnotationKeyRegistryServiceProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/AnnotationKeyRegistryServiceProvider.java new file mode 100644 index 000000000000..1adc948d25fe --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/AnnotationKeyRegistryServiceProvider.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.plugin; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; +import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; +import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class AnnotationKeyRegistryServiceProvider implements Provider { + + private final CommonLoggerFactory commonLoggerFactory; + private final TraceMetadataLoaderService traceMetadataLoaderService; + + @Inject + public AnnotationKeyRegistryServiceProvider(CommonLoggerFactory commonLoggerFactory, TraceMetadataLoaderService traceMetadataLoaderService) { + this.commonLoggerFactory = Assert.requireNonNull(commonLoggerFactory, "commonLoggerFactory must not be null"); + this.traceMetadataLoaderService = Assert.requireNonNull(traceMetadataLoaderService, "traceMetadataLoaderService must not be null"); + } + + @Override + public AnnotationKeyRegistryService get() { + AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(traceMetadataLoaderService, commonLoggerFactory); + return annotationKeyRegistryService; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/JarPluginLoader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/JarPluginLoader.java new file mode 100644 index 000000000000..cb70af27b245 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/JarPluginLoader.java @@ -0,0 +1,188 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.plugin; + +import com.navercorp.pinpoint.common.plugin.JarFileUtils; +import com.navercorp.pinpoint.common.plugin.JarPlugin; +import com.navercorp.pinpoint.common.plugin.Plugin; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.StringUtils; +import com.navercorp.pinpoint.profiler.plugin.PluginConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.ServiceLoader; +import java.util.jar.JarFile; + +/** + * TODO Loading all plugins with a single class loader could cause class collisions. + * Also, with current implementation, plugins can use dependencies by putting them in the plugin directory too. + * But it can lead to dependency collision between plugins because they are loaded by a single class loader. + *

+ * How can we prevent this? + * A ClassLoader per plugin could do it but then we have to create "N of target class loader" x "N of plugin" class loaders. + * It seems too much. For now, Just leave it as it is. + * + * @author Jongho Moon + * @author emeroad + */ +public class JarPluginLoader implements PluginLoader { + private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final ClassLoader parentClassLoader; + + private final List serviceLoaderList; + + public JarPluginLoader(List pluginJar, ClassLoader parentClassLoader) { + this.serviceLoaderList = loadPluginJar(pluginJar); + //@Nullable + this.parentClassLoader = parentClassLoader; + } + + private List loadPluginJar(List pluginJar) { + Assert.requireNonNull(pluginJar, "pluginJar must not be null"); + // considering cl shared policy + return isolationPolicy(pluginJar); + } + + private List isolationPolicy(List pluginJar) { + final List list = new ArrayList(); + for (String filePath : pluginJar) { + final File file = toFile(filePath); + final URL url = toUrl(file); + + final ClassLoader pluginClassLoader = createPluginClassLoader(new URL[]{url}, parentClassLoader); + Entry entry = new Entry(url, file, pluginClassLoader); + list.add(entry); + } + return list; + } + + private URL toUrl(File file) { + try { + return file.toURI().toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException("Invalid URL:" + file); + } + } + + private File toFile(String filePath) { + final File file = new File(filePath); + if (!file.exists()) { + throw new RuntimeException(file + " File not exist"); + } + if (!file.isFile()) { + throw new RuntimeException(file + " is not file"); + } + if (!file.canRead()) { + throw new RuntimeException(file + " File cannot be read"); + } + return file; + } + + public class Entry { + private final URL filePath; + private final File file; + private final ClassLoader classLoader; + + public Entry(URL filePath, File file, ClassLoader classLoader) { + this.filePath = Assert.requireNonNull(filePath, "filePath must not be null"); + this.file = Assert.requireNonNull(file, "file must not be null"); + this.classLoader = Assert.requireNonNull(classLoader, "classLoader must not be null"); + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + public URL getURL() { + return filePath; + } + + public File getFile() { + return file; + } + } + + private ClassLoader createPluginClassLoader(final URL[] urls, final ClassLoader parent) { + if (logger.isDebugEnabled()) { + logger.debug("createPluginClassLoader(urls = [{}], parent = [{}])", Arrays.toString(urls), parent); + } + if (SECURITY_MANAGER != null) { + return AccessController.doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return new URLClassLoader(urls, parent); + } + }); + } else { + return new URLClassLoader(urls, parent); + } + } + + + private static List toList(Iterable iterable, Class serviceType) { + final List list = new ArrayList(); + for (T plugin : iterable) { + list.add(serviceType.cast(plugin)); + } + return list; + } + + @Override + public List> load(Class serviceType) { + List> result = new ArrayList>(); + for (Entry entry : serviceLoaderList) { + final Plugin plugin = newPlugin(serviceType, entry); + result.add(plugin); + } + + return result; + } + + private Plugin newPlugin(Class serviceType, Entry entry) { + URL pluginURL = entry.getURL(); + ServiceLoader serviceLoader = ServiceLoader.load(serviceType, entry.getClassLoader()); + List pluginList = toList(serviceLoader, serviceType); + JarFile jarFile = createJarFile(entry.getFile()); + String pluginPackages = JarFileUtils.getManifestValue(jarFile, PluginConfig.PINPOINT_PLUGIN_PACKAGE, PluginConfig.DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME); + List pluginPackageList = StringUtils.tokenizeToStringList(pluginPackages, ","); + + return new JarPlugin(pluginURL, jarFile, pluginList, pluginPackageList); + } + + + private JarFile createJarFile(File pluginJar) { + try { + return new JarFile(pluginJar); + } catch (IOException e) { + throw new RuntimeException("IO error. " + e.getCause(), e); + } + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/PluginLoaderProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/PluginLoaderProvider.java new file mode 100644 index 000000000000..1f95e8f469fc --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/PluginLoaderProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.plugin; + + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.profiler.context.module.PluginJars; + +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PluginLoaderProvider implements Provider { + + private final ClassLoader parentClassLoader; + private final PluginLoader pluginLoader; + + @Inject + public PluginLoaderProvider(@PluginJars List urls) { + // TODO configuration support + this.parentClassLoader = Object.class.getClassLoader(); + + this.pluginLoader = new JarPluginLoader(urls, parentClassLoader); + } + + @Override + public PluginLoader get() { + return pluginLoader; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/ProfilerPluginLoader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/ProfilerPluginLoader.java new file mode 100644 index 000000000000..a20da7c6f0ca --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/ProfilerPluginLoader.java @@ -0,0 +1,120 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.context.provider.plugin; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.common.plugin.Plugin; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjector; +import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjectorFactory; +import com.navercorp.pinpoint.profiler.plugin.ClassNameFilter; +import com.navercorp.pinpoint.profiler.plugin.ClassNameFilterChain; +import com.navercorp.pinpoint.profiler.plugin.PinpointProfilerPackageSkipFilter; +import com.navercorp.pinpoint.profiler.plugin.PluginConfig; +import com.navercorp.pinpoint.profiler.plugin.PluginPackageFilter; +import com.navercorp.pinpoint.profiler.plugin.PluginSetup; +import com.navercorp.pinpoint.profiler.plugin.SetupResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Jongho Moon + * + */ +public class ProfilerPluginLoader { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ClassNameFilter profilerPackageFilter = new PinpointProfilerPackageSkipFilter(); + + private final ProfilerConfig profilerConfig; + private final PluginSetup pluginSetup; + private final ClassInjectorFactory classInjectorFactory; + private final PluginLoader pluginLoader; + + + public ProfilerPluginLoader(ProfilerConfig profilerConfig, PluginSetup pluginSetup, + ClassInjectorFactory classInjectorFactory, PluginLoader pluginLoader) { + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.pluginSetup = Assert.requireNonNull(pluginSetup, "pluginSetup must not be null"); + this.classInjectorFactory = Assert.requireNonNull(classInjectorFactory, "classInjectorFactory must not be null"); + this.pluginLoader = Assert.requireNonNull(pluginLoader, "pluginLoader must not be null"); + + } + + public List load() { + + List> plugins = pluginLoader.load(ProfilerPlugin.class); + + List pluginContexts = new ArrayList(plugins.size()); + for (Plugin plugin : plugins) { + List setupResults = loadProfilerPlugin(plugin); + pluginContexts.addAll(setupResults); + } + + return pluginContexts; + } + + private List loadProfilerPlugin(Plugin plugin) { + List pluginPackageList = plugin.getPackageList(); + final ClassNameFilter pluginFilterChain = createPluginFilterChain(pluginPackageList); + + List filterProfilerPlugin = filterProfilerPlugin(plugin.getInstanceList(), profilerConfig.getDisabledPlugins()); + + List result = new ArrayList(); + for (ProfilerPlugin profilerPlugin : filterProfilerPlugin) { + if (logger.isInfoEnabled()) { + logger.info("{} Plugin {}:{}", profilerPlugin.getClass(), PluginConfig.PINPOINT_PLUGIN_PACKAGE, pluginPackageList); + logger.info("Loading plugin:{} pluginPackage:{}", profilerPlugin.getClass().getName(), profilerPlugin); + } + + PluginConfig pluginConfig = new PluginConfig(plugin, pluginFilterChain); + final ClassInjector classInjector = classInjectorFactory.newClassInjector(pluginConfig); + final SetupResult setupResult = pluginSetup.setupPlugin(profilerPlugin, classInjector); + result.add(setupResult); + } + return result; + } + + private List filterProfilerPlugin(List originalProfilerPlugin, List disabled) { + List result = new ArrayList(); + for (ProfilerPlugin profilerPlugin : originalProfilerPlugin) { + if (disabled.contains(profilerPlugin.getClass().getName())) { + logger.info("Skip disabled plugin: {}", profilerPlugin.getClass().getName()); + continue; + } + result.add(profilerPlugin); + } + return result; + } + + private ClassNameFilter createPluginFilterChain(List packageList) { + + final ClassNameFilter pluginPackageFilter = new PluginPackageFilter(packageList); + + final List chain = Arrays.asList(profilerPackageFilter, pluginPackageFilter); + + final ClassNameFilter filterChain = new ClassNameFilterChain(chain); + + return filterChain; + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/ServiceTypeRegistryServiceProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/ServiceTypeRegistryServiceProvider.java new file mode 100644 index 000000000000..68d223a6fc08 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/ServiceTypeRegistryServiceProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.plugin; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; +import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; +import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ServiceTypeRegistryServiceProvider implements Provider { + + private final TraceMetadataLoaderService traceMetadataLoaderService; + private final CommonLoggerFactory commonLoggerFactory; + + @Inject + public ServiceTypeRegistryServiceProvider(CommonLoggerFactory commonLoggerFactory, TraceMetadataLoaderService traceMetadataLoaderService) { + this.traceMetadataLoaderService = Assert.requireNonNull(traceMetadataLoaderService, "traceMetadataLoaderService must not be null"); + this.commonLoggerFactory = Assert.requireNonNull(commonLoggerFactory, "commonLoggerFactory must not be null"); + } + + @Override + public ServiceTypeRegistryService get() { + + ServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(traceMetadataLoaderService, commonLoggerFactory); + return serviceTypeRegistryService ; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/Slf4jCommonLoggerFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/Slf4jCommonLoggerFactory.java new file mode 100644 index 000000000000..e277ee16875a --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/Slf4jCommonLoggerFactory.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.plugin; + +import com.navercorp.pinpoint.common.util.logger.CommonLogger; +import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class Slf4jCommonLoggerFactory implements CommonLoggerFactory { + + @Override + public CommonLogger getLogger(String loggerName) { + Logger logger = LoggerFactory.getLogger(loggerName); + return new Sl4jCommonLogger(logger); + } + + + private class Sl4jCommonLogger implements CommonLogger { + + private final Logger logger; + + private Sl4jCommonLogger(Logger logger) { + if (logger == null) { + throw new NullPointerException("logger must not be null"); + } + this.logger = logger; + } + + @Override + public boolean isTraceEnabled() { + return logger.isTraceEnabled(); + } + + @Override + public void trace(String msg) { + logger.trace(msg); + } + + @Override + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + @Override + public void debug(String msg) { + logger.debug(msg); + } + + @Override + public boolean isWarnEnabled() { + return logger.isWarnEnabled(); + } + + @Override + public void warn(String msg) { + logger.warn(msg); + } + + @Override + public void warn(String msg, Throwable throwable) { + logger.warn(msg, throwable); + } + + @Override + public boolean isInfoEnabled() { + return logger.isInfoEnabled(); + } + + @Override + public void info(String msg) { + logger.info(msg); + } + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/TraceMetadataLoaderServiceProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/TraceMetadataLoaderServiceProvider.java new file mode 100644 index 000000000000..cfb312500a1e --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/plugin/TraceMetadataLoaderServiceProvider.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.plugin; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.common.plugin.Plugin; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.common.service.DefaultTraceMetadataLoaderService; +import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; +import com.navercorp.pinpoint.common.trace.TraceMetadataProvider; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class TraceMetadataLoaderServiceProvider implements Provider { + + private final PluginLoader pluginLoader; + private final CommonLoggerFactory commonLoggerFactory; + + @Inject + public TraceMetadataLoaderServiceProvider(CommonLoggerFactory commonLoggerFactory, PluginLoader pluginLoader) { + this.commonLoggerFactory = Assert.requireNonNull(commonLoggerFactory, "commonLogger must not be null"); + this.pluginLoader = Assert.requireNonNull(pluginLoader, "pluginLoader must not be null"); + } + + @Override + public TraceMetadataLoaderService get() { + + List> plugins = pluginLoader.load(TraceMetadataProvider.class); + List providers = new ArrayList(); + for (Plugin plugin : plugins) { + List pluginList = plugin.getInstanceList(); + providers.addAll(pluginList); + } + + TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(providers, commonLoggerFactory); + return typeLoaderService; + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/activethread/ActiveTraceMetricCollectorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/activethread/ActiveTraceMetricCollectorProvider.java index bc19ac5950de..3977cf198c9a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/activethread/ActiveTraceMetricCollectorProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/activethread/ActiveTraceMetricCollectorProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,30 +18,29 @@ import com.google.inject.Inject; import com.google.inject.Provider; -import com.navercorp.pinpoint.profiler.monitor.collector.activethread.ActiveTraceMetricCollector; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.UnsupportedMetricCollector; import com.navercorp.pinpoint.profiler.monitor.collector.activethread.DefaultActiveTraceMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.activethread.UnsupportedActiveTraceMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.activethread.ActiveTraceMetric; +import com.navercorp.pinpoint.thrift.dto.TActiveTrace; /** * @author HyunGil Jeong */ -public class ActiveTraceMetricCollectorProvider implements Provider { +public class ActiveTraceMetricCollectorProvider implements Provider> { private final ActiveTraceMetric activeTraceMetric; @Inject public ActiveTraceMetricCollectorProvider(ActiveTraceMetric activeTraceMetric) { - if (activeTraceMetric == null) { - throw new NullPointerException("activeTraceMetric must not be null"); - } - this.activeTraceMetric = activeTraceMetric; + this.activeTraceMetric = Assert.requireNonNull(activeTraceMetric, "activeTraceMetric must not be null"); } @Override - public ActiveTraceMetricCollector get() { + public AgentStatMetricCollector get() { if (activeTraceMetric == ActiveTraceMetric.UNSUPPORTED_ACTIVE_TRACE_METRIC) { - return new UnsupportedActiveTraceMetricCollector(); + return new UnsupportedMetricCollector(); } return new DefaultActiveTraceMetricCollector(activeTraceMetric); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/buffer/BufferMetricCollectorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/buffer/BufferMetricCollectorProvider.java new file mode 100644 index 000000000000..8626f8433df8 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/buffer/BufferMetricCollectorProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.stat.buffer; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.UnsupportedMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.buffer.DefaultBufferMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.metric.buffer.BufferMetric; +import com.navercorp.pinpoint.thrift.dto.TDirectBuffer; + + +/** + * @author Roy Kim + */ +public class BufferMetricCollectorProvider implements Provider> { + + private final BufferMetric bufferMetric; + + @Inject + public BufferMetricCollectorProvider(BufferMetric bufferMetric) { + this.bufferMetric = Assert.requireNonNull(bufferMetric, "bufferMetric must not be null"); + } + + @Override + public AgentStatMetricCollector get() { + if (bufferMetric == BufferMetric.UNSUPPORTED_BUFFER_METRIC) { + return new UnsupportedMetricCollector(); + } + return new DefaultBufferMetricCollector(bufferMetric); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/buffer/BufferMetricProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/buffer/BufferMetricProvider.java new file mode 100644 index 000000000000..6a790c645444 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/buffer/BufferMetricProvider.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.stat.buffer; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.JvmVersion; +import com.navercorp.pinpoint.profiler.monitor.metric.buffer.BufferMetric; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Constructor; + +/** + * @author Roy Kim + */ +public class BufferMetricProvider implements Provider { + + private static final String BUFFER_METRIC = "com.navercorp.pinpoint.profiler.monitor.metric.buffer.DefaultBufferMetric"; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Inject + public BufferMetricProvider() { + } + + @Override + public BufferMetric get() { + + final JvmVersion jvmVersion = JvmUtils.getVersion(); + if (!jvmVersion.onOrAfter(JvmVersion.JAVA_7)) { + logger.debug("Unsupported JVM version. {}", jvmVersion); + return BufferMetric.UNSUPPORTED_BUFFER_METRIC; + } + + BufferMetric bufferMetric = createBufferMetric(BUFFER_METRIC); + logger.info("loaded : {}", bufferMetric); + return bufferMetric; + } + + private BufferMetric createBufferMetric(String classToLoad) { + if (classToLoad == null) { + return BufferMetric.UNSUPPORTED_BUFFER_METRIC; + } + try { + @SuppressWarnings("unchecked") + Class bufferMetricClass = (Class) Class.forName(classToLoad); + Constructor bufferMetricConstructor = bufferMetricClass.getConstructor(); + return bufferMetricConstructor.newInstance(); + } catch (Exception e) { + logger.warn("BufferMetric initialize fail: {}", classToLoad, e); + return BufferMetric.UNSUPPORTED_BUFFER_METRIC; + } + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/cpu/CpuLoadMetricCollectorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/cpu/CpuLoadMetricCollectorProvider.java index 9f1bb03c5d62..a4bcfd7bb32e 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/cpu/CpuLoadMetricCollectorProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/cpu/CpuLoadMetricCollectorProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,30 +18,29 @@ import com.google.inject.Inject; import com.google.inject.Provider; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.UnsupportedMetricCollector; import com.navercorp.pinpoint.profiler.monitor.collector.cpu.DefaultCpuLoadMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.cpu.CpuLoadMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.cpu.UnsupportedCpuLoadMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetric; +import com.navercorp.pinpoint.thrift.dto.TCpuLoad; /** * @author HyunGil Jeong */ -public class CpuLoadMetricCollectorProvider implements Provider { +public class CpuLoadMetricCollectorProvider implements Provider> { private final CpuLoadMetric cpuLoadMetric; @Inject public CpuLoadMetricCollectorProvider(CpuLoadMetric cpuLoadMetric) { - if (cpuLoadMetric == null) { - throw new NullPointerException("cpuLoadMetric must not be null"); - } - this.cpuLoadMetric = cpuLoadMetric; + this.cpuLoadMetric = Assert.requireNonNull(cpuLoadMetric, "cpuLoadMetric must not be null"); } @Override - public CpuLoadMetricCollector get() { + public AgentStatMetricCollector get() { if (cpuLoadMetric == CpuLoadMetric.UNSUPPORTED_CPU_LOAD_METRIC) { - return new UnsupportedCpuLoadMetricCollector(); + return new UnsupportedMetricCollector(); } return new DefaultCpuLoadMetricCollector(cpuLoadMetric); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/cpu/CpuLoadMetricProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/cpu/CpuLoadMetricProvider.java index 322e31d4b252..449b8a191ba7 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/cpu/CpuLoadMetricProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/cpu/CpuLoadMetricProvider.java @@ -26,9 +26,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.management.ManagementFactory; -import java.lang.management.OperatingSystemMXBean; -import java.lang.management.RuntimeMXBean; import java.lang.reflect.Constructor; /** @@ -57,58 +54,52 @@ public CpuLoadMetricProvider(ProfilerConfig profilerConfig) { @Override public CpuLoadMetric get() { - String classToLoad = null; JvmType jvmType = JvmType.fromVendor(vendorName); if (jvmType == JvmType.UNKNOWN) { jvmType = JvmUtils.getType(); } - JvmVersion jvmVersion = JvmUtils.getVersion(); + final String classToLoad = getCpuLoadMetricClassName(jvmType); + final CpuLoadMetric cpuLoadMetric = createCpuLoadMetric(classToLoad); + logger.info("loaded : {}", cpuLoadMetric); + return cpuLoadMetric; + } + + private String getCpuLoadMetricClassName(JvmType jvmType) { + final JvmVersion jvmVersion = JvmUtils.getVersion(); if (jvmType == JvmType.ORACLE || jvmType == JvmType.OPENJDK) { if (jvmVersion.onOrAfter(JvmVersion.JAVA_7)) { - classToLoad = ORACLE_CPU_LOAD_METRIC; + return ORACLE_CPU_LOAD_METRIC; } else if (jvmVersion.onOrAfter(JvmVersion.JAVA_5)) { - classToLoad = ORACLE_JDK6_CPU_LOAD_METRIC; + return ORACLE_JDK6_CPU_LOAD_METRIC; } - } else if (jvmType == JvmType.IBM) { + } + + if (jvmType == JvmType.IBM) { if (jvmVersion.onOrAfter(JvmVersion.JAVA_7)) { - classToLoad = IBM_CPU_LOAD_METRIC; + return IBM_CPU_LOAD_METRIC; } else if (jvmVersion == JvmVersion.JAVA_6) { - classToLoad = IBM_JDK6_CPU_LOAD_METRIC; + return IBM_JDK6_CPU_LOAD_METRIC; } } - CpuLoadMetric cpuLoadMetric = createCpuLoadMetric(classToLoad); - logger.info("loaded : {}", cpuLoadMetric); - return cpuLoadMetric; + return null; } private CpuLoadMetric createCpuLoadMetric(String classToLoad) { if (classToLoad == null) { return CpuLoadMetric.UNSUPPORTED_CPU_LOAD_METRIC; } - OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); - if (operatingSystemMXBean == null) { - return CpuLoadMetric.UNSUPPORTED_CPU_LOAD_METRIC; - } try { @SuppressWarnings("unchecked") Class cpuLoadMetricClass = (Class) Class.forName(classToLoad); try { - // Create CpuLoadMetric for Java 7+ - Constructor cpuLoadMetricConstructor = cpuLoadMetricClass.getConstructor(OperatingSystemMXBean.class); - return cpuLoadMetricConstructor.newInstance(operatingSystemMXBean); - } catch (NoSuchMethodException e1) { - try { - // Create CpuLoadMetric for Java 6 - RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); - Constructor cpuLoadMetricConstructor = cpuLoadMetricClass.getConstructor(OperatingSystemMXBean.class, RuntimeMXBean.class); - return cpuLoadMetricConstructor.newInstance(operatingSystemMXBean, runtimeMXBean); - } catch (NoSuchMethodException e2) { - logger.warn("Unknown CpuLoadMetric : {}", classToLoad); - return CpuLoadMetric.UNSUPPORTED_CPU_LOAD_METRIC; - } + Constructor cpuLoadMetricConstructor = cpuLoadMetricClass.getConstructor(); + return cpuLoadMetricConstructor.newInstance(); + } catch (NoSuchMethodException e) { + logger.warn("Unknown CpuLoadMetric : {}", classToLoad); + return CpuLoadMetric.UNSUPPORTED_CPU_LOAD_METRIC; } } catch (Exception e) { - logger.warn("Error creating CpuLoadMetric [" + classToLoad + "]", e); + logger.warn("Error creating CpuLoadMetric [" + classToLoad + "]"); return CpuLoadMetric.UNSUPPORTED_CPU_LOAD_METRIC; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/datasource/DataSourceMetricCollectorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/datasource/DataSourceMetricCollectorProvider.java index cff516c4c233..4d32c1f6de6e 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/datasource/DataSourceMetricCollectorProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/datasource/DataSourceMetricCollectorProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,31 +18,30 @@ import com.google.inject.Inject; import com.google.inject.Provider; -import com.navercorp.pinpoint.profiler.monitor.collector.datasource.DataSourceMetricCollector; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.UnsupportedMetricCollector; import com.navercorp.pinpoint.profiler.monitor.collector.datasource.DefaultDataSourceMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.datasource.UnsupportedDataSourceMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.datasource.DataSourceMetric; +import com.navercorp.pinpoint.thrift.dto.TDataSourceList; /** * @author Taejin Koo * @author HyunGil Jeong */ -public class DataSourceMetricCollectorProvider implements Provider { +public class DataSourceMetricCollectorProvider implements Provider> { private final DataSourceMetric dataSourceMetric; @Inject public DataSourceMetricCollectorProvider(DataSourceMetric dataSourceMetric) { - if (dataSourceMetric == null) { - throw new NullPointerException("dataSourceMetric must not be null"); - } - this.dataSourceMetric = dataSourceMetric; + this.dataSourceMetric = Assert.requireNonNull(dataSourceMetric, "dataSourceMetric must not be null"); } @Override - public DataSourceMetricCollector get() { + public AgentStatMetricCollector get() { if (dataSourceMetric == DataSourceMetric.UNSUPPORTED_DATA_SOURCE_METRIC) { - return new UnsupportedDataSourceMetricCollector(); + return new UnsupportedMetricCollector(); } return new DefaultDataSourceMetricCollector(dataSourceMetric); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/datasource/DataSourceMetricProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/datasource/DataSourceMetricProvider.java index 95bf56177fac..5a7f80f721c1 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/datasource/DataSourceMetricProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/datasource/DataSourceMetricProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -44,13 +44,16 @@ public DataSourceMetricProvider(DataSourceMonitorRegistryService dataSourceMonit @Override public DataSourceMetric get() { - DataSourceMetric dataSourceMetric; - if (dataSourceMonitorRegistryService == null || jdbcUrlParsingService == null) { - dataSourceMetric = DataSourceMetric.UNSUPPORTED_DATA_SOURCE_METRIC; - } else { - dataSourceMetric = new DefaultDataSourceMetric(dataSourceMonitorRegistryService, jdbcUrlParsingService); - } + final DataSourceMetric dataSourceMetric = newDataSourceMetric(); logger.info("loaded : {}", dataSourceMetric); return dataSourceMetric; } + + private DataSourceMetric newDataSourceMetric() { + if (dataSourceMonitorRegistryService == null || jdbcUrlParsingService == null) { + return DataSourceMetric.UNSUPPORTED_DATA_SOURCE_METRIC; + } + + return new DefaultDataSourceMetric(dataSourceMonitorRegistryService, jdbcUrlParsingService); + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/deadlock/DeadlockMetricCollectorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/deadlock/DeadlockMetricCollectorProvider.java index 6073e571faea..6b7507ce696a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/deadlock/DeadlockMetricCollectorProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/deadlock/DeadlockMetricCollectorProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,30 +18,29 @@ import com.google.inject.Inject; import com.google.inject.Provider; -import com.navercorp.pinpoint.profiler.monitor.collector.deadlock.DeadlockMetricCollector; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.UnsupportedMetricCollector; import com.navercorp.pinpoint.profiler.monitor.collector.deadlock.DefaultDeadlockMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.deadlock.UnsupportedDeadlockMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.deadlock.DeadlockMetric; +import com.navercorp.pinpoint.thrift.dto.TDeadlock; /** * @author Taejin Koo */ -public class DeadlockMetricCollectorProvider implements Provider { +public class DeadlockMetricCollectorProvider implements Provider> { private final DeadlockMetric deadlockMetric; @Inject public DeadlockMetricCollectorProvider(DeadlockMetric deadlockMetric) { - if (deadlockMetric == null) { - throw new NullPointerException("deadlockMetric must not be null"); - } - this.deadlockMetric = deadlockMetric; + this.deadlockMetric = Assert.requireNonNull(deadlockMetric, "deadlockMetric must not be null"); } @Override - public DeadlockMetricCollector get() { + public AgentStatMetricCollector get() { if (deadlockMetric == DeadlockMetric.UNSUPPORTED_DEADLOCK_SOURCE_METRIC) { - return new UnsupportedDeadlockMetricCollector(); + return new UnsupportedMetricCollector(); } return new DefaultDeadlockMetricCollector(deadlockMetric); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/filedescriptor/FileDescriptorMetricCollectorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/filedescriptor/FileDescriptorMetricCollectorProvider.java new file mode 100644 index 000000000000..6028e208e712 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/filedescriptor/FileDescriptorMetricCollectorProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.stat.filedescriptor; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.UnsupportedMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.filedescriptor.DefaultFileDescriptorMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.FileDescriptorMetric; +import com.navercorp.pinpoint.thrift.dto.TFileDescriptor; + +/** + * @author Roy Kim + */ +public class FileDescriptorMetricCollectorProvider implements Provider> { + + private final FileDescriptorMetric fileDescriptorMetric; + + @Inject + public FileDescriptorMetricCollectorProvider(FileDescriptorMetric fileDescriptorMetric) { + this.fileDescriptorMetric = Assert.requireNonNull(fileDescriptorMetric, "fileDescriptorMetric must not be null"); + } + + @Override + public AgentStatMetricCollector get() { + if (fileDescriptorMetric == FileDescriptorMetric.UNSUPPORTED_FILE_DESCRIPTOR_METRIC) { + return new UnsupportedMetricCollector(); + } + return new DefaultFileDescriptorMetricCollector(fileDescriptorMetric); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/filedescriptor/FileDescriptorMetricProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/filedescriptor/FileDescriptorMetricProvider.java new file mode 100644 index 000000000000..49306ed4fb2f --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/filedescriptor/FileDescriptorMetricProvider.java @@ -0,0 +1,146 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.stat.filedescriptor; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; +import com.navercorp.pinpoint.common.util.*; +import com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.FileDescriptorMetric; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.reflect.Constructor; +import java.util.EnumSet; + +/** + * @author Roy Kim + */ +public class FileDescriptorMetricProvider implements Provider { + + private static final String UNSUPPORTED_METRIC = "UNSUPPORTED_FILE_DESCRIPTOR_METRIC"; + + private static final String ORACLE_FILE_DESCRIPTOR_METRIC = "com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.oracle.DefaultFileDescriptorMetric"; + private static final String IBM_FILE_DESCRIPTOR_METRIC = "com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.ibm.DefaultFileDescriptorMetric"; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final String vendorName; + private final String osName; + + @Inject + public FileDescriptorMetricProvider(ProfilerConfig profilerConfig) { + if (profilerConfig == null) { + throw new NullPointerException("profilerConfig must not be null"); + } + vendorName = profilerConfig.getProfilerJvmVendorName(); + osName = profilerConfig.getProfilerOSName(); + } + + @Override + public FileDescriptorMetric get() { + + final JvmVersion jvmVersion = JvmUtils.getVersion(); + final JvmType jvmType = getJvmType(); + final OsType osType = getOsType(); + + final String classToLoad = getMetricClassName(osType, jvmVersion, jvmType); + + FileDescriptorMetric fileDescriptorMetric = createFileDescriptorMetric(classToLoad); + logger.info("loaded : {}", fileDescriptorMetric); + return fileDescriptorMetric; + } + + @VisibleForTesting + String getMetricClassName(OsType osType, JvmVersion jvmVersion, JvmType jvmType) { + if (!isSupportedOS(osType)) { + logger.warn("Unsupported operating system {}/{}/{}", osType, jvmVersion, jvmType); + return UNSUPPORTED_METRIC; + } + if (isOracleJdk(jvmType)) { + if (jvmVersion.onOrAfter(JvmVersion.JAVA_5)) { + return ORACLE_FILE_DESCRIPTOR_METRIC; + } + } + + if (jvmType == JvmType.IBM) { + if (jvmVersion.onOrAfter(JvmVersion.JAVA_8)) { + return IBM_FILE_DESCRIPTOR_METRIC; + } + } + + return UNSUPPORTED_METRIC; + } + + private boolean isOracleJdk(JvmType jvmType) { + EnumSet orackeJdk = EnumSet.of(JvmType.ORACLE, JvmType.OPENJDK); + return orackeJdk.contains(jvmType); + } + + private boolean isSupportedOS(OsType osType) { + EnumSet supportedOs = EnumSet.of(OsType.MAC, OsType.SOLARIS, OsType.LINUX + , OsType.AIX, OsType.HP_UX, OsType.BSD); + return supportedOs.contains(osType); + } + + private JvmType getJvmType() { + final JvmType jvmType = JvmType.fromVendor(vendorName); + if (jvmType == JvmType.UNKNOWN) { + return JvmUtils.getType(); + } + return jvmType; + } + + private OsType getOsType() { + final OsType osType = OsType.fromVendor(osName); + if (osType == OsType.UNKNOWN) { + return OsUtils.getType(); + } + return osType; + } + + private FileDescriptorMetric createFileDescriptorMetric(String classToLoad) { + if (classToLoad == null) { + return FileDescriptorMetric.UNSUPPORTED_FILE_DESCRIPTOR_METRIC; + } + if (UNSUPPORTED_METRIC.equals(classToLoad)) { + return FileDescriptorMetric.UNSUPPORTED_FILE_DESCRIPTOR_METRIC; + } + + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); + if (operatingSystemMXBean == null) { + return FileDescriptorMetric.UNSUPPORTED_FILE_DESCRIPTOR_METRIC; + } + try { + @SuppressWarnings("unchecked") + Class fileDescriptorMetricClass = (Class) Class.forName(classToLoad); + try { + Constructor fileDescriptorMetricConstructor = fileDescriptorMetricClass.getConstructor(OperatingSystemMXBean.class); + return fileDescriptorMetricConstructor.newInstance(operatingSystemMXBean); + } catch (NoSuchMethodException e) { + logger.warn("Unknown FileDescriptorMetric : {}", classToLoad); + return FileDescriptorMetric.UNSUPPORTED_FILE_DESCRIPTOR_METRIC; + } + } catch (Exception e) { + logger.warn("Error creating FileDescriptorMetric [" + classToLoad + "]"); + return FileDescriptorMetric.UNSUPPORTED_FILE_DESCRIPTOR_METRIC; + } + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/jvmgc/JvmGcMetricCollectorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/jvmgc/JvmGcMetricCollectorProvider.java index f8c738dccd7c..a3a3d4639496 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/jvmgc/JvmGcMetricCollectorProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/jvmgc/JvmGcMetricCollectorProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,19 +19,20 @@ import com.google.inject.Inject; import com.google.inject.Provider; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.monitor.collector.jvmgc.DetailedJvmGcMetricCollector; import com.navercorp.pinpoint.profiler.monitor.collector.jvmgc.BasicJvmGcMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.jvmgc.JvmGcMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.gc.DetailedGarbageCollectorMetric; import com.navercorp.pinpoint.profiler.monitor.metric.gc.GarbageCollectorMetric; import com.navercorp.pinpoint.profiler.monitor.metric.memory.DetailedMemoryMetric; import com.navercorp.pinpoint.profiler.monitor.metric.memory.MemoryMetric; +import com.navercorp.pinpoint.thrift.dto.TJvmGc; /** * @author HyunGil Jeong */ -public class JvmGcMetricCollectorProvider implements Provider { +public class JvmGcMetricCollectorProvider implements Provider> { private final boolean collectDetailedMetrics; private final Provider memoryMetricProivider; @@ -69,10 +70,10 @@ public JvmGcMetricCollectorProvider( } @Override - public JvmGcMetricCollector get() { + public AgentStatMetricCollector get() { MemoryMetric memoryMetric = memoryMetricProivider.get(); GarbageCollectorMetric garbageCollectorMetric = garbageCollectorMetricProvider.get(); - JvmGcMetricCollector jvmGcMetricCollector = new BasicJvmGcMetricCollector(memoryMetric, garbageCollectorMetric); + BasicJvmGcMetricCollector jvmGcMetricCollector = new BasicJvmGcMetricCollector(memoryMetric, garbageCollectorMetric); if (collectDetailedMetrics) { DetailedMemoryMetric detailedMemoryMetric = detailedMemoryMetricProvider.get(); DetailedGarbageCollectorMetric detailedGarbageCollectorMetric = detailedGarbageCollectorMetricProvider.get(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/jvmgc/MemoryMetricProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/jvmgc/MemoryMetricProvider.java index 18000da78950..865b75388025 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/jvmgc/MemoryMetricProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/jvmgc/MemoryMetricProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -41,11 +41,7 @@ public MemoryMetricProvider() { @Override public MemoryMetric get() { - MemoryMetric memoryMetric = new UnknownMemoryMetric(); - MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); - if (memoryMXBean != null) { - memoryMetric = new DefaultMemoryMetric(memoryMXBean); - } + MemoryMetric memoryMetric = new DefaultMemoryMetric(); logger.info("loaded : {}", memoryMetric); return memoryMetric; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/response/ResponseTimeMetricCollectorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/response/ResponseTimeMetricCollectorProvider.java index 984dec43fda8..a25bbddf7b4a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/response/ResponseTimeMetricCollectorProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/response/ResponseTimeMetricCollectorProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,30 +18,29 @@ import com.google.inject.Inject; import com.google.inject.Provider; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.UnsupportedMetricCollector; import com.navercorp.pinpoint.profiler.monitor.collector.response.DefaultResponseTimeMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.response.ResponseTimeMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.response.UnsupportedResponseTimeMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeMetric; +import com.navercorp.pinpoint.thrift.dto.TResponseTime; /** * @author Taejin Koo */ -public class ResponseTimeMetricCollectorProvider implements Provider { +public class ResponseTimeMetricCollectorProvider implements Provider> { private final ResponseTimeMetric responseTimeMetric; @Inject public ResponseTimeMetricCollectorProvider(ResponseTimeMetric responseTimeMetric) { - if (responseTimeMetric == null) { - throw new NullPointerException("responseTimeMetric must not be null"); - } - this.responseTimeMetric = responseTimeMetric; + this.responseTimeMetric = Assert.requireNonNull(responseTimeMetric, "responseTimeMetric must not be null"); } @Override - public ResponseTimeMetricCollector get() { + public AgentStatMetricCollector get() { if (responseTimeMetric == ResponseTimeMetric.UNSUPPORTED_RESPONSE_TIME_METRIC) { - return new UnsupportedResponseTimeMetricCollector(); + return new UnsupportedMetricCollector(); } return new DefaultResponseTimeMetricCollector(responseTimeMetric); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/transaction/TransactionMetricCollectorProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/transaction/TransactionMetricCollectorProvider.java index 36c7ce404eab..c3693dd2fe95 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/transaction/TransactionMetricCollectorProvider.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/provider/stat/transaction/TransactionMetricCollectorProvider.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,30 +18,29 @@ import com.google.inject.Inject; import com.google.inject.Provider; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.collector.UnsupportedMetricCollector; import com.navercorp.pinpoint.profiler.monitor.collector.transaction.DefaultTransactionMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.transaction.TransactionMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.transaction.UnsupportedTransactionMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.transaction.TransactionMetric; +import com.navercorp.pinpoint.thrift.dto.TTransaction; /** * @author HyunGil Jeong */ -public class TransactionMetricCollectorProvider implements Provider { +public class TransactionMetricCollectorProvider implements Provider> { private final TransactionMetric transactionMetric; @Inject public TransactionMetricCollectorProvider(TransactionMetric transactionMetric) { - if (transactionMetric == null) { - throw new NullPointerException("transactionMetric must not be null"); - } - this.transactionMetric = transactionMetric; + this.transactionMetric = Assert.requireNonNull(transactionMetric, "transactionMetric must not be null"); } @Override - public TransactionMetricCollector get() { + public AgentStatMetricCollector get() { if (transactionMetric == TransactionMetric.UNSUPPORTED_TRANSACTION_METRIC) { - return new UnsupportedTransactionMetricCollector(); + return new UnsupportedMetricCollector(); } return new DefaultTransactionMetricCollector(transactionMetric); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/AbstractRecorder.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/AbstractRecorder.java index feb6e8b6a0c1..5492c51803c8 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/AbstractRecorder.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/AbstractRecorder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -134,15 +134,18 @@ private void recordArgs(Object[] args) { } public void recordAttribute(AnnotationKey key, String value) { - addAnnotation(new Annotation(key.getCode(), value)); + Annotation annotation = new Annotation(key.getCode(), value); + addAnnotation(annotation); } public void recordAttribute(AnnotationKey key, int value) { - addAnnotation(new Annotation(key.getCode(), value)); + Annotation annotation = new Annotation(key.getCode(), value); + addAnnotation(annotation); } public void recordAttribute(AnnotationKey key, Object value) { - addAnnotation(new Annotation(key.getCode(), value)); + Annotation annotation = new Annotation(key.getCode(), value); + addAnnotation(annotation); } abstract void addAnnotation(Annotation annotation); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultRecorderFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultRecorderFactory.java index 1518dd3572a7..6eddbed8e52b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultRecorderFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultRecorderFactory.java @@ -54,16 +54,16 @@ public SpanRecorder newTraceRootSpanRecorder(TraceRoot traceRoot, boolean sampli } @Override - public WrappedSpanEventRecorder newWrappedSpanEventRecorder() { + public WrappedSpanEventRecorder newWrappedSpanEventRecorder(TraceRoot traceRoot) { final AsyncContextFactory asyncContextFactory = asyncContextFactoryProvider.get(); - return new WrappedSpanEventRecorder(asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); + return new WrappedSpanEventRecorder(traceRoot, asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); } @Override - public WrappedSpanEventRecorder newWrappedSpanEventRecorder(AsyncState asyncState) { + public WrappedSpanEventRecorder newWrappedSpanEventRecorder(TraceRoot traceRoot, AsyncState asyncState) { Assert.requireNonNull(asyncState, "asyncState must not be null"); final AsyncContextFactory asyncContextFactory = asyncContextFactoryProvider.get(); - return new WrappedSpanEventRecorder(asyncContextFactory, stringMetaDataService, sqlMetaDataService, asyncState); + return new WrappedSpanEventRecorder(traceRoot, asyncContextFactory, stringMetaDataService, sqlMetaDataService, asyncState); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultSpanRecorder.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultSpanRecorder.java index 3298bf1feff8..bd75afbbb8ee 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultSpanRecorder.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultSpanRecorder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,9 @@ */ package com.navercorp.pinpoint.profiler.context.recorder; +import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; +import com.navercorp.pinpoint.common.trace.LoggingInfo; +import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.profiler.context.Annotation; import com.navercorp.pinpoint.profiler.context.DefaultTrace; import com.navercorp.pinpoint.profiler.context.Span; @@ -24,10 +27,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; -import com.navercorp.pinpoint.common.trace.LoggingInfo; -import com.navercorp.pinpoint.common.trace.ServiceType; - /** * * @author jaehong.kim @@ -89,7 +88,7 @@ public void recordServiceType(ServiceType serviceType) { @Override public void recordRpcName(String rpc) { - span.setRpc(rpc); +// span.setRpc(rpc); span.getTraceRoot().getShared().setRpcName(rpc); } @@ -100,7 +99,7 @@ public void recordRemoteAddress(String remoteAddress) { @Override public void recordEndPoint(String endPoint) { - span.setEndPoint(endPoint); +// span.setEndPoint(endPoint); span.getTraceRoot().getShared().setEndPoint(endPoint); } @@ -141,14 +140,12 @@ public void recordLogging(LoggingInfo loggingInfo) { public void recordTime(boolean autoTimeRecoding) { span.setTimeRecording(autoTimeRecoding); if (autoTimeRecoding) { - if (!span.isSetStartTime()) { + if (!(span.getStartTime() == 0)) { span.markBeforeTime(); } } else { - span.setElapsed(0); - span.setElapsedIsSet(false); + span.setElapsedTime(0); span.setStartTime(0); - span.setStartTimeIsSet(false); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/RecorderFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/RecorderFactory.java index 98ca07e12300..8b3ed792f891 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/RecorderFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/RecorderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ public interface RecorderFactory { SpanRecorder newTraceRootSpanRecorder(TraceRoot traceRoot, boolean sampling); - WrappedSpanEventRecorder newWrappedSpanEventRecorder(); + WrappedSpanEventRecorder newWrappedSpanEventRecorder(TraceRoot traceRoot); - WrappedSpanEventRecorder newWrappedSpanEventRecorder(AsyncState asyncState); + WrappedSpanEventRecorder newWrappedSpanEventRecorder(TraceRoot traceRoot, AsyncState asyncState); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorder.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorder.java index 28e9a3a65d76..581a92744224 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorder.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,12 @@ import com.navercorp.pinpoint.bootstrap.context.AsyncContext; import com.navercorp.pinpoint.bootstrap.context.AsyncState; +import com.navercorp.pinpoint.bootstrap.context.ParsingResult; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.common.trace.AnnotationKey; +import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.IntStringStringValue; import com.navercorp.pinpoint.common.util.StringUtils; import com.navercorp.pinpoint.profiler.context.Annotation; import com.navercorp.pinpoint.profiler.context.AsyncContextFactory; @@ -31,14 +36,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; -import com.navercorp.pinpoint.common.trace.AnnotationKey; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.bootstrap.context.ParsingResult; -import com.navercorp.pinpoint.thrift.dto.TIntStringStringValue; - /** - * + * * @author jaehong.kim * */ @@ -46,13 +45,16 @@ public class WrappedSpanEventRecorder extends AbstractRecorder implements SpanEv private static final Logger logger = LoggerFactory.getLogger(DefaultTrace.class.getName()); private static final boolean isDebug = logger.isDebugEnabled(); + private final TraceRoot traceRoot; private final AsyncContextFactory asyncContextFactory; private final AsyncState asyncState; private SpanEvent spanEvent; - public WrappedSpanEventRecorder(AsyncContextFactory asyncContextFactory, final StringMetaDataService stringMetaDataService, final SqlMetaDataService sqlMetaCacheService, AsyncState asyncState) { + public WrappedSpanEventRecorder(TraceRoot traceRoot, AsyncContextFactory asyncContextFactory, final StringMetaDataService stringMetaDataService, final SqlMetaDataService sqlMetaCacheService, AsyncState asyncState) { super(stringMetaDataService, sqlMetaCacheService); + this.traceRoot = Assert.requireNonNull(traceRoot, "traceRoot must not be null"); + this.asyncContextFactory = Assert.requireNonNull(asyncContextFactory, "asyncContextFactory must not be null"); // @Nullable @@ -92,20 +94,23 @@ public void recordSqlParsingResult(ParsingResult parsingResult, String bindValue } } - final TIntStringStringValue tSqlValue = new TIntStringStringValue(parsingResult.getId()); - final String output = parsingResult.getOutput(); - if (StringUtils.hasLength(output)) { - tSqlValue.setStringValue1(output); - } - if (StringUtils.hasLength(bindValue)) { - tSqlValue.setStringValue2(bindValue); - } - recordSqlParam(tSqlValue); + String output = defaultString2(parsingResult.getOutput(), null); + bindValue = defaultString2(bindValue, null); + final IntStringStringValue sqlValue = new IntStringStringValue(parsingResult.getId(), output, bindValue); + + recordSqlParam(sqlValue); } + private String defaultString2(String string, String defaultString) { + if (StringUtils.isEmpty(string)) { + return defaultString; + } + return string; + } - private void recordSqlParam(TIntStringStringValue tIntStringStringValue) { - spanEvent.addAnnotation(new Annotation(AnnotationKey.SQL_ID.getCode(), tIntStringStringValue)); + private void recordSqlParam(IntStringStringValue intStringStringValue) { + Annotation annotation = new Annotation(AnnotationKey.SQL_ID.getCode(), intStringStringValue); + spanEvent.addAnnotation(annotation); } @Override @@ -121,27 +126,20 @@ public void recordNextSpanId(long nextSpanId) { spanEvent.setNextSpanId(nextSpanId); } - @Override - public void recordAsyncId(int asyncId) { - spanEvent.setAsyncId(asyncId); - } - - @Override public AsyncContext recordNextAsyncContext() { - final SpanEvent spanEvent = this.spanEvent; - final TraceRoot traceRoot = spanEvent.getTraceRoot(); + final TraceRoot traceRoot = this.traceRoot; - final AsyncId asyncIdObject = getAsyncIdObject(); + final AsyncId asyncIdObject = getNextAsyncId(); final AsyncContext asyncContext = asyncContextFactory.newAsyncContext(traceRoot, asyncIdObject); return asyncContext; } @Override public AsyncContext recordNextAsyncContext(boolean asyncStateSupport) { - final SpanEvent spanEvent = this.spanEvent; - final TraceRoot traceRoot = spanEvent.getTraceRoot(); - final AsyncId asyncIdObject = getAsyncIdObject(); + + final TraceRoot traceRoot = this.traceRoot; + final AsyncId asyncIdObject = getNextAsyncId(); final AsyncState asyncState = this.asyncState; if (asyncStateSupport && asyncState != null) { @@ -155,20 +153,16 @@ public AsyncContext recordNextAsyncContext(boolean asyncStateSupport) { } - @Deprecated - @Override - public void recordNextAsyncId(int nextAsyncId) { - spanEvent.setNextAsyncId(nextAsyncId); - } +// @Deprecated +// @Override +// public void recordNextAsyncId(int nextAsyncId) { +// spanEvent.setNextAsyncId(nextAsyncId); +// } - @Override - public void recordAsyncSequence(short asyncSequence) { - spanEvent.setAsyncSequence(asyncSequence); - } @Override void maskErrorCode(int errorCode) { - this.spanEvent.getTraceRoot().getShared().maskErrorCode(errorCode); + this.traceRoot.getShared().maskErrorCode(errorCode); } @Override @@ -208,14 +202,12 @@ public void recordEndPoint(String endPoint) { public void recordTime(boolean time) { spanEvent.setTimeRecording(time); if (time) { - if(!spanEvent.isSetStartElapsed()) { + if (!(spanEvent.getStartTime() == 0)) { spanEvent.markStartTime(); } } else { - spanEvent.setEndElapsed(0); - spanEvent.setEndElapsedIsSet(false); - spanEvent.setStartElapsed(0); - spanEvent.setStartElapsedIsSet(false); + spanEvent.setStartTime(0); + spanEvent.setElapsedTime(0); } } @@ -234,13 +226,12 @@ public Object attachFrameObject(Object frameObject) { return spanEvent.attachFrameObject(frameObject); } - public AsyncId getAsyncIdObject() { - AsyncId asyncIdObject = spanEvent.getAsyncIdObject(); - if (asyncIdObject == null) { - asyncIdObject = asyncContextFactory.newAsyncId(); - spanEvent.setAsyncIdObject(asyncIdObject); - spanEvent.setNextAsyncId(asyncIdObject.getAsyncId()); + private AsyncId getNextAsyncId() { + AsyncId nextAsyncId = spanEvent.getAsyncIdObject(); + if (nextAsyncId == null) { + nextAsyncId = asyncContextFactory.newAsyncId(); + spanEvent.setAsyncIdObject(nextAsyncId); } - return asyncIdObject; + return nextAsyncId; } } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorage.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorage.java index b040f3c20e3f..9276e072bf1b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorage.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorage.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -42,17 +42,13 @@ public class BufferedStorage implements Storage { private final TraceRoot traceRoot; private List storage; - private final DataSender dataSender; + private final DataSender dataSender; - private final SpanPostProcessor spanPostProcessor; - private final SpanChunkFactory spanChunkFactory; - public BufferedStorage(TraceRoot traceRoot, DataSender dataSender, SpanPostProcessor spanPostProcessor, SpanChunkFactory spanChunkFactory, int bufferSize) { + public BufferedStorage(TraceRoot traceRoot, DataSender dataSender, int bufferSize) { this.traceRoot = Assert.requireNonNull(traceRoot, "traceRoot must not be null"); this.dataSender = Assert.requireNonNull(dataSender, "dataSender must not be null"); - this.spanPostProcessor = Assert.requireNonNull(spanPostProcessor, "spanPostProcessor must not be null"); - this.spanChunkFactory = Assert.requireNonNull(spanChunkFactory, "spanChunkFactory must not be null"); this.bufferSize = bufferSize; this.storage = allocateBuffer(); } @@ -64,11 +60,11 @@ public void store(SpanEvent spanEvent) { if (overflow(storage)) { final List flushData = clearBuffer(); - final SpanChunk spanChunk = spanChunkFactory.create(traceRoot, flushData); + final SpanChunk spanChunk = wrapSpanCHunk(flushData); + final boolean success = this.dataSender.send(spanChunk); if (isDebug) { - logger.debug("[BufferedStorage] Flush span-chunk {}", spanChunk); + flushLog(success, spanChunk); } - dataSender.send(spanChunk); } } @@ -98,26 +94,41 @@ private List clearBuffer() { @Override public void store(Span span) { - final List storage = clearBuffer(); - span = spanPostProcessor.postProcess(span, storage); - dataSender.send(span); + final List spanEventList = clearBuffer(); + span.setSpanEventList(spanEventList); + span.finish(); + final boolean success = this.dataSender.send(span); if (isDebug) { - logger.debug("[BufferedStorage] Flush span {}", span); + flushLog(success, span); } } public void flush() { - final List storage = clearBuffer(); - if (CollectionUtils.hasLength(storage)) { - final SpanChunk spanChunk = spanChunkFactory.create(traceRoot, storage); - dataSender.send(spanChunk); + final List spanEventList = clearBuffer(); + if (CollectionUtils.hasLength(spanEventList)) { + final SpanChunk spanChunk = wrapSpanCHunk(spanEventList); + + final boolean success = this.dataSender.send(spanChunk); if (isDebug) { - logger.debug("flush span chunk {}", spanChunk); + flushLog(success, spanChunk); } } } + private void flushLog(boolean success, Object message) { + if (success) { + logger.debug("Flush {}", message); + } else { + logger.debug("Flush fail {}", message); + } + } + + private SpanChunk wrapSpanCHunk(List spanEventList) { + final SpanChunk spanChunk = new SpanChunk(traceRoot, spanEventList); + return spanChunk; + } + @Override public void close() { } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorageFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorageFactory.java index 0642d22dce39..2c6c46959a73 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorageFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorageFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,8 +16,7 @@ package com.navercorp.pinpoint.profiler.context.storage; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactory; -import com.navercorp.pinpoint.profiler.context.SpanPostProcessor; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; import com.navercorp.pinpoint.profiler.sender.DataSender; @@ -28,28 +27,17 @@ public class BufferedStorageFactory implements StorageFactory { private final DataSender dataSender; private final int ioBufferingBufferSize; - private final SpanPostProcessor spanPostProcessor; - private final SpanChunkFactory spanChunkFactory; - - public BufferedStorageFactory(int ioBufferingBufferSize, DataSender dataSender, SpanPostProcessor spanPostProcessor, SpanChunkFactory spanChunkFactory) { - if (dataSender == null) { - throw new NullPointerException("dataSender must not be null"); - } - if (spanChunkFactory == null) { - throw new NullPointerException("spanChunkFactory must not be null"); - } - this.dataSender = dataSender; + public BufferedStorageFactory(int ioBufferingBufferSize, DataSender dataSender) { + this.dataSender = Assert.requireNonNull(dataSender, "dataSender must not be null"); this.ioBufferingBufferSize = ioBufferingBufferSize; - this.spanPostProcessor = spanPostProcessor; - this.spanChunkFactory = spanChunkFactory; } @Override public Storage createStorage(TraceRoot traceRoot) { - BufferedStorage bufferedStorage = new BufferedStorage(traceRoot, this.dataSender, spanPostProcessor, spanChunkFactory, this.ioBufferingBufferSize); - return bufferedStorage; + Storage storage = new BufferedStorage(traceRoot, this.dataSender, this.ioBufferingBufferSize); + return storage; } @Override @@ -57,7 +45,6 @@ public String toString() { return "BufferedStorageFactory{" + "dataSender=" + dataSender + ", ioBufferingBufferSize=" + ioBufferingBufferSize + - ", spanChunkFactory=" + spanChunkFactory + '}'; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/SpanStorage.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/SpanStorage.java index c7c96ef0e23d..e9d217ea07e7 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/SpanStorage.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/storage/SpanStorage.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,6 @@ import com.navercorp.pinpoint.profiler.context.SpanEvent; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; import com.navercorp.pinpoint.profiler.sender.DataSender; -import com.navercorp.pinpoint.thrift.dto.TSpanEvent; import java.util.ArrayList; import java.util.List; @@ -30,7 +29,7 @@ */ public class SpanStorage implements Storage { - protected List spanEventList = new ArrayList(10); + protected List spanEventList = new ArrayList(10); private final TraceRoot traceRoot; private final DataSender dataSender; @@ -50,7 +49,7 @@ public void store(SpanEvent spanEvent) { if (spanEvent == null) { throw new NullPointerException("spanEvent must not be null"); } - final List spanEventList = this.spanEventList; + final List spanEventList = this.spanEventList; if (spanEventList != null) { spanEventList.add(spanEvent); } else { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/BypassMessageConverter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/BypassMessageConverter.java new file mode 100644 index 000000000000..9d62a41dea97 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/BypassMessageConverter.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.thrift; + +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; + +/** + * @author Woonduk Kang(emeroad) + */ +public class BypassMessageConverter implements MessageConverter { + @Override + public T toMessage(Object message) { + return null; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/MessageConverter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/MessageConverter.java new file mode 100644 index 000000000000..fe318f7370be --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/MessageConverter.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.thrift; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface MessageConverter { + + M toMessage(Object message); + + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/MetadataMessageConverter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/MetadataMessageConverter.java new file mode 100644 index 000000000000..f76ce069020c --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/MetadataMessageConverter.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.thrift; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.metadata.ApiMetaData; +import com.navercorp.pinpoint.profiler.metadata.SqlMetaData; +import com.navercorp.pinpoint.profiler.metadata.StringMetaData; +import com.navercorp.pinpoint.thrift.dto.TApiMetaData; +import com.navercorp.pinpoint.thrift.dto.TSqlMetaData; +import com.navercorp.pinpoint.thrift.dto.TStringMetaData; +import org.apache.thrift.TBase; + +/** + * @author Woonduk Kang(emeroad) + */ +public class MetadataMessageConverter implements MessageConverter> { + + private final String applicationName; + private final String agentId; + private final long agentStartTime; + + public MetadataMessageConverter(String applicationName, String agentId, long agentStartTime) { + this.applicationName = Assert.requireNonNull(applicationName, "applicationName must not be null"); + this.agentId = Assert.requireNonNull(agentId, "agentId must not be null"); + this.agentStartTime = agentStartTime; + } + + @Override + public TBase toMessage(Object message) { + if (message instanceof SqlMetaData) { + final SqlMetaData sqlMetaData = (SqlMetaData) message; + return new TSqlMetaData(agentId, agentStartTime, sqlMetaData.getSqlId(), sqlMetaData.getSql()); + } + if (message instanceof ApiMetaData) { + final ApiMetaData apiMetaData = (ApiMetaData) message; + final TApiMetaData tApiMetaData = new TApiMetaData(agentId, agentStartTime, apiMetaData.getApiId(), apiMetaData.getApiInfo()); + tApiMetaData.setLine(apiMetaData.getLine()); + tApiMetaData.setType(apiMetaData.getType()); + return tApiMetaData; + } + if (message instanceof StringMetaData) { + final StringMetaData stringMetaData = (StringMetaData) message; + return new TStringMetaData(agentId, agentStartTime, stringMetaData.getStringId(), stringMetaData.getStringValue()); + } + return null; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/SpanThriftMessageConverter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/SpanThriftMessageConverter.java new file mode 100644 index 000000000000..d19f9470f390 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/thrift/SpanThriftMessageConverter.java @@ -0,0 +1,277 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.thrift; + +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.common.util.IntStringValue; +import com.navercorp.pinpoint.profiler.context.Annotation; +import com.navercorp.pinpoint.profiler.context.AsyncId; +import com.navercorp.pinpoint.profiler.context.LocalAsyncId; +import com.navercorp.pinpoint.profiler.context.Span; +import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; +import com.navercorp.pinpoint.profiler.context.compress.Context; +import com.navercorp.pinpoint.profiler.context.id.Shared; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; +import com.navercorp.pinpoint.profiler.util.AnnotationValueMapper; +import com.navercorp.pinpoint.thrift.dto.TAnnotation; +import com.navercorp.pinpoint.thrift.dto.TAnnotationValue; +import com.navercorp.pinpoint.thrift.dto.TIntStringValue; +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; +import com.navercorp.pinpoint.thrift.dto.TSpanEvent; +import org.apache.thrift.TBase; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class SpanThriftMessageConverter implements MessageConverter> { + + private final String agentId; + private final String applicationName; + private final long agentStartTime; + private final short applicationServiceType; + private final TransactionIdEncoder transactionIdEncoder; + private final SpanPostProcessor spanPostProcessor; + + public SpanThriftMessageConverter(String applicationName, String agentId, long agentStartTime, short applicationServiceType, + TransactionIdEncoder transactionIdEncoder, SpanPostProcessor spanPostProcessor) { + this.applicationName = Assert.requireNonNull(applicationName, "applicationName must not be null"); + this.agentId = Assert.requireNonNull(agentId, "agentId must not be null"); + this.agentStartTime = agentStartTime; + this.applicationServiceType = applicationServiceType; + this.transactionIdEncoder = Assert.requireNonNull(transactionIdEncoder, "transactionIdEncoder must not be null"); + this.spanPostProcessor = Assert.requireNonNull(spanPostProcessor, "spanPostProcessor must not be null"); + + } + + + @Override + public TBase toMessage(Object message) { + if (message instanceof SpanChunk) { + final SpanChunk spanChunk = (SpanChunk) message; + final TSpanChunk tSpanChunk = buildTSpanChunk(spanChunk); + return tSpanChunk; + } + if (message instanceof Span) { + final Span span = (Span) message; + + return buildTSpan(span); + } + return null; + } + + + @VisibleForTesting + TSpan buildTSpan(Span span) { + final TSpan tSpan = new TSpan(); + +// tSpan.setVersion(span.getVersion()); + + tSpan.setApplicationName(applicationName); + tSpan.setAgentId(agentId); + tSpan.setAgentStartTime(agentStartTime); + tSpan.setApplicationServiceType(applicationServiceType); + + final TraceRoot traceRoot = span.getTraceRoot(); + final TraceId traceId = traceRoot.getTraceId(); + final ByteBuffer transactionId = transactionIdEncoder.encodeTransactionId(traceId); + tSpan.setTransactionId(transactionId); + tSpan.setSpanId(traceId.getSpanId()); + tSpan.setParentSpanId(traceId.getParentSpanId()); + + tSpan.setStartTime(span.getStartTime()); + tSpan.setElapsed(span.getElapsedTime()); + tSpan.setServiceType(span.getServiceType()); + + tSpan.setRemoteAddr(span.getRemoteAddr()); + + final Shared shared = traceRoot.getShared(); + tSpan.setRpc(shared.getRpcName()); + tSpan.setEndPoint(shared.getEndPoint()); + tSpan.setFlag(traceId.getFlags()); + tSpan.setErr(shared.getErrorCode()); + + tSpan.setParentApplicationName(span.getParentApplicationName()); + tSpan.setParentApplicationType(span.getParentApplicationType()); + tSpan.setAcceptorHost(span.getAcceptorHost()); + + tSpan.setApiId(span.getApiId()); + + final IntStringValue exceptionInfo = span.getExceptionInfo(); + if (exceptionInfo != null) { + TIntStringValue tIntStringValue = buildTIntStringValue(exceptionInfo); + tSpan.setExceptionInfo(tIntStringValue); + } + + tSpan.setLoggingTransactionInfo(shared.getLoggingInfo()); + + final List annotations = span.getAnnotations(); + if (CollectionUtils.hasLength(annotations)) { + final List tAnnotations = buildTAnnotation(annotations); + tSpan.setAnnotations(tAnnotations); + } + + final List spanEventList = span.getSpanEventList(); + if (CollectionUtils.hasLength(spanEventList)) { + final Context context = spanPostProcessor.newContext(span, tSpan); + final List tSpanEvents = buildTSpanEventList(spanEventList, context); + context.finish(); + tSpan.setSpanEventList(tSpanEvents); + } + return tSpan; + + } + + private List buildTSpanEventList(List spanEventList, Context context) { + final int eventSize = spanEventList.size(); + final List tSpanEventList = new ArrayList(eventSize); + for (SpanEvent spanEvent : spanEventList) { + final TSpanEvent tSpanEvent = buildTSpanEvent(spanEvent, context); + this.spanPostProcessor.postProcess(context, spanEvent, tSpanEvent); + context.next(); + tSpanEventList.add(tSpanEvent); + } + return tSpanEventList; + } + + @VisibleForTesting + TSpanChunk buildTSpanChunk(SpanChunk spanChunk) { + final TSpanChunk tSpanChunk = new TSpanChunk(); + + tSpanChunk.setApplicationName(applicationName); + tSpanChunk.setAgentId(agentId); + tSpanChunk.setAgentStartTime(agentStartTime); + tSpanChunk.setApplicationServiceType(applicationServiceType); + + final TraceRoot traceRoot = spanChunk.getTraceRoot(); + final TraceId traceId = traceRoot.getTraceId(); + final ByteBuffer transactionId = transactionIdEncoder.encodeTransactionId(traceId); + tSpanChunk.setTransactionId(transactionId); + + tSpanChunk.setSpanId(traceId.getSpanId()); + + final Shared shared = traceRoot.getShared(); + tSpanChunk.setEndPoint(shared.getEndPoint()); + + final List spanEventList = spanChunk.getSpanEventList(); + if (CollectionUtils.hasLength(spanEventList)) { + final Context context = spanPostProcessor.newContext(spanChunk, tSpanChunk); + final List tSpanEvents = buildTSpanEventList(spanEventList, context); + context.finish(); + tSpanChunk.setSpanEventList(tSpanEvents); + } + + return tSpanChunk; + } + + @VisibleForTesting + TSpanEvent buildTSpanEvent(SpanEvent spanEvent, Context context) { + final TSpanEvent tSpanEvent = new TSpanEvent(); + +// if (spanEvent.getStartElapsed() != 0) { +// tSpanEvent.setStartElapsed(spanEvent.getStartElapsed()); +// } +// tSpanEvent.setStartElapsed(spanEvent.getStartElapsed()); + if (spanEvent.getElapsedTime() != 0) { + tSpanEvent.setEndElapsed(spanEvent.getElapsedTime()); + } + tSpanEvent.setSequence(spanEvent.getSequence()); +// tSpanEvent.setRpc(spanEvent.getRpc()); + tSpanEvent.setServiceType(spanEvent.getServiceType()); + tSpanEvent.setEndPoint(spanEvent.getEndPoint()); + + // tSpanEvent.setAnnotations(); + if (spanEvent.getDepth() != -1) { + tSpanEvent.setDepth(spanEvent.getDepth()); + } + if (spanEvent.getNextSpanId() != -1) { + tSpanEvent.setNextSpanId(spanEvent.getNextSpanId()); + } + + tSpanEvent.setDestinationId(spanEvent.getDestinationId()); + tSpanEvent.setApiId(spanEvent.getApiId()); + + final IntStringValue exceptionInfo = spanEvent.getExceptionInfo(); + if (exceptionInfo != null) { + TIntStringValue tIntStringValue = buildTIntStringValue(exceptionInfo); + tSpanEvent.setExceptionInfo(tIntStringValue); + } + + + final AsyncId asyncIdObject = spanEvent.getAsyncIdObject(); + if (asyncIdObject != null) { + tSpanEvent.setNextAsyncId(asyncIdObject.getAsyncId()); + } + final LocalAsyncId localAsyncId = spanEvent.getLocalAsyncId(); + if (localAsyncId != null) { + tSpanEvent.setAsyncId(localAsyncId.getAsyncId()); + tSpanEvent.setAsyncSequence(localAsyncId.getSequence()); + } + + final List annotations = spanEvent.getAnnotations(); + if (CollectionUtils.hasLength(annotations)) { + final List tAnnotations = buildTAnnotation(annotations); + tSpanEvent.setAnnotations(tAnnotations); + } + + return tSpanEvent; + } + + private TIntStringValue buildTIntStringValue(IntStringValue exceptionInfo) { + TIntStringValue tIntStringValue = new TIntStringValue(exceptionInfo.getIntValue()); + final String stringValue = exceptionInfo.getStringValue(); + if (stringValue != null) { + tIntStringValue.setStringValue(stringValue); + } + return tIntStringValue; + } + + @VisibleForTesting + List buildTAnnotation(List annotations) { + final List tAnnotationList = new ArrayList(annotations.size()); + for (Annotation annotation : annotations) { + final TAnnotation tAnnotation = new TAnnotation(annotation.getAnnotationKey()); + final TAnnotationValue tAnnotationValue = AnnotationValueMapper.buildTAnnotationValue(annotation.getValue()); + if (tAnnotationValue != null) { + tAnnotation.setValue(tAnnotationValue); + } + + tAnnotationList.add(tAnnotation); + } + return tAnnotationList; + } + + @Override + public String toString() { + return "SpanThriftMessageConverter{" + + "agentId='" + agentId + '\'' + + ", applicationName='" + applicationName + '\'' + + ", agentStartTime=" + agentStartTime + + ", applicationServiceType=" + applicationServiceType + + '}'; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClass.java index 81a02e2b315f..956504fd5c90 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClass.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClass.java @@ -32,14 +32,15 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; import com.navercorp.pinpoint.bootstrap.plugin.ObjectFactory; import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.JvmVersion; import com.navercorp.pinpoint.exception.PinpointException; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; import com.navercorp.pinpoint.profiler.objectfactory.AutoBindingObjectFactory; import com.navercorp.pinpoint.profiler.objectfactory.InterceptorArgumentProvider; import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,36 +57,22 @@ public class ASMClass implements InstrumentClass { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final ObjectBinderFactory objectBinderFactory; + private final EngineComponent engineComponent; + private final InstrumentContext pluginContext; - private final InterceptorRegistryBinder interceptorRegistryBinder; - private final ApiMetaDataService apiMetaDataService; private final ClassLoader classLoader; private final ASMClassNodeAdapter classNode; private boolean modified = false; private String name; - public ASMClass(ObjectBinderFactory objectBinderFactory, final InstrumentContext pluginContext, final InterceptorRegistryBinder interceptorRegistryBinder, ApiMetaDataService apiMetaDataService, final ClassLoader classLoader, final ClassNode classNode) { - this(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService, classLoader, new ASMClassNodeAdapter(pluginContext, classLoader, classNode)); + public ASMClass(EngineComponent engineComponent, final InstrumentContext pluginContext, final ClassLoader classLoader, final ClassNode classNode) { + this(engineComponent, pluginContext, classLoader, new ASMClassNodeAdapter(pluginContext, classLoader, classNode)); } - public ASMClass(ObjectBinderFactory objectBinderFactory, final InstrumentContext pluginContext, final InterceptorRegistryBinder interceptorRegistryBinder, ApiMetaDataService apiMetaDataService, final ClassLoader classLoader, final ASMClassNodeAdapter classNode) { - if (objectBinderFactory == null) { - throw new NullPointerException("objectBinderFactory must not be null"); - } - -// if (pluginContext == null) { -// throw new NullPointerException("pluginContext must not be null"); -// } - if (apiMetaDataService == null) { - throw new NullPointerException("apiMetaDataService must not be null"); - } - - this.objectBinderFactory = objectBinderFactory; + public ASMClass(EngineComponent engineComponent, final InstrumentContext pluginContext, final ClassLoader classLoader, final ASMClassNodeAdapter classNode) { + this.engineComponent = Assert.requireNonNull(engineComponent, "engineComponent must not be null"); this.pluginContext = pluginContext; - this.interceptorRegistryBinder = interceptorRegistryBinder; - this.apiMetaDataService = apiMetaDataService; this.classLoader = classLoader; this.classNode = classNode; // for performance. @@ -98,7 +85,14 @@ public ClassLoader getClassLoader() { @Override public boolean isInterceptable() { - return !isInterface() && !isAnnotation() && !isModified(); + if (isAnnotation() || isModified()) { + return false; + } + // interface static method or default method is java 1.8 or later + if (isInterface() && (this.classNode.getMajorVersion() < 52 || !JvmUtils.getVersion().onOrAfter(JvmVersion.JAVA_8))) { + return false; + } + return true; } @Override @@ -133,7 +127,7 @@ public InstrumentMethod getDeclaredMethod(final String name, final String... par return null; } - return new ASMMethod(this.objectBinderFactory, this.pluginContext, this.interceptorRegistryBinder, apiMetaDataService, this, methodNode); + return new ASMMethod(this.engineComponent, this.pluginContext, this, methodNode); } @Override @@ -149,7 +143,7 @@ public List getDeclaredMethods(final MethodFilter methodFilter final List candidateList = new ArrayList(); for (ASMMethodNodeAdapter methodNode : this.classNode.getDeclaredMethods()) { - final InstrumentMethod method = new ASMMethod(this.objectBinderFactory, this.pluginContext, this.interceptorRegistryBinder, apiMetaDataService, this, methodNode); + final InstrumentMethod method = new ASMMethod(this.engineComponent, this.pluginContext, this, methodNode); if (methodFilter.accept(method)) { candidateList.add(method); } @@ -233,7 +227,7 @@ public InstrumentMethod addDelegatorMethod(final String methodName, final String final ASMMethodNodeAdapter methodNode = this.classNode.addDelegatorMethod(superMethodNode); setModified(true); - return new ASMMethod(this.objectBinderFactory, this.pluginContext, this.interceptorRegistryBinder, apiMetaDataService, this, methodNode); + return new ASMMethod(this.engineComponent, this.pluginContext, this, methodNode); } @Override @@ -243,7 +237,8 @@ public void addField(final String accessorTypeName) throws InstrumentException { final AccessorAnalyzer accessorAnalyzer = new AccessorAnalyzer(); final AccessorAnalyzer.AccessorDetails accessorDetails = accessorAnalyzer.analyze(accessorType); - final ASMFieldNodeAdapter fieldNode = this.classNode.addField(FIELD_PREFIX + JavaAssistUtils.javaClassNameToVariableName(accessorTypeName), accessorDetails.getFieldType()); + final Type type = Type.getType(accessorDetails.getFieldType()); + final ASMFieldNodeAdapter fieldNode = this.classNode.addField(FIELD_PREFIX + JavaAssistUtils.javaClassNameToVariableName(accessorTypeName), type.getDescriptor()); this.classNode.addInterface(accessorTypeName); this.classNode.addGetterMethod(accessorDetails.getGetter().getName(), fieldNode); this.classNode.addSetterMethod(accessorDetails.getSetter().getName(), fieldNode); @@ -473,6 +468,7 @@ private int addInterceptor0(TargetFilter annotation, String interceptorClassName final String filterTypeName = annotation.type(); Assert.requireNonNull(filterTypeName, "type of @TargetFilter must not be null"); + ObjectBinderFactory objectBinderFactory = engineComponent.getObjectBinderFactory(); final InterceptorArgumentProvider interceptorArgumentProvider = objectBinderFactory.newInterceptorArgumentProvider(this); final AutoBindingObjectFactory filterFactory = objectBinderFactory.newAutoBindingObjectFactory(pluginContext, classLoader, interceptorArgumentProvider); final ObjectFactory objectFactory = ObjectFactory.byConstructor(filterTypeName, (Object[]) annotation.constructorArguments()); @@ -491,7 +487,7 @@ private int addInterceptor0(TargetFilter annotation, String interceptorClassName } if (interceptorId == -1) { - logger.warn("No methods are intercepted. target: " + this.classNode.getInternalName(), ", interceptor: " + interceptorClassName + ", methodFilter: " + filterTypeName); + logger.warn("No methods are intercepted. target:{}, interceptor:{}, methodFilter:{} ", this.classNode.getInternalName(), interceptorClassName, filterTypeName); } return interceptorId; @@ -564,7 +560,7 @@ private int addScopedInterceptor0(MethodFilter filter, String interceptorClassNa } if (interceptorId == -1) { - logger.warn("No methods are intercepted. target: " + this.classNode.getInternalName(), ", interceptor: " + interceptorClassName + ", methodFilter: " + filter.getClass().getName()); + logger.warn("No methods are intercepted. target:{}, interceptor:{}, methodFilter:{}", this.classNode.getInternalName(), interceptorClassName, filter.getClass().getName()); } return interceptorId; @@ -574,7 +570,7 @@ private int addScopedInterceptor0(MethodFilter filter, String interceptorClassNa public List getNestedClasses(ClassFilter filter) { final List nestedClasses = new ArrayList(); for (ASMClassNodeAdapter innerClassNode : this.classNode.getInnerClasses()) { - final ASMNestedClass nestedClass = new ASMNestedClass(objectBinderFactory, this.pluginContext, this.interceptorRegistryBinder, apiMetaDataService, this.classLoader, innerClassNode); + final ASMNestedClass nestedClass = new ASMNestedClass(engineComponent, this.pluginContext, this.classLoader, innerClassNode); if (filter.accept(nestedClass)) { nestedClasses.add(nestedClass); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeAdapter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeAdapter.java index e44fd33cf9ad..92042754ec34 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeAdapter.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeAdapter.java @@ -16,6 +16,8 @@ package com.navercorp.pinpoint.profiler.instrument; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.common.util.IOUtils; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; @@ -54,32 +56,26 @@ public static ASMClassNodeAdapter get(final InstrumentContext pluginContext, fin throw new NullPointerException("classInternalName must not be null"); } - InputStream in = null; + final String classPath = classInternalName.concat(".class"); + final InputStream in = pluginContext.getResourceAsStream(classLoader, classPath); + if (in == null) { + return null; + } + final byte[] bytes; try { - in = pluginContext.getResourceAsStream(classLoader, classInternalName + ".class"); - if (in != null) { - final ClassReader classReader = new ClassReader(in); - final ClassNode classNode = new ClassNode(); - if (skipCode) { - classReader.accept(classNode, ClassReader.SKIP_CODE); - } else { - classReader.accept(classNode, 0); - } - - return new ASMClassNodeAdapter(pluginContext, classLoader, classNode, skipCode); - } - } catch (IOException ignored) { - // not found class. - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ignored) { - } - } + bytes = IOUtils.toByteArray(in); + } catch (IOException ignore) { + return null; + } + final ClassReader classReader = new ClassReader(bytes); + final ClassNode classNode = new ClassNode(); + if (skipCode) { + classReader.accept(classNode, ClassReader.SKIP_CODE); + } else { + classReader.accept(classNode, 0); } - return null; + return new ASMClassNodeAdapter(pluginContext, classLoader, classNode, skipCode); } private final InstrumentContext pluginContext; @@ -124,7 +120,7 @@ public boolean isAnnotation() { public String[] getInterfaceNames() { final List interfaces = this.classNode.interfaces; - if (interfaces == null || interfaces.size() == 0) { + if (CollectionUtils.isEmpty(interfaces)) { return new String[0]; } @@ -135,7 +131,7 @@ public String[] getInterfaceNames() { } } - return list.toArray(new String[list.size()]); + return list.toArray(new String[0]); } public ASMMethodNodeAdapter getDeclaredMethod(final String methodName, final String desc) { @@ -266,13 +262,15 @@ public ASMFieldNodeAdapter getField(final String fieldName, final String fieldDe return null; } - public ASMFieldNodeAdapter addField(final String fieldName, final Class fieldClass) { - if (fieldName == null || fieldClass == null) { - throw new IllegalArgumentException("fieldNode name or fieldNode class must not be null."); + public ASMFieldNodeAdapter addField(final String fieldName, final String fieldDesc) { + if (fieldName == null) { + throw new IllegalArgumentException("fieldName must not be null"); + } + if (fieldDesc == null) { + throw new IllegalArgumentException("fieldDesc must not be null"); } - final Type type = Type.getType(fieldClass); - final FieldNode fieldNode = new FieldNode(Opcodes.ACC_PRIVATE, fieldName, type.getDescriptor(), null, null); + final FieldNode fieldNode = new FieldNode(Opcodes.ACC_PRIVATE, fieldName, fieldDesc, null, null); if (this.classNode.fields == null) { this.classNode.fields = new ArrayList(); } @@ -288,7 +286,7 @@ public ASMMethodNodeAdapter addDelegatorMethod(final ASMMethodNodeAdapter superM String[] exceptions = null; if (superMethodNode.getExceptions() != null) { - exceptions = superMethodNode.getExceptions().toArray(new String[superMethodNode.getExceptions().size()]); + exceptions = superMethodNode.getExceptions().toArray(new String[0]); } final ASMMethodNodeAdapter methodNode = new ASMMethodNodeAdapter(getInternalName(), new MethodNode(superMethodNode.getAccess(), superMethodNode.getName(), superMethodNode.getDesc(), superMethodNode.getSignature(), exceptions)); @@ -440,7 +438,7 @@ public boolean subclassOf(final String classInternalName) { public List getInnerClasses() { if (this.classNode.innerClasses == null) { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } final List innerClasses = new ArrayList(); @@ -459,6 +457,11 @@ public List getInnerClasses() { return innerClasses; } + public int getMajorVersion() { + final int majorVersion = this.classNode.version & 0xFFFF; + return majorVersion; + } + public byte[] toByteArray() { final int majorVersion = this.classNode.version & 0xFFFF; int flags = ClassWriter.COMPUTE_FRAMES; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClassWriter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClassWriter.java index 66e0215c80aa..ed5c518d03ed 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClassWriter.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMClassWriter.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.instrument; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; +import com.navercorp.pinpoint.common.util.IOUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -212,23 +213,17 @@ private ClassReader getClassReader(final String classInternalName) { return null; } - InputStream in = null; - try { - in = pluginContext.getResourceAsStream(this.classLoader, classInternalName + ".class"); - if (in != null) { - return new ClassReader(in); - } - } catch (IOException ignored) { - // not found class. - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ignored) { - } - } + final String classFileName = classInternalName.concat(".class"); + final InputStream in = pluginContext.getResourceAsStream(this.classLoader, classFileName); + if (in == null) { + return null; } - return null; + try { + final byte[] bytes =IOUtils.toByteArray(in); + return new ClassReader(bytes); + } catch (IOException e) { + return null; + } } } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMEngine.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMEngine.java index 94007c262585..9ca78dcee4a0 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMEngine.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMEngine.java @@ -15,13 +15,10 @@ */ package com.navercorp.pinpoint.profiler.instrument; -import com.google.inject.Provider; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; import com.navercorp.pinpoint.bootstrap.instrument.NotFoundInstrumentException; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; -import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; @@ -29,7 +26,7 @@ import org.slf4j.LoggerFactory; import java.lang.instrument.Instrumentation; -import java.util.List; +import java.security.ProtectionDomain; import java.util.jar.JarFile; /** @@ -40,34 +37,16 @@ public class ASMEngine implements InstrumentEngine { private final boolean isInfo = logger.isInfoEnabled(); private final Instrumentation instrumentation; - private final ObjectBinderFactory objectBinderFactory; - private final InterceptorRegistryBinder interceptorRegistryBinder; - private final Provider apiMetaDataService; + private final EngineComponent engineComponent; - public ASMEngine(Instrumentation instrumentation, ObjectBinderFactory objectBinderFactory, final InterceptorRegistryBinder interceptorRegistryBinder, Provider apiMetaDataService, final List bootStrapJars) { - if (instrumentation == null) { - throw new NullPointerException("instrumentation must not be null"); - } - if (objectBinderFactory == null) { - throw new NullPointerException("objectBinderFactory must not be null"); - } - if (interceptorRegistryBinder == null) { - throw new NullPointerException("interceptorRegistryBinder must not be null"); - } - if (apiMetaDataService == null) { - throw new NullPointerException("apiMetaDataService must not be null"); - } - - this.instrumentation = instrumentation; - this.objectBinderFactory = objectBinderFactory; - this.interceptorRegistryBinder = interceptorRegistryBinder; - this.apiMetaDataService = apiMetaDataService; - + public ASMEngine(Instrumentation instrumentation, EngineComponent engineComponent) { + this.instrumentation = Assert.requireNonNull(instrumentation, "instrumentation must not be null"); + this.engineComponent = Assert.requireNonNull(engineComponent, "engineComponent must not be null"); } @Override - public InstrumentClass getClass(InstrumentContext instrumentContext, ClassLoader classLoader, String className, byte[] classFileBuffer) throws NotFoundInstrumentException { + public InstrumentClass getClass(InstrumentContext instrumentContext, ClassLoader classLoader, String className, ProtectionDomain protectionDomain, byte[] classFileBuffer) throws NotFoundInstrumentException { if (className == null) { throw new NullPointerException("class name must not be null."); } @@ -78,8 +57,7 @@ public InstrumentClass getClass(InstrumentContext instrumentContext, ClassLoader if (classNode == null) { return null; } - ApiMetaDataService apiMetaDataService = this.apiMetaDataService.get(); - return new ASMClass(objectBinderFactory, instrumentContext, interceptorRegistryBinder, apiMetaDataService, classLoader, classNode); + return new ASMClass(engineComponent, instrumentContext, classLoader, classNode); } // Use ASM tree api. @@ -87,18 +65,13 @@ public InstrumentClass getClass(InstrumentContext instrumentContext, ClassLoader final ClassNode classNode = new ClassNode(); classReader.accept(classNode, 0); - ApiMetaDataService apiMetaDataService = this.apiMetaDataService.get(); - return new ASMClass(objectBinderFactory, instrumentContext, interceptorRegistryBinder, apiMetaDataService, classLoader, classNode); + + return new ASMClass(engineComponent, instrumentContext, classLoader, classNode); } catch (Exception e) { throw new NotFoundInstrumentException(e); } } - @Override - public boolean hasClass(ClassLoader classLoader, String className) { - // TODO deprecated - return classLoader.getResource(JavaAssistUtils.javaNameToJvmName(className) + ".class") != null; - } @Override public void appendToBootstrapClassPath(JarFile jarFile) { @@ -106,7 +79,7 @@ public void appendToBootstrapClassPath(JarFile jarFile) { throw new NullPointerException("jarFile must not be null"); } if (isInfo) { - logger.info("appendToBootstrapClassPath:{}", jarFile); + logger.info("appendToBootstrapClassPath:{}", jarFile.getName()); } instrumentation.appendToBootstrapClassLoaderSearch(jarFile); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMMethod.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMMethod.java index d3209d27b4e6..9292df80d490 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMMethod.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMMethod.java @@ -27,11 +27,8 @@ import com.navercorp.pinpoint.profiler.context.DefaultMethodDescriptor; import com.navercorp.pinpoint.profiler.instrument.interceptor.CaptureType; import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinition; -import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinitionFactory; import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorType; import com.navercorp.pinpoint.profiler.interceptor.factory.AnnotatedInterceptorFactory; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import org.objectweb.asm.tree.MethodNode; @@ -42,43 +39,26 @@ * @author jaehong.kim */ public class ASMMethod implements InstrumentMethod { - // TODO fix inject InterceptorDefinitionFactory - private static final InterceptorDefinitionFactory interceptorDefinitionFactory = new InterceptorDefinitionFactory(); private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private final ObjectBinderFactory objectBinderFactory; + private final EngineComponent engineComponent; private final InstrumentContext pluginContext; - private final InterceptorRegistryBinder interceptorRegistryBinder; private final ASMClass declaringClass; private final ASMMethodNodeAdapter methodNode; private final MethodDescriptor descriptor; - private final ApiMetaDataService apiMetaDataService; - // TODO fix inject ScopeFactory - private static final ScopeFactory scopeFactory = new ScopeFactory(); - public ASMMethod(ObjectBinderFactory objectBinderFactory, InstrumentContext pluginContext, ApiMetaDataService apiMetaDataService, InterceptorRegistryBinder interceptorRegistryBinder, ASMClass declaringClass, MethodNode methodNode) { - this(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService, declaringClass, new ASMMethodNodeAdapter(JavaAssistUtils.javaNameToJvmName(declaringClass.getName()), methodNode)); + public ASMMethod(EngineComponent engineComponent, InstrumentContext pluginContext, ASMClass declaringClass, MethodNode methodNode) { + this(engineComponent, pluginContext, declaringClass, new ASMMethodNodeAdapter(JavaAssistUtils.javaNameToJvmName(declaringClass.getName()), methodNode)); } - public ASMMethod(ObjectBinderFactory objectBinderFactory, InstrumentContext pluginContext, InterceptorRegistryBinder interceptorRegistryBinder, ApiMetaDataService apiMetaDataService, ASMClass declaringClass, ASMMethodNodeAdapter methodNode) { - if (objectBinderFactory == null) { - throw new NullPointerException("objectBinderFactory must not be null"); - } - if (pluginContext == null) { - throw new NullPointerException("pluginContext must not be null"); - } - if (apiMetaDataService == null) { - throw new NullPointerException("apiMetaDataService must not be null"); - } - this.objectBinderFactory = objectBinderFactory; - this.pluginContext = pluginContext; - this.interceptorRegistryBinder = interceptorRegistryBinder; - this.apiMetaDataService = apiMetaDataService; + public ASMMethod(EngineComponent engineComponent, InstrumentContext pluginContext, ASMClass declaringClass, ASMMethodNodeAdapter methodNode) { + this.engineComponent = Assert.requireNonNull(engineComponent, "engineComponent must not be null"); + this.pluginContext = Assert.requireNonNull(pluginContext, "pluginContext must not be null"); this.declaringClass = declaringClass; this.methodNode = methodNode; @@ -224,9 +204,10 @@ int addInterceptorInternal(String interceptorClassName, Object[] constructorArgs private int addInterceptor0(String interceptorClassName, Object[] constructorArgs, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { final ClassLoader classLoader = this.declaringClass.getClassLoader(); + final ScopeFactory scopeFactory = this.engineComponent.getScopeFactory(); final ScopeInfo scopeInfo = scopeFactory.newScopeInfo(classLoader, pluginContext, interceptorClassName, scope, executionPolicy); final Interceptor interceptor = createInterceptor(classLoader, interceptorClassName, scopeInfo, constructorArgs); - final int interceptorId = this.interceptorRegistryBinder.getInterceptorRegistryAdaptor().addInterceptor(interceptor); + final int interceptorId = this.engineComponent.addInterceptor(interceptor); addInterceptor0(interceptor, interceptorId); return interceptorId; @@ -234,7 +215,8 @@ private int addInterceptor0(String interceptorClassName, Object[] constructorArg private Interceptor createInterceptor(ClassLoader classLoader, String interceptorClassName, ScopeInfo scopeInfo, Object[] constructorArgs) { // exception handling. - final AnnotatedInterceptorFactory factory = objectBinderFactory.newAnnotatedInterceptorFactory(this.pluginContext, true); + ObjectBinderFactory objectBinderFactory = this.engineComponent.getObjectBinderFactory(); + final AnnotatedInterceptorFactory factory = objectBinderFactory.newAnnotatedInterceptorFactory(this.pluginContext); final Interceptor interceptor = factory.getInterceptor(classLoader, interceptorClassName, constructorArgs, scopeInfo, this.declaringClass, this); return interceptor; @@ -245,7 +227,7 @@ private void addInterceptor0(Interceptor interceptor, int interceptorId) { throw new NullPointerException("interceptor must not be null"); } - final InterceptorDefinition interceptorDefinition = this.interceptorDefinitionFactory.createInterceptorDefinition(interceptor.getClass()); + final InterceptorDefinition interceptorDefinition = this.engineComponent.createInterceptorDefinition(interceptor.getClass()); final Class interceptorClass = interceptorDefinition.getInterceptorClass(); final CaptureType captureType = interceptorDefinition.getCaptureType(); if (this.methodNode.hasInterceptor()) { @@ -260,7 +242,7 @@ private void addInterceptor0(Interceptor interceptor, int interceptorId) { int apiId = -1; if (interceptorDefinition.getInterceptorType() == InterceptorType.API_ID_AWARE) { - apiId = this.apiMetaDataService.cacheApi(this.descriptor); + apiId = this.engineComponent.cacheApi(this.descriptor); } // add before interceptor. diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodInsnNodeRemapper.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodInsnNodeRemapper.java index 2f1e189c42df..77fe54c68ae9 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodInsnNodeRemapper.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodInsnNodeRemapper.java @@ -83,7 +83,7 @@ public void setDesc(final String desc) { } public ASMMethodInsnNodeRemapper build() { - Filter[] copyFilter = this.filters.toArray(new Filter[this.filters.size()]); + Filter[] copyFilter = this.filters.toArray(new Filter[0]); return new ASMMethodInsnNodeRemapper(copyFilter, owner, name, desc); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMNestedClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMNestedClass.java index c50b97ec63c5..6413d0fde1c8 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMNestedClass.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMNestedClass.java @@ -24,12 +24,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExecutionPolicy; import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; -import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; import org.objectweb.asm.tree.ClassNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.List; @@ -38,16 +33,15 @@ * @author jaehong.kim */ public class ASMNestedClass implements InstrumentClass { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final ASMClass aClass; - public ASMNestedClass(ObjectBinderFactory objectBinderFactory, final InstrumentContext pluginContext, final InterceptorRegistryBinder interceptorRegistryBinder, ApiMetaDataService apiMetaDataService, final ClassLoader classLoader, final ClassNode classNode) { - this.aClass = new ASMClass(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService, classLoader, classNode); + public ASMNestedClass(EngineComponent engineComponent, final InstrumentContext pluginContext, final ClassLoader classLoader, final ClassNode classNode) { + this.aClass = new ASMClass(engineComponent, pluginContext, classLoader, classNode); } - public ASMNestedClass(ObjectBinderFactory objectBinderFactory, final InstrumentContext pluginContext, final InterceptorRegistryBinder interceptorRegistryBinder, ApiMetaDataService apiMetaDataService, final ClassLoader classLoader, final ASMClassNodeAdapter classNodeAdapter) { - this.aClass = new ASMClass(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService, classLoader, classNodeAdapter); + public ASMNestedClass(EngineComponent engineComponent, final InstrumentContext pluginContext, final ClassLoader classLoader, final ASMClassNodeAdapter classNodeAdapter) { + this.aClass = new ASMClass(engineComponent, pluginContext, classLoader, classNodeAdapter); } public ClassLoader getClassLoader() { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMVersion.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMVersion.java new file mode 100644 index 000000000000..37fd92af3258 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/ASMVersion.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument; + +import org.objectweb.asm.Opcodes; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class ASMVersion { + private ASMVersion() { + } + + public static final int VERSION = Opcodes.ASM7; +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/BootstrapPackage.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/BootstrapPackage.java index 9d88133bc8d6..469aa19ddbf4 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/BootstrapPackage.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/BootstrapPackage.java @@ -16,17 +16,39 @@ package com.navercorp.pinpoint.profiler.instrument; -import java.util.Arrays; -import java.util.List; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; /** * @author Woonduk Kang(emeroad) */ public class BootstrapPackage { - private static final List BOOTSTRAP_PACKAGE_LIST = Arrays.asList("com.navercorp.pinpoint.bootstrap", "com.navercorp.pinpoint.common", "com.navercorp.pinpoint.exception"); + public BootstrapPackage() { + } + + private static final String[] BOOTSTRAP_PACKAGE_LIST = { + "com.navercorp.pinpoint.bootstrap", + "com.navercorp.pinpoint.common", + "com.navercorp.pinpoint.exception" + }; + + private static final String[] INTERNAL_BOOTSTRAP_PACKAGE_LIST = toInternalName(BOOTSTRAP_PACKAGE_LIST); + + private static String[] toInternalName(String[] bootstrapPackageList) { + String[] internalPackageNames = new String[bootstrapPackageList.length]; + for (int i = 0; i < bootstrapPackageList.length; i++) { + String packageName = bootstrapPackageList[i]; + internalPackageNames[i] = JavaAssistUtils.javaNameToJvmName(packageName); + } + return internalPackageNames; + } + public boolean isBootstrapPackage(String className) { + if (className == null) { + return false; + } + for (String bootstrapPackage : BOOTSTRAP_PACKAGE_LIST) { if (className.startsWith(bootstrapPackage)) { return true; @@ -34,4 +56,20 @@ public boolean isBootstrapPackage(String className) { } return false; } + + + public boolean isBootstrapPackageByInternalName(String internalClassName) { + if (internalClassName == null) { + return false; + } + + for (String bootstrapPackage : INTERNAL_BOOTSTRAP_PACKAGE_LIST) { + if (internalClassName.startsWith(bootstrapPackage)) { + return true; + } + } + return false; + } + + } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/DefaultEngineComponent.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/DefaultEngineComponent.java new file mode 100644 index 000000000000..3d4d5595c865 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/DefaultEngineComponent.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument; + +import com.google.inject.Provider; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.interceptor.Interceptor; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinition; +import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinitionFactory; +import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; +import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; +import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultEngineComponent implements EngineComponent { + + private final ObjectBinderFactory objectBinderFactory; + private final InterceptorRegistryBinder interceptorRegistryBinder; + private final InterceptorDefinitionFactory interceptorDefinitionFactory; + private final Provider apiMetaDataServiceProvider; + private final ScopeFactory scopeFactory; + + public DefaultEngineComponent(ObjectBinderFactory objectBinderFactory, + InterceptorRegistryBinder interceptorRegistryBinder, + InterceptorDefinitionFactory interceptorDefinitionFactory, + Provider apiMetaDataServiceProvider, + ScopeFactory scopeFactory) { + this.objectBinderFactory = Assert.requireNonNull(objectBinderFactory, "objectBinderFactory must not be null"); + this.interceptorRegistryBinder = Assert.requireNonNull(interceptorRegistryBinder, "interceptorRegistryBinder must not be null"); + this.interceptorDefinitionFactory = Assert.requireNonNull(interceptorDefinitionFactory, "interceptorDefinitionFactory must not be null"); + this.apiMetaDataServiceProvider = Assert.requireNonNull(apiMetaDataServiceProvider, "apiMetaDataService must not be null"); + this.scopeFactory = Assert.requireNonNull(scopeFactory, "scopeFactory must not be null"); + } + + @Override + public ScopeFactory getScopeFactory() { + return scopeFactory; + } + + @Override + public InterceptorDefinition createInterceptorDefinition(Class interceptorClazz) { + return this.interceptorDefinitionFactory.createInterceptorDefinition(interceptorClazz); + } + + @Override + public ObjectBinderFactory getObjectBinderFactory() { + return objectBinderFactory; + } + + + @Override + public int addInterceptor(Interceptor interceptor) { + return interceptorRegistryBinder.getInterceptorRegistryAdaptor().addInterceptor(interceptor); + } + + @Override + public int cacheApi(MethodDescriptor methodDescriptor) { + ApiMetaDataService apiMetaDataService = this.apiMetaDataServiceProvider.get(); + return apiMetaDataService.cacheApi(methodDescriptor); + } + +} + diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/EngineComponent.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/EngineComponent.java new file mode 100644 index 000000000000..a857c436af78 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/EngineComponent.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument; + +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.interceptor.Interceptor; +import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinition; +import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface EngineComponent { + + ScopeFactory getScopeFactory(); + + InterceptorDefinition createInterceptorDefinition(Class interceptorClazz); + + ObjectBinderFactory getObjectBinderFactory(); + + int addInterceptor(Interceptor interceptor); + + int cacheApi(MethodDescriptor methodDescriptor); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/GuardInstrumentContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/GuardInstrumentContext.java index a83cda2bdc2e..b909ad0d74ef 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/GuardInstrumentContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/GuardInstrumentContext.java @@ -23,6 +23,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; import java.io.InputStream; +import java.security.ProtectionDomain; /** * @author Woonduk Kang(emeroad) @@ -42,15 +43,15 @@ public GuardInstrumentContext(InstrumentContext instrumentContext) { @Override - public InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, byte[] classfileBuffer) { + public InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, ProtectionDomain protectionDomain, byte[] classfileBuffer) { checkOpen(); - return instrumentContext.getInstrumentClass(classLoader, className, classfileBuffer); + return instrumentContext.getInstrumentClass(classLoader, className, protectionDomain, classfileBuffer); } @Override - public boolean exist(ClassLoader classLoader, String className) { + public boolean exist(ClassLoader classLoader, String className, ProtectionDomain protectionDomain) { checkOpen(); - return instrumentContext.exist(classLoader, className); + return instrumentContext.exist(classLoader, className, protectionDomain); } @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/GuardInstrumentor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/GuardInstrumentor.java index 86155f7681c4..6f6f0b3c71bd 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/GuardInstrumentor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/GuardInstrumentor.java @@ -24,6 +24,8 @@ import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformCallback; import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; +import java.security.ProtectionDomain; + /** * @author emeroad */ @@ -48,18 +50,31 @@ public ProfilerConfig getProfilerConfig() { return profilerConfig; } + @Override + public InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + checkOpen(); + return instrumentContext.getInstrumentClass(classLoader, className, protectionDomain, classfileBuffer); + } + @Override public InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, byte[] classfileBuffer) { checkOpen(); - return instrumentContext.getInstrumentClass(classLoader, className, classfileBuffer); + return instrumentContext.getInstrumentClass(classLoader, className, null, classfileBuffer); + } + + @Override + public boolean exist(ClassLoader classLoader, String className, ProtectionDomain protectionDomain) { + checkOpen(); + return instrumentContext.exist(classLoader, className, protectionDomain); } @Override public boolean exist(ClassLoader classLoader, String className) { checkOpen(); - return instrumentContext.exist(classLoader, className); + return instrumentContext.exist(classLoader, className, null); } + @Override public InterceptorScope getInterceptorScope(String scopeName) { checkOpen(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/InstrumentEngine.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/InstrumentEngine.java index 221e871fba38..f35d3f25c1e5 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/InstrumentEngine.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/InstrumentEngine.java @@ -20,6 +20,7 @@ import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; import com.navercorp.pinpoint.bootstrap.instrument.NotFoundInstrumentException; +import java.security.ProtectionDomain; import java.util.jar.JarFile; /** @@ -28,9 +29,7 @@ */ public interface InstrumentEngine { - InstrumentClass getClass(InstrumentContext instrumentContext, ClassLoader classLoader, String classInternalName, byte[] classFileBuffer) throws NotFoundInstrumentException; - - boolean hasClass(ClassLoader classLoader, String classBinaryName); + InstrumentClass getClass(InstrumentContext instrumentContext, ClassLoader classLoader, String classInternalName, ProtectionDomain protectionDomain, byte[] classFileBuffer) throws NotFoundInstrumentException; void appendToBootstrapClassPath(JarFile jarFile); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JavassistClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JavassistClass.java deleted file mode 100644 index be67fab3b1f7..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JavassistClass.java +++ /dev/null @@ -1,738 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import com.navercorp.pinpoint.bootstrap.instrument.*; -import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; -import com.navercorp.pinpoint.common.util.ArrayUtils; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; -import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; -import javassist.CannotCompileException; -import javassist.ClassPool; -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.CtConstructor; -import javassist.CtField; -import javassist.CtMethod; -import javassist.CtNewMethod; -import javassist.Modifier; -import javassist.NotFoundException; -import javassist.bytecode.MethodInfo; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetConstructor; -import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetConstructors; -import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetFilter; -import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetMethod; -import com.navercorp.pinpoint.bootstrap.interceptor.annotation.TargetMethods; -import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExecutionPolicy; -import com.navercorp.pinpoint.bootstrap.plugin.ObjectFactory; -import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.exception.PinpointException; -import com.navercorp.pinpoint.profiler.instrument.AccessorAnalyzer.AccessorDetails; -import com.navercorp.pinpoint.profiler.instrument.GetterAnalyzer.GetterDetails; -import com.navercorp.pinpoint.profiler.instrument.SetterAnalyzer.SetterDetails; -import com.navercorp.pinpoint.profiler.instrument.aspect.AspectWeaverClass; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.objectfactory.AutoBindingObjectFactory; -import com.navercorp.pinpoint.profiler.objectfactory.InterceptorArgumentProvider; -import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; - -/** - * @author emeroad - * @author netspider - * @author minwoo.jung - */ -public class JavassistClass implements InstrumentClass { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - - private final ObjectBinderFactory objectBinderFactory; - private final InstrumentContext pluginContext; - - private final InterceptorRegistryBinder interceptorRegistryBinder; - private final ApiMetaDataService apiMetaDataService; - private final ClassLoader classLoader; - - private final CtClass ctClass; - private static final String FIELD_PREFIX = "_$PINPOINT$_"; - private static final String SETTER_PREFIX = "_$PINPOINT$_set"; - private static final String GETTER_PREFIX = "_$PINPOINT$_get"; - - - public JavassistClass(ObjectBinderFactory objectBinderFactory, InstrumentContext pluginContext, InterceptorRegistryBinder interceptorRegistryBinder, ApiMetaDataService apiMetaDataService, ClassLoader classLoader, CtClass ctClass) { - if (objectBinderFactory == null) { - throw new NullPointerException("objectBinderFactory must not be null"); - } - if (pluginContext == null) { - throw new NullPointerException("pluginContext must not be null"); - } - if (apiMetaDataService == null) { - throw new NullPointerException("apiMetaDataService must not be null"); - } - this.objectBinderFactory = objectBinderFactory; - this.pluginContext = pluginContext; - this.ctClass = ctClass; - this.interceptorRegistryBinder = interceptorRegistryBinder; - this.apiMetaDataService = apiMetaDataService; - this.classLoader = classLoader; - } - - public ClassLoader getClassLoader() { - return classLoader; - } - - @Override - public boolean isInterceptable() { - return !ctClass.isInterface() && !ctClass.isAnnotation() && !ctClass.isModified(); - } - - @Override - public boolean isInterface() { - return this.ctClass.isInterface(); - } - - @Override - public String getName() { - return this.ctClass.getName(); - } - - @Override - public String getSuperClass() { - return this.ctClass.getClassFile2().getSuperclass(); - } - - @Override - public String[] getInterfaces() { - return this.ctClass.getClassFile2().getInterfaces(); - } - - private static CtMethod getCtMethod0(CtClass ctClass, String methodName, String[] parameterTypes) { - final String jvmSignature = JavaAssistUtils.javaTypeToJvmSignature(parameterTypes); - - for (CtMethod method : ctClass.getDeclaredMethods()) { - if (!method.getName().equals(methodName)) { - continue; - } - final String descriptor = method.getMethodInfo2().getDescriptor(); - if (descriptor.startsWith(jvmSignature)) { - return method; - } - } - - return null; - } - - @Override - public InstrumentMethod getDeclaredMethod(String name, String... parameterTypes) { - CtMethod method = getCtMethod0(ctClass, name, parameterTypes); - if (method == null) { - return null; - } - return new JavassistMethod(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService, this, method); - } - - @Override - public List getDeclaredMethods() { - return getDeclaredMethods(MethodFilters.ACCEPT_ALL); - } - - @Override - public List getDeclaredMethods(MethodFilter methodFilter) { - if (methodFilter == null) { - throw new NullPointerException("methodFilter must not be null"); - } - final CtMethod[] declaredMethod = ctClass.getDeclaredMethods(); - final List candidateList = new ArrayList(declaredMethod.length); - for (CtMethod ctMethod : declaredMethod) { - final InstrumentMethod method = new JavassistMethod(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService, this, ctMethod); - if (methodFilter.accept(method)) { - candidateList.add(method); - } - } - - return candidateList; - } - - private CtConstructor getCtConstructor0(String[] parameterTypes) { - final String jvmSignature = JavaAssistUtils.javaTypeToJvmSignature(parameterTypes); - // constructor return type is void - for (CtConstructor constructor : ctClass.getDeclaredConstructors()) { - final String descriptor = constructor.getMethodInfo2().getDescriptor(); - // skip return type check - if (descriptor.startsWith(jvmSignature) && constructor.isConstructor()) { - return constructor; - } - } - - return null; - } - - @Override - public InstrumentMethod getConstructor(String... parameterTypes) { - CtConstructor constructor = getCtConstructor0(parameterTypes); - if (constructor == null) { - return null; - } - - return new JavassistMethod(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService, this, constructor); - } - - @Override - public boolean hasDeclaredMethod(String methodName, String... args) { - return getCtMethod0(ctClass, methodName, args) != null; - } - - @Override - public boolean hasMethod(String methodName, String... parameterTypes) { - final String jvmSignature = JavaAssistUtils.javaTypeToJvmSignature(parameterTypes); - - for (CtMethod method : ctClass.getMethods()) { - if (!method.getName().equals(methodName)) { - continue; - } - final String descriptor = method.getMethodInfo2().getDescriptor(); - if (descriptor.startsWith(jvmSignature)) { - return true; - } - } - - return false; - } - - @Override - public boolean hasEnclosingMethod(String methodName, String... parameterTypes) { - CtBehavior behavior; - try { - behavior = ctClass.getEnclosingBehavior(); - } catch (NotFoundException ignored) { - return false; - } - - if(behavior == null) { - return false; - } - - final MethodInfo methodInfo = behavior.getMethodInfo2(); - if (!methodInfo.getName().equals(methodName)) { - return false; - } - - final String jvmSignature = JavaAssistUtils.javaTypeToJvmSignature(parameterTypes); - if (methodInfo.getDescriptor().startsWith(jvmSignature)) { - return true; - } - - return false; - } - - @Override - public boolean hasConstructor(String... parameterTypeArray) { - final String signature = JavaAssistUtils.javaTypeToJvmSignature(parameterTypeArray, "void"); - try { - CtConstructor c = ctClass.getConstructor(signature); - return c != null; - } catch (NotFoundException e) { - return false; - } - } - - @Override - public boolean hasField(String name, String type) { - try { - String vmType = null; - if (type != null) { - vmType = JavaAssistUtils.toJvmSignature(type); - } - - ctClass.getField(name, vmType); - } catch (NotFoundException e) { - return false; - } - - return true; - } - - @Override - public boolean hasField(String name) { - return hasField(name, null); - } - - @Override - public void weave(String adviceClassName) throws InstrumentException { - pluginContext.injectClass(classLoader, adviceClassName); - - CtClass adviceClass; - try { - adviceClass = getCtClass(adviceClassName); - } catch (NotFoundException e) { - throw new NotFoundInstrumentException(adviceClassName + " not found. Caused:" + e.getMessage(), e); - } - try { - AspectWeaverClass weaverClass = new AspectWeaverClass(); - weaverClass.weaving(ctClass, adviceClass); - } catch (CannotCompileException e) { - throw new InstrumentException("weaving fail. sourceClassName:" + ctClass.getName() + " adviceClassName:" + adviceClassName + " Caused:" + e.getMessage(), e); - } catch (NotFoundException e) { - throw new InstrumentException("weaving fail. sourceClassName:" + ctClass.getName() + " adviceClassName:" + adviceClassName + " Caused:" + e.getMessage(), e); - } - } - - @Override - public InstrumentMethod addDelegatorMethod(String methodName, String... paramTypes) throws InstrumentException { - if (getCtMethod0(ctClass, methodName, paramTypes) != null) { - throw new InstrumentException(getName() + "already have method(" + methodName + ")."); - } - - try { - final CtClass superClass = ctClass.getSuperclass(); - CtMethod superMethod = getCtMethod0(superClass, methodName, paramTypes); - - if (superMethod == null) { - throw new NotFoundInstrumentException(methodName + Arrays.toString(paramTypes) + " is not found in " + superClass.getName()); - } - - CtMethod delegatorMethod = CtNewMethod.delegator(superMethod, ctClass); - ctClass.addMethod(delegatorMethod); - - return new JavassistMethod(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService, this, delegatorMethod); - } catch (NotFoundException ex) { - throw new InstrumentException(getName() + "don't have super class(" + getSuperClass() + "). Cause:" + ex.getMessage(), ex); - } catch (CannotCompileException ex) { - throw new InstrumentException(methodName + " addDelegatorMethod fail. Cause:" + ex.getMessage(), ex); - } - } - - @Override - public byte[] toBytecode() { - try { - byte[] bytes = ctClass.toBytecode(); - ctClass.detach(); - return bytes; - } catch (IOException e) { - logger.info("IoException class:{} Caused:{}", ctClass.getName(), e.getMessage(), e); - } catch (CannotCompileException e) { - logger.info("CannotCompileException class:{} Caused:{}", ctClass.getName(), e.getMessage(), e); - } - return null; - } - - @Override - public void addField(String accessorTypeName) throws InstrumentException { - addField0(accessorTypeName, null); - } - - private void addField0(String accessorTypeName, String initValExp) throws InstrumentException { - try { - Class accessorType = pluginContext.injectClass(classLoader, accessorTypeName); - final AccessorAnalyzer accessorAnalyzer = new AccessorAnalyzer(); - final AccessorDetails accessorDetails = accessorAnalyzer.analyze(accessorType); - - Class fieldType = accessorDetails.getFieldType(); - String fieldTypeName = JavaAssistUtils.javaClassNameToObjectName(fieldType.getName()); - - final CtField newField = CtField.make("private " + fieldTypeName + " " + FIELD_PREFIX + JavaAssistUtils.javaClassNameToVariableName(accessorTypeName) + ";", ctClass); - - if (initValExp == null) { - ctClass.addField(newField); - } else { - ctClass.addField(newField, initValExp); - } - final CtClass accessorInterface = getCtClass(accessorTypeName); - ctClass.addInterface(accessorInterface); - - CtMethod getterMethod = CtNewMethod.getter(accessorDetails.getGetter().getName(), newField); - ctClass.addMethod(getterMethod); - - CtMethod setterMethod = CtNewMethod.setter(accessorDetails.getSetter().getName(), newField); - ctClass.addMethod(setterMethod); - } catch (Exception e) { - throw new InstrumentException("Failed to add field with accessor [" + accessorTypeName + "]. Cause:" + e.getMessage(), e); - } - } - - @Override - public void addGetter(String getterTypeName, String fieldName) throws InstrumentException { - try { - - Class getterType = pluginContext.injectClass(classLoader, getterTypeName); - GetterAnalyzer getterAnalyzer = new GetterAnalyzer(); - GetterDetails getterDetails = getterAnalyzer.analyze(getterType); - - CtField field = ctClass.getField(fieldName); - String fieldTypeName = JavaAssistUtils.javaClassNameToObjectName(getterDetails.getFieldType().getName()); - - if (!field.getType().getName().equals(fieldTypeName)) { - throw new IllegalArgumentException("Return type of the getter is different with the field type. getterMethod: " + getterDetails.getGetter() + ", fieldType: " + field.getType().getName()); - } - - CtMethod getterMethod = CtNewMethod.getter(getterDetails.getGetter().getName(), field); - - if (getterMethod.getDeclaringClass() != ctClass) { - getterMethod = CtNewMethod.copy(getterMethod, ctClass, null); - } - - ctClass.addMethod(getterMethod); - - CtClass ctInterface = getCtClass(getterTypeName); - ctClass.addInterface(ctInterface); - } catch (Exception e) { - throw new InstrumentException("Failed to add getter: " + getterTypeName, e); - } - } - - private CtClass getCtClass(String className) throws NotFoundException { - final ClassPool classPool = ctClass.getClassPool(); - return classPool.get(className); - } - - @Override - public void addSetter(String setterTypeName, String fieldName) throws InstrumentException { - this.addSetter(setterTypeName, fieldName, false); - } - - @Override - public void addSetter(String setterTypeName, String fieldName, boolean removeFinalFlag) throws InstrumentException { - try { - Class setterType = pluginContext.injectClass(classLoader, setterTypeName); - - SetterAnalyzer setterAnalyzer = new SetterAnalyzer(); - SetterDetails setterDetails = setterAnalyzer.analyze(setterType); - - CtField field = ctClass.getField(fieldName); - String fieldTypeName = JavaAssistUtils.javaClassNameToObjectName(setterDetails.getFieldType().getName()); - - if (!field.getType().getName().equals(fieldTypeName)) { - throw new IllegalArgumentException("Argument type of the setter is different with the field type. setterMethod: " + setterDetails.getSetter() + ", fieldType: " + field.getType().getName()); - } - - final int originalModifiers = field.getModifiers(); - if (Modifier.isStatic(originalModifiers)) { - throw new IllegalArgumentException("Cannot add setter to static fields. setterMethod: " + setterDetails.getSetter().getName() + ", fieldName: " + fieldName); - } - - boolean finalRemoved = false; - if (Modifier.isFinal(originalModifiers)) { - if (!removeFinalFlag) { - throw new IllegalArgumentException("Cannot add setter to final field. setterMethod: " + setterDetails.getSetter().getName() + ", fieldName: " + fieldName); - } else { - final int modifiersWithFinalRemoved = Modifier.clear(originalModifiers, Modifier.FINAL); - field.setModifiers(modifiersWithFinalRemoved); - finalRemoved = true; - } - } - - try { - CtMethod setterMethod = CtNewMethod.setter(setterDetails.getSetter().getName(), field); - if (setterMethod.getDeclaringClass() != ctClass) { - setterMethod = CtNewMethod.copy(setterMethod, ctClass, null); - } - ctClass.addMethod(setterMethod); - - CtClass ctInterface = getCtClass(setterTypeName); - ctClass.addInterface(ctInterface); - } - catch (Exception e) { - if (finalRemoved) { - field.setModifiers(originalModifiers); - } - throw e; - } - } catch (Exception e) { - throw new InstrumentException("Failed to add setter: " + setterTypeName, e); - } - - } - - @Override - public int addInterceptor(String interceptorClassName) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - return addInterceptor0(interceptorClassName, null, null, null); - } - @Override - public int addInterceptor(String interceptorClassName, Object[] constructorArgs) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - return addInterceptor0(interceptorClassName, constructorArgs, null, null); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, String scopeName) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - final InterceptorScope interceptorScope = pluginContext.getInterceptorScope(scopeName); - return addInterceptor0(interceptorClassName, null, interceptorScope, ExecutionPolicy.BOUNDARY); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, InterceptorScope scope) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scope, "scope must not be null"); - return addInterceptor0(interceptorClassName, null, scope, ExecutionPolicy.BOUNDARY); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, Object[] constructorArgs, String scopeName) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - final InterceptorScope interceptorScope = pluginContext.getInterceptorScope(scopeName); - return addInterceptor0(interceptorClassName, constructorArgs, interceptorScope, ExecutionPolicy.BOUNDARY); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, Object[] constructorArgs, InterceptorScope scope) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scope, "scope must not be null"); - return addInterceptor0(interceptorClassName, constructorArgs, scope, ExecutionPolicy.BOUNDARY); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, String scopeName, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - final InterceptorScope interceptorScope = pluginContext.getInterceptorScope(scopeName); - return addInterceptor0(interceptorClassName, null, interceptorScope, executionPolicy); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scope, "scope must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - return addInterceptor0(interceptorClassName, null, scope, executionPolicy); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, Object[] constructorArgs, String scopeName, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - final InterceptorScope interceptorScope = pluginContext.getInterceptorScope(scopeName); - return addInterceptor0(interceptorClassName, constructorArgs, interceptorScope, executionPolicy); - } - - - @Override - public int addScopedInterceptor(String interceptorClassName, Object[] constructorArgs, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scope, "scope must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - return addInterceptor0(interceptorClassName, constructorArgs, scope, executionPolicy); - } - - private int addInterceptor0(String interceptorClassName, Object[] constructorArgs, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - - int interceptorId = -1; - final Class interceptorType = pluginContext.injectClass(classLoader, interceptorClassName); - - - final TargetMethods targetMethods = interceptorType.getAnnotation(TargetMethods.class); - if (targetMethods != null) { - for (TargetMethod m : targetMethods.value()) { - interceptorId = addInterceptor0(m, interceptorClassName, constructorArgs, scope, executionPolicy); - } - } - - final TargetMethod targetMethod = interceptorType.getAnnotation(TargetMethod.class); - if (targetMethod != null) { - interceptorId = addInterceptor0(targetMethod, interceptorClassName, constructorArgs, scope, executionPolicy); - } - - final TargetConstructors targetConstructors = interceptorType.getAnnotation(TargetConstructors.class); - if (targetConstructors != null) { - for (TargetConstructor c : targetConstructors.value()) { - interceptorId = addInterceptor0(c, interceptorClassName, scope, executionPolicy, constructorArgs); - } - } - - final TargetConstructor targetConstructor = interceptorType.getAnnotation(TargetConstructor.class); - if (targetConstructor != null) { - interceptorId = addInterceptor0(targetConstructor, interceptorClassName, scope, executionPolicy, constructorArgs); - } - - final TargetFilter targetFilter = interceptorType.getAnnotation(TargetFilter.class); - if (targetFilter != null) { - interceptorId = addInterceptor0(targetFilter, interceptorClassName, scope, executionPolicy, constructorArgs); - } - - if (interceptorId == -1) { - throw new PinpointException("No target is specified. At least one of @Targets, @TargetMethod, @TargetConstructor, @TargetFilter must present. interceptor: " + interceptorClassName); - } - - return interceptorId; - } - - private int addInterceptor0(TargetConstructor c, String interceptorClassName, InterceptorScope scope, ExecutionPolicy executionPolicy, Object... constructorArgs) throws InstrumentException { - final InstrumentMethod constructor = getConstructor(c.value()); - - if (constructor == null) { - throw new NotFoundInstrumentException("Cannot find constructor with parameter types: " + Arrays.toString(c.value())); - } - // TODO casting fix - return ((JavassistMethod)constructor).addInterceptorInternal(interceptorClassName, constructorArgs, scope, executionPolicy); - } - - private int addInterceptor0(TargetMethod m, String interceptorClassName, Object[] constructorArgs, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - InstrumentMethod method = getDeclaredMethod(m.name(), m.paramTypes()); - - if (method == null) { - throw new NotFoundInstrumentException("Cannot find method " + m.name() + " with parameter types: " + Arrays.toString(m.paramTypes())); - } - // TODO casting fix - return ((JavassistMethod)method).addInterceptorInternal(interceptorClassName, constructorArgs, scope, executionPolicy); - } - - private int addInterceptor0(TargetFilter annotation, String interceptorClassName, InterceptorScope scope, ExecutionPolicy executionPolicy, Object[] constructorArgs) throws InstrumentException { - String filterTypeName = annotation.type(); - Assert.requireNonNull(filterTypeName, "type of @TargetFilter must not be null"); - - InterceptorArgumentProvider interceptorArgumentProvider = this.objectBinderFactory.newInterceptorArgumentProvider(this); - AutoBindingObjectFactory filterFactory = this.objectBinderFactory.newAutoBindingObjectFactory(pluginContext, classLoader, interceptorArgumentProvider); - final ObjectFactory objectFactory = ObjectFactory.byConstructor(filterTypeName, (Object[]) annotation.constructorArguments()); - MethodFilter filter = (MethodFilter) filterFactory.createInstance(objectFactory); - - boolean singleton = annotation.singleton(); - int interceptorId = -1; - - for (InstrumentMethod m : getDeclaredMethods(filter)) { - if (singleton && interceptorId != -1) { - m.addInterceptor(interceptorId); - } else { - // TODO casting fix - interceptorId = ((JavassistMethod)m).addInterceptorInternal(interceptorClassName, constructorArgs, scope, executionPolicy); - } - } - - if (interceptorId == -1) { - logger.warn("No methods are intercepted. target: " + ctClass.getName(), ", interceptor: " + interceptorClassName + ", methodFilter: " + filterTypeName); - } - - return interceptorId; - } - - @Override - public int addInterceptor(MethodFilter filter, String interceptorClassName) throws InstrumentException { - Assert.requireNonNull(filter, "filter must not be null"); - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - return addScopedInterceptor0(filter, interceptorClassName, null, null, null); - } - - @Override - public int addInterceptor(MethodFilter filter, String interceptorClassName, Object[] constructorArgs) throws InstrumentException { - Assert.requireNonNull(filter, "filter must not be null"); - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - return addScopedInterceptor0(filter, interceptorClassName, constructorArgs, null, null); - } - - @Override - public int addScopedInterceptor(MethodFilter filter, String interceptorClassName, String scopeName, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(filter, "filter must not be null"); - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - final InterceptorScope interceptorScope = pluginContext.getInterceptorScope(scopeName); - return addScopedInterceptor0(filter, interceptorClassName, null, interceptorScope, executionPolicy); - } - - @Override - public int addScopedInterceptor(MethodFilter filter, String interceptorClassName, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(filter, "filter must not be null"); - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scope, "scope must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - return addScopedInterceptor0(filter, interceptorClassName, null, scope, executionPolicy); - } - - @Override - public int addScopedInterceptor(MethodFilter filter, String interceptorClassName, Object[] constructorArgs, String scopeName, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(filter, "filter must not be null"); - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - final InterceptorScope interceptorScope = pluginContext.getInterceptorScope(scopeName); - return addScopedInterceptor0(filter, interceptorClassName, null, interceptorScope, executionPolicy); - } - - @Override - public int addScopedInterceptor(MethodFilter filter, String interceptorClassName, Object[] constructorArgs, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(filter, "filter must not be null"); - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scope, "scope must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - return addScopedInterceptor0(filter, interceptorClassName, constructorArgs, scope, executionPolicy); - } - - private int addScopedInterceptor0(MethodFilter filter, String interceptorClassName, Object[] constructorArgs, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - int interceptorId = -1; - - for (InstrumentMethod m : getDeclaredMethods(filter)) { - if (interceptorId != -1) { - m.addInterceptor(interceptorId); - } else { - // TODO casting fix - interceptorId = ((JavassistMethod)m).addInterceptorInternal(interceptorClassName, constructorArgs, scope, executionPolicy); - } - } - - if (interceptorId == -1) { - logger.warn("No methods are intercepted. target: " + ctClass.getName(), ", interceptor: " + interceptorClassName + ", methodFilter: " + filter.getClass().getName()); - } - - return interceptorId; - } - - @Override - public List getNestedClasses(ClassFilter filter) { - List list = new ArrayList(); - CtClass[] nestedClasses; - try { - nestedClasses = ctClass.getNestedClasses(); - } catch (NotFoundException ex) { - return list; - } - - if (ArrayUtils.isEmpty(nestedClasses)) { - return list; - } - - for (CtClass nested : nestedClasses) { - final InstrumentClass clazz = new JavassistClass(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService, classLoader, nested); - if (filter.accept(clazz)) { - list.add(clazz); - } - } - - return list; - } - -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JavassistEngine.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JavassistEngine.java deleted file mode 100644 index acbeddb8251f..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JavassistEngine.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument; - -import java.lang.instrument.Instrumentation; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.List; -import java.util.jar.JarFile; - -import com.google.inject.Provider; -import com.navercorp.pinpoint.bootstrap.instrument.*; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; -import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; -import com.navercorp.pinpoint.profiler.plugin.PluginConfig; -import com.navercorp.pinpoint.profiler.plugin.PluginInstrumentContext; -import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; -import javassist.*; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.exception.PinpointException; -import com.navercorp.pinpoint.profiler.instrument.classpool.IsolateMultipleClassPool; -import com.navercorp.pinpoint.profiler.instrument.classpool.MultipleClassPool; -import com.navercorp.pinpoint.profiler.instrument.classpool.NamedClassPool; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; - -/** - * @author emeroad - */ -@Deprecated -public class JavassistEngine implements InstrumentEngine { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean isInfo = logger.isInfoEnabled(); - private final boolean isDebug = logger.isDebugEnabled(); - - private final Instrumentation instrumentation; - private final ObjectBinderFactory objectBinderFactory; - private final Provider apiMetaDataService; - private final MultipleClassPool childClassPool; - private final InterceptorRegistryBinder interceptorRegistryBinder; - - private final IsolateMultipleClassPool.EventListener classPoolEventListener = new IsolateMultipleClassPool.EventListener() { - @Override - public void onCreateClassPool(ClassLoader classLoader, NamedClassPool classPool) { - dumpClassLoaderLibList(classLoader, classPool); - } - - private void dumpClassLoaderLibList(ClassLoader classLoader, NamedClassPool classPool) { - if (isInfo) { - if (classLoader instanceof URLClassLoader) { - final URLClassLoader urlClassLoader = (URLClassLoader) classLoader; - final URL[] urlList = urlClassLoader.getURLs(); - if (urlList != null) { - final String classLoaderName = classLoader.getClass().getName(); - final String classPoolName = classPool.getName(); - logger.info("classLoader lib cl:{} classPool:{}", classLoaderName, classPoolName); - for (URL tempURL : urlList) { - String filePath = tempURL.getFile(); - logger.info("lib:{} ", filePath); - } - } - } - } - } - }; - - - - public JavassistEngine(Instrumentation instrumentation, ObjectBinderFactory objectBinderFactory, InterceptorRegistryBinder interceptorRegistryBinder, Provider apiMetaDataService, final List bootStrapJars) { - if (instrumentation == null) { - throw new NullPointerException("instrumentation must not be null"); - } - if (objectBinderFactory == null) { - throw new NullPointerException("objectBinderFactory must not be null"); - } - if (interceptorRegistryBinder == null) { - throw new NullPointerException("interceptorRegistryBinder must not be null"); - } - if (apiMetaDataService == null) { - throw new NullPointerException("apiMetaDataService must not be null"); - } - this.instrumentation = instrumentation; - this.objectBinderFactory = objectBinderFactory; - this.apiMetaDataService = apiMetaDataService; - this.childClassPool = new IsolateMultipleClassPool(classPoolEventListener, new IsolateMultipleClassPool.ClassPoolHandler() { - @Override - public void handleClassPool(NamedClassPool systemClassPool) { - try { - if (bootStrapJars != null) { - // append bootstarp jars - for (String bootStrapJar : bootStrapJars) { - systemClassPool.appendClassPath(bootStrapJar); - } - } - } catch (NotFoundException ex) { - throw new PinpointException("bootStrapJar not found. Caused by:" + ex.getMessage(), ex); - } - // append pinpoint classLoader - systemClassPool.appendClassPath(new ClassClassPath(this.getClass())); - } - }); - - this.interceptorRegistryBinder = interceptorRegistryBinder; - } - - - @Override - public InstrumentClass getClass(InstrumentContext instrumentContext, ClassLoader classLoader, String jvmInternalClassName, byte[] classFileBuffer) throws NotFoundInstrumentException { - if (jvmInternalClassName == null) { - throw new NullPointerException("jvmInternalClassName must not be null"); - } - - if (isDebug) { - logger.debug("Get javassist class {}", jvmInternalClassName); - } - final CtClass cc = getCtClass(instrumentContext, classLoader, jvmInternalClassName, classFileBuffer); - final ApiMetaDataService apiMetaDataService = this.apiMetaDataService.get(); - return new JavassistClass(objectBinderFactory, instrumentContext, interceptorRegistryBinder, apiMetaDataService, classLoader, cc); - } - - - private CtClass getCtClass(InstrumentContext instrumentContext, ClassLoader classLoader, String className, byte[] classfileBuffer) throws NotFoundInstrumentException { - final NamedClassPool classPool = getClassPool(classLoader); - try { - if (classfileBuffer == null) { - // compatibility code - logger.info("classFileBuffer is null className:{}", className); - return classPool.get(className); - } else { - final ClassPool contextCassPool = getContextClassPool(instrumentContext, classPool, className, classfileBuffer); - return contextCassPool.get(className); - } - } catch (NotFoundException e) { - throw new NotFoundInstrumentException(className + " class not found. Cause:" + e.getMessage(), e); - } - } - - private ClassPool getContextClassPool(InstrumentContext instrumentContext, NamedClassPool parent, String jvmInternalClassName, byte[] classfileBuffer) throws NotFoundException { - final ClassPool contextCassPool = new ClassPool(parent); - contextCassPool.childFirstLookup = true; - - final String javaName = JavaAssistUtils.jvmNameToJavaName(jvmInternalClassName); - if (isDebug) { - logger.debug("getContextClassPool() className={}", javaName); - } - final ClassPath byteArrayClassPath = new ByteArrayClassPath(javaName, classfileBuffer); - contextCassPool.insertClassPath(byteArrayClassPath); - - // append plugin jar for jboss - // plugin class not found in jboss classLoader - if (instrumentContext instanceof PluginInstrumentContext) { - final PluginConfig pluginConfig = ((PluginInstrumentContext) instrumentContext).getPluginConfig(); - if (pluginConfig != null) { - String jarPath = pluginConfig.getPluginJar().getPath(); - contextCassPool.appendClassPath(jarPath); - } - } - return contextCassPool; - } - - - public CtClass getClass(ClassLoader classLoader, String jvmInternalClassName) throws NotFoundInstrumentException { - final NamedClassPool classPool = getClassPool(classLoader); - try { - return classPool.get(jvmInternalClassName); - } catch (NotFoundException e) { - throw new NotFoundInstrumentException(jvmInternalClassName + " class not found. Cause:" + e.getMessage(), e); - } - } - - - public NamedClassPool getClassPool(ClassLoader classLoader) { - return childClassPool.getClassPool(classLoader); - } - - public boolean hasClass(String javassistClassName, ClassPool classPool) { - URL url = classPool.find(javassistClassName); - if (url == null) { - return false; - } - return true; - } - - @Override - public boolean hasClass(ClassLoader classLoader, String classBinaryName) { - ClassPool classPool = getClassPool(classLoader); - return hasClass(classBinaryName, classPool); - } - - @Override - public void appendToBootstrapClassPath(JarFile jarFile) { - if (jarFile == null) { - throw new NullPointerException("jarFile must not be null"); - } - - if (isInfo) { - logger.info("appendToBootstrapClassPath:{}", jarFile); - } - synchronized (this) { - this.instrumentation.appendToBootstrapClassLoaderSearch(jarFile); - try { - getClassPool(null).appendClassPath(jarFile.getName()); - } catch (NotFoundException e) { - throw new PinpointException(e); - } - } - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JavassistMethod.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JavassistMethod.java deleted file mode 100644 index 79ccd584fe5c..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/JavassistMethod.java +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument; - -import java.lang.reflect.Method; - -import com.navercorp.pinpoint.bootstrap.instrument.*; -import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; -import com.navercorp.pinpoint.profiler.instrument.interceptor.*; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; -import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; -import javassist.CannotCompileException; -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.CtConstructor; -import javassist.CtMethod; -import javassist.Modifier; -import javassist.NotFoundException; -import javassist.bytecode.BadBytecode; -import javassist.bytecode.Bytecode; -import javassist.bytecode.CodeAttribute; -import javassist.bytecode.CodeIterator; -import javassist.bytecode.ConstPool; -import javassist.bytecode.Descriptor; -import javassist.compiler.CompileError; -import javassist.compiler.Javac; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; -import com.navercorp.pinpoint.bootstrap.interceptor.Interceptor; -import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExecutionPolicy; -import com.navercorp.pinpoint.bootstrap.interceptor.registry.InterceptorRegistry; -import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.profiler.context.DefaultMethodDescriptor; -import com.navercorp.pinpoint.profiler.interceptor.factory.AnnotatedInterceptorFactory; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; - -public class JavassistMethod implements InstrumentMethod { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean isDebug = logger.isDebugEnabled(); - - private final ObjectBinderFactory objectBinderFactory; - private final InstrumentContext pluginContext; - - private final InterceptorRegistryBinder interceptorRegistryBinder; - private final ApiMetaDataService apiMetaDataService; - - private final CtBehavior behavior; - private final InstrumentClass declaringClass; - - private final MethodDescriptor descriptor; - // TODO fix inject InterceptorDefinitionFactory - private static final InterceptorDefinitionFactory interceptorDefinitionFactory = new InterceptorDefinitionFactory(); - - // TODO fix inject ScopeFactory - private static final ScopeFactory scopeFactory = new ScopeFactory(); - - - public JavassistMethod(ObjectBinderFactory objectBinderFactory, InstrumentContext pluginContext, InterceptorRegistryBinder interceptorRegistryBinder, ApiMetaDataService apiMetaDataService, InstrumentClass declaringClass, CtBehavior behavior) { - if (objectBinderFactory == null) { - throw new NullPointerException("objectBinderFactory must not be null"); - } - if (pluginContext == null) { - throw new NullPointerException("pluginContext must not be null"); - } - - this.objectBinderFactory = objectBinderFactory; - this.pluginContext = pluginContext; - this.interceptorRegistryBinder = interceptorRegistryBinder; - this.apiMetaDataService = apiMetaDataService; - this.behavior = behavior; - this.declaringClass = declaringClass; - - String[] parameterVariableNames = JavaAssistUtils.getParameterVariableName(behavior); - int lineNumber = JavaAssistUtils.getLineNumber(behavior); - - DefaultMethodDescriptor descriptor = new DefaultMethodDescriptor(behavior.getDeclaringClass().getName(), behavior.getName(), getParameterTypes(), parameterVariableNames); - descriptor.setLineNumber(lineNumber); - - this.descriptor = descriptor; - } - - @Override - public String getName() { - return behavior.getName(); - } - - @Override - public String[] getParameterTypes() { - return JavaAssistUtils.parseParameterSignature(behavior.getSignature()); - } - - @Override - public String getReturnType() { - if (behavior instanceof CtMethod) { - try { - return ((CtMethod) behavior).getReturnType().getName(); - } catch (NotFoundException e) { - return null; - } - } - - return null; - } - - @Override - public int getModifiers() { - return behavior.getModifiers(); - } - - @Override - public boolean isConstructor() { - return behavior instanceof CtConstructor; - } - - @Override - public MethodDescriptor getDescriptor() { - return descriptor; - } - - @Override - public int addInterceptor(String interceptorClassName) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - return addInterceptor0(interceptorClassName, null, null, null); - } - - @Override - public int addInterceptor(String interceptorClassName, Object[] constructorArgs) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - return addInterceptor0(interceptorClassName, constructorArgs, null, null); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, String scopeName) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - final InterceptorScope interceptorScope = this.pluginContext.getInterceptorScope(scopeName); - return addInterceptor0(interceptorClassName, null, interceptorScope, null); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, InterceptorScope scope) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scope, "scope must not be null"); - return addInterceptor0(interceptorClassName, null, scope, null); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, String scopeName, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - final InterceptorScope interceptorScope = this.pluginContext.getInterceptorScope(scopeName); - return addInterceptor0(interceptorClassName, null, interceptorScope, executionPolicy); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(scope, "scope must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - return addInterceptor0(interceptorClassName, null, scope, executionPolicy); - } - - - @Override - public int addScopedInterceptor(String interceptorClassName, Object[] constructorArgs, String scopeName) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - final InterceptorScope interceptorScope = this.pluginContext.getInterceptorScope(scopeName); - return addInterceptor0(interceptorClassName, constructorArgs, interceptorScope, null); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, Object[] constructorArgs, InterceptorScope scope) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scope, "scope"); - return addInterceptor0(interceptorClassName, constructorArgs, scope, null); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, Object[] constructorArgs, String scopeName, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scopeName, "scopeName must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - final InterceptorScope interceptorScope = this.pluginContext.getInterceptorScope(scopeName); - return addInterceptor0(interceptorClassName, constructorArgs, interceptorScope, executionPolicy); - } - - @Override - public int addScopedInterceptor(String interceptorClassName, Object[] constructorArgs, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - Assert.requireNonNull(interceptorClassName, "interceptorClassName must not be null"); - Assert.requireNonNull(constructorArgs, "constructorArgs must not be null"); - Assert.requireNonNull(scope, "scope must not be null"); - Assert.requireNonNull(executionPolicy, "executionPolicy must not be null"); - return addInterceptor0(interceptorClassName, constructorArgs, scope, executionPolicy); - } - - @Override - public void addInterceptor(int interceptorId) throws InstrumentException { - Interceptor interceptor = InterceptorRegistry.getInterceptor(interceptorId); - - try { - addInterceptor0(interceptor, interceptorId); - } catch (Exception e) { - throw new InstrumentException("Failed to add interceptor " + interceptor.getClass().getName() + " to " + behavior.getLongName(), e); - } - } - - // for internal api - int addInterceptorInternal(String interceptorClassName, Object[] constructorArgs, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - if (interceptorClassName == null) { - throw new NullPointerException("interceptorClassName must not be null"); - } - return addInterceptor0(interceptorClassName, constructorArgs, scope, executionPolicy); - } - - private int addInterceptor0(String interceptorClassName, Object[] constructorArgs, InterceptorScope scope, ExecutionPolicy executionPolicy) throws InstrumentException { - try { - final ClassLoader classLoader = declaringClass.getClassLoader(); - final ScopeInfo scopeInfo = scopeFactory.newScopeInfo(classLoader, pluginContext, interceptorClassName, scope, executionPolicy); - Interceptor interceptor = createInterceptor(classLoader, interceptorClassName, scopeInfo, constructorArgs); - int interceptorId = interceptorRegistryBinder.getInterceptorRegistryAdaptor().addInterceptor(interceptor); - - addInterceptor0(interceptor, interceptorId); - return interceptorId; - } catch (CannotCompileException ccex) { - throw new InstrumentException("Failed to add interceptor " + interceptorClassName + " to " + behavior.getLongName(), ccex); - } catch (NotFoundException nex) { - throw new InstrumentException("Failed to add interceptor " + interceptorClassName + " to " + behavior.getLongName(), nex); - } - } - - private Interceptor createInterceptor(ClassLoader classLoader, String interceptorClassName, ScopeInfo scopeInfo, Object[] constructorArgs) { - - AnnotatedInterceptorFactory factory = objectBinderFactory.newAnnotatedInterceptorFactory(pluginContext, false); - Interceptor interceptor = factory.getInterceptor(classLoader, interceptorClassName, constructorArgs, scopeInfo, declaringClass, this); - - return interceptor; - } - - private void addInterceptor0(Interceptor interceptor, int interceptorId) throws CannotCompileException, NotFoundException { - if (interceptor == null) { - throw new NullPointerException("interceptor must not be null"); - } - - final InterceptorDefinition interceptorDefinition = interceptorDefinitionFactory.createInterceptorDefinition(interceptor.getClass()); - - final String localVariableName = initializeLocalVariable(interceptorId); - int originalCodeOffset = insertBefore(-1, localVariableName); - - boolean localVarsInitialized = false; - - final int offset = addBeforeInterceptor(interceptorDefinition, interceptorId, originalCodeOffset); - if (offset != -1) { - localVarsInitialized = true; - originalCodeOffset = offset; - } - - addAfterInterceptor(interceptorDefinition, interceptorId, localVarsInitialized, originalCodeOffset); - } - - private String initializeLocalVariable(int interceptorId) throws CannotCompileException, NotFoundException { - - final String interceptorInstanceVar = InvokeCodeGenerator.getInterceptorVar(interceptorId); - addLocalVariable(interceptorInstanceVar, Interceptor.class); - - final StringBuilder initVars = new StringBuilder(); - initVars.append(interceptorInstanceVar); - initVars.append(" = null;"); - return initVars.toString(); - } - - private void addAfterInterceptor(InterceptorDefinition interceptorDefinition, int interceptorId, boolean localVarsInitialized, int originalCodeOffset) throws NotFoundException, CannotCompileException { - - final Class interceptorClass = interceptorDefinition.getInterceptorClass(); - final CaptureType captureType = interceptorDefinition.getCaptureType(); - if (!isAfterInterceptor(captureType)) { - return; - } - final Method interceptorMethod = interceptorDefinition.getAfterMethod(); - - if (interceptorMethod == null) { - if (isDebug) { - logger.debug("Skip adding after interceptor because the interceptor doesn't have after method: {}", interceptorClass.getName()); - } - return; - } - - InvokeAfterCodeGenerator catchGenerator = new InvokeAfterCodeGenerator(interceptorId, interceptorDefinition, declaringClass, this, apiMetaDataService, localVarsInitialized, true); - String catchCode = catchGenerator.generate(); - - if (isDebug) { - logger.debug("addAfterInterceptor catch behavior:{} code:{}", behavior.getLongName(), catchCode); - } - - CtClass throwable = behavior.getDeclaringClass().getClassPool().get("java.lang.Throwable"); - insertCatch(originalCodeOffset, catchCode, throwable, "$e"); - - - InvokeAfterCodeGenerator afterGenerator = new InvokeAfterCodeGenerator(interceptorId, interceptorDefinition, declaringClass, this, apiMetaDataService, localVarsInitialized, false); - final String afterCode = afterGenerator.generate(); - - if (isDebug) { - logger.debug("addAfterInterceptor after behavior:{} code:{}", behavior.getLongName(), afterCode); - } - - behavior.insertAfter(afterCode); - } - - private boolean isAfterInterceptor(CaptureType captureType) { - return CaptureType.AFTER == captureType || CaptureType.AROUND == captureType; - } - - private int addBeforeInterceptor(InterceptorDefinition interceptorDefinition, int interceptorId, int pos) throws CannotCompileException, NotFoundException { - final Class interceptorClass = interceptorDefinition.getInterceptorClass(); - final CaptureType captureType = interceptorDefinition.getCaptureType(); - if (!isBeforeInterceptor(captureType)) { - return -1; - } - final Method interceptorMethod = interceptorDefinition.getBeforeMethod(); - - if (interceptorMethod == null) { - if (isDebug) { - logger.debug("Skip adding before interceptorDefinition because the interceptorDefinition doesn't have before method: {}", interceptorClass.getName()); - } - return -1; - } - - final InvokeBeforeCodeGenerator generator = new InvokeBeforeCodeGenerator(interceptorId, interceptorDefinition, declaringClass, this, apiMetaDataService); - final String beforeCode = generator.generate(); - - if (isDebug) { - logger.debug("addBeforeInterceptor before behavior:{} code:{}", behavior.getLongName(), beforeCode); - } - - return insertBefore(pos, beforeCode); - } - - private boolean isBeforeInterceptor(CaptureType captureType) { - return CaptureType.BEFORE == captureType || CaptureType.AROUND == captureType; - } - - private void addLocalVariable(String name, Class type) throws CannotCompileException, NotFoundException { - final String interceptorClassName = type.getName(); - final CtClass interceptorCtClass = behavior.getDeclaringClass().getClassPool().get(interceptorClassName); - behavior.addLocalVariable(name, interceptorCtClass); - } - - private int insertBefore(int pos, String src) throws CannotCompileException { - if (isConstructor()) { - return insertBeforeConstructor(pos, src); - } else { - return insertBeforeMethod(pos, src); - } - } - - private int insertBeforeMethod(int pos, String src) throws CannotCompileException { - CtClass cc = behavior.getDeclaringClass(); - CodeAttribute ca = behavior.getMethodInfo().getCodeAttribute(); - if (ca == null) - throw new CannotCompileException("no method body"); - - CodeIterator iterator = ca.iterator(); - Javac jv = new Javac(cc); - try { - int nvars = jv.recordParams(behavior.getParameterTypes(), Modifier.isStatic(getModifiers())); - jv.recordParamNames(ca, nvars); - jv.recordLocalVariables(ca, 0); - jv.recordType(getReturnType0()); - jv.compileStmnt(src); - Bytecode b = jv.getBytecode(); - int stack = b.getMaxStack(); - int locals = b.getMaxLocals(); - - if (stack > ca.getMaxStack()) - ca.setMaxStack(stack); - - if (locals > ca.getMaxLocals()) - ca.setMaxLocals(locals); - - if (pos != -1) { - iterator.insertEx(pos, b.get()); - } else { - pos = iterator.insertEx(b.get()); - } - - iterator.insert(b.getExceptionTable(), pos); - behavior.getMethodInfo().rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); - - return pos + b.length(); - } catch (NotFoundException e) { - throw new CannotCompileException(e); - } catch (CompileError e) { - throw new CannotCompileException(e); - } catch (BadBytecode e) { - throw new CannotCompileException(e); - } - } - - private int insertBeforeConstructor(int pos, String src) throws CannotCompileException { - CtClass cc = behavior.getDeclaringClass(); - - CodeAttribute ca = behavior.getMethodInfo().getCodeAttribute(); - CodeIterator iterator = ca.iterator(); - Bytecode b = new Bytecode(behavior.getMethodInfo().getConstPool(), - ca.getMaxStack(), ca.getMaxLocals()); - b.setStackDepth(ca.getMaxStack()); - Javac jv = new Javac(b, cc); - try { - jv.recordParams(behavior.getParameterTypes(), false); - jv.recordLocalVariables(ca, 0); - jv.compileStmnt(src); - ca.setMaxStack(b.getMaxStack()); - ca.setMaxLocals(b.getMaxLocals()); - iterator.skipConstructor(); - if (pos != -1) { - iterator.insertEx(pos, b.get()); - } else { - pos = iterator.insertEx(b.get()); - } - iterator.insert(b.getExceptionTable(), pos); - behavior.getMethodInfo().rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); - - return pos + b.length(); - } - catch (NotFoundException e) { - throw new CannotCompileException(e); - } - catch (CompileError e) { - throw new CannotCompileException(e); - } - catch (BadBytecode e) { - throw new CannotCompileException(e); - } - } - - - private void insertCatch(int from, String src, CtClass exceptionType, String exceptionName) throws CannotCompileException { - CtClass cc = behavior.getDeclaringClass(); - ConstPool cp = behavior.getMethodInfo().getConstPool(); - CodeAttribute ca = behavior.getMethodInfo().getCodeAttribute(); - CodeIterator iterator = ca.iterator(); - Bytecode b = new Bytecode(cp, ca.getMaxStack(), ca.getMaxLocals()); - b.setStackDepth(1); - Javac jv = new Javac(b, cc); - try { - jv.recordParams(behavior.getParameterTypes(), Modifier.isStatic(getModifiers())); - jv.recordLocalVariables(ca, from); - int var = jv.recordVariable(exceptionType, exceptionName); - b.addAstore(var); - jv.compileStmnt(src); - - int stack = b.getMaxStack(); - int locals = b.getMaxLocals(); - - if (stack > ca.getMaxStack()) - ca.setMaxStack(stack); - - if (locals > ca.getMaxLocals()) - ca.setMaxLocals(locals); - - int len = iterator.getCodeLength(); - int pos = iterator.append(b.get()); - - ca.getExceptionTable().add(from, len, len, cp.addClassInfo(exceptionType)); - iterator.append(b.getExceptionTable(), pos); - behavior.getMethodInfo().rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); - } catch (NotFoundException e) { - throw new CannotCompileException(e); - } catch (CompileError e) { - throw new CannotCompileException(e); - } catch (BadBytecode e) { - throw new CannotCompileException(e); - } - } - - private CtClass getReturnType0() throws NotFoundException { - return Descriptor.getReturnType(behavior.getMethodInfo().getDescriptor(), - behavior.getDeclaringClass().getClassPool()); - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/aspect/AspectWeaverClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/aspect/AspectWeaverClass.java deleted file mode 100644 index c7eef0cc45f5..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/aspect/AspectWeaverClass.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument.aspect; - -import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; -import com.navercorp.pinpoint.profiler.instrument.MethodNameReplacer; -import com.navercorp.pinpoint.profiler.instrument.interceptor.CodeBuilder; - -import javassist.*; -import javassist.expr.ExprEditor; -import javassist.expr.MethodCall; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author emeroad - */ -public class AspectWeaverClass { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private static final MethodNameReplacer DEFAULT_METHOD_NAME_REPLACER = new DefaultMethodNameReplacer(); - - private final MethodNameReplacer methodNameReplacer; - - - public AspectWeaverClass() { - methodNameReplacer = DEFAULT_METHOD_NAME_REPLACER; - } - - public void weaving(CtClass sourceClass, CtClass adviceClass) throws NotFoundException, CannotCompileException { - if (logger.isInfoEnabled()) { - logger.info("weaving sourceClass:{} advice:{}", sourceClass.getName(), adviceClass.getName()); - } - if (!isAspectClass(adviceClass)) { - throw new RuntimeException("@Aspect not found. adviceClass:" + adviceClass); - } - // advice class hierarchy check, - final boolean isSubClass = adviceClass.subclassOf(sourceClass); - if (!isSubClass) { - final CtClass superClass = adviceClass.getSuperclass(); - if (!superClass.getName().equals("java.lang.Object")) { - throw new CannotCompileException("invalid class hierarchy. " + sourceClass.getName() + " adviceSuperClass:" + superClass.getName()); - } - } - - copyUtilMethod(sourceClass, adviceClass); - - final List pointCutMethodList = findAnnotationMethod(adviceClass, PointCut.class); - final List jointPointList = findAnnotationMethod(adviceClass, JointPoint.class); - - for (CtMethod adviceMethod : pointCutMethodList) { - final CtMethod sourceMethod = sourceClass.getDeclaredMethod(adviceMethod.getName(), adviceMethod.getParameterTypes()); - if (!sourceMethod.getSignature().equals(adviceMethod.getSignature())) { - throw new CannotCompileException("Signature miss match. method:" + adviceMethod.getName() + " source:" + sourceMethod.getSignature() + " advice:" + adviceMethod.getSignature()); - } - if (logger.isInfoEnabled()) { - logger.info("weaving method:{}{}", sourceMethod.getName(), sourceMethod.getSignature()); - } - weavingMethod(sourceClass, sourceMethod, adviceMethod, jointPointList, isSubClass); - } - - - } - - private void copyUtilMethod(CtClass sourceClass, CtClass adviceClass) throws CannotCompileException { - final List utilMethodList = findUtilMethod(adviceClass); - for (CtMethod method : utilMethodList) { - final CtMethod copyMethod = CtNewMethod.copy(method, method.getName(), sourceClass, null); - sourceClass.addMethod(copyMethod); - } - } - - private List findUtilMethod(CtClass adviceClass) throws CannotCompileException { - List utilMethodList = new ArrayList(); - for (CtMethod method : adviceClass.getDeclaredMethods()) { - if (method.hasAnnotation(PointCut.class) || method.hasAnnotation(JointPoint.class)) { - continue; - } - int modifiers = method.getModifiers(); - if (!Modifier.isPrivate(modifiers)) { - throw new CannotCompileException("non private UtilMethod unsupported. method:" + method.getLongName()); - } - utilMethodList.add(method); - } - return utilMethodList; - } - - private boolean isAspectClass(CtClass aspectClass) { - return aspectClass.hasAnnotation(Aspect.class); - } - - private void weavingMethod(CtClass sourceClass, CtMethod sourceMethod, CtMethod adviceMethod, List jointPointList, boolean isSubClass) throws CannotCompileException { - final CtMethod copyMethod = copyMethod(sourceClass, sourceMethod); - sourceClass.addMethod(copyMethod); - - sourceMethod.setBody(adviceMethod, null); - - sourceMethod.instrument(new JointPointMethodEditor(sourceClass, sourceMethod, copyMethod, jointPointList, isSubClass)); - } - - public class JointPointMethodEditor extends ExprEditor { - private final CtClass sourceClass; - private final CtMethod sourceMethod; - private final CtMethod replaceMethod; - private final List jointPointList; - private final boolean isSubClass; - - public JointPointMethodEditor(CtClass sourceClass, CtMethod sourceMethod, CtMethod replaceMethod, List jointPointList, boolean isSubClass) { - if (replaceMethod == null) { - throw new NullPointerException("replaceMethod must not be null"); - } - this.sourceClass = sourceClass; - this.sourceMethod = sourceMethod; - this.replaceMethod = replaceMethod; - this.jointPointList = jointPointList; - this.isSubClass = isSubClass; - } - - @Override - public void edit(MethodCall methodCall) throws CannotCompileException { - - - final boolean joinPointMethod = isJoinPointMethod(jointPointList, methodCall.getMethodName(), methodCall.getSignature()); - if (joinPointMethod) { - if (!methodCall.getSignature().equals(replaceMethod.getSignature())) { - throw new CannotCompileException("Signature miss match. method:" + sourceMethod.getName() + " source:" + sourceMethod.getSignature() + " jointPoint:" + replaceMethod.getSignature()); - } - final String invokeSource = invokeSourceMethod(); - if (logger.isDebugEnabled()) { - logger.debug("JointPoint method {}{} -> invokeOriginal:{}", methodCall.getMethodName(), methodCall.getSignature(), invokeSource); - } - methodCall.replace(invokeSource); - } else { - if (isSubClass) { - // validate super class method - try { - CtMethod method = methodCall.getMethod(); - CtClass declaringClass = method.getDeclaringClass(); - if (sourceClass.subclassOf(declaringClass)) { - sourceClass.getMethod(methodCall.getMethodName(), methodCall.getSignature()); - } - } catch (NotFoundException e) { - throw new CannotCompileException(e.getMessage(), e); - } - } - } - } - - private boolean isJoinPointMethod(List jointPointList, String methodName, String methodSignature) { - for (CtMethod method : jointPointList) { - if (method.getName().equals(methodName) && method.getSignature().equals(methodSignature)) { - return true; - } - } - return false; - } - - - private String invokeSourceMethod() { - CodeBuilder builder = new CodeBuilder(32); - if (!isVoid(replaceMethod.getSignature())) { - builder.append("$_="); - } - - builder.format("%1$s($$);", methodNameReplacer.replaceMethodName(sourceMethod.getName())); - return builder.toString(); - } - - public boolean isVoid(String signature) { - return signature.endsWith("V"); - } - } - - private CtMethod copyMethod(CtClass sourceClass, CtMethod sourceMethod) throws CannotCompileException { - - // need id? - - String copyMethodName = methodNameReplacer.replaceMethodName(sourceMethod.getName()); - - final CtMethod copy = CtNewMethod.copy(sourceMethod, copyMethodName, sourceClass, null); - - // set private - final int modifiers = copy.getModifiers(); - copy.setModifiers(Modifier.setPrivate(modifiers)); - - return copy; - - } - - - private List findAnnotationMethod(CtClass ctClass, Class annotation) { - if (ctClass == null) { - throw new NullPointerException("ctClass must not be null"); - } - if (annotation == null) { - throw new NullPointerException("annotation must not be null"); - } - - final List annotationList = new ArrayList(); - - for (CtMethod method : ctClass.getDeclaredMethods()) { - if (method.hasAnnotation(annotation)) { - annotationList.add(method); - } - } - return annotationList; - } - - public static class DefaultMethodNameReplacer implements MethodNameReplacer { - public static final String PREFIX = "__"; - public static final String POSTFIX = "_$$pinpoint"; - - public String replaceMethodName(String methodName) { - if (methodName == null) { - throw new NullPointerException("methodName must not be null"); - } - return PREFIX + methodName + POSTFIX; - } - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/BootstrapClassLoaderHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/BootstrapClassLoaderHandler.java index f55aa7834e57..1892a02c8b08 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/BootstrapClassLoaderHandler.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/BootstrapClassLoaderHandler.java @@ -16,14 +16,14 @@ package com.navercorp.pinpoint.profiler.instrument.classloading; -import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.exception.PinpointException; +import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; import com.navercorp.pinpoint.profiler.plugin.PluginConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; /** * @author Woonduk Kang(emeroad) @@ -34,65 +34,68 @@ public class BootstrapClassLoaderHandler implements ClassInjector { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final PluginConfig pluginConfig; - - private final Object lock = new Object(); - private boolean injectedToRoot = false; - + private final BootstrapCore bootstrapCore; private final InstrumentEngine instrumentEngine; + private final Object lock = new Object(); + private volatile boolean injectedToRoot = false; - public BootstrapClassLoaderHandler(PluginConfig pluginConfig, InstrumentEngine instrumentEngine) { - if (pluginConfig == null) { - throw new NullPointerException("pluginConfig must not be null"); - } - if (instrumentEngine == null) { - throw new NullPointerException("instrumentEngine must not be null"); - } - this.pluginConfig = pluginConfig; - this.instrumentEngine = instrumentEngine; + public BootstrapClassLoaderHandler(PluginConfig pluginConfig, BootstrapCore bootstrapCore, InstrumentEngine instrumentEngine) { + this.pluginConfig = Assert.requireNonNull(pluginConfig, "pluginConfig must not be null"); + this.bootstrapCore = Assert.requireNonNull(bootstrapCore, "bootstrapCore must not be null"); + this.instrumentEngine = Assert.requireNonNull(instrumentEngine, "instrumentEngine must not be null"); } @Override @SuppressWarnings("unchecked") public Class injectClass(ClassLoader classLoader, String className) { + if (classLoader != Object.class.getClassLoader()) { + throw new IllegalStateException("not BootStrapClassLoader"); + } try { - if (classLoader == null) { - return (Class) injectClass0(className); - } + return (Class) injectClass0(className); } catch (Exception e) { logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e); throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + classLoader, e); } - throw new PinpointException("invalid ClassLoader"); } - private Class injectClass0(String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { + private Class injectClass0(String className) throws IllegalArgumentException, ClassNotFoundException { appendToBootstrapClassLoaderSearch(); return Class.forName(className, false, null); } private void appendToBootstrapClassLoaderSearch() { + // DCL + if (injectedToRoot) { + return; + } synchronized (lock) { if (this.injectedToRoot == false) { - this.injectedToRoot = true; instrumentEngine.appendToBootstrapClassPath(pluginConfig.getPluginJarFile()); + // Memory visibility WARNING + // Reordering is not recommended. + this.injectedToRoot = true; } } } @Override - public InputStream getResourceAsStream(ClassLoader targetClassLoader, String classPath) { + public InputStream getResourceAsStream(ClassLoader targetClassLoader, String internalName) { try { if (targetClassLoader == null) { + if (bootstrapCore.isBootstrapPackageByInternalName(internalName)) { + return bootstrapCore.openStream(internalName); + } ClassLoader classLoader = ClassLoader.getSystemClassLoader(); if (classLoader == null) { return null; } appendToBootstrapClassLoaderSearch(); - return classLoader.getResourceAsStream(classPath); + return classLoader.getResourceAsStream(internalName); } } catch (Exception e) { - logger.warn("Failed to load plugin resource as stream {} with classLoader {}", classPath, targetClassLoader, e); + logger.warn("Failed to load plugin resource as stream {} with classLoader {}", internalName, targetClassLoader, e); return null; } logger.warn("Invalid bootstrap class loader. cl={}", targetClassLoader); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/BootstrapCore.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/BootstrapCore.java new file mode 100644 index 000000000000..5fcaedbcc85d --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/BootstrapCore.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.classloading; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.instrument.BootstrapPackage; +import com.navercorp.pinpoint.profiler.instrument.scanner.JarFileRepository; + +import java.io.InputStream; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class BootstrapCore { + private final BootstrapPackage bootstrapPackage; + private final JarFileRepository bootstrapRepository; + + + public BootstrapCore(List bootstrapJarPaths) { + Assert.requireNonNull(bootstrapJarPaths, "bootstrapJarPaths must not be null"); + + this.bootstrapRepository = new JarFileRepository(bootstrapJarPaths); + this.bootstrapPackage = new BootstrapPackage(); + } + + public boolean isBootstrapPackage(String className) { + return bootstrapPackage.isBootstrapPackage(className); + } + + public boolean isBootstrapPackageByInternalName(String internalClassName) { + return bootstrapPackage.isBootstrapPackageByInternalName(internalClassName); + } + + public InputStream openStream(String internalClassName) { + return bootstrapRepository.openStream(internalClassName); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjector.java index e6d39d4b6595..5932186ec3b2 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjector.java @@ -25,6 +25,6 @@ public interface ClassInjector { Class injectClass(ClassLoader classLoader, String className); - InputStream getResourceAsStream(ClassLoader classLoader, String classPath); + InputStream getResourceAsStream(ClassLoader classLoader, String internalName); } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjectorFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjectorFactory.java new file mode 100644 index 000000000000..d8c571261d35 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ClassInjectorFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.classloading; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; +import com.navercorp.pinpoint.profiler.plugin.PluginConfig; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClassInjectorFactory { + + private final InstrumentEngine instrumentEngine; + private final BootstrapCore bootstrapCore; + + public ClassInjectorFactory(InstrumentEngine instrumentEngine, BootstrapCore bootstrapCore) { + this.instrumentEngine = Assert.requireNonNull(instrumentEngine, "instrumentEngine must not be null"); + this.bootstrapCore = Assert.requireNonNull(bootstrapCore, "bootstrapCore must not be null"); + } + + public ClassInjector newClassInjector(PluginConfig pluginConfig) { + return new JarProfilerPluginClassInjector(pluginConfig, instrumentEngine, bootstrapCore); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DebugTransformerClassInjector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DebugTransformerClassInjector.java index 9212c8fbe99d..caf5bbf1c05e 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DebugTransformerClassInjector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DebugTransformerClassInjector.java @@ -19,14 +19,13 @@ import com.navercorp.pinpoint.exception.PinpointException; import com.navercorp.pinpoint.profiler.instrument.BootstrapPackage; -import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjector; /** * @author Woonduk Kang(emeroad) */ public class DebugTransformerClassInjector implements ClassInjector { - private final BootstrapPackage bootstrapPackage = new BootstrapPackage(); + private static final BootstrapPackage bootstrapPackage = new BootstrapPackage(); public DebugTransformerClassInjector() { } @@ -34,13 +33,13 @@ public DebugTransformerClassInjector() { @Override @SuppressWarnings("unchecked") public Class injectClass(ClassLoader classLoader, String className) { - - ClassLoader targetClassLoader = getClassLoader(classLoader); - - targetClassLoader = filterBootstrapPackage(targetClassLoader, className); + ClassLoader targetClassLoader = classLoader; + if (bootstrapPackage.isBootstrapPackage(className)) { + targetClassLoader = Object.class.getClassLoader(); + } try { - return (Class) targetClassLoader.loadClass(className); + return (Class) Class.forName(className, false, targetClassLoader); } catch (ClassNotFoundException e) { throw new PinpointException("ClassNo class " + className + " with classLoader " + classLoader, e); } @@ -48,12 +47,12 @@ public Class injectClass(ClassLoader classLoader, String classN @Override - public InputStream getResourceAsStream(ClassLoader classLoader, String classPath) { + public InputStream getResourceAsStream(ClassLoader classLoader, String internalName) { ClassLoader targetClassLoader = getClassLoader(classLoader); - targetClassLoader = filterBootstrapPackage(targetClassLoader, classPath); + targetClassLoader = filterBootstrapPackage(targetClassLoader, internalName); - return targetClassLoader.getResourceAsStream(classPath); + return targetClassLoader.getResourceAsStream(internalName); } private static ClassLoader getClassLoader(ClassLoader classLoader) { @@ -65,7 +64,7 @@ private static ClassLoader getClassLoader(ClassLoader classLoader) { private ClassLoader filterBootstrapPackage(ClassLoader classLoader, String classPath) { - if (bootstrapPackage.isBootstrapPackage(classPath)) { + if (bootstrapPackage.isBootstrapPackageByInternalName(classPath)) { return ClassLoader.getSystemClassLoader(); } return classLoader; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DefineClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DefineClass.java new file mode 100644 index 000000000000..70876dce5395 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DefineClass.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.classloading; + + +/** + * @author Woonduk Kang(emeroad) + */ +interface DefineClass { + Class defineClass(ClassLoader classLoader, String className, byte[] b); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DefineClassFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DefineClassFactory.java new file mode 100644 index 000000000000..1c1bf43a7ee0 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/DefineClassFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.classloading; + +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.JvmVersion; + +import java.lang.reflect.Constructor; + +/** + * @author Woonduk Kang(emeroad) + */ +final class DefineClassFactory { + private static final DefineClass defineClass = newDefineClass(); + + private static DefineClass newDefineClass() { + final JvmVersion version = JvmUtils.getVersion(); + if (version.onOrAfter(JvmVersion.JAVA_9)) { + final ClassLoader agentClassLoader = DefineClassFactory.class.getClassLoader(); + final String name = "com.navercorp.pinpoint.profiler.instrument.classloading.Java9DefineClass"; + try { + Class defineClassClazz = (Class) agentClassLoader.loadClass(name); + Constructor constructor = defineClassClazz.getDeclaredConstructor(); + return constructor.newInstance(); + } catch (Exception e) { + throw new IllegalStateException(name + " create fail Caused by:" + e.getMessage(), e); + } + } + + return new ReflectionDefineClass(); + } + + static DefineClass getDefineClass() { + return defineClass; + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjector.java index 93fbddd11eec..5daa9ab53804 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjector.java @@ -30,27 +30,20 @@ * @author Jongho Moon * @author jaehong.kim */ -public class JarProfilerPluginClassInjector implements PluginClassInjector { +public class JarProfilerPluginClassInjector implements ClassInjector { private final Logger logger = LoggerFactory.getLogger(JarProfilerPluginClassInjector.class); private final ClassInjector bootstrapClassLoaderHandler; private final ClassInjector urlClassLoaderHandler; private final ClassInjector plainClassLoaderHandler; - private final PluginConfig pluginConfig; - public JarProfilerPluginClassInjector(PluginConfig pluginConfig, InstrumentEngine instrumentEngine) { + public JarProfilerPluginClassInjector(PluginConfig pluginConfig, InstrumentEngine instrumentEngine, BootstrapCore bootstrapCore) { if (pluginConfig == null) { throw new NullPointerException("pluginConfig must not be null"); } - this.bootstrapClassLoaderHandler = new BootstrapClassLoaderHandler(pluginConfig, instrumentEngine); - this.urlClassLoaderHandler = new URLClassLoaderHandler(pluginConfig); - this.plainClassLoaderHandler = new PlainClassLoaderHandler(pluginConfig); - this.pluginConfig = pluginConfig; - } - - @Override - public PluginConfig getPluginConfig() { - return pluginConfig; + this.bootstrapClassLoaderHandler = new BootstrapClassLoaderHandler(pluginConfig, bootstrapCore, instrumentEngine); + this.urlClassLoaderHandler = new URLClassLoaderHandler(pluginConfig, bootstrapCore); + this.plainClassLoaderHandler = new PlainClassLoaderHandler(pluginConfig, bootstrapCore); } @Override @@ -72,18 +65,18 @@ public Class injectClass(ClassLoader classLoader, String classN } } - public InputStream getResourceAsStream(ClassLoader targetClassLoader, String classPath) { + public InputStream getResourceAsStream(ClassLoader targetClassLoader, String internalName) { try { if (targetClassLoader == null) { - return bootstrapClassLoaderHandler.getResourceAsStream(null, classPath); + return bootstrapClassLoaderHandler.getResourceAsStream(null, internalName); } else if (targetClassLoader instanceof URLClassLoader) { final URLClassLoader urlClassLoader = (URLClassLoader) targetClassLoader; - return urlClassLoaderHandler.getResourceAsStream(urlClassLoader, classPath); + return urlClassLoaderHandler.getResourceAsStream(urlClassLoader, internalName); } else { - return plainClassLoaderHandler.getResourceAsStream(targetClassLoader, classPath); + return plainClassLoaderHandler.getResourceAsStream(targetClassLoader, internalName); } } catch (Throwable e) { - logger.warn("Failed to load plugin resource as stream {} with classLoader {}", classPath, targetClassLoader, e); + logger.warn("Failed to load plugin resource as stream {} with classLoader {}", internalName, targetClassLoader, e); return null; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/LegacyProfilerPluginClassInjector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/LegacyProfilerPluginClassInjector.java deleted file mode 100644 index 09f97827c12e..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/LegacyProfilerPluginClassInjector.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.profiler.instrument.classloading; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collection; - -import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjector; -import javassist.CannotCompileException; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.LoaderClassPath; -import javassist.NotFoundException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.exception.PinpointException; - -/** - * @deprecated Since 1.6.1 - * @author Jongho Moon - */ -@Deprecated -public class LegacyProfilerPluginClassInjector implements ClassInjector { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private static final Method DEFINE_CLASS; - - static { - try { - DEFINE_CLASS = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); - DEFINE_CLASS.setAccessible(true); - } catch (Exception e) { - throw new PinpointException("Cannot access ClassLoader.defineClass(String, byte[], int, int)", e); - } - } - - private final ClassLoader sourceClassLoader; - - public LegacyProfilerPluginClassInjector(ClassLoader sourceClassLoader) { - if (sourceClassLoader == null) { - throw new NullPointerException("sourceClassLoader must not be null"); - } - this.sourceClassLoader = sourceClassLoader; - } - - @Override - @SuppressWarnings("unchecked") - public Class injectClass(ClassLoader classLoader, String className) { - - classLoader = getClassLoader(classLoader); - - try { - return (Class)loadFromOtherClassLoader(classLoader, className); - } catch (Exception e) { - logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e); - throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + classLoader, e); - } - } - - private Class loadFromOtherClassLoader(ClassLoader classLoader, String className) throws NotFoundException, IllegalArgumentException, IOException, CannotCompileException, IllegalAccessException, InvocationTargetException { - ClassPool pool = new ClassPool(); - - pool.appendClassPath(new LoaderClassPath(classLoader)); - pool.appendClassPath(new LoaderClassPath(sourceClassLoader)); - - return loadFromOtherClassLoader(pool, classLoader, className); - } - - private Class loadFromOtherClassLoader(ClassPool pool, ClassLoader classLoader, String className) throws NotFoundException, IOException, CannotCompileException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { - Class c = null; - - try { - c = classLoader.loadClass(className); - } catch (ClassNotFoundException ignore) { - - } - - if (c != null) { - return c; - } - - CtClass ct = pool.get(className); - - if (ct == null) { - throw new NotFoundException(className); - } - - - CtClass superClass = ct.getSuperclass(); - - if (superClass != null) { - loadFromOtherClassLoader(pool, classLoader, superClass.getName()); - } - - CtClass[] interfaces = ct.getInterfaces(); - - for (CtClass i : interfaces) { - loadFromOtherClassLoader(pool, classLoader, i.getName()); - } - - Collection refs = ct.getRefClasses(); - - for (String ref : refs) { - try { - loadFromOtherClassLoader(pool, classLoader, ref); - } catch (NotFoundException e) { - logger.warn("Skip a referenced class because of NotFoundException : ", e); - } - } - - byte[] bytes = ct.toBytecode(); - return (Class)DEFINE_CLASS.invoke(classLoader, ct.getName(), bytes, 0, bytes.length); - } - - @Override - public InputStream getResourceAsStream(ClassLoader classLoader, String classPath) { - - classLoader = getClassLoader(classLoader); - - return classLoader.getResourceAsStream(classPath); - } - - private static ClassLoader getClassLoader(ClassLoader classLoader) { - if (classLoader == null) { - return ClassLoader.getSystemClassLoader(); - } - return classLoader; - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandler.java index caec30b914e1..7e4903e0895c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandler.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,9 @@ package com.navercorp.pinpoint.profiler.instrument.classloading; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.common.util.jsr166.ConcurrentWeakHashMap; import com.navercorp.pinpoint.exception.PinpointException; -import com.navercorp.pinpoint.profiler.instrument.BootstrapPackage; import com.navercorp.pinpoint.profiler.instrument.classreading.SimpleClassMetadata; import com.navercorp.pinpoint.profiler.instrument.classreading.SimpleClassMetadataReader; import com.navercorp.pinpoint.profiler.plugin.ClassLoadingChecker; @@ -32,9 +32,6 @@ import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - import java.util.HashMap; import java.util.List; import java.util.Map; @@ -49,40 +46,34 @@ public class PlainClassLoaderHandler implements ClassInjector { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); - private static final Method DEFINE_CLASS; private final JarReader pluginJarReader; - private final BootstrapPackage bootstrapPackage = new BootstrapPackage(); - // TODO remove static field private static final ConcurrentMap classLoaderAttachment = new ConcurrentWeakHashMap(); - static { - try { - DEFINE_CLASS = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); - DEFINE_CLASS.setAccessible(true); - } catch (Exception e) { - throw new PinpointException("Cannot access ClassLoader.defineClass(String, byte[], int, int)", e); - } - } private final PluginConfig pluginConfig; + private final BootstrapCore bootstrapCore; + + public PlainClassLoaderHandler(PluginConfig pluginConfig, BootstrapCore bootstrapCore) { + this.pluginConfig = Assert.requireNonNull(pluginConfig, "pluginConfig must not be null"); - public PlainClassLoaderHandler(PluginConfig pluginConfig) { - if (pluginConfig == null) { - throw new NullPointerException("pluginConfig must not be null"); - } - this.pluginConfig = pluginConfig; this.pluginJarReader = new JarReader(pluginConfig.getPluginJarFile()); + this.bootstrapCore = Assert.requireNonNull(bootstrapCore, "bootstrapCore must not be null"); + } @Override @SuppressWarnings("unchecked") public Class injectClass(ClassLoader classLoader, String className) { + if (classLoader == Object.class.getClassLoader()) { + throw new IllegalStateException("BootStrapClassLoader"); + } + try { - if (bootstrapPackage.isBootstrapPackage(className)) { - ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); - return loadClass(systemClassLoader, className); + if (bootstrapCore.isBootstrapPackage(className)) { + final ClassLoader bootstrapClassLoader = Object.class.getClassLoader(); + return loadClass(bootstrapClassLoader, className); } if (!isPluginPackage(className)) { return loadClass(classLoader, className); @@ -95,30 +86,29 @@ public Class injectClass(ClassLoader classLoader, String classN } @Override - public InputStream getResourceAsStream(ClassLoader targetClassLoader, String classPath) { + public InputStream getResourceAsStream(ClassLoader targetClassLoader, String internalName) { try { - String name = JavaAssistUtils.jvmNameToJavaName(classPath); - if (bootstrapPackage.isBootstrapPackage(name)) { - ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); - if (systemClassLoader != null) { - return systemClassLoader.getResourceAsStream(classPath); - } - return null; + if (bootstrapCore.isBootstrapPackageByInternalName(internalName)) { + return bootstrapCore.openStream(internalName); } + final String name = JavaAssistUtils.jvmNameToJavaName(internalName); if (!isPluginPackage(name)) { - return targetClassLoader.getResourceAsStream(classPath); + return targetClassLoader.getResourceAsStream(internalName); } - final InputStream inputStream = getInputStream(targetClassLoader, classPath); - if (inputStream == null) { - if (logger.isInfoEnabled()) { - logger.info("can not find resource : {} {} ", classPath, pluginConfig.getPluginJarURLExternalForm()); - } - // fallback - return targetClassLoader.getResourceAsStream(classPath); + + getClassLoaderAttachment(targetClassLoader, internalName); + final InputStream inputStream = getPluginInputStream(internalName); + if (inputStream != null) { + return inputStream; + } + + if (logger.isInfoEnabled()) { + logger.info("can not find resource : {} {} ", internalName, pluginConfig.getPluginJarURLExternalForm()); } - return inputStream; + // fallback + return targetClassLoader.getResourceAsStream(internalName); } catch (Exception e) { - logger.warn("Failed to load plugin resource as stream {} with classLoader {}", classPath, targetClassLoader, e); + logger.warn("Failed to load plugin resource as stream {} with classLoader {}", internalName, targetClassLoader, e); return null; } } @@ -128,32 +118,29 @@ private boolean isPluginPackage(String className) { } - - private Class injectClass0(ClassLoader classLoader, String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + private Class injectClass0(ClassLoader classLoader, String className) throws IllegalArgumentException { if (isDebug) { logger.debug("Inject class className:{} cl:{}", className, classLoader); } final String pluginJarPath = pluginConfig.getPluginJarURLExternalForm(); final ClassLoaderAttachment attachment = getClassLoaderAttachment(classLoader, pluginJarPath); final Class findClazz = attachment.getClass(className); - if (findClazz == null) { - if (logger.isInfoEnabled()) { - logger.info("can not find class : {} {} ", className, pluginConfig.getPluginJarURLExternalForm()); - } - // fallback - return loadClass(classLoader, className); + if (findClazz != null) { + return findClazz; } - return findClazz; + if (logger.isInfoEnabled()) { + logger.info("can not find class : {} {} ", className, pluginConfig.getPluginJarURLExternalForm()); + } + // fallback + return loadClass(classLoader, className); } - private InputStream getInputStream(ClassLoader classLoader, String classPath) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + private InputStream getPluginInputStream(String classPath) throws IllegalArgumentException { if (isDebug) { - logger.debug("Get input stream className:{} cl:{}", classPath, classLoader); + logger.debug("Get input stream className:{}", classPath); } - final String pluginJarPath = pluginConfig.getPluginJarURLExternalForm(); - final ClassLoaderAttachment attachment = getClassLoaderAttachment(classLoader, pluginJarPath); try { return pluginJarReader.getInputStream(classPath); } catch(Exception ex) { @@ -176,6 +163,7 @@ private ClassLoaderAttachment getClassLoaderAttachment(ClassLoader classLoader, // } final PluginLock pluginLock = attachment.getPluginLock(pluginJarPath); +// not recommended pluginLock.isLoaded() check synchronized (pluginLock) { if (!pluginLock.isLoaded()) { pluginLock.setLoaded(); @@ -206,8 +194,11 @@ private Class loadClass(ClassLoader classLoader, String className) { if (isDebug) { logger.debug("loadClass:{}", className); } - return (Class) classLoader.loadClass(className); - + if (classLoader == Object.class.getClassLoader()) { + return (Class) Class.forName(className, false, classLoader); + } else { + return (Class) classLoader.loadClass(className); + } } catch (ClassNotFoundException ex) { if (isDebug) { logger.debug("ClassNotFound {} cl:{}", ex.getMessage(), classLoader); @@ -257,7 +248,7 @@ private SimpleClassMetadata parseClass(FileBinary fileBinary) { return classMetadata; } - private void define0(ClassLoader classLoader, ClassLoaderAttachment attachment, SimpleClassMetadata currentClass, Map classMetaMap, ClassLoadingChecker classLoadingChecker) { + private void define0(final ClassLoader classLoader, ClassLoaderAttachment attachment, SimpleClassMetadata currentClass, Map classMetaMap, ClassLoadingChecker classLoadingChecker) { if ("java.lang.Object".equals(currentClass.getClassName())) { return; } @@ -297,31 +288,17 @@ private void define0(ClassLoader classLoader, ClassLoaderAttachment attachment, } private Class defineClass(ClassLoader classLoader, SimpleClassMetadata classMetadata) { - classLoader = getClassLoader(classLoader); + if (isDebug) { logger.debug("define class:{} cl:{}", classMetadata.getClassName(), classLoader); } - // for debug - byte[] classBytes = classMetadata.getClassBinary(); - final Integer offset = 0; - final Integer length = classBytes.length; - try { - return (Class) DEFINE_CLASS.invoke(classLoader, classMetadata.getClassName(), classBytes, offset, length); - } catch (IllegalAccessException e) { - throw handleDefineClassFail(e, classLoader, classMetadata); - } catch (InvocationTargetException e) { - throw handleDefineClassFail(e, classLoader, classMetadata); - } - } - - private RuntimeException handleDefineClassFail(Throwable throwable, ClassLoader classLoader, SimpleClassMetadata classMetadata) { - logger.warn("{} define fail classMetadata:{} cl:{} Caused by:{}", classMetadata.getClassName(), classMetadata, classLoader, throwable.getMessage(), throwable); - - return new RuntimeException(classMetadata.getClassName() + " define fail Caused by:" + throwable.getMessage(), throwable); + // for debug + final String className = classMetadata.getClassName(); + final byte[] classBytes = classMetadata.getClassBinary(); + return DefineClassFactory.getDefineClass().defineClass(classLoader, className, classBytes); } - private boolean isSkipClass(final String className, final ClassLoadingChecker classLoadingChecker) { if (!isPluginPackage(className)) { if (isDebug) { @@ -391,11 +368,4 @@ public void setLoaded() { } - private static ClassLoader getClassLoader(ClassLoader classLoader) { - if (classLoader == null) { - return ClassLoader.getSystemClassLoader(); - } - return classLoader; - } - } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ReflectionDefineClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ReflectionDefineClass.java new file mode 100644 index 000000000000..0f8f992f3fcf --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/ReflectionDefineClass.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.classloading; + +import com.navercorp.pinpoint.exception.PinpointException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * @author Woonduk Kang(emeroad) + */ +final class ReflectionDefineClass implements DefineClass { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static final Method DEFINE_CLASS; + static { + try { + DEFINE_CLASS = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); + DEFINE_CLASS.setAccessible(true); + } catch (Exception e) { + throw new IllegalStateException("Cannot access ClassLoader.defineClass(String, byte[], int, int)", e); + } + } + + @Override + public final Class defineClass(ClassLoader classLoader, String name, byte[] bytes) { + if (logger.isDebugEnabled()) { + logger.debug("define class:{} cl:{}", name, classLoader); + } + try { + return (Class) DEFINE_CLASS.invoke(classLoader, name, bytes, 0, bytes.length); + } catch (IllegalAccessException e) { + throw handleDefineClassFail(classLoader, name, e); + } catch (InvocationTargetException e) { + throw handleDefineClassFail(classLoader, name, e); + } + } + + private RuntimeException handleDefineClassFail(ClassLoader classLoader, String className, Exception e) { + logger.warn("{} define fail cl:{} Caused by:{}", className, classLoader, e.getMessage(), e); + return new RuntimeException(className + " define fail Caused by:" + e.getMessage(), e); + } + + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/URLClassLoaderHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/URLClassLoaderHandler.java index 980ff833dc85..806b37e2fea0 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/URLClassLoaderHandler.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/URLClassLoaderHandler.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.instrument.classloading; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.exception.PinpointException; import com.navercorp.pinpoint.profiler.plugin.PluginConfig; import org.slf4j.Logger; @@ -43,19 +44,16 @@ public class URLClassLoaderHandler implements ClassInjector { ADD_URL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); ADD_URL.setAccessible(true); } catch (Exception e) { - throw new PinpointException("Cannot access URLClassLoader.addURL(URL)", e); + throw new IllegalStateException("Cannot access URLClassLoader.addURL(URL)", e); } } - private final URL pluginURL; - private final String pluginURLString; + private final PluginConfig pluginConfig; + private final BootstrapCore bootstrapCore; - public URLClassLoaderHandler(PluginConfig pluginConfig) { - if (pluginConfig == null) { - throw new NullPointerException("pluginConfig must not be null"); - } - this.pluginURL = pluginConfig.getPluginJar(); - this.pluginURLString = pluginURL.toExternalForm(); + public URLClassLoaderHandler(PluginConfig pluginConfig, BootstrapCore bootstrapCore) { + this.pluginConfig = Assert.requireNonNull(pluginConfig, "pluginConfig must not be null"); + this.bootstrapCore = Assert.requireNonNull(bootstrapCore, "bootstrapCore must not be null"); } @Override @@ -75,29 +73,33 @@ public Class injectClass(ClassLoader classLoader, String classN } @Override - public InputStream getResourceAsStream(ClassLoader targetClassLoader, String classPath) { + public InputStream getResourceAsStream(ClassLoader targetClassLoader, String internalName) { try { if (targetClassLoader instanceof URLClassLoader) { + if (bootstrapCore.isBootstrapPackageByInternalName(internalName)) { + return bootstrapCore.openStream(internalName); + } + final URLClassLoader urlClassLoader = (URLClassLoader) targetClassLoader; addPluginURLIfAbsent(urlClassLoader); - return targetClassLoader.getResourceAsStream(classPath); + return targetClassLoader.getResourceAsStream(internalName); } } catch (Exception e) { - logger.warn("Failed to load plugin resource as stream {} with classLoader {}", classPath, targetClassLoader, e); + logger.warn("Failed to load plugin resource as stream {} with classLoader {}", internalName, targetClassLoader, e); return null; } return null; } - private void addPluginURLIfAbsent(URLClassLoader classLoader) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { + private void addPluginURLIfAbsent(URLClassLoader classLoader) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { final URL[] urls = classLoader.getURLs(); if (urls != null) { final boolean hasPluginJar = hasPluginJar(urls); if (!hasPluginJar) { if (isDebug) { - logger.debug("add Jar:{}", pluginURLString); + logger.debug("add Jar:{}", pluginConfig.getPluginJarURLExternalForm()); } - ADD_URL.invoke(classLoader, pluginURL); + ADD_URL.invoke(classLoader, pluginConfig.getPluginJar()); } } } @@ -107,7 +109,7 @@ private boolean hasPluginJar(URL[] urls) { // if (url.equals(pluginJarURL)) { fix very slow // http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html final String externalForm = url.toExternalForm(); - if (pluginURLString.equals(externalForm)) { + if (pluginConfig.getPluginJarURLExternalForm().equals(externalForm)) { return true; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/HierarchyMultipleClassPool.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/HierarchyMultipleClassPool.java deleted file mode 100644 index cf519abee967..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/HierarchyMultipleClassPool.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument.classpool; - -import com.navercorp.pinpoint.common.util.ClassLoaderUtils; -import com.navercorp.pinpoint.profiler.util.Maps; -import javassist.ClassPath; -import javassist.LoaderClassPath; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.Deque; -import java.util.LinkedList; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * @author emeroad - */ -public class HierarchyMultipleClassPool implements MultipleClassPool { - private static final AtomicInteger ID = new AtomicInteger(); - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private static final ClassLoader SYSTEM = ClassLoader.getSystemClassLoader(); - - private final ConcurrentMap classMap; - private final NamedClassPool parentClassPool; - - - public HierarchyMultipleClassPool(NamedClassPool parentClassPool) { - if (parentClassPool == null) { - throw new NullPointerException("parentClassPool must not be null"); - } - this.classMap = Maps.newWeakConcurrentMap(); - this.parentClassPool = parentClassPool; - } - - - public HierarchyMultipleClassPool() { - this.classMap = Maps.newWeakConcurrentMap(); - this.parentClassPool = new NamedClassPool("system"); - parentClassPool.appendSystemPath(); - } - - - - @Override - public NamedClassPool getClassPool(ClassLoader classLoader) { - if (classLoader == null) { - throw new NullPointerException("classLoader must not be null"); - } - final NamedClassPool hit = this.classMap.get(classLoader); - if (hit != null) { - return hit; - } - // concurrent classPool create - prepareHierarchyClassPool(classLoader); - - final NamedClassPool classPool = this.classMap.get(classLoader); - if (classPool == null) { - throw new IllegalStateException("unexpected condition. ClassPool not found. classLoader:" + classLoader); - } - return classPool; - } - - private NamedClassPool put(ClassLoader classLoader, NamedClassPool classPool) { - final NamedClassPool exist = this.classMap.putIfAbsent(classLoader, classPool); - if (exist != null) { - return exist; - } - return classPool; - } - - - - - private NamedClassPool createClassPool(ClassLoader classLoader, NamedClassPool parentClassPool) { - String classLoaderName = classLoader.getClass().getName(); - NamedClassPool newClassPool = new NamedClassPool(parentClassPool, classLoaderName + "-" + ID.getAndIncrement()); - newClassPool.childFirstLookup = true; - - final ClassPath classPath = new LoaderClassPath(classLoader); - newClassPool.appendClassPath(classPath); - return newClassPool; - } - - private void prepareHierarchyClassPool(ClassLoader findClassLoader) { - - final Collection classLoaderHierarchyList = findClassLoaderHierarchy(findClassLoader); - logger.debug("ClassLoaderHierarchy:{}", classLoaderHierarchyList); - - NamedClassPool parentClassPool = this.parentClassPool; - for (ClassLoader classLoader : classLoaderHierarchyList) { - final NamedClassPool existClassPool = this.classMap.get(classLoader); - if (existClassPool != null) { - parentClassPool = existClassPool; - } else { - NamedClassPool classPool = createClassPool(classLoader, parentClassPool); - parentClassPool = put(classLoader, classPool); - } - } - } - - private Collection findClassLoaderHierarchy(ClassLoader classLoader) { - if (classLoader == null) { - throw new NullPointerException("classLoader must not be null"); - } - - Deque classLoaderHierarchyList = new LinkedList(); - classLoaderHierarchyList.addFirst(classLoader); - - // search classLoader; - ClassLoader parent; - while (true) { - parent = classLoader.getParent(); - if (ClassLoaderUtils.isJvmClassLoader(parent)) { - classLoaderHierarchyList.addFirst(SYSTEM); - break; - } - classLoaderHierarchyList.addFirst(parent); - classLoader = parent; - } - return classLoaderHierarchyList; - } - - - public int size() { - return this.classMap.size(); - } - - - public Collection values() { - return classMap.values(); - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/IsolateMultipleClassPool.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/IsolateMultipleClassPool.java deleted file mode 100644 index 5a3bc3a8b37d..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/IsolateMultipleClassPool.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument.classpool; - -import java.util.Collection; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicInteger; - -import javassist.ClassPath; -import javassist.LoaderClassPath; - -import com.navercorp.pinpoint.common.util.ClassLoaderUtils; -import com.navercorp.pinpoint.profiler.util.Maps; - -/** - * @author emeroad - */ -public class IsolateMultipleClassPool implements MultipleClassPool { - - private static final AtomicInteger ID = new AtomicInteger(); - - private static final ClassLoader AGENT_CLASS_LOADER = IsolateMultipleClassPool.class.getClassLoader(); - - private final NamedClassPool rootClassPool; - - private final ConcurrentMap classPoolMap; - - private final EventListener eventListener; - - public static final boolean DEFAULT_CHILD_FIRST_LOOKUP = true; - private final boolean childFirstLookup; - - - public static final EventListener EMPTY_EVENT_LISTENER = new EventListener() { - @Override - public void onCreateClassPool(ClassLoader classLoader, NamedClassPool classPool) { - } - }; - - public interface ClassPoolHandler { - void handleClassPool(NamedClassPool classPool); - } - - public interface EventListener { - void onCreateClassPool(ClassLoader classLoader, NamedClassPool classPool); - } - - public IsolateMultipleClassPool(EventListener eventListener, ClassPoolHandler systemClassPoolHandler) { - this(DEFAULT_CHILD_FIRST_LOOKUP, eventListener, systemClassPoolHandler); - } - - public IsolateMultipleClassPool() { - this(DEFAULT_CHILD_FIRST_LOOKUP, EMPTY_EVENT_LISTENER, null); - } - - public IsolateMultipleClassPool(boolean childFirstLookup, EventListener eventListener, ClassPoolHandler rootClassPoolHandler) { - if (eventListener == null) { - throw new NullPointerException("eventListener must not be null"); - } - - this.rootClassPool = createRootClassPool(rootClassPoolHandler); - this.classPoolMap = Maps.newWeakConcurrentMap(); - this.eventListener = eventListener; - this.childFirstLookup = childFirstLookup; - } - - - - private NamedClassPool createRootClassPool(ClassPoolHandler rootClassPoolHandler) { - NamedClassPool systemClassPool = new NamedClassPool("rootClassPool"); - systemClassPool.appendSystemPath(); - if (rootClassPoolHandler != null ) { - rootClassPoolHandler.handleClassPool(systemClassPool); - - } - return systemClassPool; - } - - @Override - public NamedClassPool getClassPool(ClassLoader classLoader) { - if (ClassLoaderUtils.isJvmClassLoader(classLoader)) { - return rootClassPool; - } - - if (AGENT_CLASS_LOADER == classLoader) { - throw new IllegalArgumentException("unexpected classLoader access. classLoader:" + classLoader); - } - final NamedClassPool hit = this.classPoolMap.get(classLoader); - if (hit != null) { - return hit; - } - NamedClassPool newClassPool = createClassPool(classLoader); - return put(classLoader, newClassPool); - } - - private NamedClassPool put(ClassLoader classLoader, NamedClassPool classPool) { - final NamedClassPool exist = this.classPoolMap.putIfAbsent(classLoader, classPool); - if (exist != null) { - return exist; - } - fireOnCreateClassPool(classLoader, classPool); - return classPool; - } - - private void fireOnCreateClassPool(ClassLoader classLoader, NamedClassPool classPool) { - eventListener.onCreateClassPool(classLoader, classPool); - } - - - private NamedClassPool createClassPool(ClassLoader classLoader) { - String classLoaderName = classLoader.toString(); - NamedClassPool newClassPool = new NamedClassPool(rootClassPool, classLoaderName + "-" + getNextId()); - if (childFirstLookup) { - newClassPool.childFirstLookup = true; - } - - final ClassPath classPath = new LoaderClassPath(classLoader); - newClassPool.appendClassPath(classPath); - - return newClassPool; - } - - private int getNextId() { - return ID.getAndIncrement(); - } - - - public int size() { - return this.classPoolMap.size(); - } - - // for Test - Collection values() { - return classPoolMap.values(); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("IsolateMultipleClassPool{"); - sb.append("classPoolMap=").append(classPoolMap); - sb.append('}'); - return sb.toString(); - } - - -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/MultipleClassPool.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/MultipleClassPool.java deleted file mode 100644 index 46c266ded34c..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/MultipleClassPool.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument.classpool; - -/** - * @author emeroad - */ -public interface MultipleClassPool { - - NamedClassPool getClassPool(ClassLoader classLoader); - -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/NamedClassPool.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/NamedClassPool.java deleted file mode 100644 index f7d69ebb91fc..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/NamedClassPool.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument.classpool; - -import javassist.ClassPool; - -/** - * @author emeroad - */ -public class NamedClassPool extends ClassPool { - private final String name; - - public NamedClassPool(String name) { - this.name = name; - } - - public NamedClassPool(boolean useDefaultPath, String name) { - super(useDefaultPath); - this.name = name; - } - - public NamedClassPool(ClassPool parent, String name) { - super(parent); - this.name = name; - } - - public String getName() { - return name; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("NamedClassPool{"); - sb.append("name='").append(name).append('\''); - sb.append(", super='").append(super.toString()).append('\''); - sb.append('}'); - return sb.toString(); - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/SingleClassPool.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/SingleClassPool.java deleted file mode 100644 index 7fc48e632e48..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classpool/SingleClassPool.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument.classpool; - -import javassist.ClassPath; -import javassist.LoaderClassPath; - -import java.util.Map; -import java.util.WeakHashMap; - -/** - * @author emeroad - */ -public class SingleClassPool implements MultipleClassPool { - - private static final Object EXIST = new Object(); - - private final NamedClassPool classPool; - - - private final Map checker = new WeakHashMap(); - - - public SingleClassPool() { - this.classPool = new NamedClassPool("singlePool"); - this.classPool.appendSystemPath(); - } - - @Override - public NamedClassPool getClassPool(ClassLoader classLoader) { - - synchronized (classPool) { - final Object hit = this.checker.get(classLoader); - if (hit != null) { - return classPool; - } - - this.checker.put(classLoader, EXIST); - - final ClassPath classPath = new LoaderClassPath(classLoader); - this.classPool.appendClassPath(classPath); - return classPool; - } - - } - - - - -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapper.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapper.java index 3b4407fc7d50..1a46b4fac94a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapper.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapper.java @@ -30,6 +30,7 @@ package com.navercorp.pinpoint.profiler.instrument.classreading; import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.IOUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -71,6 +72,7 @@ public ClassReaderWrapper(final ClassLoader classLoader, final String classInter // classloader and class internal name. public ClassReaderWrapper(final ClassLoader classLoader, final String classInternalName, final boolean readAttributes) throws IOException { Assert.requireNonNull(classInternalName, "classInternalName must not be null"); + ClassLoader cl = classLoader; if (cl == null) { cl = ClassLoader.getSystemClassLoader(); @@ -80,21 +82,16 @@ public ClassReaderWrapper(final ClassLoader classLoader, final String classInter } } - final InputStream in = cl.getResourceAsStream(classInternalName + ".class"); + final String classPath = classInternalName.concat(".class"); + final InputStream in = cl.getResourceAsStream(classPath); if (in == null) { throw new IOException("not found class. classLoader=" + cl + ", classInternalName=" + classInternalName); } - try { - this.classReader = new ClassReader(in); - if (readAttributes) { - readAttributes(); - } - } finally { - try { - in.close(); - } catch (IOException ignored) { - } + byte[] bytes = IOUtils.toByteArray(in); + this.classReader = new ClassReader(bytes); + if (readAttributes) { + readAttributes(); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadata.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadata.java index 7eea28aa6e18..9981b64f01ae 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadata.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadata.java @@ -35,17 +35,8 @@ public DefaultInternalClassMetadata(final String classInternalName, final String this.classInternalName = classInternalName; this.superClassInternalName = superClassInternalName; - if (interfaceInternalNames == null) { - this.interfaceInternalNames = Collections.EMPTY_LIST; - } else { - this.interfaceInternalNames = Collections.unmodifiableList(interfaceInternalNames); - } - - if (annotationInternalNames == null) { - this.annotationInternalNames = Collections.EMPTY_LIST; - } else { - this.annotationInternalNames = Collections.unmodifiableList(annotationInternalNames); - } + this.interfaceInternalNames = defaultInterfaceName(interfaceInternalNames); + this.annotationInternalNames = defaultAnnotationName(annotationInternalNames); this.isInterface = isInterface; this.isAnnotation = isAnnotation; @@ -53,6 +44,19 @@ public DefaultInternalClassMetadata(final String classInternalName, final String this.isInnerClass = isInnerClass; } + private List defaultInterfaceName(List interfaceInternalNames) { + if (interfaceInternalNames == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(interfaceInternalNames); + } + private List defaultAnnotationName(List annotationInternalNames) { + if (annotationInternalNames == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(annotationInternalNames); + } + @Override public String getClassInternalName() { return this.classInternalName; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadata.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadata.java index 6ac357c61018..d3c871d70f9a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadata.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadata.java @@ -45,19 +45,24 @@ public DefaultSimpleClassMetadata(final int version, final int accessFlag, final this.accessFlag = accessFlag; this.className = JavaAssistUtils.jvmNameToJavaName(classInternalName); + this.superClassName = defaultSuperClassName(superClassInternalName); + this.interfaceNames = defaultInterfaceName(interfaceInternalNames); + + this.classBinary = classBinary; + } + + private String defaultSuperClassName(String superClassInternalName) { if (superClassInternalName == null) { - this.superClassName = null; - } else { - this.superClassName = JavaAssistUtils.jvmNameToJavaName(superClassInternalName); + return null; } + return JavaAssistUtils.jvmNameToJavaName(superClassInternalName); + } + private List defaultInterfaceName(List interfaceInternalNames) { if (interfaceInternalNames == null) { - this.interfaceNames = Collections.EMPTY_LIST; - } else { - this.interfaceNames = Collections.unmodifiableList(JavaAssistUtils.jvmNameToJavaName(interfaceInternalNames)); + return Collections.emptyList(); } - - this.classBinary = classBinary; + return Collections.unmodifiableList(JavaAssistUtils.jvmNameToJavaName(interfaceInternalNames)); } @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReader.java index 2bda9919b3dd..083aac3fcf8f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReader.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReader.java @@ -24,12 +24,14 @@ public class InternalClassMetadataReader { private final InternalClassMetadata classMetadata; public static InternalClassMetadata readInternalClassMetadata(final byte[] classBinary) { - final InternalClassMetadataReader internalClassMetadataReader = new InternalClassMetadataReader(new ClassReaderWrapper(classBinary, true)); + final ClassReaderWrapper classReader = new ClassReaderWrapper(classBinary, true); + final InternalClassMetadataReader internalClassMetadataReader = new InternalClassMetadataReader(classReader); return internalClassMetadataReader.getInternalClassMetadata(); } public static InternalClassMetadata readInternalClassMetadata(final ClassLoader classLoader, final String classInternalName) throws IOException { - final InternalClassMetadataReader internalClassMetadataReader = new InternalClassMetadataReader(new ClassReaderWrapper(classLoader, classInternalName, true)); + final ClassReaderWrapper classReader = new ClassReaderWrapper(classLoader, classInternalName, true); + final InternalClassMetadataReader internalClassMetadataReader = new InternalClassMetadataReader(classReader); return internalClassMetadataReader.getInternalClassMetadata(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeAfterCodeGenerator.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeAfterCodeGenerator.java index 6425379b80a1..f1f67587ab39 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeAfterCodeGenerator.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeAfterCodeGenerator.java @@ -56,8 +56,6 @@ public String generate() { // // throw e; - builder.append("try { "); - if (!localVarsInitialized) { builder.format("%1$s = %2$s.getInterceptor(%3$d); ", getInterceptorVar(), getInterceptorRegistryClassName(), interceptorId); } @@ -68,8 +66,6 @@ public String generate() { builder.format(");"); } - builder.format("} catch (java.lang.Throwable _$PINPOINT_EXCEPTION$_) { %1$s.handleException(_$PINPOINT_EXCEPTION$_); }", getInterceptorInvokerHelperClassName()); - if (catchClause) { builder.append(" throw $e;"); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeBeforeCodeGenerator.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeBeforeCodeGenerator.java index bac1dcb2048a..d7f5baa828a4 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeBeforeCodeGenerator.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeBeforeCodeGenerator.java @@ -47,7 +47,6 @@ public String generate() { // InterceptorInvokerHelper.handleException(t); // } - builder.append("try { "); builder.format("%1$s = %2$s.getInterceptor(%3$d); ", getInterceptorVar(), getInterceptorRegistryClassName(), interceptorId); final Method beforeMethod = interceptorDefinition.getBeforeMethod(); @@ -57,8 +56,6 @@ public String generate() { builder.format(");"); } - builder.format("} catch (java.lang.Throwable _$PINPOINT_EXCEPTION$_) { %1$s.handleException(_$PINPOINT_EXCEPTION$_); }", getInterceptorInvokerHelperClassName()); - builder.end(); return builder.toString(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeCodeGenerator.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeCodeGenerator.java index c81bae69fab3..a41c4a361f20 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeCodeGenerator.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InvokeCodeGenerator.java @@ -78,10 +78,7 @@ protected int getApiId() { final int apiId = apiMetaDataService.cacheApi(descriptor); return apiId; } - - protected String getInterceptorInvokerHelperClassName() { - return InterceptorInvokerHelper.class.getName(); - } + protected String getInterceptorRegistryClassName() { return InterceptorRegistry.class.getName(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaClass.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaClass.java new file mode 100644 index 000000000000..e6e87c29538c --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaClass.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface LambdaClass { + + String getUnsafeClass(); + + String getUnsafeMethod(); + + String getDelegateClass(); + + String getDelegateMethod(); + + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaClassJava8.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaClassJava8.java new file mode 100644 index 000000000000..56d15463bb90 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaClassJava8.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda; + +/** + * @author Woonduk Kang(emeroad) + */ +public class LambdaClassJava8 implements LambdaClass { + + public static final String DELEGATE_CLASS = "com/navercorp/pinpoint/bootstrap/java8/lambda/UnsafeDelegatorJava8"; + + @Override + public String getUnsafeClass() { + return "sun/misc/Unsafe"; + } + + @Override + public String getUnsafeMethod() { + return "defineAnonymousClass"; + } + + @Override + public String getDelegateClass() { + return DELEGATE_CLASS; + } + + @Override + public String getDelegateMethod() { + return "defineAnonymousClass"; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaClassJava9.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaClassJava9.java new file mode 100644 index 000000000000..84c102b3641a --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaClassJava9.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda; + +/** + * @author Woonduk Kang(emeroad) + */ +public class LambdaClassJava9 implements LambdaClass { + + public static final String DELEGATE_CLASS = "com/navercorp/pinpoint/bootstrap/java9/lambda/UnsafeDelegatorJava9"; + + @Override + public String getUnsafeClass() { + return "jdk/internal/misc/Unsafe"; + } + + @Override + public String getUnsafeMethod() { + return "defineAnonymousClass"; + } + + @Override + public String getDelegateClass() { + return DELEGATE_CLASS; + } + + @Override + public String getDelegateMethod() { + return "defineAnonymousClass"; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaTransformBootloader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaTransformBootloader.java new file mode 100644 index 000000000000..7c7e25d10770 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/lambda/LambdaTransformBootloader.java @@ -0,0 +1,109 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.lambda; + +import com.navercorp.pinpoint.bootstrap.instrument.lambda.LambdaBytecodeHandler; +import com.navercorp.pinpoint.bootstrap.module.ClassFileTransformModuleAdaptor; +import com.navercorp.pinpoint.bootstrap.module.JavaModuleFactory; +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.JvmVersion; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Method; +import java.security.ProtectionDomain; +import java.util.Arrays; + +/** + * @author Woonduk Kang(emeroad) + */ +public class LambdaTransformBootloader { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + + public void transformLambdaFactory(Instrumentation instrumentation, final ClassFileTransformModuleAdaptor classFileTransformer, final JavaModuleFactory javaModuleFactory) { + logger.info("LambdaTransformBootloader.transformLambdaFactory"); + try { + redefineLambdaClass(instrumentation); + } catch (Exception e) { + logger.warn("Lambda transform fail Caused by:" + e.getMessage(), e); + } + + try { + logger.info("Add LambdaBytecodeHandler"); + final boolean debugEnabled = logger.isDebugEnabled(); + // for java9 handler + LambdaBytecodeHandler lambdaBytecodeHandler = new LambdaBytecodeHandler() { + @Override + public byte[] handleLambdaBytecode(Class hostClass, byte[] data, Object[] cpPatches) { + if (debugEnabled) { + logger.debug("handleLambdaBytecode hostClass:{} cpPatches:{}", hostClass, Arrays.toString(cpPatches)); + } + try { + final ClassLoader classLoader = hostClass.getClassLoader(); + final Object module = javaModuleFactory.getModule(hostClass); + final ProtectionDomain protectionDomain = hostClass.getProtectionDomain(); + final byte[] transform = classFileTransformer.transform(module, classLoader, null, null, protectionDomain, data); + if (transform != null) { + return transform; + } + return data; + } catch (IllegalClassFormatException e) { + return data; + } + } + }; + + Class unsafeDelegator = getUnsafeDelegator(); + Method register = unsafeDelegator.getMethod("register", LambdaBytecodeHandler.class); + register.invoke(unsafeDelegator, lambdaBytecodeHandler); + } catch (Exception e) { + logger.warn("LambdaBytecodeHandler add fail Caused by:" + e.getMessage(), e); + } + } + + private void redefineLambdaClass(Instrumentation instrumentation) throws Exception { + final Class lamdbaFactoryClazz = systemClassLoader.loadClass("java.lang.invoke.InnerClassLambdaMetafactory"); + + final Class lambdaAdaptor = this.getClass().getClassLoader().loadClass("com.navercorp.pinpoint.profiler.instrument.lambda.LambdaFactoryClassAdaptor"); + final Object instance = lambdaAdaptor.getConstructor().newInstance(); + + Method loadTransformedBytecodeMethod = lambdaAdaptor.getMethod("loadTransformedBytecode"); + byte[] transformBytecode = (byte[]) loadTransformedBytecodeMethod.invoke(instance); + + ClassDefinition classDefinition = new ClassDefinition(lamdbaFactoryClazz, transformBytecode); + instrumentation.redefineClasses(classDefinition); + } + + private Class getUnsafeDelegator() throws ClassNotFoundException { + String delegatorName = getDelegatorName(); + return systemClassLoader.loadClass(delegatorName); + } + + private String getDelegatorName() { + if (JvmUtils.getVersion().onOrAfter(JvmVersion.JAVA_9)) { + return JavaAssistUtils.jvmNameToJavaName(LambdaClassJava9.DELEGATE_CLASS); + } else { + return JavaAssistUtils.jvmNameToJavaName(LambdaClassJava8.DELEGATE_CLASS); + } + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/ClassLoaderScanner.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/ClassLoaderScanner.java new file mode 100644 index 000000000000..56f8554c380b --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/ClassLoaderScanner.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.scanner; + +import com.navercorp.pinpoint.common.util.Assert; + +import java.io.InputStream; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClassLoaderScanner implements Scanner { + private final ClassLoader classLoader; + + public ClassLoaderScanner(ClassLoader classLoader) { + if (classLoader == null) { + classLoader = ClassLoader.getSystemClassLoader(); + } + this.classLoader = classLoader; + } + + @Override + public boolean exist(String fileName) { + Assert.requireNonNull(fileName, "fileName must not be null"); + + // TODO + return classLoader.getResource(fileName) != null; + } + + @Override + public InputStream openStream(String fileName) { + Assert.requireNonNull(fileName, "fileName must not be null"); + + return classLoader.getResourceAsStream(fileName); + } + + @Override + public void close() { + + } + + @Override + public String toString() { + return "ClassLoaderScanner{" + + "classLoader=" + classLoader + + '}'; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/ClassScannerFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/ClassScannerFactory.java new file mode 100644 index 000000000000..d7fec9b10f49 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/ClassScannerFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.scanner; + +import com.navercorp.pinpoint.common.util.CodeSourceUtils; + +import java.net.URL; +import java.security.ProtectionDomain; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClassScannerFactory { + + public static Scanner newScanner(ProtectionDomain protectionDomain, ClassLoader classLoader) { + final URL codeLocation = CodeSourceUtils.getCodeLocation(protectionDomain); + if (codeLocation == null) { + return new ClassLoaderScanner(classLoader); + } + + if (codeLocation.getProtocol().equals("file")) { + final String path = codeLocation.getPath(); + final boolean isJarFile = path.endsWith(".jar"); + if (isJarFile) { + return new JarFileScanner(path); + } + final boolean isDirectory = path.endsWith("/"); + if (isDirectory) { + return new DirectoryScanner(path); + } + } + throw new IllegalArgumentException("unknown scanner type classLoader:" + classLoader + " protectionDomain:" + protectionDomain); + } + + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/DirectoryScanner.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/DirectoryScanner.java new file mode 100644 index 000000000000..a5be9afb1ff6 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/DirectoryScanner.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.scanner; + +import com.navercorp.pinpoint.common.util.Assert; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DirectoryScanner implements Scanner { + + private final String directory; + + public DirectoryScanner(String directory) { + this.directory = Assert.requireNonNull(directory, "directory must not be null"); + } + + @Override + public boolean exist(String fileName) { + Assert.requireNonNull(fileName, "fileName must not be null"); + + final String fullPath = getFullPath(fileName); + final File file = new File(fullPath); + + return file.isFile(); + } + + private String getFullPath(String fileName) { + return directory + fileName; + } + + @Override + public InputStream openStream(String fileName) { + Assert.requireNonNull(fileName, "fileName must not be null"); + + final String fullPath = getFullPath(fileName); + try { + return new FileInputStream(fullPath); + } catch (FileNotFoundException e) { + return null; + } + } + + @Override + public void close() { + + } + + @Override + public String toString() { + return "DirectoryScanner{" + + "directory='" + directory + '\'' + + '}'; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/JarFileRepository.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/JarFileRepository.java new file mode 100644 index 000000000000..e109e08575b7 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/JarFileRepository.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.scanner; + +import com.navercorp.pinpoint.common.util.Assert; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class JarFileRepository { + private final JarFileScanner[] scanners; + + + public JarFileRepository(List jarFilePathList) { + this.scanners = newJarScanner(jarFilePathList); + } + + private JarFileScanner[] newJarScanner(List jarFilePathList) { + Assert.requireNonNull(jarFilePathList, "jarFilePathList must not be null"); + + final List jarFileList = new ArrayList(jarFilePathList.size()); + for (String jarFilePath : jarFilePathList) { + JarFileScanner jarFileScanner = new JarFileScanner(jarFilePath); + jarFileList.add(jarFileScanner); + } + return jarFileList.toArray(new JarFileScanner[0]); + } + + + public InputStream openStream(String resourceName) { + Assert.requireNonNull(resourceName, "resourceName must not be null"); + + for (Scanner scanner : scanners) { + final InputStream inputStream = scanner.openStream(resourceName); + if (inputStream != null) { + return inputStream; + } + } + return null; + } + + public void close() { + for (Scanner scanner : scanners) { + scanner.close(); + } + } + + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/JarFileScanner.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/JarFileScanner.java new file mode 100644 index 000000000000..4dd542dc97de --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/JarFileScanner.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.scanner; + +import com.navercorp.pinpoint.common.util.Assert; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * @author Woonduk Kang(emeroad) + */ +public class JarFileScanner implements Scanner { + + private final JarFile jarFile; + + public JarFileScanner(String path) { + Assert.requireNonNull(path, "path must not be null"); + try { + this.jarFile = new JarFile(path); + } catch (IOException e) { + throw new IllegalStateException(path + " create fail"); + } + } + + @Override + public boolean exist(String fileName) { + final JarEntry jarEntry = jarFile.getJarEntry(fileName); + if (jarEntry == null) { + return false; + } + return true; + } + + + @Override + public InputStream openStream(String fileName) { + final JarEntry jarEntry = jarFile.getJarEntry(fileName); + if (jarEntry == null) { + return null; + } + try { + return jarFile.getInputStream(jarEntry); + } catch (IOException e) { + return null; + } + } + + public void close() { + if (jarFile != null) { + try { + jarFile.close(); + } catch (IOException ignore) { + ; + } + } + } + + @Override + public String toString() { + return "JarFileScanner{" + + "jarFile=" + jarFile.getName() + + '}'; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/Scanner.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/Scanner.java new file mode 100644 index 000000000000..bc7c5c9f82e7 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/scanner/Scanner.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.scanner; + +import java.io.InputStream; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface Scanner { + + boolean exist(String fileName); + + InputStream openStream(String fileName); + + void close(); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/BaseTransformerRegistry.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/BaseTransformerRegistry.java new file mode 100644 index 000000000000..b87552146fcf --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/BaseTransformerRegistry.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.transformer; + +import com.navercorp.pinpoint.bootstrap.instrument.matcher.Matcher; + +import java.lang.instrument.ClassFileTransformer; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface BaseTransformerRegistry extends TransformerRegistry { + void addTransformer(Matcher matcher, ClassFileTransformer transformer); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/BypassLambdaClassFileResolver.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/BypassLambdaClassFileResolver.java new file mode 100644 index 000000000000..d224f2750ff8 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/BypassLambdaClassFileResolver.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.transformer; + +import java.security.ProtectionDomain; + +/** + * @author Woonduk Kang(emeroad) + */ +public class BypassLambdaClassFileResolver implements LambdaClassFileResolver { + @Override + public String resolve(ClassLoader classLoader, String classInternalName, ProtectionDomain protectionDomain, byte[] classFileBuffer) { + return classInternalName; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DebugTransformer.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DebugTransformer.java index 9c1ab6c5de2e..1f989331aa22 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DebugTransformer.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DebugTransformer.java @@ -54,7 +54,7 @@ public DebugTransformer(InstrumentEngine instrumentEngine, InstrumentContext ins @Override public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { try { - final InstrumentClass target = instrumentEngine.getClass(instrumentContext, loader, className, classfileBuffer); + final InstrumentClass target = instrumentEngine.getClass(instrumentContext, loader, className, protectionDomain, classfileBuffer); if (target == null) { if (logger.isWarnEnabled()) { logger.warn("targetClass not found. className:{}, classBeingRedefined:{} :{} ", className, classBeingRedefined, loader); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DebugTransformerRegistry.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DebugTransformerRegistry.java index ccaa244b8368..bb31b574a3d5 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DebugTransformerRegistry.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DebugTransformerRegistry.java @@ -23,7 +23,6 @@ import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjector; import com.navercorp.pinpoint.profiler.instrument.classloading.DebugTransformerClassInjector; -import com.navercorp.pinpoint.profiler.instrument.classloading.LegacyProfilerPluginClassInjector; import com.navercorp.pinpoint.profiler.instrument.classreading.InternalClassMetadata; import com.navercorp.pinpoint.profiler.plugin.ClassFileTransformerLoader; import com.navercorp.pinpoint.profiler.plugin.PluginInstrumentContext; @@ -37,13 +36,6 @@ */ public class DebugTransformerRegistry implements TransformerRegistry { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - // TODO remove next release - private static final String DEBUG_INJECTOR_TYPE = "profiler.debug.injector.type"; - private static final String LEGACY = "legacy"; - private static final String DEBUG = "debug"; - private final Filter debugTargetFilter; private final DebugTransformer debugTransformer; @@ -63,7 +55,7 @@ public DebugTransformerRegistry(ProfilerConfig profilerConfig, InstrumentEngine private DebugTransformer newDebugTransformer(ProfilerConfig profilerConfig, InstrumentEngine instrumentEngine, DynamicTransformTrigger dynamicTransformTrigger) { - ClassInjector classInjector = newClassInjector(profilerConfig); + ClassInjector classInjector = new DebugTransformerClassInjector(); ClassFileTransformerLoader transformerRegistry = new ClassFileTransformerLoader(profilerConfig, dynamicTransformTrigger); InstrumentContext debugContext = new PluginInstrumentContext(profilerConfig, instrumentEngine, dynamicTransformTrigger, classInjector, transformerRegistry); @@ -71,19 +63,6 @@ private DebugTransformer newDebugTransformer(ProfilerConfig profilerConfig, Inst return new DebugTransformer(instrumentEngine, debugContext); } - private ClassInjector newClassInjector(ProfilerConfig profilerConfig) { - // TODO remove next release - // bug workaround for DebugTransformerClassInjector - final String debugInjectorType = profilerConfig.readString(DEBUG_INJECTOR_TYPE, DEBUG); - logger.info("{}:{}", DEBUG_INJECTOR_TYPE, debugInjectorType); - if (LEGACY.equals(debugInjectorType)) { - return new LegacyProfilerPluginClassInjector(getClass().getClassLoader()); - } - logger.info("newDebugTransformerClassInjector()"); - return new DebugTransformerClassInjector(); - - } - @Override public ClassFileTransformer findTransformer(ClassLoader classLoader, String classInternalName, byte[] classFileBuffer) { return findTransformer(classLoader, classInternalName, classFileBuffer, null); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DefaultLambdaClassFileResolver.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DefaultLambdaClassFileResolver.java new file mode 100644 index 000000000000..8ed4bb982821 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DefaultLambdaClassFileResolver.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.transformer; + +import com.navercorp.pinpoint.profiler.instrument.classreading.InternalClassMetadata; +import com.navercorp.pinpoint.profiler.instrument.classreading.InternalClassMetadataReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.ProtectionDomain; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultLambdaClassFileResolver implements LambdaClassFileResolver { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public String resolve(ClassLoader classLoader, String classInternalName, ProtectionDomain protectionDomain, byte[] classFileBuffer) { + if (classInternalName != null) { + return classInternalName; + } + + // proxy-like class specific for lambda expressions. + // e.g. Example$$Lambda$1/1072591677 + try { + final InternalClassMetadata classMetadata = InternalClassMetadataReader.readInternalClassMetadata(classFileBuffer); + return classMetadata.getClassInternalName(); + } catch (Exception e) { + if (logger.isInfoEnabled()) { + logger.info("Failed to read metadata of lambda expressions. classLoader={}", classLoader, e); + } + return null; + } + + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DefaultTransformerRegistry.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DefaultTransformerRegistry.java index 3a8f51f48ee1..0c8be6a5e51f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DefaultTransformerRegistry.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/DefaultTransformerRegistry.java @@ -34,7 +34,7 @@ * @author Minwoo Jung * @author jaehong.kim */ -public class DefaultTransformerRegistry implements TransformerRegistry { +public class DefaultTransformerRegistry implements BaseTransformerRegistry { // No concurrent issue because only one thread put entries to the map and get operations are started AFTER the map is completely build. // Set the map size big intentionally to keep hash collision low. @@ -50,6 +50,7 @@ public ClassFileTransformer findTransformer(ClassLoader classLoader, String clas return registry.get(classInternalName); } + @Override public void addTransformer(Matcher matcher, ClassFileTransformer transformer) { // TODO extract matcher process if (matcher instanceof ClassNameMatcher) { @@ -69,8 +70,7 @@ public void addTransformer(Matcher matcher, ClassFileTransformer transformer) { private void addModifier0(ClassFileTransformer transformer, String className) { final String classInternalName = JavaAssistUtils.javaNameToJvmName(className); - ClassFileTransformer old = registry.put(classInternalName, transformer); - + final ClassFileTransformer old = registry.put(classInternalName, transformer); if (old != null) { throw new IllegalStateException("Transformer already exist. className:" + classInternalName + " new:" + transformer.getClass() + " old:" + old.getClass()); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/LambdaClassFileResolver.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/LambdaClassFileResolver.java new file mode 100644 index 000000000000..22239fd1046f --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/LambdaClassFileResolver.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.transformer; + +import java.security.ProtectionDomain; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface LambdaClassFileResolver { + String resolve(ClassLoader classLoader, String classInternalName, ProtectionDomain protectionDomain, byte[] classFileBuffer); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/MatchableTransformerRegistry.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/MatchableTransformerRegistry.java index 475570b01a89..e06b682ec31f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/MatchableTransformerRegistry.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/transformer/MatchableTransformerRegistry.java @@ -40,7 +40,7 @@ /** * @author jaehong.kim */ -public class MatchableTransformerRegistry implements TransformerRegistry { +public class MatchableTransformerRegistry implements BaseTransformerRegistry { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); @@ -75,25 +75,25 @@ public ClassFileTransformer findTransformer(ClassLoader classLoader, String clas @Override public ClassFileTransformer findTransformer(final ClassLoader classLoader, final String classInternalName, final byte[] classFileBuffer, final InternalClassMetadata classMetadata) { // find default. - ClassFileTransformer transformer = this.defaultTransformerRegistry.findTransformer(classLoader, classInternalName, classFileBuffer); + final ClassFileTransformer transformer = this.defaultTransformerRegistry.findTransformer(classLoader, classInternalName, classFileBuffer); if (transformer != null) { return transformer; } - ClassMetadataWrapper classMetadataWrapper = new ClassMetadataWrapper(classFileBuffer, classMetadata); + final ClassMetadataWrapper classMetadataWrapper = new ClassMetadataWrapper(classFileBuffer, classMetadata); // find class name based. if (!this.classNameBasedIndex.isEmpty()) { - transformer = findClassBasedTransformer(classLoader, classInternalName, classMetadataWrapper); - if (transformer != null) { - return transformer; + final ClassFileTransformer classBaseTransformer = findClassBasedTransformer(classLoader, classInternalName, classMetadataWrapper); + if (classBaseTransformer != null) { + return classBaseTransformer; } } // find package name based. if (!this.packageNameBasedIndex.isEmpty()) { - transformer = findPackageBasedTransformer(classLoader, classInternalName, classMetadataWrapper); - if (transformer != null) { - return transformer; + final ClassFileTransformer packagedBasedTransformer = findPackageBasedTransformer(classLoader, classInternalName, classMetadataWrapper); + if (packagedBasedTransformer != null) { + return packagedBasedTransformer; } } @@ -149,6 +149,7 @@ private ClassFileTransformer match(final ClassLoader classLoader, final IndexVal return null; } + @Override public void addTransformer(final Matcher matcher, final ClassFileTransformer transformer) { if (MatcherType.isBasedMatcher(matcher)) { // class or package based. diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/AnnotatedInterceptorFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/AnnotatedInterceptorFactory.java index b5212bd27b5b..d25129819557 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/AnnotatedInterceptorFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/AnnotatedInterceptorFactory.java @@ -38,6 +38,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandleAroundInterceptor4; import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandleAroundInterceptor5; import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandleStaticAroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.bootstrap.interceptor.Interceptor; import com.navercorp.pinpoint.bootstrap.interceptor.StaticAroundInterceptor; import com.navercorp.pinpoint.bootstrap.interceptor.scope.ExceptionHandleScopedApiIdAwareAroundInterceptor; @@ -62,6 +63,7 @@ import com.navercorp.pinpoint.bootstrap.interceptor.scope.InterceptorScope; import com.navercorp.pinpoint.bootstrap.plugin.ObjectFactory; import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitorRegistry; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.instrument.ScopeInfo; import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; import com.navercorp.pinpoint.profiler.objectfactory.AutoBindingObjectFactory; @@ -77,30 +79,20 @@ public class AnnotatedInterceptorFactory implements InterceptorFactory { private final DataSourceMonitorRegistry dataSourceMonitorRegistry; private final ApiMetaDataService apiMetaDataService; private final InstrumentContext pluginContext; - private final boolean exceptionHandle; - - public AnnotatedInterceptorFactory(ProfilerConfig profilerConfig, TraceContext traceContext, DataSourceMonitorRegistry dataSourceMonitorRegistry, ApiMetaDataService apiMetaDataService, InstrumentContext pluginContext, boolean exceptionHandle) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (traceContext == null) { - throw new NullPointerException("traceContext must not be null"); - } - if (dataSourceMonitorRegistry == null) { - throw new NullPointerException("dataSourceMonitorRegistry must not be null"); - } - if (apiMetaDataService == null) { - throw new NullPointerException("apiMetaDataService must not be null"); - } - if (pluginContext == null) { - throw new NullPointerException("pluginContext must not be null"); - } - this.profilerConfig = profilerConfig; - this.traceContext = traceContext; - this.dataSourceMonitorRegistry = dataSourceMonitorRegistry; - this.apiMetaDataService = apiMetaDataService; - this.pluginContext = pluginContext; - this.exceptionHandle = exceptionHandle; + private final ExceptionHandlerFactory exceptionHandlerFactory; + + public AnnotatedInterceptorFactory(ProfilerConfig profilerConfig, + TraceContext traceContext, + DataSourceMonitorRegistry dataSourceMonitorRegistry, + ApiMetaDataService apiMetaDataService, + InstrumentContext pluginContext, + ExceptionHandlerFactory exceptionHandlerFactory) { + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.traceContext = Assert.requireNonNull(traceContext, "traceContext must not be null"); + this.dataSourceMonitorRegistry = Assert.requireNonNull(dataSourceMonitorRegistry, "dataSourceMonitorRegistry must not be null"); + this.apiMetaDataService = Assert.requireNonNull(apiMetaDataService, "apiMetaDataService must not be null"); + this.pluginContext = Assert.requireNonNull(pluginContext, "pluginContext must not be null"); + this.exceptionHandlerFactory = Assert.requireNonNull(exceptionHandlerFactory, "exceptionHandlerFactory must not be null"); } @Override @@ -114,13 +106,13 @@ public Interceptor getInterceptor(ClassLoader classLoader, String interceptorCla Interceptor interceptor = (Interceptor) factory.createInstance(objectFactory, interceptorArgumentProvider); if (interceptorScope != null) { - if (exceptionHandle) { + if (exceptionHandlerFactory.isHandleException()) { interceptor = wrapByExceptionHandleScope(interceptor, interceptorScope, getExecutionPolicy(scopeInfo.getExecutionPolicy())); } else { interceptor = wrapByScope(interceptor, interceptorScope, getExecutionPolicy(scopeInfo.getExecutionPolicy())); } } else { - if (exceptionHandle) { + if (exceptionHandlerFactory.isHandleException()) { interceptor = wrapByExceptionHandle(interceptor); } } @@ -160,48 +152,50 @@ private Interceptor wrapByScope(Interceptor interceptor, InterceptorScope scope, } private Interceptor wrapByExceptionHandleScope(Interceptor interceptor, InterceptorScope scope, ExecutionPolicy policy) { + final ExceptionHandler exceptionHandler = exceptionHandlerFactory.getExceptionHandler(); if (interceptor instanceof AroundInterceptor) { - return new ExceptionHandleScopedInterceptor((AroundInterceptor) interceptor, scope, policy); + return new ExceptionHandleScopedInterceptor((AroundInterceptor) interceptor, scope, policy, exceptionHandler); } else if (interceptor instanceof StaticAroundInterceptor) { - return new ExceptionHandleScopedStaticAroundInterceptor((StaticAroundInterceptor) interceptor, scope, policy); + return new ExceptionHandleScopedStaticAroundInterceptor((StaticAroundInterceptor) interceptor, scope, policy, exceptionHandler); } else if (interceptor instanceof AroundInterceptor5) { - return new ExceptionHandleScopedInterceptor5((AroundInterceptor5) interceptor, scope, policy); + return new ExceptionHandleScopedInterceptor5((AroundInterceptor5) interceptor, scope, policy, exceptionHandler); } else if (interceptor instanceof AroundInterceptor4) { - return new ExceptionHandleScopedInterceptor4((AroundInterceptor4) interceptor, scope, policy); + return new ExceptionHandleScopedInterceptor4((AroundInterceptor4) interceptor, scope, policy, exceptionHandler); } else if (interceptor instanceof AroundInterceptor3) { - return new ExceptionHandleScopedInterceptor3((AroundInterceptor3) interceptor, scope, policy); + return new ExceptionHandleScopedInterceptor3((AroundInterceptor3) interceptor, scope, policy, exceptionHandler); } else if (interceptor instanceof AroundInterceptor2) { - return new ExceptionHandleScopedInterceptor2((AroundInterceptor2) interceptor, scope, policy); + return new ExceptionHandleScopedInterceptor2((AroundInterceptor2) interceptor, scope, policy, exceptionHandler); } else if (interceptor instanceof AroundInterceptor1) { - return new ExceptionHandleScopedInterceptor1((AroundInterceptor1) interceptor, scope, policy); + return new ExceptionHandleScopedInterceptor1((AroundInterceptor1) interceptor, scope, policy, exceptionHandler); } else if (interceptor instanceof AroundInterceptor0) { - return new ExceptionHandleScopedInterceptor0((AroundInterceptor0) interceptor, scope, policy); + return new ExceptionHandleScopedInterceptor0((AroundInterceptor0) interceptor, scope, policy, exceptionHandler); } else if (interceptor instanceof ApiIdAwareAroundInterceptor) { - return new ExceptionHandleScopedApiIdAwareAroundInterceptor((ApiIdAwareAroundInterceptor) interceptor, scope, policy); + return new ExceptionHandleScopedApiIdAwareAroundInterceptor((ApiIdAwareAroundInterceptor) interceptor, scope, policy, exceptionHandler); } throw new IllegalArgumentException("Unexpected interceptor type: " + interceptor.getClass()); } private Interceptor wrapByExceptionHandle(Interceptor interceptor) { + final ExceptionHandler exceptionHandler = exceptionHandlerFactory.getExceptionHandler(); if (interceptor instanceof AroundInterceptor) { - return new ExceptionHandleAroundInterceptor((AroundInterceptor) interceptor); + return new ExceptionHandleAroundInterceptor((AroundInterceptor) interceptor, exceptionHandler); } else if (interceptor instanceof StaticAroundInterceptor) { - return new ExceptionHandleStaticAroundInterceptor((StaticAroundInterceptor) interceptor); + return new ExceptionHandleStaticAroundInterceptor((StaticAroundInterceptor) interceptor, exceptionHandler); } else if (interceptor instanceof AroundInterceptor5) { - return new ExceptionHandleAroundInterceptor5((AroundInterceptor5) interceptor); + return new ExceptionHandleAroundInterceptor5((AroundInterceptor5) interceptor, exceptionHandler); } else if (interceptor instanceof AroundInterceptor4) { - return new ExceptionHandleAroundInterceptor4((AroundInterceptor4) interceptor); + return new ExceptionHandleAroundInterceptor4((AroundInterceptor4) interceptor, exceptionHandler); } else if (interceptor instanceof AroundInterceptor3) { - return new ExceptionHandleAroundInterceptor3((AroundInterceptor3) interceptor); + return new ExceptionHandleAroundInterceptor3((AroundInterceptor3) interceptor, exceptionHandler); } else if (interceptor instanceof AroundInterceptor2) { - return new ExceptionHandleAroundInterceptor2((AroundInterceptor2) interceptor); + return new ExceptionHandleAroundInterceptor2((AroundInterceptor2) interceptor, exceptionHandler); } else if (interceptor instanceof AroundInterceptor1) { - return new ExceptionHandleAroundInterceptor1((AroundInterceptor1) interceptor); + return new ExceptionHandleAroundInterceptor1((AroundInterceptor1) interceptor, exceptionHandler); } else if (interceptor instanceof AroundInterceptor0) { - return new ExceptionHandleAroundInterceptor0((AroundInterceptor0) interceptor); + return new ExceptionHandleAroundInterceptor0((AroundInterceptor0) interceptor, exceptionHandler); } else if (interceptor instanceof ApiIdAwareAroundInterceptor) { - return new ExceptionHandleApiIdAwareAroundInterceptor((ApiIdAwareAroundInterceptor) interceptor); + return new ExceptionHandleApiIdAwareAroundInterceptor((ApiIdAwareAroundInterceptor) interceptor, exceptionHandler); } throw new IllegalArgumentException("Unexpected interceptor type: " + interceptor.getClass()); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/ExceptionHandlerFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/ExceptionHandlerFactory.java new file mode 100644 index 000000000000..cdaf31e1e097 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/ExceptionHandlerFactory.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.interceptor.factory; + +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ExceptionHandlerFactory { + private final boolean exceptionGuard; + private final ExceptionHandler exceptionHandler; + + public ExceptionHandlerFactory(boolean exceptionGuard) { + this.exceptionGuard = exceptionGuard; + this.exceptionHandler = newExceptionHandler(exceptionGuard); + } + + private ExceptionHandler newExceptionHandler(boolean propagate) { + if (propagate) { + return new GuardExceptionHandler(); + } else { + return new RethrowExceptionHandler(); + } + } + + public boolean isHandleException() { + return exceptionGuard; + } + + public ExceptionHandler getExceptionHandler() { + return exceptionHandler; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/GuardExceptionHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/GuardExceptionHandler.java new file mode 100644 index 000000000000..40c43ca63702 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/GuardExceptionHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.interceptor.factory; + +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class GuardExceptionHandler implements ExceptionHandler { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + @Override + public void handleException(Throwable t) { + logger.warn("Exception occurred from interceptor", t); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/RethrowExceptionHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/RethrowExceptionHandler.java new file mode 100644 index 000000000000..5e0727c070b9 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/interceptor/factory/RethrowExceptionHandler.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.interceptor.factory; + +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RethrowExceptionHandler implements ExceptionHandler { + + private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); + + @Override + public void handleException(Throwable t) { + logger.warn("Exception occurred from interceptor", t); + + throw new RuntimeException(t); + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/logging/Slf4jPLoggerAdapter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/logging/Slf4jPLoggerAdapter.java index fc385559b7aa..9def067a3c59 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/logging/Slf4jPLoggerAdapter.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/logging/Slf4jPLoggerAdapter.java @@ -18,15 +18,17 @@ import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.plugin.jdbc.SqlModule; import com.navercorp.pinpoint.common.util.ArrayUtils; import org.slf4j.Marker; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; -import java.sql.Time; -import java.sql.Timestamp; -import java.util.*; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.IdentityHashMap; +import java.util.Map; /** * @author emeroad @@ -34,37 +36,53 @@ public class Slf4jPLoggerAdapter implements PLogger { public static final int BUFFER_SIZE = 512; - private static final Map, Class> SIMPLE_TYPE = new IdentityHashMap, Class>(); - static { - SIMPLE_TYPE.put(String.class, String.class); - SIMPLE_TYPE.put(Boolean.class, Boolean.class); - SIMPLE_TYPE.put(boolean.class, boolean.class); - SIMPLE_TYPE.put(Byte.class, Byte.class); - SIMPLE_TYPE.put(byte.class, byte.class); - SIMPLE_TYPE.put(Short.class, Short.class); - SIMPLE_TYPE.put(short.class, short.class); - SIMPLE_TYPE.put(Integer.class, Integer.class); - SIMPLE_TYPE.put(int.class, int.class); - SIMPLE_TYPE.put(Long.class, Long.class); - SIMPLE_TYPE.put(long.class, long.class); - SIMPLE_TYPE.put(Float.class, Float.class); - SIMPLE_TYPE.put(float.class, float.class); - SIMPLE_TYPE.put(Double.class, Double.class); - SIMPLE_TYPE.put(double.class, double.class); - SIMPLE_TYPE.put(Character.class, Character.class); - SIMPLE_TYPE.put(char.class, char.class); - SIMPLE_TYPE.put(BigDecimal.class, BigDecimal.class); - SIMPLE_TYPE.put(StringBuffer.class, StringBuffer.class); - SIMPLE_TYPE.put(BigInteger.class, BigInteger.class); - SIMPLE_TYPE.put(Class.class, Class.class); - SIMPLE_TYPE.put(java.sql.Date.class, java.sql.Date.class); - SIMPLE_TYPE.put(java.util.Date.class, java.util.Date.class); - SIMPLE_TYPE.put(Time.class, Time.class); - SIMPLE_TYPE.put(Timestamp.class, Timestamp.class); - SIMPLE_TYPE.put(Calendar.class, Calendar.class); - SIMPLE_TYPE.put(GregorianCalendar.class, GregorianCalendar.class); - SIMPLE_TYPE.put(URL.class, URL.class); - SIMPLE_TYPE.put(Object.class, Object.class); + private static Object EXIST = new Object(); + + private static final Map, Object> SIMPLE_TYPE = prepare(); + + private static Map, Object> prepare() { + final Map, Object> map = new IdentityHashMap, Object>(64); + put(map , String.class); + put(map, Boolean.class); + put(map, boolean.class); + put(map, Byte.class); + put(map, byte.class); + put(map, Short.class); + put(map, short.class); + put(map, Integer.class); + put(map, int.class); + put(map, Long.class); + put(map, long.class); + put(map, Float.class); + put(map, float.class); + put(map, Double.class); + put(map, double.class); + put(map, Character.class); + put(map, char.class); + put(map, BigDecimal.class); + put(map, StringBuffer.class); + put(map, BigInteger.class); + put(map, java.util.Date.class); + put(map, Class.class); + put(map, Calendar.class); + put(map, GregorianCalendar.class); + put(map, URL.class); + put(map, Object.class); + + if (SqlModule.isSqlModuleEnable()) { + addSqlModuleSupport(map); + } + return map; + } + + private static void addSqlModuleSupport(Map, Object> map) { + put(map, SqlModule.getSqlDate()); + put(map, SqlModule.getSqlTime()); + put(map, SqlModule.getSqlTimestamp()); + } + + private static void put(Map, Object> map, Class key) { + map.put(key, EXIST); } @@ -203,19 +221,38 @@ private static String normalizedParameter(Object arg) { if (isSimpleType(arg)) { return arg.toString(); } else { - return arg.getClass().getSimpleName(); + return getSimpleName(arg.getClass()); } } } - private static boolean isSimpleType(Object arg) { - Class find = SIMPLE_TYPE.get(arg.getClass()); + static boolean isSimpleType(Object arg) { + final Object find = SIMPLE_TYPE.get(arg.getClass()); if (find == null) { return false; } return true; } + static String getSimpleName(final Class clazz) { + if (clazz.isArray()) { + return getSimpleName(clazz.getComponentType()) + "[]"; + } + + final String simpleName = clazz.getName(); + if (simpleName == null) { + // Defense + return ""; + } + + final int lastPackagePosition = simpleName.lastIndexOf('.'); + if (lastPackagePosition != -1) { + // Strip the package name + return simpleName.substring(lastPackagePosition + 1); + } + return simpleName; + } + @Override public boolean isTraceEnabled() { return logger.isTraceEnabled(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/ApiMetaData.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/ApiMetaData.java new file mode 100644 index 000000000000..edd73796984d --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/ApiMetaData.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.metadata; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ApiMetaData { + + private final int apiId; // required + private final String apiInfo; // required + private int line; // optional + private int type; // optional + + public ApiMetaData(int apiId, String apiInfo) { + this.apiId = apiId; + this.apiInfo = apiInfo; + } + + public int getApiId() { + return apiId; + } + + + public String getApiInfo() { + return apiInfo; + } + + public int getLine() { + return line; + } + + public void setLine(int line) { + this.line = line; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultApiMetaDataService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultApiMetaDataService.java index dac157ba85e0..675c445887c3 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultApiMetaDataService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultApiMetaDataService.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; -import com.navercorp.pinpoint.thrift.dto.TApiMetaData; /** * @author Woonduk Kang(emeroad) @@ -27,19 +26,12 @@ public class DefaultApiMetaDataService implements ApiMetaDataService { private final SimpleCache apiCache = new SimpleCache(); - private final String agentId; - private final long agentStartTime; - private final EnhancedDataSender enhancedDataSender; + private final EnhancedDataSender enhancedDataSender; - public DefaultApiMetaDataService(String agentId, long agentStartTime, EnhancedDataSender enhancedDataSender) { - if (agentId == null) { - throw new NullPointerException("agentId must not be null"); - } + public DefaultApiMetaDataService(EnhancedDataSender enhancedDataSender) { if (enhancedDataSender == null) { throw new NullPointerException("enhancedDataSender must not be null"); } - this.agentId = agentId; - this.agentStartTime = agentStartTime; this.enhancedDataSender = enhancedDataSender; } @@ -51,12 +43,7 @@ public int cacheApi(final MethodDescriptor methodDescriptor) { methodDescriptor.setApiId(result.getId()); if (result.isNewValue()) { - final TApiMetaData apiMetadata = new TApiMetaData(); - apiMetadata.setAgentId(agentId); - apiMetadata.setAgentStartTime(agentStartTime); - - apiMetadata.setApiId(result.getId()); - apiMetadata.setApiInfo(methodDescriptor.getApiDescriptor()); + final ApiMetaData apiMetadata = new ApiMetaData(result.getId(), methodDescriptor.getApiDescriptor()); apiMetadata.setLine(methodDescriptor.getLineNumber()); apiMetadata.setType(methodDescriptor.getType()); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultParsingResult.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultParsingResult.java index cd0913a110cb..2bc5e0b5355d 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultParsingResult.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultParsingResult.java @@ -18,7 +18,6 @@ import com.navercorp.pinpoint.bootstrap.context.ParsingResult; -import com.navercorp.pinpoint.profiler.metadata.ParsingResultInternal; /** * @author emeroad diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultSqlMetaDataService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultSqlMetaDataService.java index 314a54116c62..4323702fdd01 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultSqlMetaDataService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultSqlMetaDataService.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,10 +19,7 @@ import com.google.inject.Inject; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.context.ParsingResult; -import com.navercorp.pinpoint.profiler.context.module.AgentId; -import com.navercorp.pinpoint.profiler.context.module.AgentStartTime; import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; -import com.navercorp.pinpoint.thrift.dto.TSqlMetaData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,25 +33,17 @@ public class DefaultSqlMetaDataService implements SqlMetaDataService { private final CachingSqlNormalizer cachingSqlNormalizer; - private final String agentId; - private final long agentStartTime; - private final EnhancedDataSender enhancedDataSender; + private final EnhancedDataSender enhancedDataSender; @Inject - public DefaultSqlMetaDataService(ProfilerConfig profilerConfig, @AgentId String agentId, - @AgentStartTime long agentStartTime, EnhancedDataSender enhancedDataSender) { - this(agentId, agentStartTime, enhancedDataSender, profilerConfig.getJdbcSqlCacheSize()); + public DefaultSqlMetaDataService(ProfilerConfig profilerConfig, EnhancedDataSender enhancedDataSender) { + this(enhancedDataSender, profilerConfig.getJdbcSqlCacheSize()); } - public DefaultSqlMetaDataService(String agentId, long agentStartTime, EnhancedDataSender enhancedDataSender, int jdbcSqlCacheSize) { - if (agentId == null) { - throw new NullPointerException("agentId must not be null"); - } + public DefaultSqlMetaDataService(EnhancedDataSender enhancedDataSender, int jdbcSqlCacheSize) { if (enhancedDataSender == null) { throw new NullPointerException("enhancedDataSender must not be null"); } - this.agentId = agentId; - this.agentStartTime = agentStartTime; this.enhancedDataSender = enhancedDataSender; this.cachingSqlNormalizer = new DefaultCachingSqlNormalizer(jdbcSqlCacheSize); } @@ -82,12 +71,7 @@ public boolean cacheSql(ParsingResult parsingResult) { // isNewValue means that the value is newly cached. // So the sql could be new one. We have to send sql metadata to collector. - final TSqlMetaData sqlMetaData = new TSqlMetaData(); - sqlMetaData.setAgentId(agentId); - sqlMetaData.setAgentStartTime(agentStartTime); - - sqlMetaData.setSqlId(parsingResult.getId()); - sqlMetaData.setSql(parsingResult.getSql()); + final SqlMetaData sqlMetaData = new SqlMetaData(parsingResult.getId(), parsingResult.getSql()); this.enhancedDataSender.request(sqlMetaData); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultStringMetaDataService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultStringMetaDataService.java index f27221a9a8f3..af97567493b0 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultStringMetaDataService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/DefaultStringMetaDataService.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,7 @@ package com.navercorp.pinpoint.profiler.metadata; import com.google.inject.Inject; -import com.navercorp.pinpoint.profiler.context.module.AgentId; -import com.navercorp.pinpoint.profiler.context.module.AgentStartTime; import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; -import com.navercorp.pinpoint.thrift.dto.TStringMetaData; /** * @author Woonduk Kang(emeroad) @@ -29,20 +26,13 @@ public class DefaultStringMetaDataService implements StringMetaDataService { private final SimpleCache stringCache = new SimpleCache(); - private final String agentId; - private final long agentStartTime; - private final EnhancedDataSender enhancedDataSender; + private final EnhancedDataSender enhancedDataSender; @Inject - public DefaultStringMetaDataService(@AgentId String agentId, @AgentStartTime long agentStartTime, EnhancedDataSender enhancedDataSender) { - if (agentId == null) { - throw new NullPointerException("agentId must not be null"); - } + public DefaultStringMetaDataService(EnhancedDataSender enhancedDataSender) { if (enhancedDataSender == null) { throw new NullPointerException("enhancedDataSender must not be null"); } - this.agentId = agentId; - this.agentStartTime = agentStartTime; this.enhancedDataSender = enhancedDataSender; } @@ -53,12 +43,7 @@ public int cacheString(final String value) { } final Result result = this.stringCache.put(value); if (result.isNewValue()) { - final TStringMetaData stringMetaData = new TStringMetaData(); - stringMetaData.setAgentId(agentId); - stringMetaData.setAgentStartTime(agentStartTime); - - stringMetaData.setStringId(result.getId()); - stringMetaData.setStringValue(value); + final StringMetaData stringMetaData = new StringMetaData(result.getId(), value); this.enhancedDataSender.request(stringMetaData); } return result.getId(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/SqlMetaData.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/SqlMetaData.java new file mode 100644 index 000000000000..9deaa9c3f63d --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/SqlMetaData.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.metadata; + +/** + * @author Woonduk Kang(emeroad) + */ +public class SqlMetaData { + +// private java.lang.String agentId; // required +// private long agentStartTime; // required + private final int sqlId; // required + private final String sql; // required + + public SqlMetaData(int sqlId, String sql) { + this.sqlId = sqlId; + this.sql = sql; + } + + + public int getSqlId() { + return sqlId; + } + + public String getSql() { + return sql; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/StringMetaData.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/StringMetaData.java new file mode 100644 index 000000000000..e36b6e834044 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/metadata/StringMetaData.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.metadata; + +/** + * @author Woonduk Kang(emeroad) + */ +public class StringMetaData { + + private final int stringId; // required + private final String stringValue; // required + + public StringMetaData(int stringId, String stringValue) { + this.stringId = stringId; + this.stringValue = stringValue; + } + + public int getStringId() { + return stringId; + } + + public String getStringValue() { + return stringValue; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/DefaultDeadlockMonitor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/DefaultDeadlockMonitor.java index 9d8a3043f157..453b8b8f63cd 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/DefaultDeadlockMonitor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/DefaultDeadlockMonitor.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -34,14 +34,14 @@ public DefaultDeadlockMonitor(DeadlockThreadRegistry deadlockThreadRegistry, lon @Override public void start() { - deadlockMonitorThread.start(); logger.info("DefaultDeadlockMonitor started"); + deadlockMonitorThread.start(); } @Override public void stop() { - deadlockMonitorThread.stop(); logger.info("DefaultDeadlockMonitor stopped"); + deadlockMonitorThread.stop(); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/AgentStatCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/AgentStatCollector.java index 155088f9ac4c..a9d233216915 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/AgentStatCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/AgentStatCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,16 +17,19 @@ package com.navercorp.pinpoint.profiler.monitor.collector; import com.google.inject.Inject; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.module.AgentId; import com.navercorp.pinpoint.profiler.context.module.AgentStartTime; -import com.navercorp.pinpoint.profiler.monitor.collector.activethread.ActiveTraceMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.cpu.CpuLoadMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.datasource.DataSourceMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.deadlock.DeadlockMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.jvmgc.JvmGcMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.response.ResponseTimeMetricCollector; -import com.navercorp.pinpoint.profiler.monitor.collector.transaction.TransactionMetricCollector; +import com.navercorp.pinpoint.thrift.dto.TActiveTrace; import com.navercorp.pinpoint.thrift.dto.TAgentStat; +import com.navercorp.pinpoint.thrift.dto.TCpuLoad; +import com.navercorp.pinpoint.thrift.dto.TDataSourceList; +import com.navercorp.pinpoint.thrift.dto.TDeadlock; +import com.navercorp.pinpoint.thrift.dto.TDirectBuffer; +import com.navercorp.pinpoint.thrift.dto.TFileDescriptor; +import com.navercorp.pinpoint.thrift.dto.TJvmGc; +import com.navercorp.pinpoint.thrift.dto.TResponseTime; +import com.navercorp.pinpoint.thrift.dto.TTransaction; /** * @author HyunGil Jeong @@ -35,59 +38,40 @@ public class AgentStatCollector implements AgentStatMetricCollector private final String agentId; private final long agentStartTimestamp; - private final JvmGcMetricCollector jvmGcMetricCollector; - private final CpuLoadMetricCollector cpuLoadMetricCollector; - private final TransactionMetricCollector transactionMetricCollector; - private final ActiveTraceMetricCollector activeTraceMetricCollector; - private final DataSourceMetricCollector dataSourceMetricCollector; - private final ResponseTimeMetricCollector responseTimeMetricCollector; - private final DeadlockMetricCollector deadlockMetricCollector; + private final AgentStatMetricCollector jvmGcMetricCollector; + private final AgentStatMetricCollector cpuLoadMetricCollector; + private final AgentStatMetricCollector transactionMetricCollector; + private final AgentStatMetricCollector activeTraceMetricCollector; + private final AgentStatMetricCollector dataSourceMetricCollector; + private final AgentStatMetricCollector responseTimeMetricCollector; + private final AgentStatMetricCollector deadlockMetricCollector; + private final AgentStatMetricCollector fileDescriptorMetricCollector; + private final AgentStatMetricCollector bufferMetricCollector; @Inject public AgentStatCollector( @AgentId String agentId, @AgentStartTime long agentStartTimestamp, - JvmGcMetricCollector jvmGcMetricCollector, - CpuLoadMetricCollector cpuLoadMetricCollector, - TransactionMetricCollector transactionMetricCollector, - ActiveTraceMetricCollector activeTraceMetricCollector, - DataSourceMetricCollector dataSourceMetricCollector, - ResponseTimeMetricCollector responseTimeMetricCollector, - DeadlockMetricCollector deadlockMetricCollector) { - if (agentId == null) { - throw new NullPointerException("agentId must not be null"); - } - if (jvmGcMetricCollector == null) { - throw new NullPointerException("jvmGcMetricCollector must not be null"); - } - if (cpuLoadMetricCollector == null) { - throw new NullPointerException("cpuLoadMetricCollector must not be null"); - } - if (transactionMetricCollector == null) { - throw new NullPointerException("transactionMetricCollector must not be null"); - } - if (activeTraceMetricCollector == null) { - throw new NullPointerException("activeTraceMetricCollector must not be null"); - } - if (dataSourceMetricCollector == null) { - throw new NullPointerException("dataSourceMetricCollector must not be null"); - } - if (responseTimeMetricCollector == null) { - throw new NullPointerException("responseTimeMetricCollector must not be null"); - } - if (deadlockMetricCollector == null) { - throw new NullPointerException("deadlockMetricCollector may not be null"); - } - - this.agentId = agentId; + AgentStatMetricCollector jvmGcMetricCollector, + AgentStatMetricCollector cpuLoadMetricCollector, + AgentStatMetricCollector transactionMetricCollector, + AgentStatMetricCollector activeTraceMetricCollector, + AgentStatMetricCollector dataSourceMetricCollector, + AgentStatMetricCollector responseTimeMetricCollector, + AgentStatMetricCollector deadlockMetricCollector, + AgentStatMetricCollector fileDescriptorMetricCollector, + AgentStatMetricCollector bufferMetricCollector) { + this.agentId = Assert.requireNonNull(agentId, "agentId must not be null"); this.agentStartTimestamp = agentStartTimestamp; - this.jvmGcMetricCollector = jvmGcMetricCollector; - this.cpuLoadMetricCollector = cpuLoadMetricCollector; - this.transactionMetricCollector = transactionMetricCollector; - this.activeTraceMetricCollector = activeTraceMetricCollector; - this.dataSourceMetricCollector = dataSourceMetricCollector; - this.responseTimeMetricCollector = responseTimeMetricCollector; - this.deadlockMetricCollector = deadlockMetricCollector; + this.jvmGcMetricCollector = Assert.requireNonNull(jvmGcMetricCollector, "jvmGcMetricCollector must not be null"); + this.cpuLoadMetricCollector = Assert.requireNonNull(cpuLoadMetricCollector, "cpuLoadMetricCollector must not be null"); + this.transactionMetricCollector = Assert.requireNonNull(transactionMetricCollector, "transactionMetricCollector must not be null"); + this.activeTraceMetricCollector = Assert.requireNonNull(activeTraceMetricCollector, "activeTraceMetricCollector must not be null"); + this.dataSourceMetricCollector = Assert.requireNonNull(dataSourceMetricCollector, "dataSourceMetricCollector must not be null"); + this.responseTimeMetricCollector = Assert.requireNonNull(responseTimeMetricCollector, "responseTimeMetricCollector must not be null"); + this.deadlockMetricCollector = Assert.requireNonNull(deadlockMetricCollector, "deadlockMetricCollector must not be null"); + this.fileDescriptorMetricCollector = Assert.requireNonNull(fileDescriptorMetricCollector, "fileDescriptorMetricCollector must not be null"); + this.bufferMetricCollector = Assert.requireNonNull(bufferMetricCollector, "bufferMetricCollector must not be null"); } @Override @@ -102,6 +86,8 @@ public TAgentStat collect() { agentStat.setDataSourceList(dataSourceMetricCollector.collect()); agentStat.setResponseTime(responseTimeMetricCollector.collect()); agentStat.setDeadlock(deadlockMetricCollector.collect()); + agentStat.setFileDescriptor(fileDescriptorMetricCollector.collect()); + agentStat.setDirectBuffer(bufferMetricCollector.collect()); return agentStat; } @@ -118,6 +104,8 @@ public String toString() { sb.append(", dataSourceMetricCollector=").append(dataSourceMetricCollector); sb.append(", responseTimeMetricCollector=").append(responseTimeMetricCollector); sb.append(", deadlockMetricCollector=").append(deadlockMetricCollector); + sb.append(", fileDescriptorMetricCollector=").append(fileDescriptorMetricCollector); + sb.append(", bufferMetricCollector=").append(bufferMetricCollector); sb.append('}'); return sb.toString(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/AgentStatMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/AgentStatMetricCollector.java index 9b585b372896..4ca253f38bcb 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/AgentStatMetricCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/AgentStatMetricCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -22,7 +22,7 @@ /** * @author HyunGil Jeong */ -public interface AgentStatMetricCollector> { +public interface AgentStatMetricCollector { T collect(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/UnsupportedMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/UnsupportedMetricCollector.java new file mode 100644 index 000000000000..55b4a0b6b5e4 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/UnsupportedMetricCollector.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.collector; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class UnsupportedMetricCollector implements AgentStatMetricCollector { + + @Override + public T collect() { + return null; + } + + @Override + public String toString() { + return "UnsupportedMetricCollector"; + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/ActiveTraceMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/ActiveTraceMetricCollector.java deleted file mode 100644 index ddc7e8c3e0ad..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/ActiveTraceMetricCollector.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.activethread; - -import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; -import com.navercorp.pinpoint.thrift.dto.TActiveTrace; - -/** - * @author HyunGil Jeong - */ -public interface ActiveTraceMetricCollector extends AgentStatMetricCollector { -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/DefaultActiveTraceMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/DefaultActiveTraceMetricCollector.java index d8f57bd73a27..57ea128880f4 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/DefaultActiveTraceMetricCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/DefaultActiveTraceMetricCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +16,19 @@ package com.navercorp.pinpoint.profiler.monitor.collector.activethread; +import com.navercorp.pinpoint.profiler.context.active.ActiveTraceHistogram; +import com.navercorp.pinpoint.profiler.context.active.ActiveTraceHistogramUtils; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.activethread.ActiveTraceMetric; import com.navercorp.pinpoint.thrift.dto.TActiveTrace; +import com.navercorp.pinpoint.thrift.dto.TActiveTraceHistogram; + +import java.util.List; /** * @author HyunGil Jeong */ -public class DefaultActiveTraceMetricCollector implements ActiveTraceMetricCollector { +public class DefaultActiveTraceMetricCollector implements AgentStatMetricCollector { private final ActiveTraceMetric activeTraceMetric; @@ -35,8 +41,19 @@ public DefaultActiveTraceMetricCollector(ActiveTraceMetric activeTraceMetric) { @Override public TActiveTrace collect() { + final ActiveTraceHistogram histogram = activeTraceMetric.activeTraceHistogram(); + + final int histogramSchemaTypeCode = histogram.getHistogramSchema().getTypeCode(); + + TActiveTraceHistogram tActiveTraceHistogram = new TActiveTraceHistogram(); + tActiveTraceHistogram.setHistogramSchemaType(histogramSchemaTypeCode); + + final List activeTraceCounts = ActiveTraceHistogramUtils.asList(histogram); + tActiveTraceHistogram.setActiveTraceCount(activeTraceCounts); + + TActiveTrace activeTrace = new TActiveTrace(); - activeTrace.setHistogram(activeTraceMetric.activeTraceHistogram()); + activeTrace.setHistogram(tActiveTraceHistogram); return activeTrace; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/UnsupportedActiveTraceMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/UnsupportedActiveTraceMetricCollector.java deleted file mode 100644 index 01a8ee3d2be7..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/activethread/UnsupportedActiveTraceMetricCollector.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.activethread; - -import com.navercorp.pinpoint.thrift.dto.TActiveTrace; - -/** - * @author HyunGil Jeong - */ -public class UnsupportedActiveTraceMetricCollector implements ActiveTraceMetricCollector { - - @Override - public TActiveTrace collect() { - return null; - } - - @Override - public String toString() { - return "Unsupported CpuLoadMetricCollector"; - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/buffer/DefaultBufferMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/buffer/DefaultBufferMetricCollector.java new file mode 100644 index 000000000000..34e28c64ceac --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/buffer/DefaultBufferMetricCollector.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.collector.buffer; + + +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.metric.buffer.BufferMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.buffer.BufferMetricSnapshot; +import com.navercorp.pinpoint.thrift.dto.TDirectBuffer; + +/** + * @author Roy Kim + */ +public class DefaultBufferMetricCollector implements AgentStatMetricCollector { + + private final BufferMetric bufferMetric; + + public DefaultBufferMetricCollector(BufferMetric bufferMetric) { + if (bufferMetric == null) { + throw new NullPointerException("bufferMetric must not be null"); + } + this.bufferMetric = bufferMetric; + } + + @Override + public TDirectBuffer collect() { + final BufferMetricSnapshot snapshot = bufferMetric.getSnapshot(); + + TDirectBuffer tdirectBuffer = new TDirectBuffer(); + tdirectBuffer.setDirectCount(snapshot.getDirectCount()); + tdirectBuffer.setDirectMemoryUsed(snapshot.getDirectMemoryUsed()); + tdirectBuffer.setMappedCount(snapshot.getMappedCount()); + tdirectBuffer.setMappedMemoryUsed(snapshot.getMappedMemoryUsed()); + return tdirectBuffer; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DefaultBufferMetricCollector{"); + sb.append("bufferMetric=").append(bufferMetric); + sb.append('}'); + return sb.toString(); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/CpuLoadMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/CpuLoadMetricCollector.java deleted file mode 100644 index cf00eec4d9ca..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/CpuLoadMetricCollector.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.cpu; - -import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; -import com.navercorp.pinpoint.thrift.dto.TCpuLoad; - -/** - * @author HyunGil Jeong - */ -public interface CpuLoadMetricCollector extends AgentStatMetricCollector { -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/DefaultCpuLoadMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/DefaultCpuLoadMetricCollector.java index 7bfe25b619ab..76f0dee1ca00 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/DefaultCpuLoadMetricCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/DefaultCpuLoadMetricCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.monitor.collector.cpu; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetric; import com.navercorp.pinpoint.profiler.monitor.metric.cpu.CpuLoadMetricSnapshot; import com.navercorp.pinpoint.thrift.dto.TCpuLoad; @@ -23,7 +24,7 @@ /** * @author HyunGil Jeong */ -public class DefaultCpuLoadMetricCollector implements CpuLoadMetricCollector { +public class DefaultCpuLoadMetricCollector implements AgentStatMetricCollector { private final CpuLoadMetric cpuLoadMetric; @@ -36,8 +37,9 @@ public DefaultCpuLoadMetricCollector(CpuLoadMetric cpuLoadMetric) { @Override public TCpuLoad collect() { - TCpuLoad cpuLoad = new TCpuLoad(); - CpuLoadMetricSnapshot snapshot = cpuLoadMetric.getSnapshot(); + final CpuLoadMetricSnapshot snapshot = cpuLoadMetric.getSnapshot(); + + final TCpuLoad cpuLoad = new TCpuLoad(); cpuLoad.setJvmCpuLoad(snapshot.getJvmCpuUsage()); cpuLoad.setSystemCpuLoad(snapshot.getSystemCpuUsage()); return cpuLoad; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/UnsupportedCpuLoadMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/UnsupportedCpuLoadMetricCollector.java deleted file mode 100644 index 3f1495a8d71a..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/cpu/UnsupportedCpuLoadMetricCollector.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.cpu; - -import com.navercorp.pinpoint.thrift.dto.TCpuLoad; - -/** - * @author HyunGil Jeong - */ -public class UnsupportedCpuLoadMetricCollector implements CpuLoadMetricCollector { - - @Override - public TCpuLoad collect() { - return null; - } - - @Override - public String toString() { - return "UnsupportedCpuLoadMetricCollector"; - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/DataSourceMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/DataSourceMetricCollector.java deleted file mode 100644 index ba83735773a0..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/DataSourceMetricCollector.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.datasource; - -import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; -import com.navercorp.pinpoint.thrift.dto.TDataSourceList; - -/** - * @author Taejin Koo - * @author HyunGil Jeong - */ -public interface DataSourceMetricCollector extends AgentStatMetricCollector { -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/DefaultDataSourceMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/DefaultDataSourceMetricCollector.java index 525f24683a41..29e25c3dcef1 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/DefaultDataSourceMetricCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/DefaultDataSourceMetricCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +16,19 @@ package com.navercorp.pinpoint.profiler.monitor.collector.datasource; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.metric.datasource.DataSource; import com.navercorp.pinpoint.profiler.monitor.metric.datasource.DataSourceMetric; +import com.navercorp.pinpoint.thrift.dto.TDataSource; import com.navercorp.pinpoint.thrift.dto.TDataSourceList; +import java.util.List; + /** * @author HyunGil Jeong */ -public class DefaultDataSourceMetricCollector implements DataSourceMetricCollector { +public class DefaultDataSourceMetricCollector implements AgentStatMetricCollector { private final DataSourceMetric dataSourceMetric; @@ -35,6 +41,32 @@ public DefaultDataSourceMetricCollector(DataSourceMetric dataSourceMetric) { @Override public TDataSourceList collect() { - return dataSourceMetric.dataSourceList(); + final List dataSources = dataSourceMetric.dataSourceList(); + + if (CollectionUtils.isEmpty(dataSources)) { + return new TDataSourceList(); + } + + + TDataSourceList tDataSourceList = new TDataSourceList(); + for (DataSource dataSource : dataSources) { + TDataSource tDataSource = toTDataSource(dataSource); + tDataSourceList.addToDataSourceList(tDataSource); + } + + return tDataSourceList; + } + + private TDataSource toTDataSource(DataSource dataSource) { + TDataSource tDataSource = new TDataSource(dataSource.getId()); + if (dataSource.getDatabaseName() != null) { + tDataSource.setDatabaseName(dataSource.getDatabaseName()); + } + + if (dataSource.getActiveConnectionSize() != 0) { + tDataSource.setActiveConnectionSize(dataSource.getActiveConnectionSize()); + } + tDataSource.setMaxConnectionSize(dataSource.getMaxConnectionSize()); + return tDataSource; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/UnsupportedDataSourceMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/UnsupportedDataSourceMetricCollector.java deleted file mode 100644 index b840c7f9f7d9..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/datasource/UnsupportedDataSourceMetricCollector.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.datasource; - -import com.navercorp.pinpoint.thrift.dto.TDataSourceList; - -/** - * @author HyunGil Jeong - */ -public class UnsupportedDataSourceMetricCollector implements DataSourceMetricCollector { - - @Override - public TDataSourceList collect() { - return null; - } - - @Override - public String toString() { - return "Unsupported DataSourceMetricCollector"; - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/DeadlockMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/DeadlockMetricCollector.java deleted file mode 100644 index 4dcb46e2ab86..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/DeadlockMetricCollector.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.deadlock; - -import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; -import com.navercorp.pinpoint.thrift.dto.TDeadlock; - -/** - * @author Taejin Koo - */ -public interface DeadlockMetricCollector extends AgentStatMetricCollector { -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/DefaultDeadlockMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/DefaultDeadlockMetricCollector.java index c58139da0ce1..07c9b507dc84 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/DefaultDeadlockMetricCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/DefaultDeadlockMetricCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,6 +17,7 @@ package com.navercorp.pinpoint.profiler.monitor.collector.deadlock; import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.deadlock.DeadlockMetric; import com.navercorp.pinpoint.profiler.util.ThreadDumpUtils; import com.navercorp.pinpoint.thrift.dto.TDeadlock; @@ -28,7 +29,7 @@ /** * @author Taejin Koo */ -public class DefaultDeadlockMetricCollector implements DeadlockMetricCollector { +public class DefaultDeadlockMetricCollector implements AgentStatMetricCollector { private Set prevDeadlockedThreadIdSet = new HashSet(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/UnsupportedDeadlockMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/UnsupportedDeadlockMetricCollector.java deleted file mode 100644 index c5714ad3fd58..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/deadlock/UnsupportedDeadlockMetricCollector.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.deadlock; - -import com.navercorp.pinpoint.thrift.dto.TDeadlock; - -/** - * @author Taejin Koo - */ -public class UnsupportedDeadlockMetricCollector implements DeadlockMetricCollector { - - @Override - public TDeadlock collect() { - return null; - } - - @Override - public String toString() { - return "UnsupportedDeadlockMetricCollector"; - } - -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/filedescriptor/DefaultFileDescriptorMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/filedescriptor/DefaultFileDescriptorMetricCollector.java new file mode 100644 index 000000000000..ea9a60a4a032 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/filedescriptor/DefaultFileDescriptorMetricCollector.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.collector.filedescriptor; + + +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; +import com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.FileDescriptorMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.FileDescriptorMetricSnapshot; +import com.navercorp.pinpoint.thrift.dto.TFileDescriptor; + +/** + * @author Roy Kim + */ +public class DefaultFileDescriptorMetricCollector implements AgentStatMetricCollector { + + private final FileDescriptorMetric fileDescriptorMetric; + + public DefaultFileDescriptorMetricCollector(FileDescriptorMetric fileDescriptorMetric) { + if (fileDescriptorMetric == null) { + throw new NullPointerException("fileDescriptorMetric must not be null"); + } + this.fileDescriptorMetric = fileDescriptorMetric; + } + + @Override + public TFileDescriptor collect() { + FileDescriptorMetricSnapshot snapshot = fileDescriptorMetric.getSnapshot(); + + TFileDescriptor tfileDescriptor = new TFileDescriptor(); + tfileDescriptor.setOpenFileDescriptorCount(snapshot.getOpenFileDescriptorCount()); + return tfileDescriptor; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DefaultFileDescriptorMetricCollector{"); + sb.append("fileDescriptorMetric=").append(fileDescriptorMetric); + sb.append('}'); + return sb.toString(); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/BasicJvmGcMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/BasicJvmGcMetricCollector.java index a0bca3909d5f..290edfcb52be 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/BasicJvmGcMetricCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/BasicJvmGcMetricCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,8 +16,10 @@ package com.navercorp.pinpoint.profiler.monitor.collector.jvmgc; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.gc.GarbageCollectorMetric; import com.navercorp.pinpoint.profiler.monitor.metric.gc.GarbageCollectorMetricSnapshot; +import com.navercorp.pinpoint.profiler.monitor.metric.gc.JvmGcType; import com.navercorp.pinpoint.profiler.monitor.metric.memory.MemoryMetric; import com.navercorp.pinpoint.profiler.monitor.metric.memory.MemoryMetricSnapshot; import com.navercorp.pinpoint.thrift.dto.TJvmGc; @@ -26,7 +28,7 @@ /** * @author HyunGil Jeong */ -public class BasicJvmGcMetricCollector implements JvmGcMetricCollector { +public class BasicJvmGcMetricCollector implements AgentStatMetricCollector { private final MemoryMetric memoryMetric; private final GarbageCollectorMetric garbageCollectorMetric; @@ -44,20 +46,26 @@ public BasicJvmGcMetricCollector(MemoryMetric memoryMetric, GarbageCollectorMetr @Override public TJvmGc collect() { - TJvmGc jvmGc = new TJvmGc(); - TJvmGcType jvmGcType = garbageCollectorMetric.getGcType(); + + JvmGcType jvmGcType = garbageCollectorMetric.getGcType(); + TJvmGcType tJvmGcType = TJvmGcTypeUtils.toTJvmGcType(jvmGcType.getValue()); + MemoryMetricSnapshot memoryMetricSnapshot = memoryMetric.getSnapshot(); GarbageCollectorMetricSnapshot garbageCollectorMetricSnapshot = garbageCollectorMetric.getSnapshot(); + + TJvmGc jvmGc = new TJvmGc(); jvmGc.setJvmMemoryHeapMax(memoryMetricSnapshot.getHeapMax()); jvmGc.setJvmMemoryHeapUsed(memoryMetricSnapshot.getHeapUsed()); jvmGc.setJvmMemoryNonHeapMax(memoryMetricSnapshot.getNonHeapMax()); jvmGc.setJvmMemoryNonHeapUsed(memoryMetricSnapshot.getNonHeapUsed()); jvmGc.setJvmGcOldCount(garbageCollectorMetricSnapshot.getGcOldCount()); jvmGc.setJvmGcOldTime(garbageCollectorMetricSnapshot.getGcOldTime()); - jvmGc.setType(jvmGcType); + jvmGc.setType(tJvmGcType); return jvmGc; } + + @Override public String toString() { final StringBuilder sb = new StringBuilder("BasicJvmGcMetricCollector{"); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/DetailedJvmGcMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/DetailedJvmGcMetricCollector.java index 84db43b0473a..fcaf4718fffd 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/DetailedJvmGcMetricCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/DetailedJvmGcMetricCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.monitor.collector.jvmgc; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.gc.DetailedGarbageCollectorMetric; import com.navercorp.pinpoint.profiler.monitor.metric.gc.DetailedGarbageCollectorMetricSnapshot; import com.navercorp.pinpoint.profiler.monitor.metric.memory.DetailedMemoryMetric; @@ -27,14 +28,14 @@ * @author dawidmalina * @author HyunGil Jeong */ -public class DetailedJvmGcMetricCollector implements JvmGcMetricCollector { +public class DetailedJvmGcMetricCollector implements AgentStatMetricCollector { - private final JvmGcMetricCollector jvmGcMetricCollector; + private final BasicJvmGcMetricCollector jvmGcMetricCollector; private final DetailedMemoryMetric detailedMemoryMetric; private final DetailedGarbageCollectorMetric detailedGarbageCollectorMetric; public DetailedJvmGcMetricCollector( - JvmGcMetricCollector jvmGcMetricCollector, + BasicJvmGcMetricCollector jvmGcMetricCollector, DetailedMemoryMetric detailedMemoryMetric, DetailedGarbageCollectorMetric detailedGarbageCollectorMetric) { if (jvmGcMetricCollector == null) { @@ -56,7 +57,8 @@ public TJvmGc collect() { TJvmGc jvmGc = jvmGcMetricCollector.collect(); DetailedMemoryMetricSnapshot detailedMemoryMetricSnapshot = detailedMemoryMetric.getSnapshot(); DetailedGarbageCollectorMetricSnapshot detailedGarbageCollectorMetricSnapshot = detailedGarbageCollectorMetric.getSnapshot(); - TJvmGcDetailed jvmGcDetailed = new TJvmGcDetailed(); + + final TJvmGcDetailed jvmGcDetailed = new TJvmGcDetailed(); jvmGcDetailed.setJvmPoolNewGenUsed(detailedMemoryMetricSnapshot.getNewGenUsage()); jvmGcDetailed.setJvmPoolOldGenUsed(detailedMemoryMetricSnapshot.getOldGenUsage()); jvmGcDetailed.setJvmPoolSurvivorSpaceUsed(detailedMemoryMetricSnapshot.getSurvivorSpaceUsage()); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/JvmGcMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/JvmGcMetricCollector.java deleted file mode 100644 index 4b7e18518e00..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/JvmGcMetricCollector.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.jvmgc; - -import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; -import com.navercorp.pinpoint.thrift.dto.TJvmGc; - -/** - * @author HyunGil Jeong - */ -public interface JvmGcMetricCollector extends AgentStatMetricCollector { -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/TJvmGcTypeUtils.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/TJvmGcTypeUtils.java new file mode 100644 index 000000000000..3d394f1b7be4 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/jvmgc/TJvmGcTypeUtils.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.collector.jvmgc; + +import com.navercorp.pinpoint.thrift.dto.TJvmGcType; + +/** + * @author Woonduk Kang(emeroad) + */ +public final class TJvmGcTypeUtils { + private TJvmGcTypeUtils() { + } + + public static TJvmGcType toTJvmGcType(int value) { + switch (value) { + case 0: + return TJvmGcType.UNKNOWN; + case 1: + return TJvmGcType.SERIAL; + case 2: + return TJvmGcType.PARALLEL; + case 3: + return TJvmGcType.CMS; + case 4: + return TJvmGcType.G1; + default: + return null; + } + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/DefaultResponseTimeMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/DefaultResponseTimeMetricCollector.java index 6b90dfa9b737..a335ecd8d8a6 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/DefaultResponseTimeMetricCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/DefaultResponseTimeMetricCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.monitor.collector.response; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeValue; import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeMetric; import com.navercorp.pinpoint.thrift.dto.TResponseTime; @@ -23,7 +24,7 @@ /** * @author Taejin Koo */ -public class DefaultResponseTimeMetricCollector implements ResponseTimeMetricCollector { +public class DefaultResponseTimeMetricCollector implements AgentStatMetricCollector { private final ResponseTimeMetric responseTimeMetric; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/ResponseTimeMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/ResponseTimeMetricCollector.java deleted file mode 100644 index 3a5242f14d33..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/ResponseTimeMetricCollector.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.response; - -import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; -import com.navercorp.pinpoint.thrift.dto.TResponseTime; - -/** - * @author Taejin Koo - */ -public interface ResponseTimeMetricCollector extends AgentStatMetricCollector { -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/UnsupportedResponseTimeMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/UnsupportedResponseTimeMetricCollector.java deleted file mode 100644 index 9f17fb036e7c..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/response/UnsupportedResponseTimeMetricCollector.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.response; - -import com.navercorp.pinpoint.thrift.dto.TResponseTime; - -/** - * @author Taejin Koo - */ -public class UnsupportedResponseTimeMetricCollector implements ResponseTimeMetricCollector { - @Override - public TResponseTime collect() { - return null; - } - - @Override - public String toString() { - return "UnsupportedResponseTimeMetricCollector"; - } - -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/DefaultTransactionMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/DefaultTransactionMetricCollector.java index 55efdb7962b6..350dfc2a288b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/DefaultTransactionMetricCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/DefaultTransactionMetricCollector.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,6 +17,7 @@ package com.navercorp.pinpoint.profiler.monitor.collector.transaction; import com.google.inject.Inject; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.transaction.TransactionMetric; import com.navercorp.pinpoint.profiler.monitor.metric.transaction.TransactionMetricSnapshot; import com.navercorp.pinpoint.thrift.dto.TTransaction; @@ -24,7 +25,7 @@ /** * @author HyunGil Jeong */ -public class DefaultTransactionMetricCollector implements TransactionMetricCollector { +public class DefaultTransactionMetricCollector implements AgentStatMetricCollector { private final TransactionMetric transactionMetric; @@ -35,8 +36,9 @@ public DefaultTransactionMetricCollector(TransactionMetric transactionMetric) { @Override public TTransaction collect() { - TTransaction transaction = new TTransaction(); TransactionMetricSnapshot transactionMetricSnapshot = transactionMetric.getSnapshot(); + + TTransaction transaction = new TTransaction(); transaction.setSampledNewCount(transactionMetricSnapshot.getSampledNewCount()); transaction.setSampledContinuationCount(transactionMetricSnapshot.getSampledContinuationCount()); transaction.setUnsampledNewCount(transactionMetricSnapshot.getUnsampledNewCount()); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/TransactionMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/TransactionMetricCollector.java deleted file mode 100644 index 761c3cb08536..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/TransactionMetricCollector.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.transaction; - -import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; -import com.navercorp.pinpoint.thrift.dto.TTransaction; - -/** - * @author HyunGil Jeong - */ -public interface TransactionMetricCollector extends AgentStatMetricCollector { -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/UnsupportedTransactionMetricCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/UnsupportedTransactionMetricCollector.java deleted file mode 100644 index 5704a7477adf..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/collector/transaction/UnsupportedTransactionMetricCollector.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.monitor.collector.transaction; - -import com.navercorp.pinpoint.thrift.dto.TTransaction; - -/** - * @author HyunGil Jeong - */ -public class UnsupportedTransactionMetricCollector implements TransactionMetricCollector { - - @Override - public TTransaction collect() { - return null; - } - - @Override - public String toString() { - return "UnsupportedTransactionMetricCollector"; - } -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/activethread/ActiveTraceMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/activethread/ActiveTraceMetric.java index ca76ad1b75f9..1c17a4e38c4b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/activethread/ActiveTraceMetric.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/activethread/ActiveTraceMetric.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.profiler.monitor.metric.activethread; -import com.navercorp.pinpoint.thrift.dto.TActiveTraceHistogram; +import com.navercorp.pinpoint.profiler.context.active.ActiveTraceHistogram; /** * @author HyunGil Jeong @@ -26,7 +26,7 @@ public interface ActiveTraceMetric { ActiveTraceMetric UNSUPPORTED_ACTIVE_TRACE_METRIC = new ActiveTraceMetric() { @Override - public TActiveTraceHistogram activeTraceHistogram() { + public ActiveTraceHistogram activeTraceHistogram() { return null; } @@ -36,5 +36,5 @@ public String toString() { } }; - TActiveTraceHistogram activeTraceHistogram(); + ActiveTraceHistogram activeTraceHistogram(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/activethread/DefaultActiveTraceMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/activethread/DefaultActiveTraceMetric.java index 75f6a2b95bbb..c2c5cf6565f3 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/activethread/DefaultActiveTraceMetric.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/activethread/DefaultActiveTraceMetric.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,11 +18,8 @@ import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.active.ActiveTraceHistogram; -import com.navercorp.pinpoint.profiler.context.active.ActiveTraceHistogramUtils; import com.navercorp.pinpoint.profiler.context.active.ActiveTraceRepository; -import com.navercorp.pinpoint.thrift.dto.TActiveTraceHistogram; -import java.util.List; /** * @author HyunGil Jeong @@ -36,22 +33,15 @@ public DefaultActiveTraceMetric(ActiveTraceRepository activeTraceRepository) { } @Override - public TActiveTraceHistogram activeTraceHistogram() { + public ActiveTraceHistogram activeTraceHistogram() { final long currentTimeMillis = System.currentTimeMillis(); final ActiveTraceHistogram histogram = activeTraceRepository.getActiveTraceHistogram(currentTimeMillis); - final int histogramSchemaTypeCode = histogram.getHistogramSchema().getTypeCode(); - - TActiveTraceHistogram tActiveTraceHistogram = new TActiveTraceHistogram(); - tActiveTraceHistogram.setHistogramSchemaType(histogramSchemaTypeCode); - - final List activeTraceCounts = ActiveTraceHistogramUtils.asList(histogram); - tActiveTraceHistogram.setActiveTraceCount(activeTraceCounts); - return tActiveTraceHistogram; + return histogram; } @Override public String toString() { - return "Default ActiveTraceCountMetric"; + return "DefaultActiveTraceMetric"; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/BufferMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/BufferMetric.java new file mode 100644 index 000000000000..8c3163934e22 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/BufferMetric.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.buffer; + +/** + * @author Roy Kim + */ +public interface BufferMetric { + + long UNCOLLECTED_VALUE = -1L; + + BufferMetric UNSUPPORTED_BUFFER_METRIC = new BufferMetric() { + + private final BufferMetricSnapshot uncollectedSnapshot = new BufferMetricSnapshot(UNCOLLECTED_VALUE, UNCOLLECTED_VALUE, UNCOLLECTED_VALUE, UNCOLLECTED_VALUE); + + @Override + public BufferMetricSnapshot getSnapshot() { + return uncollectedSnapshot; + } + + @Override + public String toString() { + return "Unsupported BufferMetric"; + } + }; + + BufferMetricSnapshot getSnapshot(); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/BufferMetricSnapshot.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/BufferMetricSnapshot.java new file mode 100644 index 000000000000..b6ce9f88b140 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/BufferMetricSnapshot.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.buffer; + +/** + * @author Roy Kim + */ +public class BufferMetricSnapshot { + + private final long directCount; + private final long directMemoryUsed; + private final long mappedCount; + private final long mappedMemoryUsed; + + public BufferMetricSnapshot(long directCount, long directMemoryUsed, long mappedCount, long mappedMemoryUsed){ + this.directCount = directCount; + this.directMemoryUsed = directMemoryUsed; + this.mappedCount = mappedCount; + this.mappedMemoryUsed = mappedMemoryUsed; + } + + public long getDirectCount() { + return directCount; + } + + public long getDirectMemoryUsed() { + return directMemoryUsed; + } + + public long getMappedCount() { + return mappedCount; + } + + public long getMappedMemoryUsed() { + return mappedMemoryUsed; + } + + @Override + public String toString() { + return "BufferMetricSnapshot{" + + "directCount=" + directCount + + ", directMemoryUsed=" + directMemoryUsed + + ", mappedCount=" + mappedCount + + ", mappedMemoryUsed=" + mappedMemoryUsed + + '}'; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/BufferType.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/BufferType.java new file mode 100644 index 000000000000..5bbe4d08cc97 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/buffer/BufferType.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.buffer; + +/** + * @author Roy kim + */ +public enum BufferType { + DIRECT("direct"), + MAPPED("mapped"); + + private final String name; + + + BufferType(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/CpuUsageProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/CpuUsageProvider.java new file mode 100644 index 000000000000..66f0717134d1 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/cpu/CpuUsageProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.cpu; + +/** + * @author HyunGil Jeong + */ +public interface CpuUsageProvider { + + double getCpuUsage(); + + CpuUsageProvider UNSUPPORTED = new CpuUsageProvider() { + @Override + public double getCpuUsage() { + return CpuLoadMetric.UNCOLLECTED_USAGE; + } + }; +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DataSource.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DataSource.java new file mode 100644 index 000000000000..ca1d24044cfb --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DataSource.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.datasource; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DataSource { + private final int id; // required + private short serviceTypeCode; // optional + private java.lang.String databaseName; // optional + private java.lang.String url; // optional + private int activeConnectionSize; // optional + private int maxConnectionSize; // optional + + + public DataSource(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + + public short getServiceTypeCode() { + return serviceTypeCode; + } + + public void setServiceTypeCode(short serviceTypeCode) { + this.serviceTypeCode = serviceTypeCode; + } + + public String getDatabaseName() { + return databaseName; + } + + public void setDatabaseName(String databaseName) { + this.databaseName = databaseName; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public int getActiveConnectionSize() { + return activeConnectionSize; + } + + public void setActiveConnectionSize(int activeConnectionSize) { + this.activeConnectionSize = activeConnectionSize; + } + + public int getMaxConnectionSize() { + return maxConnectionSize; + } + + public void setMaxConnectionSize(int maxConnectionSize) { + this.maxConnectionSize = maxConnectionSize; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DataSourceMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DataSourceMetric.java index d5b295d329d2..5e6212357c0e 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DataSourceMetric.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DataSourceMetric.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.profiler.monitor.metric.datasource; -import com.navercorp.pinpoint.thrift.dto.TDataSourceList; +import java.util.List; /** * @author Taejin Koo @@ -26,7 +26,7 @@ public interface DataSourceMetric { DataSourceMetric UNSUPPORTED_DATA_SOURCE_METRIC = new DataSourceMetric() { @Override - public TDataSourceList dataSourceList() { + public List dataSourceList() { return null; } @@ -36,5 +36,5 @@ public String toString() { } }; - TDataSourceList dataSourceList(); + List dataSourceList(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DefaultDataSourceMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DefaultDataSourceMetric.java index bd879069a278..7f13395f8805 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DefaultDataSourceMetric.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DefaultDataSourceMetric.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,9 +21,8 @@ import com.navercorp.pinpoint.profiler.context.monitor.DataSourceMonitorRegistryService; import com.navercorp.pinpoint.profiler.context.monitor.DataSourceMonitorWrapper; import com.navercorp.pinpoint.profiler.context.monitor.JdbcUrlParsingService; -import com.navercorp.pinpoint.thrift.dto.TDataSource; -import com.navercorp.pinpoint.thrift.dto.TDataSourceList; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -49,17 +48,17 @@ public DefaultDataSourceMetric(DataSourceMonitorRegistryService dataSourceMonito } @Override - public TDataSourceList dataSourceList() { - TDataSourceList dataSourceList = new TDataSourceList(); - - List dataSourceMonitorList = dataSourceMonitorRegistryService.getPluginMonitorWrapperList(); - if (!CollectionUtils.isEmpty(dataSourceMonitorList)) { - for (DataSourceMonitorWrapper dataSourceMonitor : dataSourceMonitorList) { - TDataSource dataSource = collectDataSource(dataSourceMonitor); - dataSourceList.addToDataSourceList(dataSource); - } - } else { - dataSourceList.setDataSourceList(Collections.emptyList()); + public List dataSourceList() { + + final List dataSourceMonitorList = dataSourceMonitorRegistryService.getPluginMonitorWrapperList(); + if (CollectionUtils.isEmpty(dataSourceMonitorList)) { + return Collections.emptyList(); + } + + List dataSourceList = new ArrayList(dataSourceMonitorList.size()); + for (DataSourceMonitorWrapper dataSourceMonitor : dataSourceMonitorList) { + DataSource dataSource = collectDataSource(dataSourceMonitor); + dataSourceList.add(dataSource); } return dataSourceList; } @@ -69,9 +68,8 @@ public String toString() { return "Default DataSourceMetric"; } - private TDataSource collectDataSource(DataSourceMonitorWrapper dataSourceMonitor) { - TDataSource dataSource = new TDataSource(); - dataSource.setId(dataSourceMonitor.getId()); + private DataSource collectDataSource(DataSourceMonitorWrapper dataSourceMonitor) { + final DataSource dataSource = new DataSource(dataSourceMonitor.getId()); dataSource.setServiceTypeCode(dataSourceMonitor.getServiceType().getCode()); String jdbcUrl = dataSourceMonitor.getUrl(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/FileDescriptorMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/FileDescriptorMetric.java new file mode 100644 index 000000000000..6ef5d492feeb --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/FileDescriptorMetric.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor; + +/** + * @author Roy Kim + */ +public interface FileDescriptorMetric { + + long UNCOLLECTED_USAGE = -1L; + + FileDescriptorMetric UNSUPPORTED_FILE_DESCRIPTOR_METRIC = new FileDescriptorMetric() { + + private final FileDescriptorMetricSnapshot uncollectedSnapshot = new FileDescriptorMetricSnapshot(UNCOLLECTED_USAGE); + + @Override + public FileDescriptorMetricSnapshot getSnapshot() { + return uncollectedSnapshot; + } + + @Override + public String toString() { + return "Unsupported FileDescriptorMetric"; + } + }; + + FileDescriptorMetricSnapshot getSnapshot(); +} + diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/FileDescriptorMetricSnapshot.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/FileDescriptorMetricSnapshot.java new file mode 100644 index 000000000000..677e8387e97d --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/filedescriptor/FileDescriptorMetricSnapshot.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor; + +/** + * @author Roy Kim + */ +public class FileDescriptorMetricSnapshot { + + private final long openFileDescriptorCount; + + public FileDescriptorMetricSnapshot(long openFileDescriptorCount) { + this.openFileDescriptorCount = openFileDescriptorCount; + } + + public long getOpenFileDescriptorCount() { + return openFileDescriptorCount; + } + +} + + diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/DefaultGarbageCollectorMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/DefaultGarbageCollectorMetric.java index bba7157d1a57..214cc92a107c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/DefaultGarbageCollectorMetric.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/DefaultGarbageCollectorMetric.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,6 @@ package com.navercorp.pinpoint.profiler.monitor.metric.gc; -import com.navercorp.pinpoint.thrift.dto.TJvmGcType; import java.lang.management.GarbageCollectorMXBean; @@ -40,7 +39,7 @@ public DefaultGarbageCollectorMetric(GarbageCollectorType garbageCollectorType, } @Override - public TJvmGcType getGcType() { + public JvmGcType getGcType() { return garbageCollectorType.jvmGcType(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorMetric.java index 20ea389fc7d8..428cc464b577 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorMetric.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorMetric.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,6 @@ package com.navercorp.pinpoint.profiler.monitor.metric.gc; -import com.navercorp.pinpoint.thrift.dto.TJvmGcType; /** * @author HyunGil Jeong @@ -25,7 +24,7 @@ public interface GarbageCollectorMetric { long UNCOLLECTED_VALUE = -1L; - TJvmGcType getGcType(); + JvmGcType getGcType(); GarbageCollectorMetricSnapshot getSnapshot(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorMetricSnapshot.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorMetricSnapshot.java index c39bab9218c9..74bd0b6871a7 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorMetricSnapshot.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorMetricSnapshot.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -36,4 +36,12 @@ public long getGcOldCount() { public long getGcOldTime() { return gcOldTime; } + + @Override + public String toString() { + return "GarbageCollectorMetricSnapshot{" + + "gcOldCount=" + gcOldCount + + ", gcOldTime=" + gcOldTime + + '}'; + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorType.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorType.java index 99656ea18d65..1fb177d52ec7 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorType.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/GarbageCollectorType.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,28 +16,26 @@ package com.navercorp.pinpoint.profiler.monitor.metric.gc; -import com.navercorp.pinpoint.thrift.dto.TJvmGcType; - /** * @author HyunGil Jeong */ public enum GarbageCollectorType { - SERIAL(TJvmGcType.SERIAL, "MarkSweepCompact", "Copy"), - PARALLEL(TJvmGcType.PARALLEL, "PS MarkSweep", "PS Scavenge"), - CMS(TJvmGcType.CMS, "ConcurrentMarkSweep", "ParNew"), - G1(TJvmGcType.G1, "G1 Old Generation", "G1 Young Generation"); + SERIAL(JvmGcType.SERIAL, "MarkSweepCompact", "Copy"), + PARALLEL(JvmGcType.PARALLEL, "PS MarkSweep", "PS Scavenge"), + CMS(JvmGcType.CMS, "ConcurrentMarkSweep", "ParNew"), + G1(JvmGcType.G1, "G1 Old Generation", "G1 Young Generation"); - private final TJvmGcType jvmGcType; + private final JvmGcType jvmGcType; private final String oldGenName; private final String newGenName; - GarbageCollectorType(TJvmGcType jvmGcType, String oldGenName, String newGenName) { + GarbageCollectorType(JvmGcType jvmGcType, String oldGenName, String newGenName) { this.jvmGcType = jvmGcType; this.oldGenName = oldGenName; this.newGenName = newGenName; } - public TJvmGcType jvmGcType() { + public JvmGcType jvmGcType() { return jvmGcType; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/JvmGcType.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/JvmGcType.java new file mode 100644 index 000000000000..bb9e20bcc6d2 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/JvmGcType.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.monitor.metric.gc; + + +import com.navercorp.pinpoint.thrift.dto.TJvmGcType; + +/** + * @author Woonduk Kang(emeroad) + */ +public enum JvmGcType { + UNKNOWN(0), + SERIAL(1), + PARALLEL(2), + CMS(3), + G1(4); + + private final int value; + + private JvmGcType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/UnknownGarbageCollectorMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/UnknownGarbageCollectorMetric.java index 14fdd0e9a8cb..08e6b1f55ff2 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/UnknownGarbageCollectorMetric.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/gc/UnknownGarbageCollectorMetric.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,6 @@ package com.navercorp.pinpoint.profiler.monitor.metric.gc; -import com.navercorp.pinpoint.thrift.dto.TJvmGcType; /** * Unknown garbage collector metrics @@ -28,8 +27,8 @@ public class UnknownGarbageCollectorMetric implements GarbageCollectorMetric { private static final GarbageCollectorMetricSnapshot UNSUPPORTED_SNAPSHOT = new GarbageCollectorMetricSnapshot(UNCOLLECTED_VALUE, UNCOLLECTED_VALUE); @Override - public TJvmGcType getGcType() { - return TJvmGcType.UNKNOWN; + public JvmGcType getGcType() { + return JvmGcType.UNKNOWN; } @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/DefaultMemoryMetric.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/DefaultMemoryMetric.java index 2d5204c000cd..47a23f0dfac4 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/DefaultMemoryMetric.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/DefaultMemoryMetric.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.monitor.metric.memory; +import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; @@ -24,30 +25,21 @@ */ public class DefaultMemoryMetric implements MemoryMetric { - private final MemoryMXBean memoryMXBean; + private MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); - public DefaultMemoryMetric(MemoryMXBean memoryMXBean) { - if (memoryMXBean == null) { - throw new NullPointerException("memoryMXBean must not be null"); - } - this.memoryMXBean = memoryMXBean; + + public DefaultMemoryMetric() { } + @Override public MemoryMetricSnapshot getSnapshot() { - MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage(); - MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage(); - long heapMax = UNCOLLECTED_VALUE; - long heapUsed = UNCOLLECTED_VALUE; - if (heapMemoryUsage != null) { - heapMax = heapMemoryUsage.getMax(); - heapUsed = heapMemoryUsage.getUsed(); - } - long nonHeapMax = UNCOLLECTED_VALUE; - long nonHeapUsed = UNCOLLECTED_VALUE; - if (nonHeapMemoryUsage != null) { - nonHeapMax = nonHeapMemoryUsage.getMax(); - nonHeapUsed = nonHeapMemoryUsage.getUsed(); - } + final MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage(); + final MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage(); + final long heapMax = heapMemoryUsage.getMax(); + final long heapUsed = heapMemoryUsage.getUsed(); + final long nonHeapMax = nonHeapMemoryUsage.getMax(); + final long nonHeapUsed = nonHeapMemoryUsage.getUsed(); + return new MemoryMetricSnapshot(heapMax, heapUsed, nonHeapMax, nonHeapUsed); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/MemoryMetricSnapshot.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/MemoryMetricSnapshot.java index fb63122e122b..cbf9307ee6ff 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/MemoryMetricSnapshot.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/MemoryMetricSnapshot.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -48,4 +48,14 @@ public long getNonHeapMax() { public long getNonHeapUsed() { return nonHeapUsed; } + + @Override + public String toString() { + return "MemoryMetricSnapshot{" + + "heapMax=" + heapMax + + ", heapUsed=" + heapUsed + + ", nonHeapMax=" + nonHeapMax + + ", nonHeapUsed=" + nonHeapUsed + + '}'; + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/response/ReuseResponseTimeCollector.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/response/ReuseResponseTimeCollector.java index 30aef26dab32..5f456d0824cb 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/response/ReuseResponseTimeCollector.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/monitor/metric/response/ReuseResponseTimeCollector.java @@ -17,7 +17,8 @@ package com.navercorp.pinpoint.profiler.monitor.metric.response; import com.google.inject.Inject; -import com.navercorp.pinpoint.profiler.util.jdk.LongAdder; +import com.navercorp.pinpoint.profiler.util.Counter; +import com.navercorp.pinpoint.profiler.util.CounterFactory; import java.util.concurrent.atomic.AtomicLong; @@ -56,14 +57,14 @@ private ResponseTimeCollector reset() { return copy; } - private static class ResponseTimeCollector { - private final LongAdder totalValue; - private final LongAdder transactionCount; + private class ResponseTimeCollector { + private final Counter totalValue; + private final Counter transactionCount; private final AtomicLong maxValue = new AtomicLong(0); private ResponseTimeCollector() { - this.totalValue = new LongAdder(); - this.transactionCount = new LongAdder(); + this.totalValue = CounterFactory.newCounter(); + this.transactionCount = CounterFactory.newCounter(); } void add(long value) { @@ -95,7 +96,6 @@ public long getMaxValue() { public long getTransactionCount() { return transactionCount.longValue(); } - } private static class ResponseTimeValue0 implements ResponseTimeValue { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/objectfactory/ConstructorResolver.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/objectfactory/ConstructorResolver.java index 4d0444661b7e..bccfb0f17dda 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/objectfactory/ConstructorResolver.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/objectfactory/ConstructorResolver.java @@ -1,11 +1,12 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,6 +15,9 @@ */ package com.navercorp.pinpoint.profiler.objectfactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.util.Arrays; @@ -24,26 +28,31 @@ * */ public class ConstructorResolver { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final Class type; private final ArgumentsResolver argumentsResolver; private Constructor resolvedConstructor; private Object[] resolvedArguments; - + public ConstructorResolver(Class type, ArgumentsResolver argumentsResolver) { + if (type == null) { + throw new NullPointerException("type must not be null"); + } this.type = type; this.argumentsResolver = argumentsResolver; } public boolean resolve() { - Constructor[] constructors = (Constructor[]) type.getConstructors(); + final Constructor[] constructors = type.getConstructors(); Arrays.sort(constructors, CONSTRUCTOR_COMPARATOR); for (Constructor constructor : constructors) { - Class[] types = constructor.getParameterTypes(); - Annotation[][] annotations = constructor.getParameterAnnotations(); + final Class[] parameterTypes = constructor.getParameterTypes(); + final Annotation[][] parameterAnnotations = constructor.getParameterAnnotations(); - Object[] resolvedArguments = argumentsResolver.resolve(types, annotations); + Object[] resolvedArguments = argumentsResolver.resolve(parameterTypes, parameterAnnotations); if (resolvedArguments != null) { this.resolvedConstructor = constructor; @@ -52,7 +61,9 @@ public boolean resolve() { return true; } } - + if (logger.isWarnEnabled()) { + resolveFailLog(type); + } return false; } @@ -64,6 +75,20 @@ public Object[] getResolvedArguments() { return resolvedArguments; } + private void resolveFailLog(Class type) { + final Constructor[] constructors = type.getConstructors(); + + for (Constructor constructor : constructors) { + final Class[] parameterTypes = constructor.getParameterTypes(); + logger.warn("Constructor resolve fail. class:{} {}", type.getName(), Arrays.toString(parameterTypes)); + for (int i = 0; i < parameterTypes.length; i++) { + final Class parameterClass = parameterTypes[i]; + final ClassLoader parameterClassLoader = type.getClassLoader(); + logger.warn("index:{} {} cl:{}", i, parameterClass, parameterClassLoader); + } + } + } + private static final Comparator> CONSTRUCTOR_COMPARATOR = new Comparator>() { @Override diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/objectfactory/ObjectBinderFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/objectfactory/ObjectBinderFactory.java index a2194f30368b..51448d160ea9 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/objectfactory/ObjectBinderFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/objectfactory/ObjectBinderFactory.java @@ -22,9 +22,11 @@ import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitorRegistry; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.monitor.DataSourceMonitorRegistryAdaptor; import com.navercorp.pinpoint.profiler.context.monitor.DataSourceMonitorRegistryService; import com.navercorp.pinpoint.profiler.interceptor.factory.AnnotatedInterceptorFactory; +import com.navercorp.pinpoint.profiler.interceptor.factory.ExceptionHandlerFactory; import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; /** @@ -35,26 +37,23 @@ public class ObjectBinderFactory { private final Provider traceContextProvider; private final DataSourceMonitorRegistry dataSourceMonitorRegistry; private final Provider apiMetaDataServiceProvider; + private final ExceptionHandlerFactory exceptionHandlerFactory; - public ObjectBinderFactory(ProfilerConfig profilerConfig, Provider traceContextProvider, DataSourceMonitorRegistryService dataSourceMonitorRegistryService, Provider apiMetaDataServiceProvider) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (traceContextProvider == null) { - throw new NullPointerException("traceContextProvider must not be null"); - } - if (dataSourceMonitorRegistryService == null) { - throw new NullPointerException("dataSourceMonitorRegistryService must not be null"); - } - if (apiMetaDataServiceProvider == null) { - throw new NullPointerException("apiMetaDataServiceProvider must not be null"); - } - - this.profilerConfig = profilerConfig; - this.traceContextProvider = traceContextProvider; + public ObjectBinderFactory(ProfilerConfig profilerConfig, + Provider traceContextProvider, + DataSourceMonitorRegistryService dataSourceMonitorRegistryService, + Provider apiMetaDataServiceProvider, + ExceptionHandlerFactory exceptionHandlerFactory) { + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.traceContextProvider = Assert.requireNonNull(traceContextProvider, "traceContextProvider must not be null"); + Assert.requireNonNull(dataSourceMonitorRegistryService, "dataSourceMonitorRegistryService must not be null"); this.dataSourceMonitorRegistry = new DataSourceMonitorRegistryAdaptor(dataSourceMonitorRegistryService); - this.apiMetaDataServiceProvider = apiMetaDataServiceProvider; + + this.apiMetaDataServiceProvider = Assert.requireNonNull(apiMetaDataServiceProvider, "apiMetaDataServiceProvider must not be null"); + this.exceptionHandlerFactory = Assert.requireNonNull(exceptionHandlerFactory, "exceptionHandlerFactory must not be null"); + + } public AutoBindingObjectFactory newAutoBindingObjectFactory(InstrumentContext pluginContext, ClassLoader classLoader, ArgumentProvider... argumentProviders) { @@ -68,9 +67,9 @@ public InterceptorArgumentProvider newInterceptorArgumentProvider(InstrumentClas return new InterceptorArgumentProvider(dataSourceMonitorRegistry, apiMetaDataService, instrumentClass); } - public AnnotatedInterceptorFactory newAnnotatedInterceptorFactory(InstrumentContext pluginContext, boolean exceptionHandle) { + public AnnotatedInterceptorFactory newAnnotatedInterceptorFactory(InstrumentContext pluginContext) { final TraceContext traceContext = this.traceContextProvider.get(); ApiMetaDataService apiMetaDataService = this.apiMetaDataServiceProvider.get(); - return new AnnotatedInterceptorFactory(profilerConfig, traceContext, dataSourceMonitorRegistry, apiMetaDataService, pluginContext, exceptionHandle); + return new AnnotatedInterceptorFactory(profilerConfig, traceContext, dataSourceMonitorRegistry, apiMetaDataService, pluginContext, exceptionHandlerFactory); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChain.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChain.java index 3380bf05453c..1c97429316fa 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChain.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ClassNameFilterChain.java @@ -24,13 +24,13 @@ */ public class ClassNameFilterChain implements ClassNameFilter { - private final List filterChain; + private final ClassNameFilter[] filterChain; public ClassNameFilterChain(List filterChain) { if (filterChain == null) { throw new NullPointerException("filterChain must not be null"); } - this.filterChain = new ArrayList(filterChain); + this.filterChain = filterChain.toArray(new ClassNameFilter[0]); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultPluginContextLoadResult.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultPluginContextLoadResult.java index 051fcf796939..d0c1ae4729b1 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultPluginContextLoadResult.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultPluginContextLoadResult.java @@ -18,14 +18,17 @@ import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.instrument.DynamicTransformTrigger; +import com.navercorp.pinpoint.common.plugin.PluginLoader; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.provider.plugin.ProfilerPluginLoader; import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; import com.navercorp.pinpoint.bootstrap.plugin.ApplicationTypeDetector; import com.navercorp.pinpoint.bootstrap.plugin.jdbc.JdbcUrlParserV2; +import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjectorFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.instrument.ClassFileTransformer; -import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -36,8 +39,8 @@ public class DefaultPluginContextLoadResult implements PluginContextLoadResult { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final URL[] pluginJars; private final InstrumentEngine instrumentEngine; + private final ClassInjectorFactory classInjectorFactory; private final ProfilerConfig profilerConfig; private final DynamicTransformTrigger dynamicTransformTrigger; @@ -45,35 +48,27 @@ public class DefaultPluginContextLoadResult implements PluginContextLoadResult { private final List setupResultList; public DefaultPluginContextLoadResult(ProfilerConfig profilerConfig, DynamicTransformTrigger dynamicTransformTrigger, InstrumentEngine instrumentEngine, - URL[] pluginJars) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (dynamicTransformTrigger == null) { - throw new NullPointerException("dynamicTransformTrigger must not be null"); - } - if (instrumentEngine == null) { - throw new NullPointerException("instrumentEngine must not be null"); - } - if (pluginJars == null) { - throw new NullPointerException("pluginJars must not be null"); - } - this.profilerConfig = profilerConfig; - this.dynamicTransformTrigger = dynamicTransformTrigger; + PluginLoader pluginLoader, ClassInjectorFactory classInjectorFactory) { + this.profilerConfig = Assert.requireNonNull(profilerConfig, "profilerConfig must not be null"); + this.dynamicTransformTrigger = Assert.requireNonNull(dynamicTransformTrigger, "dynamicTransformTrigger must not be null"); + this.instrumentEngine = Assert.requireNonNull(instrumentEngine, "instrumentEngine must not be null"); - this.pluginJars = pluginJars; - this.instrumentEngine = instrumentEngine; - this.setupResultList = load(); + + this.classInjectorFactory = Assert.requireNonNull(classInjectorFactory, "bootstrapCore must not be null"); + + this.setupResultList = load(pluginLoader); } - private List load() { + private List load(PluginLoader pluginLoader) { + Assert.requireNonNull(pluginLoader, "pluginLoader must not be null"); + logger.info("load plugin"); PluginSetup pluginSetup = new DefaultPluginSetup(profilerConfig, instrumentEngine, dynamicTransformTrigger); - final ProfilerPluginLoader loader = new ProfilerPluginLoader(profilerConfig, pluginSetup, instrumentEngine); - List load = loader.load(pluginJars); + final ProfilerPluginLoader loader = new ProfilerPluginLoader(profilerConfig, pluginSetup, classInjectorFactory, pluginLoader); + List load = loader.load(); return load; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultPluginSetup.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultPluginSetup.java index 5f7697f144b3..88a8cf0f61e2 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultPluginSetup.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/DefaultPluginSetup.java @@ -63,7 +63,7 @@ public SetupResult setupPlugin(ProfilerPlugin profilerPlugin, ClassInjector clas final DefaultProfilerPluginSetupContext setupContext = new DefaultProfilerPluginSetupContext(profilerConfig); final GuardProfilerPluginContext guardSetupContext = new GuardProfilerPluginContext(setupContext); - final InstrumentContext instrumentContext = new PluginInstrumentContext(profilerConfig, instrumentEngine, dynamicTransformTrigger, classInjector, transformerRegistry ); + final InstrumentContext instrumentContext = new PluginInstrumentContext(profilerConfig, instrumentEngine, dynamicTransformTrigger, classInjector, transformerRegistry); final GuardInstrumentContext guardInstrumentContext = preparePlugin(profilerPlugin, instrumentContext); try { // WARN external plugin api diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginConfig.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginConfig.java index cd181d210f69..b52edf7a4057 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginConfig.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginConfig.java @@ -16,13 +16,11 @@ package com.navercorp.pinpoint.profiler.plugin; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.navercorp.pinpoint.common.plugin.JarPlugin; +import com.navercorp.pinpoint.common.plugin.Plugin; +import com.navercorp.pinpoint.common.util.Assert; + -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; import java.util.Collections; import java.util.List; @@ -33,55 +31,48 @@ */ public class PluginConfig { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); public static final String PINPOINT_PLUGIN_PACKAGE = "Pinpoint-Plugin-Package"; - public static final List DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME = Collections.singletonList("com.navercorp.pinpoint.plugin"); + public static final String DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME = "com.navercorp.pinpoint.plugin"; + + private final Plugin plugin; + private final JarFile pluginJar; - private final URL pluginJar; - private final JarFile pluginJarFile; private String pluginJarURLExternalForm; private final ClassNameFilter pluginPackageFilter; - public PluginConfig(URL pluginJar, ClassNameFilter pluginPackageFilter) { - if (pluginJar == null) { - throw new NullPointerException("pluginJar must not be null"); - } - this.pluginJar = pluginJar; - this.pluginJarFile = createJarFile(pluginJar); + public PluginConfig(Plugin plugin, ClassNameFilter pluginPackageFilter) { + this.plugin = Assert.requireNonNull(plugin, "plugin must not be null"); this.pluginPackageFilter = pluginPackageFilter; + this.pluginJar = getJarFile(plugin); + + } + + private JarFile getJarFile(Plugin plugin) { + if (plugin instanceof JarPlugin) { + return ((JarPlugin) plugin).getJarFile(); + } + throw new IllegalArgumentException("unsupported plugin " + plugin); } public URL getPluginJar() { - return pluginJar; + return plugin.getURL(); } public JarFile getPluginJarFile() { - return pluginJarFile; + return pluginJar; } public String getPluginJarURLExternalForm() { if (this.pluginJarURLExternalForm == null) { - this.pluginJarURLExternalForm = pluginJar.toExternalForm(); + this.pluginJarURLExternalForm = plugin.getURL().toExternalForm(); } return this.pluginJarURLExternalForm; } - private JarFile createJarFile(URL pluginJar) { - try { - final URI uri = pluginJar.toURI(); - return new JarFile(new File(uri)); - } catch (URISyntaxException e) { - throw new RuntimeException("URISyntax error. " + e.getCause(), e); - } catch (IOException e) { - throw new RuntimeException("IO error. " + e.getCause(), e); - } - } - - public ClassNameFilter getPluginPackageFilter() { return pluginPackageFilter; } @@ -89,8 +80,7 @@ public ClassNameFilter getPluginPackageFilter() { @Override public String toString() { return "PluginConfig{" + - "pluginJar=" + pluginJar + - ", pluginJarFile=" + pluginJarFile + + "pluginJar=" + plugin.getURL() + ", pluginJarURLExternalForm='" + pluginJarURLExternalForm + '\'' + ", pluginPackageFilter=" + pluginPackageFilter + '}'; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginInstrumentContext.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginInstrumentContext.java index 8941203377a8..b73c693868cb 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginInstrumentContext.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/PluginInstrumentContext.java @@ -29,15 +29,21 @@ import com.navercorp.pinpoint.profiler.context.scope.InterceptorScopeFactory; import com.navercorp.pinpoint.profiler.context.scope.Pool; import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjector; -import com.navercorp.pinpoint.profiler.instrument.classloading.PluginClassInjector; +import com.navercorp.pinpoint.profiler.instrument.scanner.ClassScannerFactory; +import com.navercorp.pinpoint.profiler.instrument.scanner.Scanner; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.InputStream; +import java.security.ProtectionDomain; /** * @author Woonduk Kang(emeroad) */ public class PluginInstrumentContext implements InstrumentContext { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final ProfilerConfig profilerConfig; private final InstrumentEngine instrumentEngine; private final DynamicTransformTrigger dynamicTransformTrigger; @@ -72,35 +78,37 @@ public PluginInstrumentContext(ProfilerConfig profilerConfig, InstrumentEngine i - public PluginConfig getPluginConfig() { - if (classInjector instanceof PluginClassInjector) { - return ((PluginClassInjector) classInjector).getPluginConfig(); - } - return null; - } - - - @Override - public InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, byte[] classFileBuffer) { + public InstrumentClass getInstrumentClass(ClassLoader classLoader, String className, ProtectionDomain protectionDomain, byte[] classFileBuffer) { if (className == null) { throw new NullPointerException("className must not be null"); } try { final InstrumentEngine instrumentEngine = getInstrumentEngine(); - return instrumentEngine.getClass(this, classLoader, className, classFileBuffer); + return instrumentEngine.getClass(this, classLoader, className, protectionDomain, classFileBuffer); } catch (NotFoundInstrumentException e) { return null; } } + @Override - public boolean exist(ClassLoader classLoader, String className) { + public boolean exist(ClassLoader classLoader, String className, ProtectionDomain protectionDomain) { if (className == null) { throw new NullPointerException("className must not be null"); } - final InstrumentEngine instrumentEngine = getInstrumentEngine(); - return instrumentEngine.hasClass(classLoader, className); + + final String jvmClassName = JavaAssistUtils.javaClassNameToJvmResourceName(className); + + final Scanner scanner = ClassScannerFactory.newScanner(protectionDomain, classLoader); + if (logger.isDebugEnabled()) { + logger.debug("scanner:{}", scanner); + } + try { + return scanner.exist(jvmClassName); + } finally { + scanner.close(); + } } private InstrumentEngine getInstrumentEngine() { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ProfilerPluginLoader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ProfilerPluginLoader.java deleted file mode 100644 index 6d605c3f2690..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/plugin/ProfilerPluginLoader.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.profiler.plugin; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.jar.Attributes; -import java.util.jar.JarFile; -import java.util.jar.Manifest; - -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.profiler.instrument.InstrumentEngine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; -import com.navercorp.pinpoint.common.plugin.PluginLoader; -import com.navercorp.pinpoint.profiler.instrument.classloading.ClassInjector; -import com.navercorp.pinpoint.profiler.instrument.classloading.JarProfilerPluginClassInjector; - -/** - * @author Jongho Moon - * - */ -public class ProfilerPluginLoader { - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private final ClassNameFilter profilerPackageFilter = new PinpointProfilerPackageSkipFilter(); - - private final ProfilerConfig profilerConfig; - private final PluginSetup pluginSetup; - private final InstrumentEngine instrumentEngine; - - - public ProfilerPluginLoader(ProfilerConfig profilerConfig, PluginSetup pluginSetup, InstrumentEngine instrumentEngine) { - if (profilerConfig == null) { - throw new NullPointerException("profilerConfig must not be null"); - } - if (pluginSetup == null) { - throw new NullPointerException("pluginSetup must not be null"); - } - if (instrumentEngine == null) { - throw new NullPointerException("instrumentEngine must not be null"); - } - - - this.profilerConfig = profilerConfig; - this.pluginSetup = pluginSetup; - this.instrumentEngine = instrumentEngine; - - } - - public List load(URL[] pluginJars) { - - List pluginContexts = new ArrayList(pluginJars.length); - - for (URL pluginJar : pluginJars) { - - final JarFile pluginJarFile = createJarFile(pluginJar); - final List pluginPackageList = getPluginPackage(pluginJarFile); - - final ClassNameFilter pluginFilterChain = createPluginFilterChain(pluginPackageList); - - final List original = PluginLoader.load(ProfilerPlugin.class, new URL[] { pluginJar }); - - List plugins = filterDisablePlugin(original); - - for (ProfilerPlugin plugin : plugins) { - if (logger.isInfoEnabled()) { - logger.info("{} Plugin {}:{}", plugin.getClass(), PluginConfig.PINPOINT_PLUGIN_PACKAGE, pluginPackageList); - } - - logger.info("Loading plugin:{} pluginPackage:{}", plugin.getClass().getName(), plugin); - - PluginConfig pluginConfig = new PluginConfig(pluginJar, pluginFilterChain); - final ClassInjector classInjector = new JarProfilerPluginClassInjector(pluginConfig, instrumentEngine); - final SetupResult result = pluginSetup.setupPlugin(plugin, classInjector); - pluginContexts.add(result); - } - } - - - return pluginContexts; - } - - private List filterDisablePlugin(List plugins) { - - List disabled = profilerConfig.getDisabledPlugins(); - - List result = new ArrayList(); - for (ProfilerPlugin plugin : plugins) { - if (disabled.contains(plugin.getClass().getName())) { - logger.info("Skip disabled plugin: {}", plugin.getClass().getName()); - continue; - } - result.add(plugin); - } - return result; - } - - private ClassNameFilter createPluginFilterChain(List packageList) { - - final ClassNameFilter pluginPackageFilter = new PluginPackageFilter(packageList); - - final List chain = Arrays.asList(profilerPackageFilter, pluginPackageFilter); - - final ClassNameFilter filterChain = new ClassNameFilterChain(chain); - - return filterChain; - } - - private JarFile createJarFile(URL pluginJar) { - try { - final URI uri = pluginJar.toURI(); - return new JarFile(new File(uri)); - } catch (URISyntaxException e) { - throw new RuntimeException("URISyntax error. " + e.getCause(), e); - } catch (IOException e) { - throw new RuntimeException("IO error. " + e.getCause(), e); - } - } - private Manifest getManifest(JarFile pluginJarFile) { - try { - return pluginJarFile.getManifest(); - } catch (IOException ex) { - logger.info("{} IoError :{}", pluginJarFile.getName(), ex.getMessage(), ex); - return null; - } - } - - public List getPluginPackage(JarFile pluginJarFile) { - - final Manifest manifest = getManifest(pluginJarFile); - if (manifest == null) { - return PluginConfig.DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME; - } - - final Attributes attributes = manifest.getMainAttributes(); - final String pluginPackage = attributes.getValue(PluginConfig.PINPOINT_PLUGIN_PACKAGE); - if (pluginPackage == null) { - return PluginConfig.DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME; - } - return StringUtils.tokenizeToStringList(pluginPackage, ","); - } - - -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/CommandDispatcher.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/CommandDispatcher.java index 1ff9419ec14d..921682293383 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/CommandDispatcher.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/CommandDispatcher.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,6 +17,8 @@ package com.navercorp.pinpoint.profiler.receiver; import com.google.inject.Inject; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.rpc.MessageListener; import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.packet.RequestPacket; @@ -41,15 +43,11 @@ public class CommandDispatcher implements MessageListener, ServerStreamChannelMe private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final ProfilerCommandServiceLocator commandServiceLocator; + private final ProfilerCommandServiceLocator, TBase> commandServiceLocator; @Inject - public CommandDispatcher(ProfilerCommandServiceLocator commandServiceLocator) { - if (commandServiceLocator == null) { - throw new NullPointerException("commandServiceLocator must not be null"); - } - - this.commandServiceLocator = commandServiceLocator; + public CommandDispatcher(ProfilerCommandServiceLocator, TBase> commandServiceLocator) { + this.commandServiceLocator = Assert.requireNonNull(commandServiceLocator, "commandServiceLocator must not be null"); } @Override @@ -61,47 +59,58 @@ public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { logger.info("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); - final TBase request = SerializationUtils.deserialize(requestPacket.getPayload(), CommandSerializer.DESERIALIZER_FACTORY, null); - logger.debug("handleRequest request:{}, remote:{}", request, pinpointSocket.getRemoteAddress()); + final Message> message = SerializationUtils.deserialize(requestPacket.getPayload(), CommandSerializer.DESERIALIZER_FACTORY, null); + if (logger.isDebugEnabled()) { + logger.debug("handleRequest request:{}, remote:{}", message, pinpointSocket.getRemoteAddress()); + } + + final TBase response = processRequest(message); + + final byte[] payload = SerializationUtils.serialize(response, CommandSerializer.SERIALIZER_FACTORY, null); + if (payload != null) { + pinpointSocket.response(requestPacket.getRequestId(), payload); + } + } - TBase response; - if (request == null) { + private TBase processRequest(Message> message) { + if (message == null) { final TResult tResult = new TResult(false); tResult.setMessage("Unsupported ServiceTypeInfo."); - response = tResult; - } else { - final ProfilerRequestCommandService service = commandServiceLocator.getRequestService(request); - if (service == null) { - TResult tResult = new TResult(false); - tResult.setMessage("Can't find suitable service(" + request + ")."); - - response = tResult; - } else { - response = service.requestCommandService(request); - } + return tResult; } - final byte[] payload = SerializationUtils.serialize(response, CommandSerializer.SERIALIZER_FACTORY, null); - if (payload != null) { - pinpointSocket.response(requestPacket, payload); + final short type = message.getHeader().getType(); + final ProfilerRequestCommandService, TBase> service = commandServiceLocator.getRequestService(type); + if (service == null) { + TResult tResult = new TResult(false); + tResult.setMessage("Can't find suitable service(" + message + ")."); + + return tResult; } + + final TBase request = message.getData(); + final TBase tResponse = service.requestCommandService(request); + return tResponse; } + @Override public StreamCode handleStreamCreate(ServerStreamChannelContext streamChannelContext, StreamCreatePacket packet) { logger.info("MessageReceived handleStreamCreate {} {}", packet, streamChannelContext); - final TBase request = SerializationUtils.deserialize(packet.getPayload(), CommandSerializer.DESERIALIZER_FACTORY, null); - if (request == null) { + final Message> message = SerializationUtils.deserialize(packet.getPayload(), CommandSerializer.DESERIALIZER_FACTORY, null); + if (message == null) { return StreamCode.TYPE_UNKNOWN; } - - final ProfilerStreamCommandService service = commandServiceLocator.getStreamService(request); + + final short type = message.getHeader().getType(); + final ProfilerStreamCommandService> service = commandServiceLocator.getStreamService(type); if (service == null) { return StreamCode.TYPE_UNSUPPORT; } - + + final TBase request = message.getData(); return service.streamCommandService(request, streamChannelContext); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/CommandSerializer.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/CommandSerializer.java index 325c110bf4de..d9005b667aeb 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/CommandSerializer.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/CommandSerializer.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,13 +18,17 @@ import com.navercorp.pinpoint.thrift.io.CommandHeaderTBaseDeserializerFactory; import com.navercorp.pinpoint.thrift.io.CommandHeaderTBaseSerializerFactory; +import com.navercorp.pinpoint.thrift.io.DeserializerFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; +import com.navercorp.pinpoint.thrift.io.SerializerFactory; /** * @author Taejin Koo */ public class CommandSerializer { - public static final CommandHeaderTBaseSerializerFactory SERIALIZER_FACTORY = new CommandHeaderTBaseSerializerFactory(); - public static final CommandHeaderTBaseDeserializerFactory DESERIALIZER_FACTORY = new CommandHeaderTBaseDeserializerFactory(); + public static final SerializerFactory SERIALIZER_FACTORY = new CommandHeaderTBaseSerializerFactory(); + public static final DeserializerFactory DESERIALIZER_FACTORY = new CommandHeaderTBaseDeserializerFactory(); } \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/DefaultProfilerCommandServiceLocator.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/DefaultProfilerCommandServiceLocator.java index b1314a24bab5..ce7f0bb66ec7 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/DefaultProfilerCommandServiceLocator.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/DefaultProfilerCommandServiceLocator.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,10 +16,9 @@ package com.navercorp.pinpoint.profiler.receiver; -import com.navercorp.pinpoint.thrift.io.TCommandType; -import org.apache.thrift.TBase; +import com.navercorp.pinpoint.common.util.apache.IntHashMap; +import com.navercorp.pinpoint.common.util.apache.IntHashMapUtils; -import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -29,27 +28,24 @@ */ public class DefaultProfilerCommandServiceLocator implements ProfilerCommandServiceLocator { - private final Map, ProfilerCommandService> profilerCommandServiceRepository; + private final IntHashMap profilerCommandServiceRepository; + private final Set codeSet; DefaultProfilerCommandServiceLocator(ProfilerCommandLocatorBuilder builder) { - this.profilerCommandServiceRepository = Collections.unmodifiableMap(builder.getProfilerCommandServiceRepository()); + Map commandServiceRepository = builder.getProfilerCommandServiceRepository(); + this.profilerCommandServiceRepository = IntHashMapUtils.copyShortMap(commandServiceRepository); + this.codeSet = buildCodeSet(commandServiceRepository); } @Override - public ProfilerCommandService getService(TBase tBase) { - if (tBase == null) { - return null; - } - return profilerCommandServiceRepository.get(tBase.getClass()); + public ProfilerCommandService getService(short commandCode) { + return profilerCommandServiceRepository.get(commandCode); } @Override - public ProfilerSimpleCommandService getSimpleService(TBase tBase) { - if (tBase == null) { - return null; - } + public ProfilerSimpleCommandService getSimpleService(short commandCode) { - final ProfilerCommandService service = profilerCommandServiceRepository.get(tBase.getClass()); + final ProfilerCommandService service = profilerCommandServiceRepository.get(commandCode); if (service instanceof ProfilerSimpleCommandService) { return (ProfilerSimpleCommandService) service; } @@ -58,12 +54,9 @@ public ProfilerSimpleCommandService getSimpleService(TBase tBase) { } @Override - public ProfilerRequestCommandService getRequestService(TBase tBase) { - if (tBase == null) { - return null; - } + public ProfilerRequestCommandService getRequestService(short commandCode) { - final ProfilerCommandService service = profilerCommandServiceRepository.get(tBase.getClass()); + final ProfilerCommandService service = profilerCommandServiceRepository.get(commandCode); if (service instanceof ProfilerRequestCommandService) { return (ProfilerRequestCommandService) service; } @@ -72,12 +65,9 @@ public ProfilerRequestCommandService getRequestService(TBase tBase) { } @Override - public ProfilerStreamCommandService getStreamService(TBase tBase) { - if (tBase == null) { - return null; - } + public ProfilerStreamCommandService getStreamService(short commandCode) { - final ProfilerCommandService service = profilerCommandServiceRepository.get(tBase.getClass()); + final ProfilerCommandService service = profilerCommandServiceRepository.get(commandCode); if (service instanceof ProfilerStreamCommandService) { return (ProfilerStreamCommandService) service; } @@ -85,23 +75,18 @@ public ProfilerStreamCommandService getStreamService(TBase tBase) { return null; } - @Override - public Set> getCommandServiceClasses() { - return profilerCommandServiceRepository.keySet(); + int getCommandServiceSize() { + return profilerCommandServiceRepository.size(); } @Override public Set getCommandServiceCodes() { - Set commandServiceCodes = new HashSet(profilerCommandServiceRepository.size()); - - Set> clazzSet = profilerCommandServiceRepository.keySet(); - for (Class clazz : clazzSet) { - TCommandType commandType = TCommandType.getType(clazz); - if (commandType != null) { - commandServiceCodes.add(commandType.getCode()); - } - } - return commandServiceCodes; + return this.codeSet; + } + + private Set buildCodeSet(Map codes) { + return new HashSet(codes.keySet()); + } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandLocatorBuilder.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandLocatorBuilder.java index c6087c2b87a5..085a1e76be48 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandLocatorBuilder.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandLocatorBuilder.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,6 @@ package com.navercorp.pinpoint.profiler.receiver; -import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,10 +29,10 @@ public class ProfilerCommandLocatorBuilder { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final Map, ProfilerCommandService> profilerCommandServiceRepository; + private final Map profilerCommandServiceRepository; public ProfilerCommandLocatorBuilder() { - profilerCommandServiceRepository = new HashMap, ProfilerCommandService>(); + this.profilerCommandServiceRepository = new HashMap(); } public void addService(ProfilerCommandServiceGroup serviceGroup) { @@ -50,33 +49,29 @@ public boolean addService(ProfilerCommandService service) { if (service == null) { throw new NullPointerException("service must not be null"); } - return addService(service.getCommandClazz(), service); + return addService(service.getCommandServiceCode(), service); } - public boolean addService(Class clazz, ProfilerCommandService service) { - if (clazz == null) { - throw new NullPointerException("clazz must not be null"); - } + boolean addService(short commandCode, ProfilerCommandService service) { if (service == null) { throw new NullPointerException("service must not be null"); } - boolean hasValue = profilerCommandServiceRepository.containsKey(clazz); - if (!hasValue) { - profilerCommandServiceRepository.put(clazz, service); - return true; - } else { - ProfilerCommandService registeredService = profilerCommandServiceRepository.get(clazz); - logger.warn("Already Register ServiceTypeInfo:{}, RegisteredService:{}.", clazz.getName(), registeredService); + final ProfilerCommandService exist = profilerCommandServiceRepository.get(commandCode); + if (exist != null) { + logger.warn("Already Register CommandCode:{}, RegisteredService:{}.", commandCode, exist); return false; } + + profilerCommandServiceRepository.put(commandCode, service); + return true; } public ProfilerCommandServiceLocator build() { return new DefaultProfilerCommandServiceLocator(this); } - protected Map, ProfilerCommandService> getProfilerCommandServiceRepository() { + protected Map getProfilerCommandServiceRepository() { return profilerCommandServiceRepository; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandService.java index b3164dc6f560..df67bb840346 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandService.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +16,11 @@ package com.navercorp.pinpoint.profiler.receiver; -import org.apache.thrift.TBase; - /** * @author koo.taejin */ public interface ProfilerCommandService { - Class getCommandClazz(); + short getCommandServiceCode(); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandServiceLocator.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandServiceLocator.java index 75dc61628f27..a221a8103fc3 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandServiceLocator.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandServiceLocator.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,24 +16,20 @@ package com.navercorp.pinpoint.profiler.receiver; -import org.apache.thrift.TBase; - import java.util.Set; /** * @author koo.taejin */ -public interface ProfilerCommandServiceLocator { - - ProfilerCommandService getService(TBase tBase); +public interface ProfilerCommandServiceLocator { - ProfilerSimpleCommandService getSimpleService(TBase tBase); + ProfilerCommandService getService(short commandCode); - ProfilerRequestCommandService getRequestService(TBase tBase); + ProfilerSimpleCommandService getSimpleService(short commandCode); - ProfilerStreamCommandService getStreamService(TBase tBase); + ProfilerRequestCommandService getRequestService(short commandCode); - Set> getCommandServiceClasses(); + ProfilerStreamCommandService getStreamService(short commandCode); Set getCommandServiceCodes(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerRequestCommandService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerRequestCommandService.java index a8a3ed035ca1..a72201ccb357 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerRequestCommandService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerRequestCommandService.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +16,11 @@ package com.navercorp.pinpoint.profiler.receiver; -import org.apache.thrift.TBase; - /** * @author koo.taejin */ -public interface ProfilerRequestCommandService extends ProfilerCommandService { +public interface ProfilerRequestCommandService extends ProfilerCommandService { - TBase requestCommandService(TBase tBase); + RES requestCommandService(REQ request); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerSimpleCommandService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerSimpleCommandService.java index 3e2cbf38b16c..5ae1c1fbdc78 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerSimpleCommandService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerSimpleCommandService.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +16,11 @@ package com.navercorp.pinpoint.profiler.receiver; -import org.apache.thrift.TBase; - /** * @author koo.taejin */ -public interface ProfilerSimpleCommandService extends ProfilerCommandService { +public interface ProfilerSimpleCommandService extends ProfilerCommandService { - void simpleCommandService(TBase tbase); + void simpleCommandService(REQ request); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerStreamCommandService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerStreamCommandService.java index 8247adea843a..3c9b738cddc1 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerStreamCommandService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/ProfilerStreamCommandService.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,12 +17,11 @@ package com.navercorp.pinpoint.profiler.receiver; import com.navercorp.pinpoint.rpc.packet.stream.StreamCode; -import org.apache.thrift.TBase; import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelContext; -public interface ProfilerStreamCommandService extends ProfilerCommandService { +public interface ProfilerStreamCommandService extends ProfilerCommandService { - StreamCode streamCommandService(TBase tBase, ServerStreamChannelContext streamChannelContext); + StreamCode streamCommandService(REQ request, ServerStreamChannelContext streamChannelContext); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadCountService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadCountService.java index af9d95622b95..1cd5a3e4d0d7 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadCountService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadCountService.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -28,8 +28,8 @@ import com.navercorp.pinpoint.rpc.stream.StreamChannelStateChangeEventHandler; import com.navercorp.pinpoint.rpc.stream.StreamChannelStateCode; import com.navercorp.pinpoint.rpc.util.TimerFactory; -import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadCount; import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadCountRes; +import com.navercorp.pinpoint.thrift.io.TCommandType; import com.navercorp.pinpoint.thrift.util.SerializationUtils; import org.apache.thrift.TBase; import org.jboss.netty.util.HashedWheelTimer; @@ -46,7 +46,7 @@ /** * @author Taejin Koo */ -public class ActiveThreadCountService implements ProfilerRequestCommandService, ProfilerStreamCommandService { +public class ActiveThreadCountService implements ProfilerRequestCommandService, TBase>, ProfilerStreamCommandService> { private static final long DEFAULT_FLUSH_DELAY = 1000; @@ -76,12 +76,12 @@ public ActiveThreadCountService(ActiveTraceRepository activeTraceRepository, lon } @Override - public Class getCommandClazz() { - return TCmdActiveThreadCount.class; + public short getCommandServiceCode() { + return TCommandType.ACTIVE_THREAD_COUNT.getCode(); } @Override - public TBase requestCommandService(TBase activeThreadCountObject) { + public TBase requestCommandService(TBase activeThreadCountObject) { if (activeThreadCountObject == null) { throw new NullPointerException("activeThreadCountObject must not be null."); } @@ -90,7 +90,7 @@ public Class getCommandClazz() { } @Override - public StreamCode streamCommandService(TBase tBase, ServerStreamChannelContext streamChannelContext) { + public StreamCode streamCommandService(TBase tBase, ServerStreamChannelContext streamChannelContext) { logger.info("streamCommandService object:{}, streamChannelContext:{}", tBase, streamChannelContext); streamChannelContext.getStreamChannel().addStateChangeEventHandler(stateChangeEventHandler); return StreamCode.OK; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadDumpService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadDumpService.java index a427750cb7fa..758413fb842c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadDumpService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadDumpService.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -24,6 +24,7 @@ import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadDump; import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadDumpRes; import com.navercorp.pinpoint.thrift.dto.command.TThreadDump; +import com.navercorp.pinpoint.thrift.io.TCommandType; import org.apache.thrift.TBase; import java.lang.management.ThreadInfo; @@ -34,7 +35,7 @@ /** * @author Taejin Koo */ -public class ActiveThreadDumpService implements ProfilerRequestCommandService { +public class ActiveThreadDumpService implements ProfilerRequestCommandService, TBase> { static final String JAVA = "JAVA"; @@ -84,7 +85,7 @@ private TActiveThreadDump createTActiveThreadDump(ThreadDump threadDump) { final ActiveTraceSnapshot activeTraceInfo = threadDump.getActiveTraceSnapshot(); final ThreadInfo threadInfo = threadDump.getThreadInfo(); - TThreadDump tThreadDump = ThreadDumpUtils.createTThreadDump(threadInfo); + final TThreadDump tThreadDump = ThreadDumpUtils.createTThreadDump(threadInfo); TActiveThreadDump activeThreadDump = new TActiveThreadDump(); activeThreadDump.setStartTime(activeTraceInfo.getStartTime()); @@ -100,8 +101,8 @@ private TActiveThreadDump createTActiveThreadDump(ThreadDump threadDump) { } @Override - public Class getCommandClazz() { - return TCmdActiveThreadDump.class; + public short getCommandServiceCode() { + return TCommandType.ACTIVE_THREAD_DUMP.getCode(); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadLightDumpService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadLightDumpService.java index 7d42ba41d79a..d184a3b0805b 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadLightDumpService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ActiveThreadLightDumpService.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -25,6 +25,7 @@ import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadLightDump; import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadLightDumpRes; import com.navercorp.pinpoint.thrift.dto.command.TThreadLightDump; +import com.navercorp.pinpoint.thrift.io.TCommandType; import org.apache.thrift.TBase; import java.lang.management.ThreadInfo; @@ -35,7 +36,7 @@ /** * @author Taejin Koo */ -public class ActiveThreadLightDumpService implements ProfilerRequestCommandService { +public class ActiveThreadLightDumpService implements ProfilerRequestCommandService, TBase> { private final ActiveThreadDumpCoreService activeThreadDump; @@ -111,8 +112,8 @@ private TActiveThreadLightDump createActiveThreadDump(ThreadDump threadDump) { } @Override - public Class getCommandClazz() { - return TCmdActiveThreadLightDump.class; + public short getCommandServiceCode() { + return TCommandType.ACTIVE_THREAD_LIGHT_DUMP.getCode(); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/EchoService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/EchoService.java index d94589977135..bea7317b5e9a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/EchoService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/EchoService.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.receiver.service; +import com.navercorp.pinpoint.thrift.io.TCommandType; import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,7 +27,7 @@ /** * @author koo.taejin */ -public class EchoService implements ProfilerRequestCommandService { +public class EchoService implements ProfilerRequestCommandService, TBase> { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Override @@ -38,8 +39,8 @@ public class EchoService implements ProfilerRequestCommandService { } @Override - public Class getCommandClazz() { - return TCommandEcho.class; + public short getCommandServiceCode() { + return TCommandType.ECHO.getCode(); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ThreadDumpService.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ThreadDumpService.java index 84e7b577c56f..466da282a978 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ThreadDumpService.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/receiver/service/ThreadDumpService.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -25,6 +25,7 @@ import com.navercorp.pinpoint.thrift.dto.command.TThreadDump; import com.navercorp.pinpoint.thrift.dto.command.TThreadDumpType; import com.navercorp.pinpoint.thrift.dto.command.TThreadState; +import com.navercorp.pinpoint.thrift.io.TCommandType; import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,7 +42,7 @@ /** * @author koo.taejin */ -public class ThreadDumpService implements ProfilerRequestCommandService { +public class ThreadDumpService implements ProfilerRequestCommandService, TBase> { private static final Set THREAD_STATES = EnumSet.allOf(TThreadState.class); @@ -180,8 +181,8 @@ private ThreadInfo[] getAllThreadInfo() { } @Override - public Class getCommandClazz() { - return TCommandThreadDump.class; + public short getCommandServiceCode() { + return TCommandType.THREAD_DUMP.getCode(); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/AbstractDataSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/AbstractDataSender.java deleted file mode 100644 index f9372fb9c231..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/AbstractDataSender.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.sender; - -import java.util.Collection; - -import org.apache.thrift.TBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.rpc.FutureListener; -import com.navercorp.pinpoint.rpc.ResponseMessage; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; -import com.navercorp.pinpoint.thrift.util.SerializationUtils; - -/** - * - * @author koo.taejin - */ -public abstract class AbstractDataSender implements DataSender { - - private Logger logger = LoggerFactory.getLogger(this.getClass()); - - abstract protected void sendPacket(Object dto); - - protected void sendPacketN(Collection messageList) { - // Cannot use toArray(T[] array) because passed messageList doesn't implement it properly. - Object[] dataList = messageList.toArray(); - - // No need to copy because this runs with single thread. - // Object[] copy = Arrays.copyOf(original, original.length); - - final int size = messageList.size(); - for (int i = 0; i < size; i++) { - try { - sendPacket(dataList[i]); - } catch (Throwable th) { - logger.warn("Unexpected Error. Cause:{}", th.getMessage(), th); - } - } - } - - protected AsyncQueueingExecutor createAsyncQueueingExecutor(int queueSize, String executorName) { - final AsyncQueueingExecutor executor = new AsyncQueueingExecutor(queueSize, executorName); - executor.setListener(new AsyncQueueingExecutorListener() { - @Override - public void execute(Collection messageList) { - sendPacketN(messageList); - } - - @Override - public void execute(Object message) { - sendPacket(message); - } - }); - return executor; - } - - protected byte[] serialize(HeaderTBaseSerializer serializer, TBase tBase) { - return SerializationUtils.serialize(tBase, serializer, null); - } - - protected TBase deserialize(HeaderTBaseDeserializer deserializer, ResponseMessage responseMessage) { - byte[] message = responseMessage.getMessage(); - return SerializationUtils.deserialize(message, deserializer, null); - } - - protected static class RequestMarker { - private final TBase tBase; - private final int retryCount; - private final FutureListener futureListener; - - protected RequestMarker(TBase tBase, int retryCount) { - this.tBase = tBase; - this.retryCount = retryCount; - this.futureListener = null; - } - - protected RequestMarker(TBase tBase, FutureListener futureListener) { - this.tBase = tBase; - this.retryCount = 3; - this.futureListener = futureListener; - } - - protected TBase getTBase() { - return tBase; - } - - protected int getRetryCount() { - return retryCount; - } - - protected FutureListener getFutureListener() { - return futureListener; - } - } - -} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/AsyncQueueingExecutor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/AsyncQueueingExecutor.java index 64a0c4d32577..b3baa6caa629 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/AsyncQueueingExecutor.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/AsyncQueueingExecutor.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,11 +17,13 @@ package com.navercorp.pinpoint.profiler.sender; import java.util.Collection; +import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import com.navercorp.pinpoint.common.util.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,10 +34,8 @@ */ public class AsyncQueueingExecutor implements Runnable { - private static final AsyncQueueingExecutorListener EMPTY_LISTENER = new EmptyAsyncQueueingExecutorListener(); - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final boolean isWarn = logger.isWarnEnabled(); + private final Logger logger; + private final boolean isWarn; private final LinkedBlockingQueue queue; private final AtomicBoolean isRun = new AtomicBoolean(true); @@ -46,17 +46,15 @@ public class AsyncQueueingExecutor implements Runnable { // Caution. single thread only. this Collection is simpler than ArrayList. private final Collection drain; - private AsyncQueueingExecutorListener listener = EMPTY_LISTENER; + private final AsyncQueueingExecutorListener listener; - public AsyncQueueingExecutor() { - this(1024 * 5, "Pinpoint-AsyncQueueingExecutor"); - } + public AsyncQueueingExecutor(int queueSize, String executorName, AsyncQueueingExecutorListener listener) { + Assert.requireNonNull(executorName, "executorName must not be null"); + + this.logger = LoggerFactory.getLogger(this.getClass().getName() + "@" + executorName); + this.isWarn = logger.isWarnEnabled(); - public AsyncQueueingExecutor(int queueSize, String executorName) { - if (executorName == null) { - throw new NullPointerException("executorName must not be null"); - } // BEFORE executeThread start this.maxDrainSize = 10; this.drain = new UnsafeArrayCollection(maxDrainSize); @@ -64,6 +62,8 @@ public AsyncQueueingExecutor(int queueSize, String executorName) { this.executeThread = this.createExecuteThread(executorName); this.executorName = executeThread.getName(); + + this.listener = Assert.requireNonNull(listener, "listener must not be null"); } private Thread createExecuteThread(String executorName) { @@ -83,15 +83,15 @@ private void doExecute() { drainStartEntry: while (isRun()) { try { - Collection dtoList = getDrainQueue(); - int drainSize = takeN(dtoList, this.maxDrainSize); + final Collection dtoList = getDrainQueue(); + final int drainSize = takeN(dtoList, this.maxDrainSize); if (drainSize > 0) { doExecute(dtoList); continue; } while (isRun()) { - T dto = takeOne(); + final T dto = takeOne(); if (dto != null) { doExecute(dto); continue drainStartEntry; @@ -110,7 +110,7 @@ private void flushQueue() { logger.debug("Loop is stop."); } while(true) { - Collection dtoList = getDrainQueue(); + final Collection dtoList = getDrainQueue(); int drainSize = takeN(dtoList, this.maxDrainSize); if (drainSize == 0) { break; @@ -122,7 +122,7 @@ private void flushQueue() { } } - protected T takeOne() { + private T takeOne() { try { return queue.poll(1000 * 2, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { @@ -131,7 +131,7 @@ protected T takeOne() { } } - protected int takeN(Collection drain, int maxDrainSize) { + private int takeN(Collection drain, int maxDrainSize) { return queue.drainTo(drain, maxDrainSize); } @@ -157,12 +157,6 @@ public boolean execute(T data) { return offer; } - public void setListener(AsyncQueueingExecutorListener listener) { - if (listener == null) { - throw new NullPointerException("listener must not be null"); - } - this.listener = listener; - } private void doExecute(Collection dtoList) { this.listener.execute(dtoList); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/BufferedUdpDataSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/BufferedUdpDataSender.java deleted file mode 100644 index 626c0be71f51..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/BufferedUdpDataSender.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.sender; - -import java.io.IOException; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; - -import org.apache.thrift.TBase; -import org.apache.thrift.TException; - -import com.navercorp.pinpoint.common.util.PinpointThreadFactory; -import com.navercorp.pinpoint.thrift.io.ChunkHeaderBufferedTBaseSerializer; -import com.navercorp.pinpoint.thrift.io.ChunkHeaderBufferedTBaseSerializerFactory; -import com.navercorp.pinpoint.thrift.io.ChunkHeaderBufferedTBaseSerializerFlushHandler; - -/** - * split & buffering - * - * only use pair collector-ChunkedUDPReceiver - * - * @author jaehong.kim - * - */ -public class BufferedUdpDataSender extends UdpDataSender { - private static final int CHUNK_SIZE = 1024 * 16; - - private static final String SCHEDULED_FLUSH = "BufferedUdpDataSender-ScheduledFlush"; - - private final ChunkHeaderBufferedTBaseSerializer chunkHeaderBufferedSerializer = new ChunkHeaderBufferedTBaseSerializerFactory().createSerializer(); - - private final Thread flushThread; - - - public BufferedUdpDataSender(String host, int port, String threadName, int queueSize) { - this(host, port, threadName, queueSize, SOCKET_TIMEOUT, SEND_BUFFER_SIZE, CHUNK_SIZE); - } - - public BufferedUdpDataSender(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize, int chunkSize) { - super(host, port, threadName, queueSize, timeout, sendBufferSize); - - chunkHeaderBufferedSerializer.setChunkSize(chunkSize); - chunkHeaderBufferedSerializer.setFlushHandler(new ChunkHeaderBufferedTBaseSerializerFlushHandler() { - @Override - public void handle(byte[] buffer, int offset, int length) { - if (buffer == null) { - logger.warn("interBufferData is null"); - return; - } - - final int internalBufferSize = length; - if (isLimit(internalBufferSize)) { - logger.warn("discard packet. Caused:too large message. size:{}", internalBufferSize); - return; - } - // We can reuse this because this runs in single thread - reusePacket.setData(buffer, 0, internalBufferSize); - - try { - udpSocket.send(reusePacket); - if (isDebug) { - logger.debug("Data sent. {size={}}", internalBufferSize); - } - } catch (IOException e) { - logger.warn("packet send error. size:{}", internalBufferSize, e); - } - } - }); - - flushThread = startScheduledFlush(); - } - - // for test - String getFlushThreadName() { - return flushThread.getName(); - } - - private Thread startScheduledFlush() { - final ThreadFactory threadFactory = new PinpointThreadFactory(SCHEDULED_FLUSH, true); - final Thread thread = threadFactory.newThread(new Runnable() { - @Override - public void run() { - final Thread currentThread = Thread.currentThread(); - while (!currentThread.isInterrupted()) { - try { - chunkHeaderBufferedSerializer.flush(); - } catch (TException e) { - logger.warn("Failed to flush. caused={}", e.getMessage(), e); - } - try { - TimeUnit.MILLISECONDS.sleep(1000); - } catch (InterruptedException ignored) { - currentThread.interrupt(); - } - } - logger.info("stop ScheduledFlush {} - {}", currentThread.getName(), currentThread.getId()); - } - }); - logger.info("stop ScheduledFlush {} - {}", thread.getName(), thread.getId()); - thread.start(); - return thread; - } - - - @Override - protected void sendPacket(Object message) { - if (message instanceof TBase) { - try { - final TBase packet = (TBase) message; - chunkHeaderBufferedSerializer.add(packet); - logger.debug("Send packet {}", packet); - } catch (TException e) { - logger.warn("sendPacket fail.", e); - } - } else { - logger.warn("sendPacket fail. invalid type:{}", message != null ? message.getClass() : null); - return; - } - } - - @Override - public void stop() { - super.stop(); - stopFlushThread(); - } - - private void stopFlushThread() { - final Thread flushThread = this.flushThread; - // terminate thread - flushThread.interrupt(); - try { - flushThread.join(5000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - } -} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ByteMessage.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ByteMessage.java new file mode 100644 index 000000000000..df2c9d8a8e90 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ByteMessage.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ByteMessage { + private final byte[] message; + private final int length; + + public ByteMessage(byte[] message, int length) { + this.message = message; + this.length = length; + } + + public byte[] getMessage() { + return message; + } + + public int getLength() { + return length; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/DataSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/DataSender.java index 476ac5a7861d..2cefd7747d59 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/DataSender.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/DataSender.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,15 +16,13 @@ package com.navercorp.pinpoint.profiler.sender; -import org.apache.thrift.TBase; - /** * @author emeroad * @author netspider */ -public interface DataSender { +public interface DataSender { - boolean send(TBase data); + boolean send(T data); void stop(); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/DefaultAsyncQueueingExecutorListener.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/DefaultAsyncQueueingExecutorListener.java new file mode 100644 index 000000000000..cb62973336b5 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/DefaultAsyncQueueingExecutorListener.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; + +/** + * @author Woonduk Kang(emeroad) + */ +public abstract class DefaultAsyncQueueingExecutorListener implements AsyncQueueingExecutorListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void execute(Collection messageList) { + // Cannot use toArray(T[] array) because passed messageList doesn't implement it properly. + Object[] dataList = messageList.toArray(); + + // No need to copy because this runs with single thread. + // Object[] copy = Arrays.copyOf(original, original.length); + + final int size = messageList.size(); + for (int i = 0; i < size; i++) { + try { + execute(dataList[i]); + } catch (Throwable th) { + logger.warn("Unexpected Error. Cause:{}", th.getMessage(), th); + } + } + } + + + public abstract void execute(Object message); + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/EmptyDataSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/EmptyDataSender.java index 4ae4b83ab5e2..09aa74958643 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/EmptyDataSender.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/EmptyDataSender.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,18 +19,18 @@ import com.navercorp.pinpoint.rpc.FutureListener; import com.navercorp.pinpoint.rpc.ResponseMessage; import com.navercorp.pinpoint.rpc.client.PinpointClientReconnectEventListener; -import org.apache.thrift.TBase; + /** * @author Woonduk Kang(emeroad) */ -public class EmptyDataSender implements EnhancedDataSender { +public class EmptyDataSender implements EnhancedDataSender { public static final DataSender INSTANCE = new EmptyDataSender(); @Override - public boolean send(TBase data) { + public boolean send(Object data) { return true; } @@ -40,18 +40,18 @@ public void stop() { } @Override - public boolean request(TBase data) { + public boolean request(Object data) { return true; } @Override - public boolean request(TBase data, int retry) { + public boolean request(Object data, int retry) { return false; } @Override - public boolean request(TBase data, FutureListener listener) { + public boolean request(Object data, FutureListener listener) { return false; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/EnhancedDataSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/EnhancedDataSender.java index 0d4511fc728b..0247d625355f 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/EnhancedDataSender.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/EnhancedDataSender.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,16 +20,15 @@ import com.navercorp.pinpoint.rpc.ResponseMessage; import com.navercorp.pinpoint.rpc.client.PinpointClientReconnectEventListener; -import org.apache.thrift.TBase; /** * @author emeroad */ -public interface EnhancedDataSender extends DataSender { +public interface EnhancedDataSender extends DataSender { - boolean request(TBase data); - boolean request(TBase data, int retry); - boolean request(TBase data, FutureListener listener); + boolean request(T data); + boolean request(T data, int retry); + boolean request(T data, FutureListener listener); boolean addReconnectEventListener(PinpointClientReconnectEventListener eventListener); boolean removeReconnectEventListener(PinpointClientReconnectEventListener eventListener); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ListenerableRequestMessage.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ListenerableRequestMessage.java new file mode 100644 index 000000000000..1fae5f9bc946 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ListenerableRequestMessage.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +import com.navercorp.pinpoint.rpc.FutureListener; + +/** + * @author Woonduk Kang(emeroad) + */ +class ListenerableRequestMessage implements RequestMessage { + private final T message; + private final FutureListener futureListener; + + + ListenerableRequestMessage(T message, FutureListener futureListener) { + this.message = message; + this.futureListener = futureListener; + } + + + @Override + public T getMessage() { + return message; + } + + @Override + public int getRetryCount() { + return 3; + } + + @Override + public FutureListener getFutureListener() { + return futureListener; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/LoggingDataSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/LoggingDataSender.java index 3138383a1216..c0b66c1e7735 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/LoggingDataSender.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/LoggingDataSender.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,6 @@ import com.navercorp.pinpoint.rpc.ResponseMessage; import com.navercorp.pinpoint.rpc.client.PinpointClientReconnectEventListener; -import org.apache.thrift.TBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,14 +28,14 @@ * @author emeroad * @author netspider */ -public class LoggingDataSender implements EnhancedDataSender { +public class LoggingDataSender implements EnhancedDataSender { public static final DataSender DEFAULT_LOGGING_DATA_SENDER = new LoggingDataSender(); private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Override - public boolean send(TBase data) { + public boolean send(Object data) { logger.info("send tBase:{}", data); return true; } @@ -48,20 +47,20 @@ public void stop() { } @Override - public boolean request(TBase data) { + public boolean request(Object data) { logger.info("request tBase:{}", data); return true; } @Override - public boolean request(TBase data, int retry) { + public boolean request(Object data, int retry) { logger.info("request tBase:{} retry:{}", data, retry); return false; } @Override - public boolean request(TBase data, FutureListener listener) { + public boolean request(Object data, FutureListener listener) { logger.info("request tBase:{} FutureListener:{}", data, listener); return false; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/MessageSerializer.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/MessageSerializer.java new file mode 100644 index 000000000000..5ed7193d91ea --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/MessageSerializer.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface MessageSerializer { + + M serializer(Object message); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/NioUDPDataSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/NioUDPDataSender.java index 57d2752d5295..ae7f7dabc4c7 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/NioUDPDataSender.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/NioUDPDataSender.java @@ -1,22 +1,24 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ package com.navercorp.pinpoint.profiler.sender; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import com.navercorp.pinpoint.common.util.IOUtils; import com.navercorp.pinpoint.rpc.PinpointSocketException; import com.navercorp.pinpoint.rpc.buffer.ByteBufferFactory; import com.navercorp.pinpoint.rpc.buffer.ByteBufferFactoryLocator; @@ -38,7 +40,7 @@ /** * @author Taejin Koo */ -public class NioUDPDataSender extends AbstractDataSender implements DataSender { +public class NioUDPDataSender implements DataSender { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); protected final boolean isDebug = logger.isDebugEnabled(); @@ -52,29 +54,20 @@ public class NioUDPDataSender extends AbstractDataSender implements DataSender { private final ByteBufferOutputStream byteBufferOutputStream; private final AsyncQueueingExecutor executor; + private final MessageConverter> messageConverter; private volatile boolean closed = false; - public NioUDPDataSender(String host, int port, String threadName, int queueSize) { - this(host, port, threadName, queueSize, SOCKET_TIMEOUT, SEND_BUFFER_SIZE); - } - public NioUDPDataSender(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize) { - if (host == null ) { - throw new NullPointerException("host must not be null"); - } - if (threadName == null) { - throw new NullPointerException("threadName must not be null"); - } - if (queueSize <= 0) { - throw new IllegalArgumentException("queueSize"); - } - if (timeout <= 0) { - throw new IllegalArgumentException("timeout"); - } - if (sendBufferSize <= 0) { - throw new IllegalArgumentException("sendBufferSize"); - } + public NioUDPDataSender(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize, + MessageConverter> messageConverter) { + Assert.requireNonNull(host, "host must not be null"); + Assert.requireNonNull(threadName, "threadName must not be null"); + Assert.isTrue(queueSize > 0, "queueSize"); + Assert.isTrue(timeout > 0, "timeout"); + Assert.isTrue(sendBufferSize > 0, "sendBufferSize"); + + this.messageConverter = Assert.requireNonNull(messageConverter, "messageConverter must not be null"); // TODO If fail to create socket, stop agent start logger.info("NioUDPDataSender initialized. host={}, port={}", host, port); @@ -90,6 +83,19 @@ public NioUDPDataSender(String host, int port, String threadName, int queueSize, this.executor = createAsyncQueueingExecutor(queueSize, threadName); } + private AsyncQueueingExecutor createAsyncQueueingExecutor(int queueSize, String executorName) { + AsyncQueueingExecutorListener listener = new DefaultAsyncQueueingExecutorListener() { + @Override + public void execute(Object message) { + NioUDPDataSender.this.sendPacket(message); + } + }; + final AsyncQueueingExecutor executor = new AsyncQueueingExecutor(queueSize, executorName, listener); + return executor; + } + + + private DatagramChannel createChannel(String host, int port, int timeout, int sendBufferSize) { DatagramChannel datagramChannel = null; DatagramSocket socket = null; @@ -111,23 +117,15 @@ private DatagramChannel createChannel(String host, int port, int timeout, int se return datagramChannel; } catch (IOException e) { - if (socket != null) { - socket.close(); - } - - if (datagramChannel != null) { - try { - datagramChannel.close(); - } catch (IOException ignored) { - } - } + IOUtils.closeQuietly(socket); + IOUtils.closeQuietly(datagramChannel); throw new IllegalStateException("DatagramChannel create fail. Cause" + e.getMessage(), e); } } @Override - public boolean send(TBase data) { + public boolean send(Object data) { return executor.execute(data); } @@ -145,38 +143,47 @@ public void stop() { } } - protected void sendPacket(Object message) { + private void sendPacket(Object message) { if (closed) { throw new PinpointSocketException("NioUDPDataSender already closed."); } if (message instanceof TBase) { - byteBufferOutputStream.clear(); - - final TBase dto = (TBase) message; - // do not copy bytes because it's single threaded + final TBase tBase = (TBase) message; + sendPacket(tBase); + return; + } + final TBase tBase = this.messageConverter.toMessage(message); + if (tBase != null) { + sendPacket(tBase); + return; + } + logger.warn("sendPacket fail. invalid type:{}", message != null ? message.getClass() : null); + if (logger.isDebugEnabled()) { + logger.debug("unknown message:{}", message); + } + } - try { - serializer.serialize(dto, byteBufferOutputStream); - } catch (TException e) { - throw new PinpointSocketException("Serialize " + dto + " failed. Error:" + e.getMessage(), e); - } - ByteBuffer byteBuffer = byteBufferOutputStream.getByteBuffer(); - int bufferSize = byteBuffer.remaining(); - try { - datagramChannel.write(byteBuffer); - } catch (IOException e) { - final Thread currentThread = Thread.currentThread(); - if (currentThread.isInterrupted()) { - logger.warn("{} thread interrupted.", currentThread.getName()); - throw new PinpointSocketException(currentThread.getName() + " thread interrupted.", e); - } else { - throw new PinpointSocketException("packet send error. size:" + bufferSize + ", " + dto, e); - } + private void sendPacket(TBase tBase) { + byteBufferOutputStream.clear(); + // do not copy bytes because it's single threaded + try { + serializer.serialize(tBase, byteBufferOutputStream); + } catch (TException e) { + throw new PinpointSocketException("Serialize " + tBase + " failed. Error:" + e.getMessage(), e); + } + ByteBuffer byteBuffer = byteBufferOutputStream.getByteBuffer(); + int bufferSize = byteBuffer.remaining(); + try { + datagramChannel.write(byteBuffer); + } catch (IOException e) { + final Thread currentThread = Thread.currentThread(); + if (currentThread.isInterrupted()) { + logger.warn("{} thread interrupted.", currentThread.getName()); + throw new PinpointSocketException(currentThread.getName() + " thread interrupted.", e); + } else { + throw new PinpointSocketException("packet send error. size:" + bufferSize + ", " + tBase, e); } - } else { - logger.warn("sendPacket fail. invalid type:{}", message != null ? message.getClass() : null); - return; } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/PortUnreachableHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/PortUnreachableHandler.java new file mode 100644 index 000000000000..84c2ff7fe8b3 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/PortUnreachableHandler.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface PortUnreachableHandler { + void handlePortUnreachable(); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RefreshStrategy.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RefreshStrategy.java new file mode 100644 index 000000000000..a2338e3fe7af --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RefreshStrategy.java @@ -0,0 +1,119 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.client.SocketAddressProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RefreshStrategy implements UdpSocketAddressProvider { + // JDK default DNS Cache time : 30 + public static final long DEFAULT_PORT_UNREACHABLE_REFRESH_DELAY = TimeUnit.SECONDS.toMillis(30); + public static final long NORMAL_REFRESH_DELAY = TimeUnit.MINUTES.toMillis(5); + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final SocketAddressProvider socketAddressProvider; + private final long normalRefreshDelay; + private final long portUnreachableRefreshDelay; + + private InetSocketAddress socketAddress; + private long lastRefreshTime; + private boolean portUnreachableState = false; + + + public RefreshStrategy(SocketAddressProvider socketAddressProvider) { + this(socketAddressProvider, NORMAL_REFRESH_DELAY, DEFAULT_PORT_UNREACHABLE_REFRESH_DELAY); + } + + public RefreshStrategy(SocketAddressProvider socketAddressProvider, long normalRefreshDelay, long portUnreachableRefreshDelay) { + this.socketAddressProvider = Assert.requireNonNull(socketAddressProvider, "socketAddressProvider must not be null"); + this.normalRefreshDelay = normalRefreshDelay; + this.portUnreachableRefreshDelay = portUnreachableRefreshDelay; + } + + @Override + public void handlePortUnreachable() { + this.portUnreachableState = true; + } + + @Override + public InetSocketAddress resolve() { + final boolean refresh = needRefresh(); + if (refresh) { + final InetSocketAddress newAddress = socketAddressProvider.resolve(); + if (isResolved(newAddress)) { + if (logger.isDebugEnabled()) { + logger.debug("DNS refresh {}", newAddress); + } + this.socketAddress = newAddress; + } + } + + return this.socketAddress; + } + + public boolean isResolved(InetSocketAddress newAddress) { + if (newAddress == null) { + return false; + } + return !newAddress.isUnresolved(); + } + + private boolean needRefresh() { + final boolean portUnreachableStatus = resetPortUnreachableState(); + final long deadline = getDeadline(portUnreachableStatus); + final long currentTimeMillis = tick(); + if (currentTimeMillis > deadline) { + // reset deadLine + this.lastRefreshTime = currentTimeMillis; + return true; + } + return false; + + } + + @VisibleForTesting + long tick() { + return System.currentTimeMillis(); + } + + private long getDeadline(boolean portUnreachableStatus) { + if (portUnreachableStatus) { + return lastRefreshTime + portUnreachableRefreshDelay; + } else { + return lastRefreshTime + normalRefreshDelay; + } + } + + + private boolean resetPortUnreachableState() { + final boolean currentState = this.portUnreachableState; + this.portUnreachableState = false; + return currentState; + } + + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RequestMessage.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RequestMessage.java new file mode 100644 index 000000000000..1d1097fb59a4 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RequestMessage.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +import com.navercorp.pinpoint.rpc.FutureListener; + +/** + * @author Woonduk Kang(emeroad) + */ +interface RequestMessage { + + M getMessage(); + + int getRetryCount(); + + FutureListener getFutureListener(); + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RequestMessageFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RequestMessageFactory.java new file mode 100644 index 000000000000..273ed04c381e --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RequestMessageFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + + +import com.navercorp.pinpoint.rpc.FutureListener; + +/** + * @author Woonduk Kang(emeroad) + */ +final class RequestMessageFactory { + + private RequestMessageFactory() { + } + + public static RequestMessage request(T message, int retryCount) { + return new RetryRequestMessage(message, retryCount); + } + + public static RequestMessage request(T message, FutureListener futureListener) { + return new ListenerableRequestMessage(message, futureListener); + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RetryRequestMessage.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RetryRequestMessage.java new file mode 100644 index 000000000000..f2430de520c7 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/RetryRequestMessage.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + + +import com.navercorp.pinpoint.rpc.FutureListener; + +/** + * @author Woonduk Kang(emeroad) + */ +public class RetryRequestMessage implements RequestMessage { + private final T message; + private final int retryCount; + + + RetryRequestMessage(T message, int retryCount) { + this.message = message; + this.retryCount = retryCount; + } + + + @Override + public T getMessage() { + return message; + } + + @Override + public int getRetryCount() { + return retryCount; + } + + @Override + public FutureListener getFutureListener() { + return null; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/SpanStreamSendDataSerializer.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/SpanStreamSendDataSerializer.java index 3562f97b7b3d..65d2eb9e7c19 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/SpanStreamSendDataSerializer.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/SpanStreamSendDataSerializer.java @@ -96,7 +96,7 @@ public PartitionedByteBufferLocator serializeSpanStream(HeaderTBaseSerializer se private TSpan copySpanWithoutSpanEvent(TSpan span) { TSpan copiedSpan = span.deepCopy(); - copiedSpan.setSpanEventList(Collections.EMPTY_LIST); + copiedSpan.setSpanEventList(Collections.emptyList()); return copiedSpan; } @@ -140,7 +140,7 @@ public PartitionedByteBufferLocator serializeSpanChunkStream(HeaderTBaseSerializ private TSpanChunk copySpanChunkWithoutSpanEvent(TSpanChunk spanChunk) { TSpanChunk copiedSpanChunk = spanChunk.deepCopy(); - copiedSpanChunk.setSpanEventList(Collections.EMPTY_LIST); + copiedSpanChunk.setSpanEventList(Collections.emptyList()); return copiedSpanChunk; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/SpanStreamUdpSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/SpanStreamUdpSender.java index 509356b36c84..4920a91cc997 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/SpanStreamUdpSender.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/SpanStreamUdpSender.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,12 +16,17 @@ package com.navercorp.pinpoint.profiler.sender; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.profiler.context.Span; import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; import com.navercorp.pinpoint.profiler.sender.planer.SendDataPlaner; import com.navercorp.pinpoint.profiler.sender.planer.SpanChunkStreamSendDataPlaner; import com.navercorp.pinpoint.profiler.util.ByteBufferUtils; +import com.navercorp.pinpoint.common.util.IOUtils; import com.navercorp.pinpoint.profiler.util.ObjectPool; +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; import org.apache.thrift.TBase; import org.slf4j.Logger; @@ -37,7 +42,7 @@ /** * @author Taejin Koo */ -public class SpanStreamUdpSender extends AbstractDataSender { +public class SpanStreamUdpSender implements DataSender { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -59,15 +64,17 @@ public class SpanStreamUdpSender extends AbstractDataSender { private final StandbySpanStreamDataSendWorker standbySpanStreamDataSendWorker; - public SpanStreamUdpSender(String host, int port, String threadName, int queueSize) { - this(host, port, threadName, queueSize, SOCKET_TIMEOUT, SEND_BUFFER_SIZE); + private final MessageConverter> messageConverter; + + public SpanStreamUdpSender(String host, int port, String threadName, int queueSize, MessageConverter> messageConverter) { + this(host, port, threadName, queueSize, SOCKET_TIMEOUT, SEND_BUFFER_SIZE, messageConverter); } - public SpanStreamUdpSender(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize) { - this(host, port, threadName, queueSize, timeout, sendBufferSize, DEFAULT_BUFFER_SIZE); + public SpanStreamUdpSender(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize, MessageConverter> messageConverter) { + this(host, port, threadName, queueSize, timeout, sendBufferSize, DEFAULT_BUFFER_SIZE, messageConverter); } - public SpanStreamUdpSender(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize, int dataBufferSize) { + public SpanStreamUdpSender(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize, int dataBufferSize, MessageConverter> messageConverter) { if (host == null) { throw new NullPointerException("host must not be null"); } @@ -99,6 +106,18 @@ public SpanStreamUdpSender(String host, int port, String threadName, int queueSi this.standbySpanStreamDataSendWorker.start(); this.executor = createAsyncQueueingExecutor(queueSize, threadName); + this.messageConverter = Assert.requireNonNull(messageConverter, "messageConverter must not be null"); + } + + private AsyncQueueingExecutor createAsyncQueueingExecutor(int queueSize, String executorName) { + AsyncQueueingExecutorListener listener = new DefaultAsyncQueueingExecutorListener() { + @Override + public void execute(Object message) { + SpanStreamUdpSender.this.sendPacket(message); + } + }; + final AsyncQueueingExecutor executor = new AsyncQueueingExecutor(queueSize, executorName, listener); + return executor; } private DatagramChannel createChannel(String host, int port, int timeout, int sendBufferSize) { @@ -122,23 +141,15 @@ private DatagramChannel createChannel(String host, int port, int timeout, int se return datagramChannel; } catch (IOException e) { - if (socket != null) { - socket.close(); - } - - if (datagramChannel != null) { - try { - datagramChannel.close(); - } catch (IOException ignored) { - } - } + IOUtils.closeQuietly(socket); + IOUtils.closeQuietly(datagramChannel); throw new IllegalStateException("DatagramChannel create fail. Cause" + e.getMessage(), e); } } @Override - public boolean send(TBase data) { + public boolean send(Object data) { return executor.execute(data); } @@ -159,8 +170,8 @@ public void stop() { executor.stop(); } - @Override - protected void sendPacket(Object message) { + + private void sendPacket(Object message) { if (logger.isDebugEnabled()) { logger.debug("sendPacket message:{}", message); } @@ -187,7 +198,9 @@ private void handleSpan(Span span) { } HeaderTBaseSerializer serializer = serializerPool.getObject(); - PartitionedByteBufferLocator partitionedByteBufferLocator = spanStreamSendDataSerializer.serializeSpanStream(serializer, span); + TBase message = this.messageConverter.toMessage(span); + TSpan tSpan = (TSpan) message; + PartitionedByteBufferLocator partitionedByteBufferLocator = spanStreamSendDataSerializer.serializeSpanStream(serializer, tSpan); if (partitionedByteBufferLocator == null) { serializerPool.returnObject(serializer); return; @@ -203,7 +216,9 @@ private void handleSpanChunk(SpanChunk spanChunk) { } HeaderTBaseSerializer serializer = serializerPool.getObject(); - PartitionedByteBufferLocator partitionedByteBufferLocator = spanStreamSendDataSerializer.serializeSpanChunkStream(serializer, spanChunk); + TBase message = this.messageConverter.toMessage(spanChunk); + TSpanChunk tSpanChunk = (TSpanChunk) message; + PartitionedByteBufferLocator partitionedByteBufferLocator = spanStreamSendDataSerializer.serializeSpanChunkStream(serializer, tSpanChunk); if (partitionedByteBufferLocator == null) { serializerPool.returnObject(serializer); return; diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/TcpDataSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/TcpDataSender.java index 488356c56228..78d7549f0fdf 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/TcpDataSender.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/TcpDataSender.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,6 +17,10 @@ package com.navercorp.pinpoint.profiler.sender; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.profiler.context.thrift.BypassMessageConverter; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; import com.navercorp.pinpoint.rpc.Future; import com.navercorp.pinpoint.rpc.FutureListener; import com.navercorp.pinpoint.rpc.ResponseMessage; @@ -28,8 +32,7 @@ import com.navercorp.pinpoint.thrift.dto.TResult; import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; +import com.navercorp.pinpoint.thrift.util.SerializationUtils; import org.apache.thrift.TBase; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.util.HashedWheelTimer; @@ -39,7 +42,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -49,9 +51,10 @@ * @author koo.taejin * @author netspider */ -public class TcpDataSender extends AbstractDataSender implements EnhancedDataSender { +public class TcpDataSender implements EnhancedDataSender { private final Logger logger; + static { // preClassLoad ChannelBuffers.buffer(2); @@ -64,83 +67,100 @@ public class TcpDataSender extends AbstractDataSender implements EnhancedDataSen private final WriteFailFutureListener writeFailFutureListener; - - private final HeaderTBaseSerializer serializer; + private final MessageSerializer messageSerializer; private final RetryQueue retryQueue = new RetryQueue(); - private AsyncQueueingExecutor executor; + protected final AsyncQueueingExecutor executor; - public TcpDataSender(InetSocketAddress address, PinpointClientFactory clientFactory) { - this(null, address, clientFactory, HeaderTBaseSerializerFactory.DEFAULT_FACTORY.createSerializer()); - } - public TcpDataSender(InetSocketAddress address, PinpointClientFactory clientFactory, HeaderTBaseSerializer serializer) { - this(null, address, clientFactory, serializer); + public TcpDataSender(String name, String host, int port, PinpointClientFactory clientFactory) { + this(name, ClientFactoryUtils.newPinpointClientProvider(host, port, clientFactory), newDefaultMessageSerializer()); } - public TcpDataSender(String name, InetSocketAddress address, PinpointClientFactory clientFactory) { - this(name, address, clientFactory, HeaderTBaseSerializerFactory.DEFAULT_FACTORY.createSerializer()); + private static ThriftMessageSerializer newDefaultMessageSerializer() { + MessageConverter> messageConverter = new BypassMessageConverter>(); + return new ThriftMessageSerializer(messageConverter); } - public TcpDataSender(String name, InetSocketAddress address, PinpointClientFactory clientFactory, HeaderTBaseSerializer serializer) { - if (address == null) { - throw new NullPointerException("address must not be null"); - } - if (clientFactory == null) { - throw new NullPointerException("clientFactory must not be null"); - } - if (serializer == null) { - throw new NullPointerException("serializer must not be null"); - } + public TcpDataSender(String name, String host, int port, PinpointClientFactory clientFactory, MessageSerializer messageSerializer) { + this(name, ClientFactoryUtils.newPinpointClientProvider(host, port, clientFactory), messageSerializer); + } - String executorName = "Pinpoint-TcpDataSender-Executor"; - if (name != null) { - logger = LoggerFactory.getLogger(this.getClass().getName() + "@" + name); - executorName = String.format("Pinpoint-TcpDataSender(%s)-Executor", name); - } else { - logger = LoggerFactory.getLogger(this.getClass()); - } + private TcpDataSender(String name, ClientFactoryUtils.PinpointClientProvider clientProvider, MessageSerializer messageSerializer) { + this.logger = newLogger(name); - PinpointClient client = ClientFactoryUtils.createPinpointClient(address, clientFactory); + Assert.requireNonNull(clientProvider, "clientProvider must not be null"); + this.client = clientProvider.get(); - this.client = client; - this.serializer = serializer; + this.messageSerializer = Assert.requireNonNull(messageSerializer, "messageSerializer must not be null"); this.timer = createTimer(name); - writeFailFutureListener = new WriteFailFutureListener(logger, "io write fail.", "host", -1); + this.writeFailFutureListener = new WriteFailFutureListener(logger, "io write fail.", "host", -1); + + final String executorName = getExecutorName(name); this.executor = createAsyncQueueingExecutor(1024 * 5, executorName); } - private Timer createTimer(String name) { - String timerName = "Pinpoint-TcpDataSender-Timer"; - if (name != null) { - timerName = String.format("Pinpoint-TcpDataSender(%s)-Timer", name); + private AsyncQueueingExecutor createAsyncQueueingExecutor(int queueSize, String executorName) { + AsyncQueueingExecutorListener listener = new DefaultAsyncQueueingExecutorListener() { + @Override + public void execute(Object message) { + TcpDataSender.this.sendPacket(message); + } + }; + final AsyncQueueingExecutor executor = new AsyncQueueingExecutor(queueSize, executorName, listener); + return executor; + } + + private Logger newLogger(String name) { + if (name == null) { + return LoggerFactory.getLogger(this.getClass()); } + return LoggerFactory.getLogger(this.getClass().getName() + "@" + name); + } + + private String getExecutorName(String name) { + if (name == null) { + return "Pinpoint-TcpDataSender-Executor"; + } + return String.format("Pinpoint-TcpDataSender(%s)-Executor", name); + } + + + private Timer createTimer(String name) { + final String timerName = getTimerName(name); HashedWheelTimer timer = TimerFactory.createHashedWheelTimer(timerName, 100, TimeUnit.MILLISECONDS, 512); timer.start(); return timer; } - + + private String getTimerName(String name) { + if (name == null) { + return "Pinpoint-TcpDataSender-Timer"; + } + return String.format("Pinpoint-TcpDataSender(%s)-Timer", name); + } + @Override - public boolean send(TBase data) { + public boolean send(Object data) { return executor.execute(data); } @Override - public boolean request(TBase data) { + public boolean request(Object data) { return this.request(data, 3); } @Override - public boolean request(TBase data, int retryCount) { - RequestMarker message = new RequestMarker(data, retryCount); + public boolean request(Object data, int retryCount) { + final RequestMessage message = RequestMessageFactory.request(data, retryCount); return executor.execute(message); } @Override - public boolean request(TBase data, FutureListener listener) { - RequestMarker message = new RequestMarker(data, listener); + public boolean request(Object data, FutureListener listener) { + final RequestMessage message = RequestMessageFactory.request(data, listener); return executor.execute(message); } @@ -172,31 +192,22 @@ public void stop() { } } - @Override protected void sendPacket(Object message) { try { - if (message instanceof TBase) { - byte[] copy = serialize(serializer, (TBase) message); + if (message instanceof TBase) { + final byte[] copy = messageSerializer.serializer(message); if (copy == null) { return; } doSend(copy); - } else if (message instanceof RequestMarker) { - RequestMarker requestMarker = (RequestMarker) message; + return; + } - TBase tBase = requestMarker.getTBase(); - int retryCount = requestMarker.getRetryCount(); - FutureListener futureListener = requestMarker.getFutureListener(); - byte[] copy = serialize(serializer, tBase); - if (copy == null) { + if (message instanceof RequestMessage) { + final RequestMessage requestMessage = (RequestMessage) message; + if (doRequest(requestMessage)) { return; } - - if (futureListener != null) { - doRequest(copy, futureListener); - } else { - doRequest(copy, retryCount, tBase); - } } else { logger.error("sendPacket fail. invalid dto type:{}", message.getClass()); return; @@ -206,7 +217,26 @@ protected void sendPacket(Object message) { } } - private void doSend(byte[] copy) { + private boolean doRequest(RequestMessage requestMessage) { + final Object message = requestMessage.getMessage(); + + final byte[] copy = messageSerializer.serializer(message); + if (copy == null) { + return false; + } + + final FutureListener futureListener = requestMessage.getFutureListener(); + if (futureListener != null) { + doRequest(copy, futureListener); + } else { + int retryCount = requestMessage.getRetryCount(); + doRequest(copy, retryCount, message); + } + + return true; + } + + protected void doSend(byte[] copy) { Future write = this.client.sendAsync(copy); write.setListener(writeFailFutureListener); } @@ -218,8 +248,9 @@ private void doRequest(final byte[] requestPacket, final int maxRetryCount, fina public void onComplete(Future future) { if (future.isSuccess()) { // Should cache? + ResponseMessage responseMessage = future.getResult(); HeaderTBaseDeserializer deserializer = HeaderTBaseDeserializerFactory.DEFAULT_FACTORY.createDeserializer(); - TBase response = deserialize(deserializer, future.getResult()); + TBase response = deserialize(deserializer, responseMessage.getMessage()); if (response instanceof TResult) { TResult result = (TResult) response; if (result.isSuccess()) { @@ -230,7 +261,7 @@ public void onComplete(Future future) { retryRequest(retryMessage); } } else { - logger.warn("Invalid respose:{}", response); + logger.warn("Invalid response:{}", response); // This is not retransmission. need to log for debugging // it could be null // retryRequest(requestPacket); @@ -254,7 +285,8 @@ public void onComplete(Future future) { if (future.isSuccess()) { // Should cache? HeaderTBaseDeserializer deserializer = HeaderTBaseDeserializerFactory.DEFAULT_FACTORY.createDeserializer(); - TBase response = deserialize(deserializer, future.getResult()); + ResponseMessage responseMessage = future.getResult(); + TBase response = deserialize(deserializer, responseMessage.getMessage()); if (response instanceof TResult) { TResult result = (TResult) response; if (result.isSuccess()) { @@ -279,13 +311,21 @@ public void onComplete(Future future) { doRequest(retryMessage.getBytes(), futureListener); } + private TBase deserialize(HeaderTBaseDeserializer deserializer, byte[] message) { + final Message> deserialize = SerializationUtils.deserialize(message, deserializer, null); + if (deserialize == null) { + return null; + } + return deserialize.getData(); + } + private void retryRequest(RetryMessage retryMessage) { retryQueue.add(retryMessage); if (fireTimeout()) { timer.newTimeout(new TimerTask() { @Override public void run(Timeout timeout) throws Exception { - while(true) { + while (true) { RetryMessage retryMessage = retryQueue.get(); if (retryMessage == null) { // Maybe concurrency issue. But ignore it because it's unlikely. diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ThriftMessageSerializer.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ThriftMessageSerializer.java new file mode 100644 index 000000000000..7d5146148b9f --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ThriftMessageSerializer.java @@ -0,0 +1,77 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; +import com.navercorp.pinpoint.thrift.io.TBaseSerializer; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ThriftMessageSerializer implements MessageSerializer { + + public static final int UDP_MAX_PACKET_LENGTH = 65507; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + // Caution. not thread safe + private final TBaseSerializer serializer; + private final MessageConverter> messageConverter; + + public ThriftMessageSerializer(MessageConverter> messageConverter) { + this(messageConverter, HeaderTBaseSerializerFactory.DEFAULT_FACTORY.createSerializer()); + } + + public ThriftMessageSerializer(MessageConverter> messageConverter, TBaseSerializer serializer) { + this.messageConverter = Assert.requireNonNull(messageConverter, "messageConverter must not be null"); + this.serializer = Assert.requireNonNull(serializer, "serializer must not be null"); + + } + + // single thread only + @Override + public byte[] serializer(Object message) { + if (message instanceof TBase) { + final TBase tBase = (TBase) message; + return serialize(serializer, tBase); + } + + final TBase tBase = messageConverter.toMessage(message); + if (tBase != null) { + return serialize(serializer, tBase); + } + return null; + } + + private byte[] serialize(TBaseSerializer serializer, TBase tBase) { + try { + return serializer.serialize(tBase); + } catch (TException e) { + if (logger.isWarnEnabled()) { + logger.warn("Serialize {} failed. Error:{}", tBase, e.getMessage(), e); + } + } + return null; + } + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ThriftUdpMessageSerializer.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ThriftUdpMessageSerializer.java new file mode 100644 index 000000000000..399e8586884b --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/ThriftUdpMessageSerializer.java @@ -0,0 +1,107 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; +import com.navercorp.pinpoint.thrift.io.SerializerFactory; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * not thread safe + * @author Woonduk Kang(emeroad) + */ +public class ThriftUdpMessageSerializer implements MessageSerializer{ + + public static final int UDP_MAX_PACKET_LENGTH = 65507; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + // Caution. not thread safe + private final HeaderTBaseSerializer serializer; + private final int maxPacketLength; + private final MessageConverter> messageConverter; + + + public ThriftUdpMessageSerializer(MessageConverter> messageConverter, int maxPacketLength) { + this.messageConverter = Assert.requireNonNull(messageConverter, "messageConverter must not be null"); + this.maxPacketLength = maxPacketLength; + // Caution. not thread safe + SerializerFactory headerTBaseSerializerFactory = new HeaderTBaseSerializerFactory(false, maxPacketLength, false); + serializer = headerTBaseSerializerFactory.createSerializer(); + } + + // single thread only + @Override + public ByteMessage serializer(Object message) { + if (message instanceof TBase) { + final TBase tBase = (TBase) message; + return serialize(tBase); + } + + final TBase tBase = messageConverter.toMessage(message); + if (tBase != null) { + return serialize(tBase); + } + return null; + } + + public ByteMessage serialize(TBase message) { + final TBase dto = message; + // do not copy bytes because it's single threaded + final byte[] internalBufferData = serialize(this.serializer, dto); + if (internalBufferData == null) { + logger.warn("interBufferData is null"); + return null; + } + + final int messageSize = this.serializer.getInterBufferSize(); + if (isLimit(messageSize)) { + // When packet size is greater than UDP packet size limit, it's better to discard packet than let the socket API fails. + logger.warn("discard packet. Caused:too large message. size:{}, {}", messageSize, dto); + return null; + } + + return new ByteMessage(internalBufferData, messageSize); + } + + private byte[] serialize(HeaderTBaseSerializer serializer, TBase tBase) { + try { + return serializer.serialize(tBase); + } catch (TException e) { + if (logger.isWarnEnabled()) { + logger.warn("Serialize " + tBase + " failed. Error:" + e.getMessage(), e); + } + } + return null; + } + + @VisibleForTesting + protected boolean isLimit(int interBufferSize) { + if (interBufferSize > maxPacketLength) { + return true; + } + return false; + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpDataSender.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpDataSender.java index 2c127ae97e40..6d14c3be706c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpDataSender.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpDataSender.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,9 +16,10 @@ package com.navercorp.pinpoint.profiler.sender; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; -import org.apache.thrift.TBase; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.client.DnsSocketAddressProvider; +import com.navercorp.pinpoint.rpc.client.SocketAddressProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,6 +27,7 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; +import java.net.PortUnreachableException; import java.net.SocketException; /** @@ -33,64 +35,70 @@ * @author emeroad * @author koo.taejin */ -public class UdpDataSender extends AbstractDataSender implements DataSender { +public class UdpDataSender implements DataSender { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); protected final boolean isDebug = logger.isDebugEnabled(); - public static final int SOCKET_TIMEOUT = 1000 * 5; - public static final int SEND_BUFFER_SIZE = 1024 * 64 * 16; - public static final int UDP_MAX_PACKET_LENGTH = 65507; - // Caution. not thread safe - protected final DatagramPacket reusePacket = new DatagramPacket(new byte[1], 1); - - protected final DatagramSocket udpSocket; + private final DatagramPacket reusePacket = new DatagramPacket(new byte[1], 1); - // Caution. not thread safe - private final HeaderTBaseSerializer serializer = new HeaderTBaseSerializerFactory(false, UDP_MAX_PACKET_LENGTH, false).createSerializer(); + private final DatagramSocket udpSocket; private final AsyncQueueingExecutor executor; - public UdpDataSender(String host, int port, String threadName, int queueSize) { - this(host, port, threadName, queueSize, SOCKET_TIMEOUT, SEND_BUFFER_SIZE); - } + private final UdpSocketAddressProvider socketAddressProvider; - public UdpDataSender(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize) { - if (host == null ) { - throw new NullPointerException("host must not be null"); - } - if (threadName == null) { - throw new NullPointerException("threadName must not be null"); - } - if (queueSize <= 0) { - throw new IllegalArgumentException("queueSize"); - } - if (timeout <= 0) { - throw new IllegalArgumentException("timeout"); - } - if (sendBufferSize <= 0) { - throw new IllegalArgumentException("sendBufferSize"); + private final MessageSerializer messageSerializer; + + + public UdpDataSender(String host, int port, String threadName, + int queueSize, int timeout, int sendBufferSize, + MessageSerializer messageSerializer) { + Assert.requireNonNull(host, "host must not be null"); + if (!HostAndPort.isValidPort(port)) { + throw new IllegalArgumentException("port out of range:" + port); } + Assert.requireNonNull(host, "host must not be null"); + Assert.isTrue(queueSize > 0, "queueSize"); + Assert.isTrue(timeout > 0, "timeout"); + Assert.isTrue(sendBufferSize > 0, "sendBufferSize"); + + this.messageSerializer = Assert.requireNonNull(messageSerializer, "messageSerializer must not be null"); + final SocketAddressProvider socketAddressProvider = new DnsSocketAddressProvider(host, port); + this.socketAddressProvider = new RefreshStrategy(socketAddressProvider); + final InetSocketAddress currentAddress = this.socketAddressProvider.resolve(); + logger.info("UdpDataSender initialized. host={}", currentAddress); // TODO If fail to create socket, stop agent start - logger.info("UdpDataSender initialized. host={}, port={}", host, port); - this.udpSocket = createSocket(host, port, timeout, sendBufferSize); + this.udpSocket = createSocket(timeout, sendBufferSize); this.executor = createAsyncQueueingExecutor(queueSize, threadName); + } @Override - public boolean send(TBase data) { + public boolean send(Object data) { return executor.execute(data); } + private AsyncQueueingExecutor createAsyncQueueingExecutor(int queueSize, String executorName) { + AsyncQueueingExecutorListener listener = new DefaultAsyncQueueingExecutorListener() { + @Override + public void execute(Object message) { + UdpDataSender.this.sendPacket(message); + } + }; + final AsyncQueueingExecutor executor = new AsyncQueueingExecutor(queueSize, executorName, listener); + return executor; + } + @Override public void stop() { executor.stop(); } - private DatagramSocket createSocket(String host, int port, int timeout, int sendBufferSize) { + private DatagramSocket createSocket(int timeout, int sendBufferSize) { try { final DatagramSocket datagramSocket = new DatagramSocket(); @@ -103,52 +111,51 @@ private DatagramSocket createSocket(String host, int port, int timeout, int send } } - final InetSocketAddress serverAddress = new InetSocketAddress(host, port); - datagramSocket.connect(serverAddress); return datagramSocket; } catch (SocketException e) { throw new IllegalStateException("DatagramSocket create fail. Cause" + e.getMessage(), e); } } - protected void sendPacket(Object message) { - if (message instanceof TBase) { - final TBase dto = (TBase) message; - // do not copy bytes because it's single threaded - final byte[] internalBufferData = serialize(this.serializer, dto); - if (internalBufferData == null) { - logger.warn("interBufferData is null"); - return; - } + private void sendPacket(Object message) { - final int internalBufferSize = this.serializer.getInterBufferSize(); - if (isLimit(internalBufferSize)) { - // When packet size is greater than UDP packet size limit, it's better to discard packet than let the socket API fails. - logger.warn("discard packet. Caused:too large message. size:{}, {}", internalBufferSize, dto); - return; - } - // it's safe to reuse because it's single threaded - reusePacket.setData(internalBufferData, 0, internalBufferSize); + final InetSocketAddress inetSocketAddress = socketAddressProvider.resolve(); + if (inetSocketAddress.getAddress() == null) { + logger.info("dns lookup fail host:{}", inetSocketAddress); + return; + } - try { - udpSocket.send(reusePacket); - if (isDebug) { - logger.debug("Data sent. size:{}, {}", internalBufferSize, dto); - } - } catch (IOException e) { - logger.info("packet send error. size:{}, {}", internalBufferSize, dto, e); + final ByteMessage byteMessage = messageSerializer.serializer(message); + if (byteMessage == null) { + logger.warn("sendPacket fail. message:{}", message != null ? message.getClass() : null); + if (logger.isDebugEnabled()) { + logger.debug("unknown message:{}", message); } - } else { - logger.warn("sendPacket fail. invalid type:{}", message != null ? message.getClass() : null); return; } - } + final DatagramPacket packet = preparePacket(inetSocketAddress, byteMessage); - // for test - protected boolean isLimit(int interBufferSize) { - if (interBufferSize > UDP_MAX_PACKET_LENGTH) { - return true; + try { + udpSocket.send(packet); + if (isDebug) { + logger.debug("Data sent. size:{}, {}", byteMessage.getLength(), message); + } + } catch (PortUnreachableException pe) { + this.socketAddressProvider.handlePortUnreachable(); + logger.info("packet send error. size:{}, {}", byteMessage.getLength(), message, pe); + } catch (IOException e) { + logger.info("packet send error. size:{}, {}", byteMessage.getLength(), message, e); } - return false; + } + + private DatagramPacket preparePacket(InetSocketAddress targetAddress, ByteMessage byteMessage) { + // it's safe to reuse because it's single threaded + reusePacket.setAddress(targetAddress.getAddress()); + reusePacket.setPort(targetAddress.getPort()); + + reusePacket.setData(byteMessage.getMessage(), 0, byteMessage.getLength()); + return reusePacket; + } + } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpDataSenderFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpDataSenderFactory.java index c1c6c8c7944a..5342b04a5b5e 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpDataSenderFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpDataSenderFactory.java @@ -1,43 +1,49 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ package com.navercorp.pinpoint.profiler.sender; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.context.module.SpanConverter; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import org.apache.thrift.TBase; + /** * @author Taejin Koo */ public final class UdpDataSenderFactory { -// String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize - + // String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize private final String host; private final int port; private final String threadName; private final int queueSize; private final int timeout; private final int sendBufferSize; + private final MessageConverter> messageConverter; - public UdpDataSenderFactory(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize) { + public UdpDataSenderFactory(String host, int port, String threadName, int queueSize, int timeout, int sendBufferSize, @SpanConverter MessageConverter> messageConverter) { this.host = host; this.port = port; this.threadName = threadName; this.queueSize = queueSize; this.timeout = timeout; this.sendBufferSize = sendBufferSize; + + this.messageConverter = Assert.requireNonNull(messageConverter, "messageConverter must not be null"); } public DataSender create(String typeName) { @@ -46,9 +52,10 @@ public DataSender create(String typeName) { public DataSender create(UdpDataSenderType type) { if (type == UdpDataSenderType.NIO) { - return new NioUDPDataSender(host, port, threadName, queueSize, timeout, sendBufferSize); + return new NioUDPDataSender(host, port, threadName, queueSize, timeout, sendBufferSize, messageConverter); } else if (type == UdpDataSenderType.OIO) { - return new UdpDataSender(host, port, threadName, queueSize, timeout, sendBufferSize); + final MessageSerializer thriftMessageSerializer = new ThriftUdpMessageSerializer(messageConverter, ThriftUdpMessageSerializer.UDP_MAX_PACKET_LENGTH); + return new UdpDataSender(host, port, threadName, queueSize, timeout, sendBufferSize, thriftMessageSerializer); } else { throw new IllegalArgumentException("Unknown type."); } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpSocketAddressProvider.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpSocketAddressProvider.java new file mode 100644 index 000000000000..a81ba1ddf4f3 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/UdpSocketAddressProvider.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +import com.navercorp.pinpoint.rpc.client.SocketAddressProvider; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface UdpSocketAddressProvider extends SocketAddressProvider, PortUnreachableHandler { +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/planer/AbstractSpanStreamSendDataPlaner.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/planer/AbstractSpanStreamSendDataPlaner.java index e9c9c5a4cd4a..26f7cd47bb34 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/planer/AbstractSpanStreamSendDataPlaner.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/planer/AbstractSpanStreamSendDataPlaner.java @@ -202,13 +202,13 @@ private int getNeedsChunkCount(SpanStreamSendData spanStreamSendData, int availa return chunkCount; } - private boolean needFlush(SpanStreamSendData spanStreamSendData, int length, int delemeterBufferSize) { - if (!spanStreamSendData.isAvailableBufferCapacity(length + delemeterBufferSize)) { + private boolean needFlush(SpanStreamSendData spanStreamSendData, int length, int delimiterBufferSize) { + if (!spanStreamSendData.isAvailableBufferCapacity(length + delimiterBufferSize)) { return true; } int availableComponentsCount = 1; - if (delemeterBufferSize > 0) { + if (delimiterBufferSize > 0) { availableComponentsCount++; } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/planer/SpanStreamSendDataPlaner.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/planer/SpanStreamSendDataPlaner.java index 85106c43b2e3..378566133ced 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/planer/SpanStreamSendDataPlaner.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/sender/planer/SpanStreamSendDataPlaner.java @@ -20,6 +20,7 @@ import com.navercorp.pinpoint.profiler.sender.SpanStreamSendDataFactory; import com.navercorp.pinpoint.thrift.dto.TSpan; import com.navercorp.pinpoint.thrift.dto.TSpanChunk; +import com.navercorp.pinpoint.thrift.dto.TSpanEvent; import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; import org.apache.thrift.TException; @@ -82,7 +83,7 @@ private byte[] getSpanChunkBuffer0() { private TSpanChunk toSpanChunk(TSpan span) { final TSpanChunk spanChunk = new TSpanChunk(); - spanChunk.setSpanEventList(Collections.EMPTY_LIST); + spanChunk.setSpanEventList(Collections.emptyList()); spanChunk.setSpanEventListIsSet(true); spanChunk.setAgentId(span.getAgentId()); spanChunk.setAgentIdIsSet(true); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/AgentInfoFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/AgentInfoFactory.java index 43a21b614c2a..7aaefa6dc32c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/AgentInfoFactory.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/AgentInfoFactory.java @@ -62,6 +62,7 @@ public TAgentInfo createAgentInfo() { tAgentInfo.setPorts(""); tAgentInfo.setAgentId(agentInformation.getAgentId()); tAgentInfo.setApplicationName(agentInformation.getApplicationName()); + tAgentInfo.setContainer(agentInformation.isContainer()); tAgentInfo.setPid(agentInformation.getPid()); tAgentInfo.setStartTimestamp(agentInformation.getStartTime()); tAgentInfo.setServiceType(agentInformation.getServerType().getCode()); diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/AnnotationValueMapper.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/AnnotationValueMapper.java index 152d4094bdd0..f90952c6e60c 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/AnnotationValueMapper.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/AnnotationValueMapper.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,13 +18,17 @@ import com.navercorp.pinpoint.common.util.IntBooleanIntBooleanValue; +import com.navercorp.pinpoint.common.util.IntStringStringValue; +import com.navercorp.pinpoint.common.util.IntStringValue; import com.navercorp.pinpoint.common.util.LongIntIntByteByteStringValue; +import com.navercorp.pinpoint.common.util.StringStringValue; import com.navercorp.pinpoint.common.util.StringUtils; - -import com.navercorp.pinpoint.thrift.dto.TAnnotation; import com.navercorp.pinpoint.thrift.dto.TAnnotationValue; import com.navercorp.pinpoint.thrift.dto.TIntBooleanIntBooleanValue; +import com.navercorp.pinpoint.thrift.dto.TIntStringStringValue; +import com.navercorp.pinpoint.thrift.dto.TIntStringValue; import com.navercorp.pinpoint.thrift.dto.TLongIntIntByteByteStringValue; +import com.navercorp.pinpoint.thrift.dto.TStringStringValue; import org.apache.thrift.TBase; /** @@ -35,39 +39,107 @@ public final class AnnotationValueMapper { private AnnotationValueMapper() { } - public static void mappingValue(TAnnotation annotation, Object value) { + public static Object checkValueType(Object value) { if (value == null) { - return; + return null; } if (value instanceof String) { - annotation.setValue(TAnnotationValue.stringValue((String) value)); - return; + return value; } else if (value instanceof Integer) { - annotation.setValue(TAnnotationValue.intValue((Integer) value)); - return; + return value; } else if (value instanceof Long) { - annotation.setValue(TAnnotationValue.longValue((Long) value)); - return; + return value; } else if (value instanceof Boolean) { - annotation.setValue(TAnnotationValue.boolValue((Boolean) value)); - return; + return value; } else if (value instanceof Byte) { - annotation.setValue(TAnnotationValue.byteValue((Byte) value)); - return; + return value; } else if (value instanceof Float) { - // thrift does not contain "float" type - annotation.setValue(TAnnotationValue.doubleValue((Float) value)); - return; + // thrift does not contain "float" typet + return value; } else if (value instanceof Double) { - annotation.setValue(TAnnotationValue.doubleValue((Double) value)); - return; + return value; } else if (value instanceof byte[]) { - annotation.setValue(TAnnotationValue.binaryValue((byte[]) value)); - return; + return value; } else if (value instanceof Short) { - annotation.setValue(TAnnotationValue.shortValue((Short) value)); - return; + return value; + } else if (value instanceof IntStringValue) { + return value; + } else if (value instanceof IntStringStringValue) { + return value; } else if (value instanceof LongIntIntByteByteStringValue) { + return value; + } else if (value instanceof IntBooleanIntBooleanValue) { + return value; + } else if (value instanceof StringStringValue) { + return value; + } else if (value instanceof TBase) { + throw new IllegalArgumentException("TBase not supported. Class:" + value.getClass()); + } + + String str = StringUtils.abbreviate(value.toString()); + return str; + } + + public static TAnnotationValue buildTAnnotationValue(Object value) { + if (value == null) { + return null; + } + if (value instanceof String) { + return TAnnotationValue.stringValue((String) value); + } + if (value instanceof Integer) { + return TAnnotationValue.intValue((Integer) value); + } + if (value instanceof Long) { + return TAnnotationValue.longValue((Long) value); + } + if (value instanceof Boolean) { + return TAnnotationValue.boolValue((Boolean) value); + } + if (value instanceof Byte) { + return TAnnotationValue.byteValue((Byte) value); + } + if (value instanceof Float) { + // thrift does not contain "float" type + return TAnnotationValue.doubleValue((Float) value); + } + if (value instanceof Double) { + return TAnnotationValue.doubleValue((Double) value); + } + if (value instanceof byte[]) { + return TAnnotationValue.binaryValue((byte[]) value); + } + if (value instanceof Short) { + return TAnnotationValue.shortValue((Short) value); + } + if (value instanceof IntStringValue) { + final IntStringValue v = (IntStringValue) value; + final TIntStringValue tIntStringValue = new TIntStringValue(v.getIntValue()); + if (v.getStringValue() != null) { + tIntStringValue.setStringValue(v.getStringValue()); + } + return TAnnotationValue.intStringValue(tIntStringValue); + } + if (value instanceof StringStringValue) { + final StringStringValue v = (StringStringValue) value; + final TStringStringValue tStringStringValue = new TStringStringValue(v.getStringValue1()); + if (v.getStringValue2() != null) { + tStringStringValue.setStringValue2(v.getStringValue2()); + } + return TAnnotationValue.stringStringValue(tStringStringValue); + } + if (value instanceof IntStringStringValue) { + final IntStringStringValue v = (IntStringStringValue) value; + final TIntStringStringValue tIntStringStringValue = new TIntStringStringValue(v.getIntValue()); + if (v.getStringValue1() != null) { + tIntStringStringValue.setStringValue1(v.getStringValue1()); + } + if (v.getStringValue2() != null) { + tIntStringStringValue.setStringValue2(v.getStringValue2()); + } + return TAnnotationValue.intStringStringValue(tIntStringStringValue); + } + if (value instanceof LongIntIntByteByteStringValue) { final LongIntIntByteByteStringValue v = (LongIntIntByteByteStringValue) value; final TLongIntIntByteByteStringValue tvalue = new TLongIntIntByteByteStringValue(v.getLongValue(), v.getIntValue1()); if (v.getIntValue2() != -1) { @@ -82,18 +154,18 @@ public static void mappingValue(TAnnotation annotation, Object value) { if (v.getStringValue() != null) { tvalue.setStringValue(v.getStringValue()); } - annotation.setValue(TAnnotationValue.longIntIntByteByteStringValue(tvalue)); - return; - } else if(value instanceof IntBooleanIntBooleanValue) { + return TAnnotationValue.longIntIntByteByteStringValue(tvalue); + } + if (value instanceof IntBooleanIntBooleanValue) { final IntBooleanIntBooleanValue v = (IntBooleanIntBooleanValue) value; final TIntBooleanIntBooleanValue tvalue = new TIntBooleanIntBooleanValue(v.getIntValue1(), v.isBooleanValue1(), v.getIntValue2(), v.isBooleanValue2()); - annotation.setValue(TAnnotationValue.intBooleanIntBooleanValue(tvalue)); - return; - } else if (value instanceof TBase) { + return TAnnotationValue.intBooleanIntBooleanValue(tvalue); + } + if (value instanceof TBase) { throw new IllegalArgumentException("TBase not supported. Class:" + value.getClass()); } String str = StringUtils.abbreviate(value.toString()); - annotation.setValue(TAnnotationValue.stringValue(str)); + return TAnnotationValue.stringValue(str); } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/Counter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/Counter.java new file mode 100644 index 000000000000..8ff827218388 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/Counter.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.util; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface Counter { + void increment(); + + void add(long x); + + long longValue(); +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/CounterFactory.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/CounterFactory.java new file mode 100644 index 000000000000..3a6516c4597f --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/CounterFactory.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.util; + +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.common.util.JvmUtils; +import com.navercorp.pinpoint.common.util.JvmVersion; + +import java.lang.reflect.Constructor; + +/** + * @author Woonduk Kang(emeroad) + */ +public class CounterFactory { + + private static final PLogger logger = PLoggerFactory.getLogger(CounterFactory.class.getName()); + + private static final ObjectFactory counterFactory = buildFactory(); + + private static ObjectFactory buildFactory() { + JvmVersion version = JvmUtils.getVersion(); + if (version.onOrAfter(JvmVersion.JAVA_8)) { + String counterName = "com.navercorp.pinpoint.profiler.util.Java8CounterFactory"; + try { + Class> counterClazz = (Class>) Class.forName(counterName, false, CounterFactory.class.getClassLoader()); + Constructor> constructor = counterClazz.getDeclaredConstructor(); + return constructor.newInstance(); + } catch (Exception e) { + logger.warn("{} not found", counterName , e); + } + } + return new Java6CounterFactory(); + } + + public static Counter newCounter() { + return counterFactory.newInstance(); + } + + interface ObjectFactory { + T newInstance(); + } + + private static class Java6CounterFactory implements ObjectFactory { + @Override + public Counter newInstance() { + return new Java6Counter(); + } + }; + +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JarReader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JarReader.java index 27b305d8a265..a9e420d6f1e3 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JarReader.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JarReader.java @@ -17,11 +17,11 @@ package com.navercorp.pinpoint.profiler.util; +import com.navercorp.pinpoint.common.util.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.ByteArrayOutputStream; -import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -65,14 +65,13 @@ public List read(JarEntryFilter jarEntryFilter) throws IOException{ final BufferedContext bufferedContext = new BufferedContext(); - String jarFileName = jarFile.getName(); Enumeration entries = jarFile.entries(); List fileBinaryList = new ArrayList(); while (entries.hasMoreElements()) { final JarEntry jarEntry = entries.nextElement(); if (jarEntryFilter.filter(jarEntry)) { if (logger.isDebugEnabled()) { - logger.debug("filter fileName:{}, JarFile:{}", jarEntry.getName(), jarFileName); + logger.debug("filter fileName:{}, JarFile:{}", jarEntry, jarFile.getName()); } FileBinary fileBinary = newFileBinary(bufferedContext, jarEntry); fileBinaryList.add(fileBinary); @@ -100,38 +99,23 @@ private byte[] read(JarEntry jarEntry) throws IOException{ try { inputStream = jarFile.getInputStream(jarEntry); if (inputStream == null) { - logger.warn("jarEntry not found. jarFile:{} jarEntry{}", jarFile, jarEntry); + logger.warn("jarEntry not found. jarFile:{} jarEntry{}", jarFile.getName(), jarEntry); return null; } return read(inputStream); } catch (IOException ioe) { - logger.warn("jarFile read error jarFile:{} jarEntry{} {}", jarFile, jarEntry, ioe.getMessage(), ioe); + logger.warn("jarFile read error jarFile:{} jarEntry{} {}", jarFile.getName(), jarEntry, ioe.getMessage(), ioe); throw ioe; } finally { - close(inputStream); + IOUtils.closeQuietly(inputStream); } } public byte[] read(InputStream input) throws IOException { this.output.reset(); - read(input, output); + IOUtils.copy(input, output, buffer); return output.toByteArray(); } - public void read(InputStream input, OutputStream output) throws IOException { - int readIndex; - while ((readIndex = input.read(buffer)) != -1) { - output.write(buffer, 0, readIndex); - } - } - - private void close(Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (IOException ignore) { - } - } - } } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/Java6Counter.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/Java6Counter.java new file mode 100644 index 000000000000..3f205f625569 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/Java6Counter.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.util; + +import com.navercorp.pinpoint.profiler.util.jdk.LongAdder; + +/** + * @author Woonduk Kang(emeroad) + */ +public class Java6Counter implements Counter { + private final LongAdder longAdder = new LongAdder(); + @Override + public void increment() { + longAdder.increment(); + } + + @Override + public void add(long x) { + longAdder.add(x); + } + + @Override + public long longValue() { + return longAdder.longValue(); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtils.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtils.java index d5da958e7962..285899027f09 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtils.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtils.java @@ -26,16 +26,6 @@ import com.navercorp.pinpoint.common.util.StringUtils; -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.Modifier; -import javassist.bytecode.AttributeInfo; -import javassist.bytecode.CodeAttribute; -import javassist.bytecode.LocalVariableAttribute; -import javassist.bytecode.MethodInfo; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * @author emeroad @@ -45,7 +35,6 @@ public final class JavaAssistUtils { private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final String ARRAY = "[]"; - private static final Logger logger = LoggerFactory.getLogger(JavaAssistUtils.class); private static final Pattern PARAMETER_SIGNATURE_PATTERN = Pattern.compile("\\[*L[^;]+;|\\[*[ZBCSIFDJ]|[ZBCSIFDJ]"); @@ -68,28 +57,6 @@ private static Map createPrimitiveJavaToJvmMap() { private JavaAssistUtils() { } - /** - * example return value: (int, java.lang.String) - * - * @param params - * @return - */ - public static String getParameterDescription(CtClass[] params) { - if (params == null) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(64); - sb.append('('); - int end = params.length - 1; - for (int i = 0; i < params.length; i++) { - sb.append(params[i].getName()); - if (i < end) { - sb.append(", "); - } - } - sb.append(')'); - return sb.toString(); - } public static String javaTypeToJvmSignature(String[] javaTypeArray, String returnType) { if (returnType == null) { @@ -157,6 +124,7 @@ private static String toJvmObject(int javaObjectArraySize, String pureJavaType) /** * java.lang.String -> java/lang/String + * * @param javaName * @return */ @@ -169,6 +137,7 @@ public static String javaNameToJvmName(String javaName) { /** * java/lang/String -> java.lang.String + * * @param jvmName * @return */ @@ -179,8 +148,23 @@ public static String jvmNameToJavaName(String jvmName) { return jvmName.replace('/', '.'); } + + /** + * java.lang.String -> java/lang/String.class + * + * @param javaName + * @return + */ + public static String javaClassNameToJvmResourceName(String javaName) { + if (javaName == null) { + throw new NullPointerException("javaName must not be null"); + } + return javaName.replace('.', '/').concat(".class"); + } + /** * java/lang/String -> java.lang.String + * * @param jvmNameArray * @return */ @@ -382,20 +366,20 @@ public static String[] getParameterType(Class[] paramsClass) { } return paramsString; } - + public static String[] toPinpointParameterType(Class[] paramClasses) { if (paramClasses == null) { return null; } - + String[] paramsString = new String[paramClasses.length]; for (int i = 0; i < paramClasses.length; i++) { paramsString[i] = toPinpointParameterType(paramClasses[i]); } - + return paramsString; } - + public static String toPinpointParameterType(Class type) { if (type.isArray()) { return toPinpointParameterType(type.getComponentType()) + "[]"; @@ -405,18 +389,6 @@ public static String toPinpointParameterType(Class type) { } - @Deprecated - static String[] getParameterType(CtClass[] paramsClass) { - if (paramsClass == null) { - return null; - } - String[] paramsString = new String[paramsClass.length]; - for (int i = 0; i < paramsClass.length; i++) { - paramsString[i] = paramsClass[i].getName(); - } - return paramsString; - } - @Deprecated public static String getParameterDescription(Class[] params) { if (params == null) { @@ -454,141 +426,4 @@ public static String getParameterDescription(String[] params) { } - public static int getLineNumber(CtBehavior method) { - if (method == null) { - return -1; - } - return method.getMethodInfo().getLineNumber(0); - } - - - public static boolean isStaticBehavior(CtBehavior behavior) { - if (behavior == null) { - throw new NullPointerException("behavior must not be null"); - } - int modifiers = behavior.getModifiers(); - return Modifier.isStatic(modifiers); - } - - - public static String[] getParameterVariableName(CtBehavior method) { - if (method == null) { - throw new NullPointerException("method must not be null"); - } - LocalVariableAttribute localVariableAttribute = lookupLocalVariableAttribute(method); - if (localVariableAttribute == null) { - return getParameterDefaultVariableName(method); - } - return getParameterVariableName(method, localVariableAttribute); - } - - /** - * get LocalVariableAttribute - * - * @param method - * @return null if the class is not compiled with debug option - */ - public static LocalVariableAttribute lookupLocalVariableAttribute(CtBehavior method) { - if (method == null) { - throw new NullPointerException("method must not be null"); - } - MethodInfo methodInfo = method.getMethodInfo2(); - CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); - - if (codeAttribute == null) { - return null; - } - - AttributeInfo localVariableTable = codeAttribute.getAttribute(LocalVariableAttribute.tag); - LocalVariableAttribute local = (LocalVariableAttribute) localVariableTable; - return local; - } - - public static String[] getParameterVariableName(CtBehavior method, LocalVariableAttribute localVariableAttribute) { - // Inspired by - // http://www.jarvana.com/jarvana/view/org/jboss/weld/servlet/weld-servlet/1.0.1-Final/weld-servlet-1.0.1-Final-sources.jar!/org/slf4j/instrumentation/JavassistHelper.java?format=ok - // http://grepcode.com/file/repo1.maven.org/maven2/jp.objectfanatics/assertion-weaver/0.0.30/jp/objectfanatics/commons/javassist/JavassistUtils.java - if (localVariableAttribute == null) { - // null means that the class is not compiled with debug option. - return null; - } - - dump(localVariableAttribute); - String[] parameterTypes = JavaAssistUtils.parseParameterSignature(method.getSignature()); - if (parameterTypes.length == 0) { - return EMPTY_STRING_ARRAY; - } - String[] parameterVariableNames = new String[parameterTypes.length]; - boolean thisExist = thisExist(method); - - int paramIndex = 0; - for (int i = 0; i < localVariableAttribute.tableLength(); i++) { - // if start pc is not 0, it's not a parameter. - if (localVariableAttribute.startPc(i) != 0) { - continue; - } - int index = localVariableAttribute.index(i); - if (index == 0 && thisExist) { - // variable this. skip. - continue; - } - String variablename = localVariableAttribute.variableName(i); - parameterVariableNames[paramIndex++] = variablename; - - if (paramIndex == parameterTypes.length) { - break; - } - } - return parameterVariableNames; - } - - private static boolean thisExist(CtBehavior method) { - int modifiers = method.getModifiers(); - if (Modifier.isStatic(modifiers)) { - return false; - } else { - return true; - } - } - - private static void dump(LocalVariableAttribute lva) { - if (logger.isDebugEnabled()) { - StringBuilder buffer = new StringBuilder(1024); - for (int i = 0; i < lva.tableLength(); i++) { - buffer.append("\n"); - buffer.append(i); - buffer.append(" start_pc:"); - buffer.append(lva.startPc(i)); - buffer.append(" index:"); - buffer.append(lva.index(i)); - buffer.append(" name:"); - buffer.append(lva.variableName(i)); - buffer.append(" nameIndex:"); - buffer.append(lva.nameIndex(i)); - } - logger.debug(buffer.toString()); - } - } - - - public static String[] getParameterDefaultVariableName(CtBehavior method) { - if (method == null) { - throw new NullPointerException("method must not be null"); - } - String[] parameterTypes = JavaAssistUtils.parseParameterSignature(method.getSignature()); - String[] variableName = new String[parameterTypes.length]; - for (int i = 0; i < variableName.length; i++) { - variableName[i] = getSimpleName(parameterTypes[i]).toLowerCase(); - } - return variableName; - } - - private static String getSimpleName(String parameterName) { - final int findIndex = parameterName.lastIndexOf('.'); - if (findIndex == -1) { - return parameterName; - } else { - return parameterName.substring(findIndex + 1); - } - } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/PreparedStatementUtils.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/PreparedStatementUtils.java deleted file mode 100644 index ffa5843ad8a1..000000000000 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/PreparedStatementUtils.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.util; - - -import java.lang.reflect.Method; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Pattern; - -/** - * @author emeroad - */ -public final class PreparedStatementUtils { - - private static final Pattern BIND_SETTER = Pattern.compile("set[A-Z]([a-zA-Z]+)"); - - private static final List bindMethod; - - private PreparedStatementUtils() { - } - - static { - bindMethod = findBindVariableSetMethod0(); - } - - public static List findBindVariableSetMethod() { - return bindMethod; - } - - public static List findBindVariableSetMethod(BindVariableFilter filter) { - if (filter == null) { - throw new NullPointerException("filter must not be null"); - } - - List temp = new ArrayList(bindMethod.size()); - for (Method method : bindMethod) { - if (filter.filter(method)) { - temp.add(method); - } - } - return temp; - } - - static List findBindVariableSetMethod0() { - Method[] methods = PreparedStatement.class.getDeclaredMethods(); - List bindMethod = new LinkedList(); - for (Method method : methods) { - if (isSetter(method.getName())) { - Class[] parameterTypes = method.getParameterTypes(); - - if (parameterTypes.length < 2) { - continue; - } - if (parameterTypes[0] != int.class) { - continue; - } - if (method.getReturnType() != void.class) { - continue; - } - if (!throwSqlException(method)) { - continue; - } - bindMethod.add(method); - } - } - return Collections.unmodifiableList(bindMethod); - } - - private static boolean throwSqlException(Method method) { - Class[] exceptionTypes = method.getExceptionTypes(); - if (exceptionTypes.length == 1) { - Class exceptionType = exceptionTypes[0]; - if (exceptionType.equals(SQLException.class)) { - return true; - } - } - return false; - } - - - public static boolean isSetter(String name) { - if (name == null) { - return false; - } - return BIND_SETTER.matcher(name).matches(); - } -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/AgentInfoSenderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/AgentInfoSenderTest.java index e052b8a234bd..f228c4a50e2c 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/AgentInfoSenderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/AgentInfoSenderTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -38,8 +38,11 @@ import com.navercorp.pinpoint.rpc.packet.RequestPacket; import com.navercorp.pinpoint.rpc.packet.SendPacket; import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.rpc.server.ServerMessageListenerFactory; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import com.navercorp.pinpoint.thrift.dto.TResult; import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; @@ -51,7 +54,6 @@ import org.slf4j.LoggerFactory; import org.springframework.util.SocketUtils; -import java.net.InetSocketAddress; import java.util.Collections; import java.util.Map; import java.util.Queue; @@ -68,14 +70,11 @@ public class AgentInfoSenderTest { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - public static final int PORT = SocketUtils.findAvailableTcpPort(50050); public static final String HOST = "127.0.0.1"; - private final int testAwaitTimeMs = 50; + private final int awaitSpinDelay = 50; - private final TestAwaitUtils awaitUtils = new TestAwaitUtils(this.testAwaitTimeMs, 60000); + private final TestAwaitUtils awaitUtils = new TestAwaitUtils(this.awaitSpinDelay, 60000); private AgentInformation agentInformation; private ServerMetaDataRegistryService serverMetaDataRegistryService; @@ -90,48 +89,49 @@ public void init() { agentInfoFactory = new AgentInfoFactory(agentInformation, serverMetaDataRegistryService, jvmInformation); } + private TcpDataSender newTcpDataSender(PinpointClientFactory clientFactory, int port) { + return new TcpDataSender(this.getClass().getName(), HOST, port, clientFactory); + } + @Test public void agentInfoShouldBeSent() throws InterruptedException { - final AtomicInteger requestCount = new AtomicInteger(); - final AtomicInteger successCount = new AtomicInteger(); final long agentInfoSendRetryIntervalMs = 100L; - ResponseServerMessageListener serverListener = new ResponseServerMessageListener(requestCount, successCount); + final ResponseServerMessageListenerFactory messageListenerFactory = new ResponseServerMessageListenerFactory(); + ResponseServerMessageListener messageListener = messageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = createServerAcceptor(serverListener); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(messageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); PinpointClientFactory clientFactory = createPinpointClientFactory(); - - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender dataSender = new TcpDataSender(address, clientFactory); + TcpDataSender dataSender = newTcpDataSender(clientFactory, bindPort); AgentInfoSender agentInfoSender = new AgentInfoSender.Builder(dataSender, agentInfoFactory).sendInterval(agentInfoSendRetryIntervalMs).build(); try { agentInfoSender.start(); - waitExpectedRequestCount(requestCount, 1); + waitExpectedRequestCount(messageListener, 1); } finally { - closeAll(serverAcceptor, agentInfoSender, clientFactory); + closeAll(agentInfoSender, clientFactory); + testPinpointServerAcceptor.close(); } - assertEquals(1, requestCount.get()); - assertEquals(1, successCount.get()); + assertEquals(1, messageListener.getRequestCount()); + assertEquals(1, messageListener.getSuccessCount()); } @Test public void agentInfoShouldRetryUntilSuccess() throws InterruptedException { - final AtomicInteger requestCount = new AtomicInteger(); - final AtomicInteger successCount = new AtomicInteger(); final long agentInfoSendRetryIntervalMs = 100L; final int maxTryPerAttempt = 3; final int expectedTriesUntilSuccess = maxTryPerAttempt; - ResponseServerMessageListener serverListener = new ResponseServerMessageListener(requestCount, successCount, expectedTriesUntilSuccess); + final ResponseServerMessageListenerFactory messageListenerFactory = new ResponseServerMessageListenerFactory(expectedTriesUntilSuccess); + ResponseServerMessageListener messageListener = messageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = createServerAcceptor(serverListener); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(messageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); PinpointClientFactory socketFactory = createPinpointClientFactory(); - - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender dataSender = new TcpDataSender(address, socketFactory); + TcpDataSender dataSender = newTcpDataSender(socketFactory, bindPort); AgentInfoSender agentInfoSender = new AgentInfoSender.Builder(dataSender, agentInfoFactory) .maxTryPerAttempt(maxTryPerAttempt) .sendInterval(agentInfoSendRetryIntervalMs) @@ -139,30 +139,29 @@ public void agentInfoShouldRetryUntilSuccess() throws InterruptedException { try { agentInfoSender.start(); - waitExpectedRequestCount(requestCount, expectedTriesUntilSuccess); + waitExpectedRequestCount(messageListener, expectedTriesUntilSuccess); } finally { - closeAll(serverAcceptor, agentInfoSender, socketFactory); + closeAll(agentInfoSender, socketFactory); + testPinpointServerAcceptor.close(); } - assertEquals(expectedTriesUntilSuccess, requestCount.get()); - assertEquals(1, successCount.get()); + assertEquals(expectedTriesUntilSuccess, messageListener.getRequestCount()); + assertEquals(1, messageListener.getSuccessCount()); } @Test public void agentInfoShouldInitiallyRetryIndefinitely() throws InterruptedException { - final AtomicInteger requestCount = new AtomicInteger(); - final AtomicInteger successCount = new AtomicInteger(); final long agentInfoSendRetryIntervalMs = 100L; final int maxTryPerAttempt = 3; final int expectedTriesUntilSuccess = maxTryPerAttempt * 5; - ResponseServerMessageListener serverListener = new ResponseServerMessageListener(requestCount, successCount, expectedTriesUntilSuccess); + final ResponseServerMessageListenerFactory messageListenerFactory = new ResponseServerMessageListenerFactory(expectedTriesUntilSuccess); + ResponseServerMessageListener messageListener = messageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = createServerAcceptor(serverListener); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(messageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); PinpointClientFactory socketFactory = createPinpointClientFactory(); - - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender dataSender = new TcpDataSender(address, socketFactory); + TcpDataSender dataSender = newTcpDataSender(socketFactory, bindPort); AgentInfoSender agentInfoSender = new AgentInfoSender.Builder(dataSender, agentInfoFactory) .maxTryPerAttempt(maxTryPerAttempt) .sendInterval(agentInfoSendRetryIntervalMs) @@ -170,19 +169,18 @@ public void agentInfoShouldInitiallyRetryIndefinitely() throws InterruptedExcept try { agentInfoSender.start(); - waitExpectedRequestCount(requestCount, expectedTriesUntilSuccess); + waitExpectedRequestCount(messageListener, expectedTriesUntilSuccess); } finally { - closeAll(serverAcceptor, agentInfoSender, socketFactory); + closeAll(agentInfoSender, socketFactory); + testPinpointServerAcceptor.close(); } - assertEquals(expectedTriesUntilSuccess, requestCount.get()); - assertEquals(1, successCount.get()); + assertEquals(expectedTriesUntilSuccess, messageListener.getRequestCount()); + assertEquals(1, messageListener.getSuccessCount()); } - + @Test public void agentInfoShouldRetryUntilAttemptsAreExhaustedWhenRefreshing() throws InterruptedException { - final AtomicInteger successServerRequestCount = new AtomicInteger(); - final AtomicInteger failServerRequestCount = new AtomicInteger(); - final AtomicInteger successCount = new AtomicInteger(); + final long agentInfoSendRetryIntervalMs = 1000L; final long agentInfoSendRefreshIntervalMs = 5000L; final int maxTryPerAttempt = 3; @@ -190,16 +188,17 @@ public void agentInfoShouldRetryUntilAttemptsAreExhaustedWhenRefreshing() throws final int expectedFailServerTries = maxTryPerAttempt; final CountDownLatch agentReconnectLatch = new CountDownLatch(1); - ResponseServerMessageListener successServerListener = new ResponseServerMessageListener(successServerRequestCount, successCount); - ResponseServerMessageListener failServerListener = new ResponseServerMessageListener(failServerRequestCount, successCount, Integer.MAX_VALUE); + final ResponseServerMessageListenerFactory successMessageListenerFactory = new ResponseServerMessageListenerFactory(); + ResponseServerMessageListener successMessageListener = successMessageListenerFactory.create(); + + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(successMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); - PinpointServerAcceptor successServerAcceptor = createServerAcceptor(successServerListener); - PinpointServerAcceptor failServerAcceptor = null; + TestPinpointServerAcceptor failTestPinpointServerAcceptor = null; PinpointClientFactory socketFactory = createPinpointClientFactory(); - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender dataSender = new TcpDataSender(address, socketFactory); + TcpDataSender dataSender = newTcpDataSender(socketFactory, bindPort); dataSender.addReconnectEventListener(new PinpointClientReconnectEventListener() { @Override public void reconnectPerformed(PinpointClient client) { @@ -211,28 +210,35 @@ public void reconnectPerformed(PinpointClient client) { .refreshInterval(agentInfoSendRefreshIntervalMs) .sendInterval(agentInfoSendRetryIntervalMs) .build(); + + final ResponseServerMessageListenerFactory failMessageListenerFactory = new ResponseServerMessageListenerFactory(Integer.MAX_VALUE); + ResponseServerMessageListener failMessageListener = failMessageListenerFactory.create(); + try { agentInfoSender.start(); - waitExpectedRequestCount(successServerRequestCount, expectedSuccessServerTries); - successServerAcceptor.close(); + waitExpectedRequestCount(successMessageListener, expectedSuccessServerTries); + testPinpointServerAcceptor.close(); Thread.sleep(agentInfoSendRetryIntervalMs * maxTryPerAttempt); - failServerAcceptor = createServerAcceptor(failServerListener); + + failTestPinpointServerAcceptor = new TestPinpointServerAcceptor(failMessageListenerFactory); + failTestPinpointServerAcceptor.bind(bindPort); + // wait till agent reconnects agentReconnectLatch.await(); - waitExpectedRequestCount(failServerRequestCount, expectedFailServerTries); - failServerAcceptor.close(); + waitExpectedRequestCount(failMessageListener, expectedFailServerTries); } finally { - closeAll(null, agentInfoSender, socketFactory); + closeAll(agentInfoSender, socketFactory); + TestPinpointServerAcceptor.staticClose(failTestPinpointServerAcceptor); + TestPinpointServerAcceptor.staticClose(testPinpointServerAcceptor); } - assertEquals(1, successCount.get()); - assertEquals(expectedSuccessServerTries, successServerRequestCount.get()); - assertEquals(expectedFailServerTries, failServerRequestCount.get()); + assertEquals(1, successMessageListener.getSuccessCount() + failMessageListener.getSuccessCount()); + assertEquals(expectedSuccessServerTries, successMessageListener.getRequestCount()); + assertEquals(expectedFailServerTries, failMessageListener.getRequestCount()); } @Test public void agentInfoShouldBeSentOnlyOnceEvenAfterReconnect() throws Exception { - final AtomicInteger requestCount = new AtomicInteger(); - final AtomicInteger successCount = new AtomicInteger(); + final AtomicInteger reconnectCount = new AtomicInteger(); final int expectedReconnectCount = 3; final long agentInfoSendRetryIntervalMs = 100L; @@ -240,14 +246,14 @@ public void agentInfoShouldBeSentOnlyOnceEvenAfterReconnect() throws Exception { final CyclicBarrier reconnectEventBarrier = new CyclicBarrier(2); - ResponseServerMessageListener serverListener = new ResponseServerMessageListener(requestCount, successCount); + final ResponseServerMessageListenerFactory messageListenerFactory = new ResponseServerMessageListenerFactory(); + ResponseServerMessageListener messageListener = messageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = createServerAcceptor(serverListener); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(messageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); PinpointClientFactory clientFactory = createPinpointClientFactory(); - - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender dataSender = new TcpDataSender(address, clientFactory); + TcpDataSender dataSender = newTcpDataSender(clientFactory, bindPort); dataSender.addReconnectEventListener(new PinpointClientReconnectEventListener() { @Override public void reconnectPerformed(PinpointClient client) { @@ -268,41 +274,42 @@ public void reconnectPerformed(PinpointClient client) { try { // initial connect agentInfoSender.start(); - waitExpectedRequestCount(requestCount, 1); - serverAcceptor.close(); + waitExpectedRequestCount(messageListener, 1); + testPinpointServerAcceptor.close(); // reconnect for (int i = 0; i < expectedReconnectCount; i++) { - PinpointServerAcceptor reconnectServerAcceptor = createServerAcceptor(serverListener); + TestPinpointServerAcceptor reconnectPinpointServerAcceptor = new TestPinpointServerAcceptor(messageListenerFactory); + reconnectPinpointServerAcceptor.bind(bindPort); + // wait for agent to reconnect reconnectEventBarrier.await(); // wait to see if AgentInfo is sent again (it shouldn't) Thread.sleep(1000L); - reconnectServerAcceptor.close(); + reconnectPinpointServerAcceptor.close(); reconnectEventBarrier.reset(); } } finally { - closeAll(null, agentInfoSender, clientFactory); + closeAll(agentInfoSender, clientFactory); + testPinpointServerAcceptor.close(); } - assertEquals(1, successCount.get()); + assertEquals(1, messageListener.getSuccessCount()); assertEquals(expectedReconnectCount, reconnectCount.get()); } @Test public void agentInfoShouldKeepRefreshing() throws InterruptedException { - final AtomicInteger requestCount = new AtomicInteger(); - final AtomicInteger successCount = new AtomicInteger(); final long agentInfoSendRetryIntervalMs = 100L; final long agentInfoSendRefreshIntervalMs = 100L; final int expectedRefreshCount = 5; - ResponseServerMessageListener serverListener = new ResponseServerMessageListener(requestCount, successCount); + final ResponseServerMessageListenerFactory messageListenerFactory = new ResponseServerMessageListenerFactory(); + ResponseServerMessageListener messageListener = messageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = createServerAcceptor(serverListener); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(messageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); PinpointClientFactory socketFactory = createPinpointClientFactory(); - - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender dataSender = new TcpDataSender(address, socketFactory); + TcpDataSender dataSender = newTcpDataSender(socketFactory, bindPort); AgentInfoSender agentInfoSender = new AgentInfoSender.Builder(dataSender, agentInfoFactory) .refreshInterval(agentInfoSendRefreshIntervalMs) .sendInterval(agentInfoSendRetryIntervalMs) @@ -310,32 +317,32 @@ public void agentInfoShouldKeepRefreshing() throws InterruptedException { try { agentInfoSender.start(); - while (requestCount.get() < expectedRefreshCount) { + while (messageListener.getRequestCount() < expectedRefreshCount) { Thread.sleep(1000L); } } finally { - closeAll(serverAcceptor, agentInfoSender, socketFactory); + closeAll(agentInfoSender, socketFactory); + testPinpointServerAcceptor.close(); } - assertTrue(requestCount.get() >= expectedRefreshCount); - assertTrue(successCount.get() >= expectedRefreshCount); + assertTrue(messageListener.getRequestCount() >= expectedRefreshCount); + assertTrue(messageListener.getSuccessCount() >= expectedRefreshCount); } @Test public void agentInfoShouldBeRefreshedOnServerMetaDataChange() throws InterruptedException { // Given - final AtomicInteger requestCount = new AtomicInteger(); - final AtomicInteger successCount = new AtomicInteger(); final int expectedRequestCount = 5; final long agentInfoSendRetryIntervalMs = 1000L; - ResponseServerMessageListener serverListener = new ResponseServerMessageListener(requestCount, successCount); + final ResponseServerMessageListenerFactory messageListenerFactory = new ResponseServerMessageListenerFactory(); + ResponseServerMessageListener messageListener = messageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = createServerAcceptor(serverListener); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(messageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); PinpointClientFactory clientFactory = createPinpointClientFactory(); - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender dataSender = new TcpDataSender(address, clientFactory); + TcpDataSender dataSender = newTcpDataSender(clientFactory, bindPort); final AgentInfoSender agentInfoSender = new AgentInfoSender.Builder(dataSender, agentInfoFactory).sendInterval(agentInfoSendRetryIntervalMs).build(); serverMetaDataRegistryService.addListener(new ServerMetaDataRegistryService.OnChangeListener() { @Override @@ -350,20 +357,19 @@ public void onServerMetaDataChange() { serverMetaDataRegistryService.notifyListeners(); } - waitExpectedRequestCount(requestCount, expectedRequestCount); + waitExpectedRequestCount(messageListener, expectedRequestCount); } finally { - closeAll(serverAcceptor, agentInfoSender, clientFactory); + closeAll(agentInfoSender, clientFactory); + testPinpointServerAcceptor.close(); } // Then - assertEquals(expectedRequestCount, requestCount.get()); - assertEquals(expectedRequestCount, successCount.get()); + assertEquals(expectedRequestCount, messageListener.getRequestCount()); + assertEquals(expectedRequestCount, messageListener.getSuccessCount()); } @Test public void agentInfoShouldBeRefreshedOnServerMetaDataChangeFromMultipleThreads() throws InterruptedException { // Given - final AtomicInteger requestCount = new AtomicInteger(); - final AtomicInteger successCount = new AtomicInteger(); final long agentInfoSendRetryIntervalMs = 1000L; final int threadCount = 50; final CountDownLatch initLatch = new CountDownLatch(threadCount); @@ -372,14 +378,15 @@ public void agentInfoShouldBeRefreshedOnServerMetaDataChangeFromMultipleThreads( final ExecutorService executorService = Executors.newFixedThreadPool(threadCount); final Queue exceptions = new ConcurrentLinkedQueue(); - ResponseServerMessageListener delayedServerListener = new ResponseServerMessageListener(requestCount, successCount); + final ResponseServerMessageListenerFactory messageListenerFactory = new ResponseServerMessageListenerFactory(); + ResponseServerMessageListener messageListener = messageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = createServerAcceptor(delayedServerListener); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(messageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); PinpointClientFactory clientFactory = createPinpointClientFactory(); - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender dataSender = new TcpDataSender(address, clientFactory); + TcpDataSender dataSender = newTcpDataSender(clientFactory, bindPort); final AgentInfoSender agentInfoSender = new AgentInfoSender.Builder(dataSender, agentInfoFactory).sendInterval(agentInfoSendRetryIntervalMs).build(); serverMetaDataRegistryService.addListener(new ServerMetaDataRegistryService.OnChangeListener() { @Override @@ -413,32 +420,33 @@ public void run() { endLatch.await(); executorService.shutdown(); try { - waitExpectedRequestCount(requestCount, threadCount); - waitExpectedRequestCount(successCount, threadCount); + waitExpectedRequestCount(messageListener, threadCount); + waitExpectedSuccessCount(messageListener, threadCount); } finally { - closeAll(serverAcceptor, agentInfoSender, clientFactory); + closeAll(agentInfoSender, clientFactory); + testPinpointServerAcceptor.close(); } // Then assertTrue("Failed with exceptions : " + exceptions, exceptions.isEmpty()); - assertEquals(threadCount, requestCount.get()); - assertEquals(threadCount, successCount.get()); + assertEquals(threadCount, messageListener.getRequestCount()); + assertEquals(threadCount, messageListener.getSuccessCount()); } public void reconnectionStressTest() throws InterruptedException { - final AtomicInteger requestCount = new AtomicInteger(); - final AtomicInteger successCount = new AtomicInteger(); final long stressTestTime = 60 * 1000L; final int randomMaxTime = 3000; final long agentInfoSendRetryIntervalMs = 1000L; final int maxTryPerAttempt = Integer.MAX_VALUE; final int expectedTriesUntilSuccess = (int) stressTestTime / (randomMaxTime * 2) - 1; - ResponseServerMessageListener serverListener = new ResponseServerMessageListener(requestCount, successCount, expectedTriesUntilSuccess); + final ResponseServerMessageListenerFactory messageListenerFactory = new ResponseServerMessageListenerFactory(expectedTriesUntilSuccess); + ResponseServerMessageListener messageListener = messageListenerFactory.create(); PinpointClientFactory clientFactory = createPinpointClientFactory(); - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender dataSender = new TcpDataSender(address, clientFactory); + int availableTcpPort = SocketUtils.findAvailableTcpPort(47000); + + TcpDataSender dataSender = newTcpDataSender(clientFactory, availableTcpPort); AgentInfoSender agentInfoSender = new AgentInfoSender.Builder(dataSender, agentInfoFactory) .sendInterval(agentInfoSendRetryIntervalMs) .maxTryPerAttempt(maxTryPerAttempt) @@ -452,75 +460,92 @@ public void reconnectionStressTest() throws InterruptedException { Random random = new Random(System.currentTimeMillis()); while (System.currentTimeMillis() < startTime + stressTestTime) { - createAndDeleteServer(serverListener, Math.abs(random.nextInt(randomMaxTime))); + createAndDeleteServer(messageListenerFactory, Math.abs(random.nextInt(randomMaxTime))); Thread.sleep(Math.abs(random.nextInt(1000))); } } finally { - closeAll(null, agentInfoSender, clientFactory); + closeAll(agentInfoSender, clientFactory); } - assertEquals(1, successCount.get()); - assertEquals(expectedTriesUntilSuccess, requestCount.get()); + assertEquals(1, messageListener.getSuccessCount()); + assertEquals(expectedTriesUntilSuccess, messageListener.getRequestCount()); } - private PinpointServerAcceptor createServerAcceptor(ServerMessageListener listener) { - PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(); - // server.setMessageListener(new - // NoResponseServerMessageListener(requestCount)); - serverAcceptor.setMessageListener(listener); - serverAcceptor.bind(HOST, PORT); + private void createAndDeleteServer(ServerMessageListenerFactory messageListenerFactory, long waitTimeMillis) throws InterruptedException { + int availableTcpPort = SocketUtils.findAvailableTcpPort(47000); - return serverAcceptor; - } - - private void createAndDeleteServer(ServerMessageListener listener, long waitTimeMillis) throws InterruptedException { - PinpointServerAcceptor server = null; + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(messageListenerFactory); try { - server = createServerAcceptor(listener); + testPinpointServerAcceptor.bind(availableTcpPort); Thread.sleep(waitTimeMillis); } finally { - if (server != null) { - server.close(); - } + TestPinpointServerAcceptor.staticClose(testPinpointServerAcceptor); } } - private void closeAll(PinpointServerAcceptor serverAcceptor, AgentInfoSender agentInfoSender, PinpointClientFactory factory) { + private void closeAll(AgentInfoSender agentInfoSender, PinpointClientFactory factory) { if (agentInfoSender != null) { agentInfoSender.stop(); } - if (serverAcceptor != null) { - serverAcceptor.close(); - } - if (factory != null) { factory.release(); } } private AgentInformation createAgentInformation() { - AgentInformation agentInfo = new DefaultAgentInformation("agentId", "appName", System.currentTimeMillis(), 1111, "hostname", "127.0.0.1", ServiceType.USER, + AgentInformation agentInfo = new DefaultAgentInformation("agentId", "appName", false, System.currentTimeMillis(), 1111, "hostname", "127.0.0.1", ServiceType.USER, JvmUtils.getSystemProperty(SystemPropertyKey.JAVA_VERSION), Version.VERSION); return agentInfo; } - class ResponseServerMessageListener implements ServerMessageListener { + + private static class ResponseServerMessageListenerFactory implements ServerMessageListenerFactory { + + private final ResponseServerMessageListener responseServerMessageListener; + + public ResponseServerMessageListenerFactory() { + this(1); + } + + public ResponseServerMessageListenerFactory(int successCondition) { + this.responseServerMessageListener = new ResponseServerMessageListener(successCondition); + } + + @Override + public ResponseServerMessageListener create() { + return responseServerMessageListener; + } + + } + + private static class ResponseServerMessageListener implements ServerMessageListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final AtomicInteger requestCount; private final AtomicInteger successCount; private final int successCondition; - public ResponseServerMessageListener(AtomicInteger requestCount, AtomicInteger successCount) { - this(requestCount, successCount, 1); + public ResponseServerMessageListener() { + this(1); } - public ResponseServerMessageListener(AtomicInteger requestCount, AtomicInteger successCount, int successCondition) { - this.requestCount = requestCount; - this.successCount = successCount; + public ResponseServerMessageListener(int successCondition) { + this.requestCount = new AtomicInteger(); + this.successCount = new AtomicInteger(); this.successCondition = successCondition; } + public int getRequestCount() { + return requestCount.get(); + } + + public int getSuccessCount() { + return successCount.get(); + } + @Override public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { logger.debug("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); @@ -543,7 +568,7 @@ public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSo this.successCount.incrementAndGet(); - pinpointSocket.response(requestPacket, resultBytes); + pinpointSocket.response(requestPacket.getRequestId(), resultBytes); } catch (TException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -564,20 +589,35 @@ public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServ private PinpointClientFactory createPinpointClientFactory() { PinpointClientFactory clientFactory = new DefaultPinpointClientFactory(); - clientFactory.setTimeoutMillis(1000 * 5); + clientFactory.setWriteTimeoutMillis(1000 * 3); + clientFactory.setRequestTimeoutMillis(1000 * 5); clientFactory.setProperties(Collections. emptyMap()); return clientFactory; } - private void waitExpectedRequestCount(final AtomicInteger requestCount, final int expectedRequestCount) { - boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { + private void waitExpectedRequestCount(final ResponseServerMessageListener listener, final int expectedRequestCount) { + TestAwaitTaskUtils task = new TestAwaitTaskUtils() { @Override public boolean checkCompleted() { - return requestCount.get() == expectedRequestCount; + return listener.getRequestCount() == expectedRequestCount; } - }); + }; + awaitTask(task); + } + + private void waitExpectedSuccessCount(final ResponseServerMessageListener listener, final int expectedRequestCount) { + TestAwaitTaskUtils task = new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return listener.getSuccessCount() == expectedRequestCount; + } + }; + awaitTask(task); + } + private void awaitTask(TestAwaitTaskUtils awaitTaskUtils) { + boolean pass = awaitUtils.await(awaitTaskUtils); Assert.assertTrue(pass); } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/TestAwaitTaskUtils.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/TestAwaitTaskUtils.java deleted file mode 100644 index 2c4c2fc596a5..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/TestAwaitTaskUtils.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler; - -/** - * @author Taejin Koo - */ -public interface TestAwaitTaskUtils { - - boolean checkCompleted(); - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/TestAwaitUtils.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/TestAwaitUtils.java deleted file mode 100644 index 38614c4e640b..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/TestAwaitUtils.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler; - -import com.navercorp.pinpoint.common.util.StopWatch; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Taejin Koo - */ -public class TestAwaitUtils { - - private final static Logger LOGGER = LoggerFactory.getLogger(TestAwaitUtils.class); - - private final long waitUnitTime; - private final long maxWaitTime; - - public TestAwaitUtils(long waitUnitTime, long maxWaitTime) { - this.waitUnitTime = waitUnitTime; - this.maxWaitTime = maxWaitTime; - } - - public boolean await(TestAwaitTaskUtils awaitTaskUtils) { - return await(awaitTaskUtils, waitUnitTime, maxWaitTime); - } - - public static boolean await(TestAwaitTaskUtils awaitTaskUtils, long waitUnitTime, long maxWaitTime) { - StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - - while (true) { - try { - if (awaitTaskUtils.checkCompleted()) { - return true; - } - } catch (Exception e) { - LOGGER.warn(e.getMessage(), e); - } - - try { - Thread.sleep(waitUnitTime); - } catch (InterruptedException e) { - } - - if (stopWatch.stop() > maxWaitTime) { - return false; - } - } - } - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/CallStackTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/CallStackTest.java index 2f5ef7b27645..abbbd1e89d2b 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/CallStackTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/CallStackTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,7 +18,6 @@ import static org.junit.Assert.*; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; import org.junit.Assert; import org.junit.Test; @@ -33,37 +32,30 @@ public abstract class CallStackTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); + protected CallStack.Factory factory = new SpanEventFactory(); - abstract CallStack newCallStack(); - abstract CallStack newCallStack(int depth); + abstract CallStack newCallStack(); + abstract CallStack newCallStack(int depth); - - abstract TraceRoot getLocalTraceId(); - abstract SpanEvent getSpanEvent(); - - - private SpanEvent createSpanEventStackFrame(TraceRoot traceRoot) { - SpanEvent spanEvent = new SpanEvent(traceRoot); - return spanEvent; + public SpanEvent getSpanEvent() { + return factory.newInstance(); } @Test public void testPush() throws Exception { - CallStack callStack = newCallStack(); + CallStack callStack = newCallStack(); int initialIndex = callStack.getIndex(); assertEquals("initial index", initialIndex, 0); - SpanEvent spanEvent = createSpanEventStackFrame(getLocalTraceId()); + SpanEvent spanEvent = factory.newInstance(); int index = callStack.push(spanEvent); assertEquals("initial index", index, 1); callStack.pop(); } - - @Test public void testLargePush() { - CallStack callStack = newCallStack(); + CallStack callStack = newCallStack(); int initialIndex = callStack.getIndex(); Assert.assertEquals("initial index", initialIndex, 0); @@ -82,7 +74,7 @@ public void testLargePush() { @Test public void testPushPop1() { - CallStack callStack = newCallStack(); + CallStack callStack = newCallStack(); callStack.push(getSpanEvent()); callStack.pop(); @@ -90,7 +82,7 @@ public void testPushPop1() { @Test public void testPushPop2() { - CallStack callStack = newCallStack(); + CallStack callStack = newCallStack(); callStack.push(getSpanEvent()); callStack.push(getSpanEvent()); @@ -101,7 +93,7 @@ public void testPushPop2() { @Test public void testPop_Fail() { - CallStack callStack = newCallStack(); + CallStack callStack = newCallStack(); callStack.push(getSpanEvent()); callStack.push(getSpanEvent()); @@ -115,7 +107,7 @@ public void testPop_Fail() { public void overflow() { final int maxDepth = 3; - DefaultCallStack callStack = (DefaultCallStack) newCallStack(maxDepth); + DefaultCallStack callStack = (DefaultCallStack) newCallStack(maxDepth); assertEquals(maxDepth, callStack.getMaxDepth()); for(int i = 0; i < maxDepth; i++) { diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultCallStackTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultCallStackTest.java index 39aea1eb98db..558c39fe9fee 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultCallStackTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultCallStackTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,43 +16,22 @@ package com.navercorp.pinpoint.profiler.context; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import org.junit.Before; - -import static org.mockito.Mockito.mock; - /** * @author emeroad * @author jaehong.kim */ public class DefaultCallStackTest extends CallStackTest { - private SpanEvent spanEvent; - private TraceRoot internalTraceId; - - @Before - public void before() { - this.internalTraceId = mock(TraceRoot.class); - this.spanEvent = new SpanEvent(internalTraceId); - } @Override - public CallStack newCallStack() { - return new DefaultCallStack(internalTraceId); + public CallStack newCallStack() { + return new DefaultCallStack(factory); } @Override - public CallStack newCallStack(int depth) { - return new DefaultCallStack(internalTraceId, depth); + public CallStack newCallStack(int depth) { + return new DefaultCallStack(factory, depth); } - @Override - TraceRoot getLocalTraceId() { - return internalTraceId; - } - @Override - public SpanEvent getSpanEvent() { - return spanEvent; - } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultTraceContextTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultTraceContextTest.java index dab70206cd92..04adda65dce0 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultTraceContextTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultTraceContextTest.java @@ -28,6 +28,7 @@ import com.navercorp.pinpoint.profiler.context.id.IdGenerator; import com.navercorp.pinpoint.profiler.context.id.TransactionCounter; import com.navercorp.pinpoint.profiler.context.module.ApplicationContext; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -36,6 +37,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.mockito.Mockito.spy; + /** * @author emeroad * @author HyunGil Jeong @@ -43,12 +46,14 @@ public class DefaultTraceContextTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private MockApplicationContext applicationContext; + private DefaultApplicationContext applicationContext; @Before public void setUp() throws Exception { - ProfilerConfig profilerConfig = new DefaultProfilerConfig(); + ProfilerConfig profilerConfig = getProfilerConfig(); + applicationContext = MockTraceContextFactory.newMockApplicationContext(profilerConfig); + applicationContext.start(); } @After @@ -92,8 +97,11 @@ public void threadLocalBindTest() { TraceContext traceContext = applicationContext.getTraceContext(); Assert.assertNotNull(traceContext.newTraceObject()); - ProfilerConfig profilerConfig = new DefaultProfilerConfig(); - MockApplicationContext applicationContext2 = MockTraceContextFactory.newMockApplicationContext(profilerConfig); + ProfilerConfig profilerConfig = getProfilerConfig(); + + DefaultApplicationContext applicationContext2 = MockTraceContextFactory.newMockApplicationContext(profilerConfig); + applicationContext2.start(); + TraceContext traceContext2 = applicationContext2.getTraceContext(); Trace notExist = traceContext2.currentRawTraceObject(); applicationContext2.close(); @@ -109,13 +117,16 @@ public void threadLocalBindTest() { public void transactionCountTest() { final int samplingRate = 5; - final ProfilerConfig profilerConfig = Mockito.spy(new DefaultProfilerConfig()); + final ProfilerConfig profilerConfig = getProfilerConfig(); Mockito.when(profilerConfig.isTraceAgentActiveThread()).thenReturn(true); Mockito.when((profilerConfig.getSamplingRate())).thenReturn(samplingRate); Mockito.when((profilerConfig.isSamplingEnable())).thenReturn(true); - MockApplicationContext customContext = MockTraceContextFactory.newMockApplicationContext(profilerConfig); + + DefaultApplicationContext customContext = MockTraceContextFactory.newMockApplicationContext(profilerConfig); + customContext.start(); + final TraceContext traceContext = customContext.getTraceContext(); IdGenerator idGenerator = customContext.getInjector().getInstance(IdGenerator.class); final TransactionCounter transactionCounter = new DefaultTransactionCounter(idGenerator); @@ -152,4 +163,10 @@ public void transactionCountTest() { Assert.assertEquals(expectedUnsampledContinuationCount, transactionCounter.getUnSampledContinuationCount()); Assert.assertEquals(expectedTotalTransactionCount, transactionCounter.getTotalTransactionCount()); } + + public ProfilerConfig getProfilerConfig() { + ProfilerConfig profilerConfig = spy(new DefaultProfilerConfig()); + Mockito.when(profilerConfig.getStaticResourceCleanup()).thenReturn(true); + return profilerConfig; + } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultTraceTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultTraceTest.java index aaa4b7546e5e..7982fbcbe41d 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultTraceTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DefaultTraceTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -28,16 +28,16 @@ import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; import com.navercorp.pinpoint.profiler.context.recorder.DefaultSpanRecorder; import com.navercorp.pinpoint.profiler.context.recorder.WrappedSpanEventRecorder; -import com.navercorp.pinpoint.profiler.context.storage.SpanStorage; +import com.navercorp.pinpoint.profiler.context.storage.Storage; import com.navercorp.pinpoint.profiler.logging.Slf4jLoggerBinderInitializer; import com.navercorp.pinpoint.profiler.metadata.SqlMetaDataService; import com.navercorp.pinpoint.profiler.metadata.StringMetaDataService; -import com.navercorp.pinpoint.profiler.sender.LoggingDataSender; import org.junit.*; import org.junit.runner.RunWith; import org.mockito.Mock; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** @@ -48,7 +48,6 @@ public class DefaultTraceTest { private final String agentId = "agentId"; private final long agentStartTime = System.currentTimeMillis(); - private final TransactionIdEncoder encoder = new DefaultTransactionIdEncoder(agentId, agentStartTime); @Mock private TraceRoot traceRoot; @@ -79,17 +78,17 @@ public void testPushPop() { TraceId traceId = new DefaultTraceId(agentId, System.currentTimeMillis(), 0); when(traceRoot.getTraceId()).thenReturn(traceId); - CallStackFactory callStackFactory = new CallStackFactoryV1(64); - CallStack callStack = callStackFactory.newCallStack(traceRoot); + CallStackFactory callStackFactory = new CallStackFactoryV1(64); + CallStack callStack = callStackFactory.newCallStack(); - SpanFactory spanFactory = new DefaultSpanFactory("appName", agentId, 0, ServiceType.STAND_ALONE, encoder); + SpanFactory spanFactory = new DefaultSpanFactory(); - SpanStorage storage = new SpanStorage(traceRoot, LoggingDataSender.DEFAULT_LOGGING_DATA_SENDER); + Storage storage = mock(Storage.class); final Span span = spanFactory.newSpan(traceRoot); final boolean root = span.getTraceRoot().getTraceId().isRoot(); final SpanRecorder spanRecorder = new DefaultSpanRecorder(span, root, true, stringMetaDataService, sqlMetaDataService); - final WrappedSpanEventRecorder wrappedSpanEventRecorder = new WrappedSpanEventRecorder(asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); + final WrappedSpanEventRecorder wrappedSpanEventRecorder = new WrappedSpanEventRecorder(traceRoot, asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); Trace trace = new DefaultTrace(span, callStack, storage, asyncContextFactory, true, spanRecorder, wrappedSpanEventRecorder, ActiveTraceHandle.EMPTY_HANDLE); trace.traceBlockBegin(); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DepthCompressCallStackTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DepthCompressCallStackTest.java index 52c1508283d8..f72506a21d3d 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DepthCompressCallStackTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/DepthCompressCallStackTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,44 +16,23 @@ package com.navercorp.pinpoint.profiler.context; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import org.junit.Before; - -import static org.mockito.Mockito.mock; - /** * @author Woonduk Kang(emeroad) */ public class DepthCompressCallStackTest extends CallStackTest { - private SpanEvent spanEvent; - private TraceRoot internalTraceId; - - @Before - public void before() { - this.internalTraceId = mock(TraceRoot.class); - this.spanEvent = new SpanEvent(internalTraceId); - } @Override - public CallStack newCallStack() { - return new DefaultCallStack(internalTraceId); + public CallStack newCallStack() { + return new DefaultCallStack(factory); } @Override - public CallStack newCallStack(int depth) { - return new DepthCompressCallStack(internalTraceId, depth); + public CallStack newCallStack(int depth) { + return new DepthCompressCallStack(factory, depth); } - @Override - TraceRoot getLocalTraceId() { - return internalTraceId; - } - @Override - public SpanEvent getSpanEvent() { - return spanEvent; - } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockApplicationContext.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockApplicationContext.java deleted file mode 100644 index 75a50ed438a8..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockApplicationContext.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context; - -import com.google.inject.AbstractModule; -import com.navercorp.pinpoint.bootstrap.AgentOption; -import com.navercorp.pinpoint.profiler.AgentInformation; -import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; -import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; -import com.navercorp.pinpoint.profiler.context.storage.LogStorageFactory; -import com.navercorp.pinpoint.profiler.context.storage.StorageFactory; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; -import com.navercorp.pinpoint.profiler.sender.LoggingDataSender; - -/** - * @author Woonduk Kang(emeroad) - */ -public class MockApplicationContext extends DefaultApplicationContext { - private InterceptorRegistryBinder interceptorRegistryBinder; - - - public MockApplicationContext(AgentOption agentOption, InterceptorRegistryBinder binder, ModuleFactory moduleFactory) { - super(agentOption, binder, moduleFactory); - if (binder == null) { - throw new NullPointerException("agentOption must not be null"); - } - this.interceptorRegistryBinder = binder; - } - - @Override - public void close() { - super.close(); - interceptorRegistryBinder.unbind(); - } - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockApplicationContextFactory.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockApplicationContextFactory.java index e06725963a1c..43922d0dac01 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockApplicationContextFactory.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockApplicationContextFactory.java @@ -19,17 +19,12 @@ import com.navercorp.pinpoint.bootstrap.AgentOption; import com.navercorp.pinpoint.bootstrap.DefaultAgentOption; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; -import com.navercorp.pinpoint.profiler.context.module.ApplicationContext; import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.util.TestInterceptorRegistryBinder; import org.mockito.Mockito; import java.lang.instrument.Instrumentation; -import java.net.URL; +import java.util.Collections; /** * @author Woonduk Kang(emeroad) @@ -40,25 +35,12 @@ public MockApplicationContextFactory() { } - public MockApplicationContext of(ProfilerConfig config, InterceptorRegistryBinder binder, ModuleFactory moduleFactory) { + public DefaultApplicationContext build(ProfilerConfig config, ModuleFactory moduleFactory) { Instrumentation instrumentation = Mockito.mock(Instrumentation.class); String mockAgent = "mockAgent"; String mockApplicationName = "mockApplicationName"; - DefaultServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(); - DefaultAnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(); - AgentOption agentOption = new DefaultAgentOption(instrumentation, mockAgent, mockApplicationName, config, new URL[0], null, serviceTypeRegistryService, annotationKeyRegistryService); - return new MockApplicationContext(agentOption, binder, moduleFactory); + AgentOption agentOption = new DefaultAgentOption(instrumentation, mockAgent, mockApplicationName, false, config, Collections.emptyList(), null); + return new DefaultApplicationContext(agentOption, moduleFactory); } - public ApplicationContext newDefaultApplicationContext(ProfilerConfig config, InterceptorRegistryBinder binder, ModuleFactory moduleFactory) { - Instrumentation instrumentation = Mockito.mock(Instrumentation.class); - String mockAgent = "mockAgent"; - String mockApplicationName = "mockApplicationName"; - DefaultServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(); - DefaultAnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(); - AgentOption agentOption = new DefaultAgentOption(instrumentation, mockAgent, mockApplicationName, config, new URL[0], null, serviceTypeRegistryService, annotationKeyRegistryService); - return new DefaultApplicationContext(agentOption, binder, moduleFactory); - } - - } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockTraceContextFactory.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockTraceContextFactory.java index 61a9148668ae..71d5aced89be 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockTraceContextFactory.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/MockTraceContextFactory.java @@ -19,19 +19,16 @@ import com.google.inject.AbstractModule; import com.google.inject.Module; -import com.google.inject.util.Modules; -import com.navercorp.pinpoint.bootstrap.AgentOption; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.interceptor.registry.InterceptorRegistryAdaptor; import com.navercorp.pinpoint.profiler.AgentInformation; -import com.navercorp.pinpoint.profiler.context.module.ApplicationContext; -import com.navercorp.pinpoint.profiler.context.module.ApplicationContextModule; import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; +import com.navercorp.pinpoint.profiler.context.module.InterceptorRegistryModule; import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; +import com.navercorp.pinpoint.profiler.context.module.OverrideModuleFactory; import com.navercorp.pinpoint.profiler.context.storage.LogStorageFactory; import com.navercorp.pinpoint.profiler.context.storage.StorageFactory; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; - import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; import com.navercorp.pinpoint.profiler.sender.LoggingDataSender; @@ -40,39 +37,16 @@ */ public class MockTraceContextFactory { - public static MockApplicationContext newMockApplicationContext(ProfilerConfig profilerConfig) { - ModuleFactory moduleFactory = new ModuleFactory() { - @Override - public Module newModule(AgentOption agentOption, InterceptorRegistryBinder interceptorRegistryBinder) { - Module module = new ApplicationContextModule(agentOption, interceptorRegistryBinder); - - LoggingModule loggingModule = new LoggingModule(); - return Modules.override(module).with(loggingModule); - } - }; - MockApplicationContextFactory factory = new MockApplicationContextFactory(); - InterceptorRegistryBinder binder = new InterceptorRegistryBinder() { - @Override - public void bind() { - - } - - @Override - public void unbind() { + public static DefaultApplicationContext newMockApplicationContext(ProfilerConfig profilerConfig) { - } + Module loggingModule = new LoggingModule(); - @Override - public InterceptorRegistryAdaptor getInterceptorRegistryAdaptor() { - return null; - } + InterceptorRegistryBinder interceptorRegistryBinder = new EmptyInterceptorRegistryBinder(); + Module interceptorRegistryModule = InterceptorRegistryModule.wrap(interceptorRegistryBinder); + ModuleFactory moduleFactory = new OverrideModuleFactory(loggingModule, interceptorRegistryModule); - @Override - public String getInterceptorRegistryClassName() { - return null; - } - }; - return factory.of(profilerConfig, binder, moduleFactory); + MockApplicationContextFactory factory = new MockApplicationContextFactory(); + return factory.build(profilerConfig, moduleFactory); } public static class LoggingModule extends AbstractModule { @@ -83,4 +57,26 @@ protected void configure() { bind(EnhancedDataSender.class).toInstance(new LoggingDataSender()); } } + + private static class EmptyInterceptorRegistryBinder implements InterceptorRegistryBinder { + @Override + public void bind() { + + } + + @Override + public void unbind() { + + } + + @Override + public InterceptorRegistryAdaptor getInterceptorRegistryAdaptor() { + return null; + } + + @Override + public String getInterceptorRegistryClassName() { + return null; + } + }; } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactoryTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactoryTest.java deleted file mode 100644 index 02a724cfc89f..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanChunkFactoryTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.context; - -import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.common.trace.ServiceType; - -import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; -import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; -import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; -import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; -import org.junit.Assert; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author emeroad - */ -public class SpanChunkFactoryTest { - - private final String agentId = "agentId"; - private final long agentStartTime = System.currentTimeMillis(); - private final TransactionIdEncoder encoder = new DefaultTransactionIdEncoder(agentId, agentStartTime); - - @Test - public void create() { - - SpanChunkFactory spanChunkFactory = new SpanChunkFactoryV1("applicationName", agentId, agentStartTime, ServiceType.STAND_ALONE, encoder); - TraceRoot internalTraceId = newInternalTraceId(); - try { - spanChunkFactory.create(internalTraceId, new ArrayList()); - Assert.fail(); - } catch (Exception ignored) { - } - // one spanEvent - List spanEvents = new ArrayList(); - spanEvents.add(new SpanEvent(internalTraceId)); - spanChunkFactory.create(internalTraceId, spanEvents); - - // two spanEvent - spanEvents.add(new SpanEvent(internalTraceId)); - spanChunkFactory.create(internalTraceId, spanEvents); - - // three - spanEvents.add(new SpanEvent(internalTraceId)); - spanChunkFactory.create(internalTraceId, spanEvents); - - } - - private TraceRoot newInternalTraceId() { - TraceId traceId = new DefaultTraceId(agentId, agentStartTime, 100); - return new DefaultTraceRoot(traceId, agentId, agentStartTime, 0); - } -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventElementFactoryTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventElementFactoryTest.java new file mode 100644 index 000000000000..be50e8c86c23 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventElementFactoryTest.java @@ -0,0 +1,8 @@ +import static org.junit.Assert.*; + +/** + * @author Woonduk Kang(emeroad) + */ +public class SpanEventElementFactoryTest { + +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventTest.java index f1ecf1e18db1..b85c1d4f4b89 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/SpanEventTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,10 +16,13 @@ package com.navercorp.pinpoint.profiler.context; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressor; -import com.navercorp.pinpoint.profiler.context.compress.SpanEventCompressorV1; +import com.navercorp.pinpoint.profiler.context.compress.Context; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessorV1; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanEvent; import org.junit.Assert; import org.junit.Test; @@ -28,36 +31,39 @@ import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; -import java.util.Collections; - /** * @author emeroad */ public class SpanEventTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final SpanEventCompressor compressorV1 = new SpanEventCompressorV1(); + private final SpanPostProcessor compressorV1 = new SpanPostProcessorV1(); + @Test - public void testMarkStartTime() throws Exception { + public void testMarkStartTime() { final DefaultTraceId traceId = new DefaultTraceId("agentId", 0, 0); TraceRoot traceRoot = new DefaultTraceRoot(traceId, "agentId", System.currentTimeMillis(),0); Span span = new Span(traceRoot); - span.setAgentId("agentId"); span.markBeforeTime(); - Thread.sleep(10); - span.markAfterTime(); + + span.setElapsedTime((int) (span.getStartTime() + 10)); logger.debug("span:{}", span); - final SpanEvent spanEvent = new SpanEvent(traceRoot); - spanEvent.markStartTime(); - Thread.sleep(10); - spanEvent.markAfterTime(); + final SpanEvent spanEvent = new SpanEvent(); + long currentTime = System.currentTimeMillis(); + spanEvent.setStartTime(currentTime); + + spanEvent.setElapsedTime(10); logger.debug("spanEvent:{}", spanEvent); - compressorV1.compress(Collections.singletonList(spanEvent), span.getStartTime()); + TSpan tSpan = new TSpan(); + TSpanEvent tSpanEvent = new TSpanEvent(); + Context context = compressorV1.newContext(span, tSpan); + + compressorV1.postProcess(context, spanEvent, tSpanEvent); - Assert.assertEquals("startTime", span.getStartTime() + spanEvent.getStartElapsed(), spanEvent.getStartTime()); - Assert.assertEquals("endTime", span.getStartTime() + spanEvent.getStartElapsed() + spanEvent.getEndElapsed(), spanEvent.getAfterTime()); + Assert.assertEquals("startTime", span.getStartTime() + tSpanEvent.getStartElapsed(), spanEvent.getStartTime()); + Assert.assertEquals("endTime", span.getStartTime() + tSpanEvent.getStartElapsed() + spanEvent.getElapsedTime(), spanEvent.getAfterTime()); } @Test diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/TestAgentInformation.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/TestAgentInformation.java index 9beb95e6fa41..d00a583fb12c 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/TestAgentInformation.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/TestAgentInformation.java @@ -31,6 +31,7 @@ public class TestAgentInformation extends DefaultAgentInformation { private static final String AGENT_ID = "test-agent"; private static final String APPLICATION_NAME = "TEST_APPLICATION"; + private static final boolean IS_CONTAINER = false; private static final int PID = 10; private static final String MACHINE_NAME = "test-machine"; private static final String HOST_IP = "127.0.0.1"; @@ -39,6 +40,6 @@ public class TestAgentInformation extends DefaultAgentInformation { private static final String AGENT_VERSION = Version.VERSION; public TestAgentInformation() { - super(AGENT_ID, APPLICATION_NAME, System.currentTimeMillis(), PID, MACHINE_NAME, HOST_IP, SERVICE_TYPE, JVM_VERSION, AGENT_VERSION); + super(AGENT_ID, APPLICATION_NAME, IS_CONTAINER, System.currentTimeMillis(), PID, MACHINE_NAME, HOST_IP, SERVICE_TYPE, JVM_VERSION, AGENT_VERSION); } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/TraceTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/TraceTest.java index 054f355f41df..25aefeb7a42e 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/TraceTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/TraceTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,20 +19,15 @@ import com.navercorp.pinpoint.bootstrap.context.SpanRecorder; import com.navercorp.pinpoint.bootstrap.context.Trace; import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.profiler.context.active.ActiveTraceHandle; -import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; -import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; import com.navercorp.pinpoint.profiler.context.recorder.DefaultSpanRecorder; import com.navercorp.pinpoint.profiler.context.recorder.WrappedSpanEventRecorder; import com.navercorp.pinpoint.profiler.context.storage.SpanStorage; import com.navercorp.pinpoint.profiler.metadata.SqlMetaDataService; import com.navercorp.pinpoint.profiler.metadata.StringMetaDataService; - - import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -54,7 +49,6 @@ public class TraceTest { private final long agentStartTime = System.currentTimeMillis(); private final long traceStartTime = agentStartTime + 100; - private final TransactionIdEncoder encoder = new DefaultTransactionIdEncoder(agentId, agentStartTime); @Mock private AsyncContextFactory asyncContextFactory = mock(AsyncContextFactory.class); @@ -63,20 +57,18 @@ public class TraceTest { @Mock private SqlMetaDataService sqlMetaDataService; - - @Test public void trace() { final TraceId traceId = new DefaultTraceId(agentId, agentStartTime, 1); final TraceRoot traceRoot = new DefaultTraceRoot(traceId, agentId, traceStartTime, 0); - final CallStack callStack = newCallStack(traceRoot); + final CallStack callStack = newCallStack(); final Span span = newSpan(traceRoot); boolean root = span.getTraceRoot().getTraceId().isRoot(); SpanRecorder spanRecorder = new DefaultSpanRecorder(span, root, true, stringMetaDataService, sqlMetaDataService); - WrappedSpanEventRecorder wrappedSpanEventRecorder = new WrappedSpanEventRecorder(asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); + WrappedSpanEventRecorder wrappedSpanEventRecorder = new WrappedSpanEventRecorder(traceRoot, asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); AsyncContextFactory asyncContextFactory = mock(AsyncContextFactory.class); @@ -103,13 +95,13 @@ public void popEventTest() { final TraceId traceId = new DefaultTraceId(agentId, agentStartTime, 1); final TraceRoot traceRoot = new DefaultTraceRoot(traceId, agentId, traceStartTime, 0); - final CallStack callStack = newCallStack(traceRoot); + final CallStack callStack = newCallStack(); final Span span = newSpan(traceRoot); final boolean root = span.getTraceRoot().getTraceId().isRoot(); SpanRecorder spanRecorder = new DefaultSpanRecorder(span, root, true, stringMetaDataService, sqlMetaDataService); - WrappedSpanEventRecorder wrappedSpanEventRecorder = new WrappedSpanEventRecorder(asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); + WrappedSpanEventRecorder wrappedSpanEventRecorder = new WrappedSpanEventRecorder(traceRoot, asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); AsyncContextFactory asyncContextFactory = mock(AsyncContextFactory.class); @@ -133,13 +125,13 @@ private void getDataFromDB(Trace trace) { } - private CallStack newCallStack(TraceRoot traceRoot) { - final CallStackFactory callStackFactory = new CallStackFactoryV1(64); - return callStackFactory.newCallStack(traceRoot); + private CallStack newCallStack() { + final CallStackFactory callStackFactory = new CallStackFactoryV1(64); + return callStackFactory.newCallStack(); } private Span newSpan(TraceRoot traceRoot) { - final SpanFactory spanFactory = new DefaultSpanFactory("appName", agentId, agentStartTime, ServiceType.STAND_ALONE, encoder); + final SpanFactory spanFactory = new DefaultSpanFactory(); return spanFactory.newSpan(traceRoot); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/active/ActiveTraceRepositoryTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/active/ActiveTraceRepositoryTest.java index a2a4947618b4..62294ea4350d 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/active/ActiveTraceRepositoryTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/active/ActiveTraceRepositoryTest.java @@ -30,10 +30,10 @@ import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.bootstrap.context.TraceContext; import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.profiler.context.MockApplicationContext; import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionCounter; import com.navercorp.pinpoint.profiler.context.MockTraceContextFactory; import com.navercorp.pinpoint.profiler.context.id.IdGenerator; +import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -58,7 +58,7 @@ public class ActiveTraceRepositoryTest { private TransactionCounter transactionCounter; private ActiveTraceRepository activeTraceRepository; - private MockApplicationContext applicationContext; + private DefaultApplicationContext applicationContext; @Before public void setUp() { @@ -70,6 +70,7 @@ public void setUp() { Mockito.when(profilerConfig.getSamplingRate()).thenReturn(SAMPLING_RATE); this.applicationContext = MockTraceContextFactory.newMockApplicationContext(profilerConfig); + applicationContext.start(); this.traceContext = applicationContext.getTraceContext(); this.transactionCounter = new DefaultTransactionCounter(applicationContext.getInjector().getInstance(IdGenerator.class)); @@ -140,7 +141,7 @@ private ListenableFuture> executeTransactions(CountDownLa } private ListenableFuture executeNewTrace(ListeningExecutorService executorService, final CountDownLatch awaitLatch, final CountDownLatch executeLatch) { - return executorService.submit(new Callable() { + Callable task = new Callable() { @Override public TraceThreadTuple call() throws Exception { try { @@ -152,7 +153,8 @@ public TraceThreadTuple call() throws Exception { traceContext.removeTraceObject(); } } - }); + }; + return (ListenableFuture) executorService.submit(task); } private ListenableFuture executeSampledContinuedTrace(ListeningExecutorService executorService, final CountDownLatch awaitLatch, final CountDownLatch executeLatch, final long id) { diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessorTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessorTest.java new file mode 100644 index 000000000000..947bd4c5f7b9 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/compress/SpanPostProcessorTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.compress; + +import com.navercorp.pinpoint.bootstrap.context.TraceId; + +import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessorV1; +import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; +import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; +import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author emeroad + */ +public class SpanPostProcessorTest { + + private final String agentId = "agentId"; + private final long agentStartTime = System.currentTimeMillis(); + + @Test + public void create() { + + SpanPostProcessor spanChunkPostProcessor = new SpanPostProcessorV1(); + + TraceRoot internalTraceId = newInternalTraceId(); + TSpanChunk tSpanChunk = new TSpanChunk(); + try { + SpanChunk spanChunk = new SpanChunk(internalTraceId, new ArrayList()); + spanChunkPostProcessor.newContext(spanChunk, tSpanChunk); + Assert.fail(); + } catch (Exception ignored) { + } + List spanEvents = new ArrayList(); + SpanChunk spanChunk = new SpanChunk(internalTraceId, spanEvents); + // one spanEvent + spanEvents.add(new SpanEvent()); + spanChunkPostProcessor.newContext(spanChunk, tSpanChunk); + + // two spanEvent + spanEvents.add(new SpanEvent()); + spanChunkPostProcessor.newContext(spanChunk, tSpanChunk); + + // three + spanEvents.add(new SpanEvent()); + spanChunkPostProcessor.newContext(spanChunk, tSpanChunk); + + } + + private TraceRoot newInternalTraceId() { + TraceId traceId = new DefaultTraceId(agentId, agentStartTime, 100); + return new DefaultTraceRoot(traceId, agentId, agentStartTime, 0); + } +} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/graph/DependencyGraph.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/graph/DependencyGraph.java index 8a371db0b89f..7e10ed894b65 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/graph/DependencyGraph.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/graph/DependencyGraph.java @@ -18,6 +18,7 @@ import com.google.inject.Guice; import com.google.inject.Injector; +import com.google.inject.Module; import com.google.inject.grapher.graphviz.GraphvizGrapher; import com.google.inject.grapher.graphviz.GraphvizModule; import com.navercorp.pinpoint.bootstrap.AgentOption; @@ -25,11 +26,14 @@ import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; import com.navercorp.pinpoint.common.Charsets; -import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; +import com.navercorp.pinpoint.profiler.context.module.InterceptorRegistryModule; +import com.navercorp.pinpoint.profiler.context.module.ModuleFactory; +import com.navercorp.pinpoint.profiler.context.module.OverrideModuleFactory; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.util.TestInterceptorRegistryBinder; +import org.mockito.Mockito; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,9 +42,10 @@ import java.io.PrintWriter; import java.lang.instrument.Instrumentation; import java.net.URL; -import java.security.CodeSource; +import java.util.Collections; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; /** * @author Woonduk Kang(emeroad) @@ -74,19 +79,24 @@ public void dumpDependencyGraph() throws IOException { } private DefaultApplicationContext newApplicationContext() { - ProfilerConfig profilerConfig = new DefaultProfilerConfig(); - InterceptorRegistryBinder binder = new TestInterceptorRegistryBinder(); + ProfilerConfig profilerConfig = spy(new DefaultProfilerConfig()); + Mockito.when(profilerConfig.getStaticResourceCleanup()).thenReturn(true); + Instrumentation instrumentation = mock(Instrumentation.class); AgentOption agentOption = new DefaultAgentOption(instrumentation, - "mockAgent", "mockApplicationName", profilerConfig, new URL[0], - null, new DefaultServiceTypeRegistryService(), new DefaultAnnotationKeyRegistryService()); + "mockAgent", "mockApplicationName", false, profilerConfig, Collections.emptyList(), + null); + + InterceptorRegistryBinder interceptorRegistryBinder = new TestInterceptorRegistryBinder(); + Module testInterceptorRegistryModule = InterceptorRegistryModule.wrap(interceptorRegistryBinder); + ModuleFactory moduleFactory = new OverrideModuleFactory(testInterceptorRegistryModule); - return new DefaultApplicationContext(agentOption, binder); + return new DefaultApplicationContext(agentOption, moduleFactory); } private String currentWorkingDir() { - CodeSource codeSource = this.getClass().getProtectionDomain().getCodeSource(); - URL location = codeSource.getLocation(); + URL location = CodeSourceUtils.getCodeLocation(Logger.class); + String dir = location.getPath(); return dir; } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/javamodule/PackageUtilsTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/javamodule/PackageUtilsTest.java new file mode 100644 index 000000000000..6515913a907d --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/javamodule/PackageUtilsTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.javamodule; + +import com.navercorp.pinpoint.common.util.ClassUtils; +import org.junit.Assert; +import org.junit.Test; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class PackageUtilsTest { + + @Test + public void getPackageName() { + + String internalName = ClassUtils.toInternalName(this.getClass().getName()); + String packageName = PackageUtils.getPackageNameFromInternalName(internalName); + + Assert.assertEquals("com.navercorp.pinpoint.profiler.context.javamodule", packageName); + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContextTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContextTest.java index e7f13987d637..39fb3f12e46f 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContextTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/DefaultApplicationContextTest.java @@ -19,14 +19,13 @@ import com.google.inject.Binding; import com.google.inject.Injector; import com.google.inject.Key; +import com.google.inject.Module; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; import com.navercorp.pinpoint.bootstrap.AgentOption; import com.navercorp.pinpoint.bootstrap.DefaultAgentOption; import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; import com.navercorp.pinpoint.profiler.AgentInfoSender; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.util.TestInterceptorRegistryBinder; @@ -35,10 +34,12 @@ import java.lang.annotation.Annotation; import java.lang.instrument.Instrumentation; -import java.net.URL; +import java.util.Collections; import java.util.Map; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; /** * @author Woonduk Kang(emeroad) @@ -83,13 +84,18 @@ private boolean isPinpointBinding(Key key) { } private DefaultApplicationContext newApplicationContext() { - ProfilerConfig profilerConfig = new DefaultProfilerConfig(); - InterceptorRegistryBinder binder = new TestInterceptorRegistryBinder(); + ProfilerConfig profilerConfig = spy(new DefaultProfilerConfig()); + when(profilerConfig.getStaticResourceCleanup()).thenReturn(true); + Instrumentation instrumentation = mock(Instrumentation.class); - AgentOption agentOption = new DefaultAgentOption(instrumentation, "mockAgent", "mockApplicationName", profilerConfig, new URL[0], - null, new DefaultServiceTypeRegistryService(), new DefaultAnnotationKeyRegistryService()); + AgentOption agentOption = new DefaultAgentOption(instrumentation, "mockAgent", "mockApplicationName", false, + profilerConfig, Collections.emptyList(), null); + + InterceptorRegistryBinder interceptorRegistryBinder = new TestInterceptorRegistryBinder(); + Module interceptorRegistryModule = InterceptorRegistryModule.wrap(interceptorRegistryBinder); + ModuleFactory moduleFactory = new OverrideModuleFactory(interceptorRegistryModule); - return new DefaultApplicationContext(agentOption, binder); + return new DefaultApplicationContext(agentOption, moduleFactory); } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/InterceptorRegistryModule.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/InterceptorRegistryModule.java new file mode 100644 index 000000000000..28d084ff7689 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/InterceptorRegistryModule.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.AbstractModule; +import com.google.inject.Module; +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; + +/** + * @author Woonduk Kang(emeroad) + */ +public class InterceptorRegistryModule extends AbstractModule { + private final InterceptorRegistryBinder interceptorRegistryBinder; + + public static Module wrap(InterceptorRegistryBinder interceptorRegistryBinder) { + return new InterceptorRegistryModule(interceptorRegistryBinder); + } + + private InterceptorRegistryModule(InterceptorRegistryBinder interceptorRegistryBinder) { + this.interceptorRegistryBinder = Assert.requireNonNull(interceptorRegistryBinder, "interceptorRegistryBinder must not be null"); + } + + @Override + protected void configure() { + bind(InterceptorRegistryBinder.class).toInstance(interceptorRegistryBinder); + } +} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactoryResolverTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactoryResolverTest.java new file mode 100644 index 000000000000..d24789c9644c --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/ModuleFactoryResolverTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.Module; +import com.navercorp.pinpoint.bootstrap.AgentOption; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Taejin Koo + */ +public class ModuleFactoryResolverTest { + + @Test + public void test() { + ModuleFactoryResolver provider = new DefaultModuleFactoryResolver(TestModuleFactory.class.getName()); + ModuleFactory moduleFactory = provider.resolve(); + + Assert.assertEquals(TestModuleFactory.class, moduleFactory.getClass()); + } + + @Test + public void test2() { + ModuleFactoryResolver provider = new DefaultModuleFactoryResolver(); + ModuleFactory moduleFactory = provider.resolve(); + + Assert.assertEquals(ApplicationContextModuleFactory.class, moduleFactory.getClass()); + } + + @Test(expected = Exception.class) + public void test3() { + ModuleFactoryResolver provider = new DefaultModuleFactoryResolver("abcde"); + provider.resolve(); + } + + public static class TestModuleFactory implements ModuleFactory { + + @Override + public Module newModule(AgentOption agentOption) { + return null; + } + + } + +} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/OverrideModuleFactory.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/OverrideModuleFactory.java new file mode 100644 index 000000000000..cdb649718235 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/module/OverrideModuleFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.module; + +import com.google.inject.Module; +import com.google.inject.util.Modules; +import com.navercorp.pinpoint.bootstrap.AgentOption; +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author Woonduk Kang(emeroad) + */ +public class OverrideModuleFactory implements ModuleFactory { + private final Module[] with; + + public OverrideModuleFactory(Module... with) { + this.with = Assert.requireNonNull(with, "with must not be null"); + } + + @Override + public Module newModule(AgentOption agentOption) { + ModuleFactory moduleFactory = new ApplicationContextModuleFactory(); + Module module = moduleFactory.newModule(agentOption); + return Modules.override(module).with(with); + } +} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/provider/stat/buffer/BufferMetricProviderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/provider/stat/buffer/BufferMetricProviderTest.java new file mode 100644 index 000000000000..33b452af99db --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/provider/stat/buffer/BufferMetricProviderTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.stat.buffer; + +import com.google.inject.Provider; +import com.navercorp.pinpoint.profiler.monitor.metric.buffer.BufferMetric; +import com.navercorp.pinpoint.profiler.monitor.metric.buffer.BufferMetricSnapshot; +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Woonduk Kang(emeroad) + */ +public class BufferMetricProviderTest { + + @Test + public void get() { + Provider provider = new BufferMetricProvider(); + BufferMetric bufferMetric = provider.get(); + BufferMetricSnapshot snapshot = bufferMetric.getSnapshot(); + Assert.assertEquals(snapshot.getDirectCount(), BufferMetric.UNCOLLECTED_VALUE); + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/provider/stat/filedescriptor/FileDescriptorMetricProviderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/provider/stat/filedescriptor/FileDescriptorMetricProviderTest.java new file mode 100644 index 000000000000..f959f57e6387 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/provider/stat/filedescriptor/FileDescriptorMetricProviderTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.provider.stat.filedescriptor; + +import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; +import com.navercorp.pinpoint.common.util.JvmType; +import com.navercorp.pinpoint.common.util.JvmVersion; +import com.navercorp.pinpoint.common.util.OsType; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; + +import static org.mockito.Mockito.mock; + +/** + * @author Woonduk Kang(emeroad) + */ +public class FileDescriptorMetricProviderTest { + + private final String ORACLE_FILE_DESCRIPTOR_METRIC = "com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.oracle.DefaultFileDescriptorMetric"; + private final String IBM_FILE_DESCRIPTOR_METRIC = "com.navercorp.pinpoint.profiler.monitor.metric.filedescriptor.ibm.DefaultFileDescriptorMetric"; + + + @Test + public void testOracle_LINUX() { + ProfilerConfig config = mock(ProfilerConfig.class); + FileDescriptorMetricProvider fileDescriptorMetricProvider = new FileDescriptorMetricProvider(config); + + String metricClassName = fileDescriptorMetricProvider.getMetricClassName(OsType.LINUX, JvmVersion.JAVA_6, JvmType.ORACLE); + Assert.assertEquals(ORACLE_FILE_DESCRIPTOR_METRIC, metricClassName); + + String metricClassName2 = fileDescriptorMetricProvider.getMetricClassName(OsType.AIX, JvmVersion.JAVA_6, JvmType.ORACLE); + Assert.assertEquals(ORACLE_FILE_DESCRIPTOR_METRIC, metricClassName2); + + String metricClassName3 = fileDescriptorMetricProvider.getMetricClassName(OsType.BSD, JvmVersion.JAVA_6, JvmType.ORACLE); + Assert.assertEquals(ORACLE_FILE_DESCRIPTOR_METRIC, metricClassName3); + + } + + @Test + public void testIBM_SOLARIS() { + ProfilerConfig config = mock(ProfilerConfig.class); + FileDescriptorMetricProvider fileDescriptorMetricProvider = new FileDescriptorMetricProvider(config); + + String metricClassName = fileDescriptorMetricProvider.getMetricClassName(OsType.SOLARIS, JvmVersion.JAVA_9, JvmType.IBM); + Assert.assertEquals(IBM_FILE_DESCRIPTOR_METRIC, metricClassName); + } + + +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultSpanRecorderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultSpanRecorderTest.java index 26b4c862177d..a99bfdc734da 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultSpanRecorderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/recorder/DefaultSpanRecorderTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,11 +24,9 @@ import com.navercorp.pinpoint.profiler.metadata.SqlMetaDataService; import com.navercorp.pinpoint.profiler.metadata.StringMetaDataService; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -50,11 +48,6 @@ public class DefaultSpanRecorderTest { @Mock private SqlMetaDataService sqlMetaDataService; - @Before - public void setUp() throws Exception { - Mockito.when(traceRoot.getTraceId()).thenReturn(traceId); - } - @Test public void testRecordApiId() throws Exception { Span span = new Span(traceRoot); @@ -79,7 +72,6 @@ public void testRecordEndPoint() throws Exception { final String endPoint = "endPoint"; recorder.recordEndPoint(endPoint); - Assert.assertEquals(span.getEndPoint(), endPoint); verify(traceRoot.getShared()).setEndPoint(endPoint); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorderTest.java index f28be27ce77e..805752ee366b 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/recorder/WrappedSpanEventRecorderTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,8 +55,8 @@ public class WrappedSpanEventRecorderTest { public void testSetExceptionInfo_RootMarkError() throws Exception { when(traceRoot.getShared()).thenReturn(shared); - SpanEvent spanEvent = new SpanEvent(traceRoot); - WrappedSpanEventRecorder recorder = new WrappedSpanEventRecorder(asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); + SpanEvent spanEvent = new SpanEvent(); + WrappedSpanEventRecorder recorder = new WrappedSpanEventRecorder(traceRoot, asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); recorder.setWrapped(spanEvent); final String exceptionMessage1 = "exceptionMessage1"; @@ -77,8 +77,8 @@ public void testSetExceptionInfo_RootMarkError() throws Exception { @Test public void testRecordAPIId() throws Exception { - SpanEvent spanEvent = new SpanEvent(traceRoot); - WrappedSpanEventRecorder recorder = new WrappedSpanEventRecorder(asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); + SpanEvent spanEvent = new SpanEvent(); + WrappedSpanEventRecorder recorder = new WrappedSpanEventRecorder(traceRoot, asyncContextFactory, stringMetaDataService, sqlMetaDataService, null); recorder.setWrapped(spanEvent); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorageTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorageTest.java index 09193f6c568d..6ec3b9d9ee8a 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorageTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/storage/BufferedStorageTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,18 +17,11 @@ package com.navercorp.pinpoint.profiler.context.storage; import com.navercorp.pinpoint.bootstrap.context.TraceId; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactoryV1; import com.navercorp.pinpoint.profiler.context.Span; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactory; import com.navercorp.pinpoint.profiler.context.SpanEvent; -import com.navercorp.pinpoint.profiler.context.SpanPostProcessor; -import com.navercorp.pinpoint.profiler.context.SpanPostProcessorV1; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; -import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; import com.navercorp.pinpoint.profiler.sender.CountingDataSender; import org.junit.Assert; @@ -37,14 +30,9 @@ public class BufferedStorageTest { - private final String agentId = "agentId"; private final long agentStartTime = System.currentTimeMillis(); - private final SpanPostProcessor spanPostProcessor = new SpanPostProcessorV1(); - - private final TransactionIdEncoder encoder = new DefaultTransactionIdEncoder(agentId, agentStartTime); - private final SpanChunkFactory spanChunkFactory = new SpanChunkFactoryV1("applicationName", agentId, agentStartTime, ServiceType.STAND_ALONE, encoder); private final CountingDataSender countingDataSender = new CountingDataSender(); private TraceRoot internalTraceId; @@ -61,10 +49,10 @@ private TraceRoot newInternalTraceId() { @Test public void testStore_Noflush() throws Exception { - BufferedStorage bufferedStorage = new BufferedStorage(internalTraceId, countingDataSender, spanPostProcessor, spanChunkFactory, 10); + BufferedStorage bufferedStorage = newBufferedStorage(10); Span span = new Span(internalTraceId); - SpanEvent spanEvent = new SpanEvent(internalTraceId); + SpanEvent spanEvent = new SpanEvent(); bufferedStorage.store(spanEvent); bufferedStorage.store(spanEvent); @@ -73,10 +61,10 @@ public void testStore_Noflush() throws Exception { @Test public void testStore_flush() throws Exception { - BufferedStorage bufferedStorage = new BufferedStorage(internalTraceId, countingDataSender, spanPostProcessor, spanChunkFactory, 1); + BufferedStorage bufferedStorage = newBufferedStorage(1); Span span = new Span(internalTraceId); - SpanEvent spanEvent = new SpanEvent(internalTraceId); + SpanEvent spanEvent = new SpanEvent(); bufferedStorage.store(spanEvent); bufferedStorage.store(spanEvent); @@ -90,7 +78,7 @@ public void testStore_flush() throws Exception { @Test public void testStore_spanFlush() throws Exception { - BufferedStorage bufferedStorage = new BufferedStorage(internalTraceId, countingDataSender, spanPostProcessor, spanChunkFactory, 10); + BufferedStorage bufferedStorage = newBufferedStorage(10); Span span = new Span(internalTraceId); bufferedStorage.store(span); @@ -106,10 +94,10 @@ public void testStore_spanFlush() throws Exception { @Test public void testStore_spanLastFlush() throws Exception { - BufferedStorage bufferedStorage = new BufferedStorage(internalTraceId, countingDataSender, spanPostProcessor, spanChunkFactory, 10); + BufferedStorage bufferedStorage = newBufferedStorage(10); Span span = new Span(internalTraceId); - SpanEvent spanEvent = new SpanEvent(internalTraceId); + SpanEvent spanEvent = new SpanEvent(); bufferedStorage.store(spanEvent); bufferedStorage.store(spanEvent); bufferedStorage.store(span); @@ -123,10 +111,10 @@ public void testStore_spanLastFlush() throws Exception { @Test public void testStore_manual_flush() throws Exception { - BufferedStorage bufferedStorage = new BufferedStorage(internalTraceId, countingDataSender, spanPostProcessor, spanChunkFactory, 10); + BufferedStorage bufferedStorage = newBufferedStorage(10); Span span = new Span(internalTraceId); - SpanEvent spanEvent = new SpanEvent(internalTraceId); + SpanEvent spanEvent = new SpanEvent(); bufferedStorage.store(spanEvent); bufferedStorage.store(spanEvent); bufferedStorage.flush(); @@ -137,4 +125,8 @@ public void testStore_manual_flush() throws Exception { Assert.assertEquals(0, countingDataSender.getSpanCounter()); Assert.assertEquals(1, countingDataSender.getSpanChunkCounter()); } + + private BufferedStorage newBufferedStorage(int bufferSize) { + return new BufferedStorage(internalTraceId, countingDataSender, bufferSize); + } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/thrift/SpanThriftMessageConverterTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/thrift/SpanThriftMessageConverterTest.java new file mode 100644 index 000000000000..d887d3556a07 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/context/thrift/SpanThriftMessageConverterTest.java @@ -0,0 +1,200 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.context.thrift; + +import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.IntStringValue; +import com.navercorp.pinpoint.profiler.context.Annotation; +import com.navercorp.pinpoint.profiler.context.DefaultAsyncId; +import com.navercorp.pinpoint.profiler.context.DefaultLocalAsyncId; +import com.navercorp.pinpoint.profiler.context.Span; +import com.navercorp.pinpoint.profiler.context.SpanChunk; +import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.profiler.context.compress.Context; +import com.navercorp.pinpoint.profiler.context.compress.ContextV1; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessorV1; +import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; +import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; +import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.id.Shared; +import com.navercorp.pinpoint.profiler.context.id.TraceRoot; +import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; +import com.navercorp.pinpoint.thrift.dto.TAnnotation; +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; +import com.navercorp.pinpoint.thrift.dto.TSpanEvent; +import org.apache.commons.lang3.RandomUtils; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class SpanThriftMessageConverterTest { + + private static final String APPLICATION_NAME = "app"; + private static final String AGENT_ID = "agent"; + private static final long AGENT_START_TIME = System.currentTimeMillis(); + + private final TransactionIdEncoder transactionIdEncoder = new DefaultTransactionIdEncoder(AGENT_ID, AGENT_START_TIME); + + private SpanPostProcessor spanPostProcessor = new SpanPostProcessorV1(); + + private final SpanThriftMessageConverter messageConverter = new SpanThriftMessageConverter( + APPLICATION_NAME, + AGENT_ID, + AGENT_START_TIME, + ServiceType.STAND_ALONE.getCode(), + transactionIdEncoder, + spanPostProcessor + ); + + + private Span newSpan() { + final TraceId traceId = new DefaultTraceId(AGENT_ID, AGENT_START_TIME, 1L); + final TraceRoot traceRoot = new DefaultTraceRoot(traceId, AGENT_ID, AGENT_START_TIME, 100L); + return new Span(traceRoot); + } + + + @Test + public void buildTSpan() { + final Span span = newSpan(); + + span.setStartTime(System.currentTimeMillis()); + span.setElapsedTime(RandomUtils.nextInt(0, 100)); + span.setAcceptorHost("acceptorHost"); + span.setExceptionInfo(new IntStringValue(RandomUtils.nextInt(0, 100), "error")); + span.setApiId(RandomUtils.nextInt(0, 100)); + span.setServiceType((short) RandomUtils.nextInt(0, 100)); + span.setRemoteAddr("remoteAddr"); + span.setParentApplicationName("pApp"); + span.setParentApplicationType((short) RandomUtils.nextInt(0, 100)); + + final TraceRoot traceRoot = span.getTraceRoot(); + Shared shared = traceRoot.getShared(); + shared.setEndPoint("endPoint"); + shared.setRpcName("rpcName"); + shared.setLoggingInfo((byte) RandomUtils.nextInt(0, 10)); + shared.maskErrorCode(RandomUtils.nextInt(0, 100)); + shared.setStatusCode(RandomUtils.nextInt(0, 100)); + + span.addAnnotation(new Annotation(1)); + span.setSpanEventList(Collections.singletonList(new SpanEvent())); + + final TSpan tSpan = messageConverter.buildTSpan(span); + + + Assert.assertEquals(span.getStartTime(), tSpan.getStartTime()); + Assert.assertEquals(span.getElapsedTime(), tSpan.getElapsed()); + Assert.assertEquals(span.getAcceptorHost(), tSpan.getAcceptorHost()); + Assert.assertEquals(span.getExceptionInfo().getIntValue(), tSpan.getExceptionInfo().getIntValue()); + Assert.assertEquals(span.getExceptionInfo().getStringValue(), tSpan.getExceptionInfo().getStringValue()); + Assert.assertEquals(span.getApiId(), tSpan.getApiId()); + Assert.assertEquals(span.getServiceType(), tSpan.getServiceType()); + Assert.assertEquals(span.getRemoteAddr(), tSpan.getRemoteAddr()); + Assert.assertEquals(span.getParentApplicationName(), tSpan.getParentApplicationName()); + Assert.assertEquals(span.getParentApplicationType(), tSpan.getParentApplicationType()); + + Assert.assertEquals(traceRoot.getTraceId().getSpanId(), tSpan.getSpanId()); + Assert.assertEquals(traceRoot.getShared().getEndPoint(), tSpan.getEndPoint()); + Assert.assertEquals(traceRoot.getShared().getRpcName(), tSpan.getRpc()); + Assert.assertEquals(traceRoot.getShared().getLoggingInfo(), tSpan.getLoggingTransactionInfo()); + Assert.assertEquals(traceRoot.getShared().getErrorCode(), tSpan.getErr()); +// TODO +// Assert.assertEquals(traceRoot.getShared().getStatusCode(), ); + + Assert.assertEquals(span.getAnnotations().size(), tSpan.getAnnotations().size()); + Assert.assertEquals(span.getSpanEventList().size(), tSpan.getSpanEventList().size()); + } + + private SpanChunk newSpanChunk() { + final TraceId traceId = new DefaultTraceId(AGENT_ID, AGENT_START_TIME, 1L); + final TraceRoot traceRoot = new DefaultTraceRoot(traceId, AGENT_ID, AGENT_START_TIME, 100L); + return new SpanChunk(traceRoot, Collections.emptyList()); + } + + + @Test + public void buildTSpanChunk() { + final SpanChunk spanChunk = newSpanChunk(); + TraceRoot traceRoot = spanChunk.getTraceRoot(); + + TSpanChunk tSpanChunk = messageConverter.buildTSpanChunk(spanChunk); + + Assert.assertEquals(traceRoot.getTraceId().getSpanId(), tSpanChunk.getSpanId()); + Assert.assertEquals(traceRoot.getShared().getEndPoint(), tSpanChunk.getEndPoint()); + } + + + @Test + public void buildTSpanEvent() { + final long startTime = System.currentTimeMillis() - 100; + + SpanEvent spanEvent = new SpanEvent(); + spanEvent.setDepth(RandomUtils.nextInt(0, 100)); + spanEvent.setStartTime(startTime + RandomUtils.nextInt(0, 100)); + spanEvent.setAfterTime(spanEvent.getStartTime() + RandomUtils.nextInt(5, 100)); + spanEvent.setDestinationId("destinationId"); + spanEvent.setSequence((short) RandomUtils.nextInt(0, 100)); + spanEvent.setNextSpanId(RandomUtils.nextInt(0, 100)); + + spanEvent.setAsyncIdObject(new DefaultAsyncId(RandomUtils.nextInt(0, 100))); + + spanEvent.setLocalAsyncId(new DefaultLocalAsyncId(RandomUtils.nextInt(0, 100), (short) RandomUtils.nextInt(0, 100))); + + spanEvent.addAnnotation(new Annotation(1)); + + Context context = new ContextV1(startTime); + TSpanEvent tSpanEvent = messageConverter.buildTSpanEvent(spanEvent, context); + spanPostProcessor.postProcess(context, spanEvent, tSpanEvent); + context.next(); + + Assert.assertEquals(spanEvent.getDepth(), tSpanEvent.getDepth()); + Assert.assertEquals(spanEvent.getStartTime(), startTime + tSpanEvent.getStartElapsed()); + Assert.assertEquals(spanEvent.getAfterTime(), startTime + tSpanEvent.getStartElapsed() + tSpanEvent.getEndElapsed()); + Assert.assertEquals(spanEvent.getDestinationId(), tSpanEvent.getDestinationId()); + Assert.assertEquals(spanEvent.getSequence(), tSpanEvent.getSequence()); + Assert.assertEquals(spanEvent.getNextSpanId(), tSpanEvent.getNextSpanId()); + + Assert.assertEquals(spanEvent.getAsyncIdObject().getAsyncId(), tSpanEvent.getNextAsyncId()); + + Assert.assertEquals(spanEvent.getLocalAsyncId().getAsyncId(), tSpanEvent.getAsyncId()); + Assert.assertEquals(spanEvent.getLocalAsyncId().getSequence(), tSpanEvent.getAsyncSequence()); + + Assert.assertEquals(spanEvent.getAnnotations().size(), tSpanEvent.getAnnotations().size()); + } + + + @Test + public void buildTAnnotation() { + Annotation annotation = new Annotation(RandomUtils.nextInt(0, 100), "value"); + List annotations = Collections.singletonList(annotation); + List tAnnotations = messageConverter.buildTAnnotation(annotations); + + TAnnotation tAnnotation = tAnnotations.get(0); + Assert.assertEquals(annotation.getAnnotationKey(), tAnnotation.getKey()); + Assert.assertEquals(annotation.getValue(), tAnnotation.getValue().getStringValue()); + } + + +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMAspectWeaverTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMAspectWeaverTest.java index e1020a5ab9a6..00f7025a5610 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMAspectWeaverTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMAspectWeaverTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.instrument; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; +import com.navercorp.pinpoint.common.util.IOUtils; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import org.junit.Before; import org.junit.Test; @@ -28,7 +29,7 @@ import java.io.InputStream; import java.lang.reflect.Method; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -130,7 +131,10 @@ private Object getInstnace(final String originalName, final String aspectName) t public Class loadClass(String name) throws ClassNotFoundException { if (name.equals(originalName)) { try { - final ClassReader cr = new ClassReader(getClass().getResourceAsStream("/" + JavaAssistUtils.javaNameToJvmName(name) + ".class")); + final String jvmClassName = "/" + JavaAssistUtils.javaClassNameToJvmResourceName(name); + final InputStream stream = getClass().getResourceAsStream(jvmClassName); + byte[] classBytes = IOUtils.toByteArray(stream); + final ClassReader cr = new ClassReader(classBytes); final ClassNode classNode = new ClassNode(); cr.accept(classNode, 0); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeAdapterTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeAdapterTest.java index 3327195fd8e5..8f5527ab620f 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeAdapterTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeAdapterTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -23,6 +23,7 @@ import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; @@ -34,7 +35,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -196,7 +197,7 @@ public void addField() throws Exception { @Override public void handle(ClassNode classNode) { ASMClassNodeAdapter classNodeAdapter = new ASMClassNodeAdapter(pluginContext, null, classNode); - classNodeAdapter.addField("_$PINPOINT$_" + JavaAssistUtils.javaClassNameToVariableName(accessorClassName), int.class); + classNodeAdapter.addField("_$PINPOINT$_" + JavaAssistUtils.javaClassNameToVariableName(accessorClassName), Type.getDescriptor(int.class)); classNodeAdapter.addInterface(accessorClassName); ASMFieldNodeAdapter fieldNode = classNodeAdapter.getField("_$PINPOINT$_" + JavaAssistUtils.javaClassNameToVariableName(accessorClassName), null); classNodeAdapter.addGetterMethod("_$PINPOINT$_getTraceInt", fieldNode); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeLoader.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeLoader.java index 27eee63de1af..5f76708ec9f9 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeLoader.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassNodeLoader.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.instrument; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; +import com.navercorp.pinpoint.common.util.IOUtils; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -28,11 +29,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.List; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -73,9 +75,11 @@ public InputStream answer(InvocationOnMock invocation) throws Throwable { } // only use for test. - public static ClassNode get(final String className) throws Exception { + public static ClassNode get(final String className) throws IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - ClassReader cr = new ClassReader(classLoader.getResourceAsStream(JavaAssistUtils.javaNameToJvmName(className) + ".class")); + InputStream inputStream = classLoader.getResourceAsStream(JavaAssistUtils.javaClassNameToJvmResourceName(className)); + byte[] bytes = IOUtils.toByteArray(inputStream); + ClassReader cr = new ClassReader(bytes); ClassNode classNode = new ClassNode(); cr.accept(classNode, ClassReader.EXPAND_FRAMES); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassTest.java index 0679b35767a7..dba3f5237621 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -24,6 +24,8 @@ import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; import com.navercorp.pinpoint.bootstrap.instrument.MethodFilters; import com.navercorp.pinpoint.profiler.context.monitor.DataSourceMonitorRegistryService; +import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinitionFactory; +import com.navercorp.pinpoint.profiler.interceptor.factory.ExceptionHandlerFactory; import com.navercorp.pinpoint.profiler.interceptor.registry.DefaultInterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; @@ -44,7 +46,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -52,14 +54,22 @@ * @author jaehong.kim */ public class ASMClassTest { - private final static InterceptorRegistryBinder interceptorRegistryBinder = new DefaultInterceptorRegistryBinder(); + private final InterceptorRegistryBinder interceptorRegistryBinder = new DefaultInterceptorRegistryBinder(); private final ProfilerConfig profilerConfig = mock(ProfilerConfig.class); private final Provider traceContextProvider = Providers.of(mock(TraceContext.class)); private final DataSourceMonitorRegistryService dataSourceMonitorRegistryService = mock(DataSourceMonitorRegistryService.class); private final Provider apiMetaDataService = Providers.of(mock(ApiMetaDataService.class)); + private final InstrumentContext pluginContext = mock(InstrumentContext.class); - private final ObjectBinderFactory objectBinderFactory = new ObjectBinderFactory(profilerConfig, traceContextProvider, dataSourceMonitorRegistryService, apiMetaDataService); + + private final ExceptionHandlerFactory exceptionHandlerFactory = new ExceptionHandlerFactory(false); + private final ObjectBinderFactory objectBinderFactory = new ObjectBinderFactory(profilerConfig, traceContextProvider, dataSourceMonitorRegistryService, apiMetaDataService, exceptionHandlerFactory); + private final ScopeFactory scopeFactory = new ScopeFactory(); + private final InterceptorDefinitionFactory interceptorDefinitionFactory = new InterceptorDefinitionFactory(); + + private final EngineComponent engineComponent = new DefaultEngineComponent(objectBinderFactory, interceptorRegistryBinder, interceptorDefinitionFactory, apiMetaDataService, scopeFactory); + @Before public void setUp() { @@ -589,9 +599,25 @@ public void getNestedClasses() throws Exception { assertEquals(1, clazz.getNestedClasses(ClassFilters.chain(ClassFilters.enclosingMethod("annonymousInnerClass"), ClassFilters.interfaze("java.util.concurrent.Callable"))).size()); } + @Test + public void isInterceptorable() throws Exception { + ASMClass clazz = getClass("com.navercorp.pinpoint.profiler.instrument.mock.BaseInterface"); + assertFalse(clazz.isInterceptable()); + + clazz = getClass("com.navercorp.pinpoint.profiler.instrument.mock.BaseClass"); + assertTrue(clazz.isInterceptable()); + + clazz = getClass("com.navercorp.pinpoint.profiler.instrument.mock.BaseEnum"); + assertTrue(clazz.isInterceptable()); + + clazz = getClass("com.navercorp.pinpoint.profiler.instrument.mock.BaseEnum"); + assertTrue(clazz.isInterceptable()); + } + + private ASMClass getClass(final String targetClassName) throws Exception { ClassNode classNode = ASMClassNodeLoader.get(targetClassName); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - return new ASMClass(objectBinderFactory, pluginContext, interceptorRegistryBinder, apiMetaDataService.get(), classLoader, classNode); + return new ASMClass(engineComponent, pluginContext, classLoader, classNode); } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassWriterTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassWriterTest.java index 486704a3cb6b..888afe8e730b 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassWriterTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMClassWriterTest.java @@ -75,7 +75,7 @@ public void accept() throws Exception { ClassNode classNode = ASMClassNodeLoader.get(JavaAssistUtils.javaNameToJvmName(className)); ASMClassWriter cw = new ASMClassWriter(pluginContext, 0, null); - TraceClassVisitor tcv = new TraceClassVisitor(cw, new PrintWriter(System.out)); + TraceClassVisitor tcv = new TraceClassVisitor(cw, null); classNode.accept(tcv); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterAddDelegatorTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterAddDelegatorTest.java index 22d443692de9..11d71260bcc3 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterAddDelegatorTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterAddDelegatorTest.java @@ -111,7 +111,7 @@ private Class addDelegatorMethod(final String targetClassName, final String s public void handle(final ClassNode classNode) { String[] exceptions = null; if (methodNode.exceptions != null) { - exceptions = methodNode.exceptions.toArray(new String[methodNode.exceptions.size()]); + exceptions = methodNode.exceptions.toArray(new String[0]); } final MethodNode newMethodNode = new MethodNode(methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, exceptions); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterAddInterceptorTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterAddInterceptorTest.java index 231cc227516e..97acae39428f 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterAddInterceptorTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterAddInterceptorTest.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.instrument; import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandleAroundInterceptor; +import com.navercorp.pinpoint.bootstrap.interceptor.ExceptionHandler; import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinition; import com.navercorp.pinpoint.profiler.instrument.interceptor.InterceptorDefinitionFactory; import com.navercorp.pinpoint.profiler.instrument.mock.ApiIdAwareInterceptor; @@ -24,6 +25,7 @@ import com.navercorp.pinpoint.profiler.instrument.mock.BasicInterceptor; import com.navercorp.pinpoint.profiler.instrument.mock.ExceptionInterceptor; import com.navercorp.pinpoint.profiler.instrument.mock.StaticInterceptor; +import com.navercorp.pinpoint.profiler.interceptor.factory.ExceptionHandlerFactory; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.util.TestInterceptorRegistryBinder; import org.junit.AfterClass; @@ -51,6 +53,8 @@ public class ASMMethodNodeAdapterAddInterceptorTest { private final static InterceptorRegistryBinder interceptorRegistryBinder = new TestInterceptorRegistryBinder(); private ASMClassNodeLoader.TestClassLoader classLoader; + private ExceptionHandlerFactory exceptionHandlerFactory = new ExceptionHandlerFactory(false); + @BeforeClass public static void beforeClass() { interceptorRegistryBinder.bind(); @@ -93,7 +97,8 @@ public void addBasicInterceptor() throws Exception { @Ignore @Test public void addExceptionInterceptor() throws Exception { - ExceptionHandleAroundInterceptor interceptor = new ExceptionHandleAroundInterceptor(new ExceptionInterceptor()); + ExceptionHandler exceptionHandler = exceptionHandlerFactory.getExceptionHandler(); + ExceptionHandleAroundInterceptor interceptor = new ExceptionHandleAroundInterceptor(new ExceptionInterceptor(), exceptionHandler); int interceptorId = interceptorRegistryBinder.getInterceptorRegistryAdaptor().addInterceptor(interceptor); addInterceptor(interceptorId, ExceptionHandleAroundInterceptor.class); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterTestMain.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterTestMain.java index 156adf905e3c..4efad3407c80 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterTestMain.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeAdapterTestMain.java @@ -19,8 +19,6 @@ import com.navercorp.pinpoint.profiler.instrument.mock.ArgsArrayInterceptor; import com.navercorp.pinpoint.profiler.interceptor.registry.DefaultInterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; -import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; @@ -98,9 +96,8 @@ public Class loadClass(String name) throws ClassNotFoundException { if (!name.startsWith("java") && !name.startsWith("sun") && super.findLoadedClass(name) == null) { try { ClassNode classNode = ASMClassNodeLoader.get(JavaAssistUtils.javaNameToJvmName(name)); - ObjectBinderFactory objectBinderFactory = mock(ObjectBinderFactory.class); - ApiMetaDataService apiMetaDataService = mock(ApiMetaDataService.class); - ASMClass asmClass = new ASMClass(objectBinderFactory, null, interceptorRegistryBinder, apiMetaDataService, null, classNode); + EngineComponent engineComponent = mock(DefaultEngineComponent.class); + ASMClass asmClass = new ASMClass(engineComponent, null, null, classNode); if (asmClass.isInterceptable()) { for (InstrumentMethod method : asmClass.getDeclaredMethods()) { try { diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeTest.java index 2e3e486a4d44..3cfa9ed99b8a 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodNodeTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,8 +20,6 @@ import com.navercorp.pinpoint.profiler.instrument.mock.ArgsArrayInterceptor; import com.navercorp.pinpoint.profiler.interceptor.registry.DefaultInterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; -import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; import org.junit.Before; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; @@ -34,7 +32,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -46,7 +44,6 @@ public class ASMMethodNodeTest { private final static InterceptorRegistryBinder interceptorRegistryBinder = new DefaultInterceptorRegistryBinder(); private final InstrumentContext pluginContext = mock(InstrumentContext.class); - private final ApiMetaDataService apiMetaDataService = mock(ApiMetaDataService.class); @Before public void setUp() { @@ -70,11 +67,11 @@ public void getter() throws Exception { ASMClass declaringClass = mock(ASMClass.class); when(declaringClass.getName()).thenReturn(targetClassName); - final ObjectBinderFactory objectBinderFactory = mock(ObjectBinderFactory.class); + EngineComponent engineComponent = mock(DefaultEngineComponent.class); final MethodNode methodNode = ASMClassNodeLoader.get(targetClassName, methodName); - ASMMethod method = new ASMMethod(objectBinderFactory, pluginContext, apiMetaDataService, interceptorRegistryBinder, declaringClass, methodNode); + ASMMethod method = new ASMMethod(engineComponent, pluginContext, declaringClass, methodNode); assertEquals(methodName, method.getName()); assertEquals(1, method.getParameterTypes().length); assertEquals("int", method.getParameterTypes()[0]); @@ -91,7 +88,7 @@ public void addInterceptor() throws Exception { final String targetClassName = "com.navercorp.pinpoint.profiler.instrument.mock.NormalClass"; final ASMClass declaringClass = mock(ASMClass.class); when(declaringClass.getName()).thenReturn(targetClassName); - final ObjectBinderFactory objectBinderFactory = mock(ObjectBinderFactory.class); + final EngineComponent engineComponent = mock(DefaultEngineComponent.class); ASMClassNodeLoader.TestClassLoader classLoader = ASMClassNodeLoader.getClassLoader(); @@ -104,7 +101,7 @@ public void addInterceptor() throws Exception { public void handle(ClassNode classNode) { List methodNodes = classNode.methods; for(MethodNode methodNode : methodNodes) { - ASMMethod method = new ASMMethod(objectBinderFactory, pluginContext, apiMetaDataService, interceptorRegistryBinder, declaringClass, methodNode); + ASMMethod method = new ASMMethod(engineComponent, pluginContext, declaringClass, methodNode); try { method.addInterceptor(interceptorId); } catch (InstrumentException e) { diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodVariablesTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodVariablesTest.java index b246afb287b3..6f6ff3ac4875 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodVariablesTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/ASMMethodVariablesTest.java @@ -133,7 +133,7 @@ public void initLocalVariables() throws Exception { final MethodNode methodNode = ASMClassNodeLoader.get(className, "argByteType"); String[] exceptions = null; if (methodNode.exceptions != null) { - exceptions = methodNode.exceptions.toArray(new String[methodNode.exceptions.size()]); + exceptions = methodNode.exceptions.toArray(new String[0]); } final ASMMethodNodeAdapter methodNodeAdapter = new ASMMethodNodeAdapter("foo", new MethodNode(methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, exceptions)); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JavassistEngineTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JavassistEngineTest.java deleted file mode 100644 index 87f75f13b0ca..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JavassistEngineTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument; - -import com.google.inject.Provider; -import com.google.inject.util.Providers; -import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; -import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; - -import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; -import com.navercorp.pinpoint.profiler.objectfactory.ObjectBinderFactory; -import com.navercorp.pinpoint.profiler.util.BytecodeUtils; -import com.navercorp.pinpoint.profiler.util.TestInterceptorRegistryBinder; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.bytecode.ConstPool; -import javassist.bytecode.MethodInfo; -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.instrument.Instrumentation; - -import static org.mockito.Mockito.mock; - -/** - * @author Woonduk Kang(emeroad) - */ -public class JavassistEngineTest { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final String mock = "com.navercorp.pinpoint.profiler.instrument.JavassistEngineTestMock"; - - @Test - public void testGetClass_original() throws Exception { - InstrumentEngine instrumentEngine = newJavassistEngine(); - - InstrumentContext instrumentContext = mock(InstrumentContext.class); - - final byte[] originalByteCode = BytecodeUtils.getClassFile(null, mock); - final InstrumentClass transformClass = instrumentEngine.getClass(instrumentContext, null, mock, originalByteCode); - - Assert.assertNotNull(transformClass.getDeclaredMethod("test")); - Assert.assertNull("transform method", transformClass.getDeclaredMethod("transformMethod")); - - } - - @Test - public void testGetClass_transform() throws Exception { - InstrumentEngine instrumentEngine = newJavassistEngine(); - - InstrumentContext instrumentContext = mock(InstrumentContext.class); - - final byte[] transformByteCode = getTransformByteCode(); - final InstrumentClass transformClass = instrumentEngine.getClass(instrumentContext, null, mock, transformByteCode); - - Assert.assertNotNull(transformClass.getDeclaredMethod("test")); - Assert.assertNotNull("transform method", transformClass.getDeclaredMethod("transformMethod")); - } - - private InstrumentEngine newJavassistEngine() { - Instrumentation instrumentation = mock(Instrumentation.class); - ObjectBinderFactory objectBinderFactory = mock(ObjectBinderFactory.class); - Provider apiMetaDataService = Providers.of(mock(ApiMetaDataService.class)); - - InterceptorRegistryBinder binder = new TestInterceptorRegistryBinder(); - return new JavassistEngine(instrumentation, objectBinderFactory, binder, apiMetaDataService, null); - } - - public byte[] getTransformByteCode() { - try { - final ClassPool pool = new ClassPool(true); - - final CtClass ctClass = pool.get(mock); - - final ConstPool constPool = ctClass.getClassFile2().getConstPool(); - - MethodInfo info = new MethodInfo(constPool, "transformMethod", "()V"); - final CtMethod newMethod = CtMethod.make(info, ctClass); - ctClass.addMethod(newMethod); - return ctClass.toBytecode(); - } catch (Exception ex) { - throw new RuntimeException(ex.getMessage(), ex); - } - } - -} - diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JavassistEngineTestMock.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JavassistEngineTestMock.java deleted file mode 100644 index 79ce9b0d7e75..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/JavassistEngineTestMock.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.instrument; - -/** - * @author Woonduk Kang(emeroad) - */ -public class JavassistEngineTestMock { - public void test() { - } -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjectorTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjectorTest.java index 9c95541be9a4..0b94ed6a6764 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjectorTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/JarProfilerPluginClassInjectorTest.java @@ -16,24 +16,24 @@ package com.navercorp.pinpoint.profiler.instrument.classloading; -import com.navercorp.pinpoint.bootstrap.classloader.LibClass; import com.navercorp.pinpoint.bootstrap.classloader.PinpointClassLoaderFactory; -import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; +import com.navercorp.pinpoint.common.plugin.JarPlugin; +import com.navercorp.pinpoint.common.plugin.Plugin; import com.navercorp.pinpoint.common.util.ClassLoaderUtils; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; import com.navercorp.pinpoint.profiler.plugin.PluginConfig; import com.navercorp.pinpoint.profiler.plugin.PluginPackageFilter; import org.junit.Assert; import org.junit.Test; -import org.mockito.Mockito; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.ReflectionUtils; +import java.io.IOException; import java.lang.reflect.Constructor; import java.net.URL; -import java.net.URLClassLoader; -import java.security.CodeSource; -import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.jar.JarFile; /** * @author Woonduk Kang(emeroad) @@ -48,17 +48,16 @@ public class JarProfilerPluginClassInjectorTest { @Test public void testInjectClass() throws Exception { - final URL sampleJar = getSampleJar("org.slf4j.impl.Log4jLoggerAdapter"); + final Plugin plugin = getMockPlugin("org.slf4j.impl.Log4jLoggerAdapter"); - final ClassLoader contextTypeMatchClassLoader = createContextTypeMatchClassLoader(new URL[]{sampleJar}); + final ClassLoader contextTypeMatchClassLoader = createContextTypeMatchClassLoader(new URL[]{plugin.getURL()}); - final ProfilerPlugin profilerPlugin = Mockito.mock(ProfilerPlugin.class); - - final PluginPackageFilter pluginPackageFilter = new PluginPackageFilter(Arrays.asList(LOG4_IMPL)); - PluginConfig pluginConfig = new PluginConfig(sampleJar, pluginPackageFilter); + final PluginPackageFilter pluginPackageFilter = new PluginPackageFilter(Collections.singletonList(LOG4_IMPL)); + PluginConfig pluginConfig = new PluginConfig(plugin, pluginPackageFilter); logger.debug("pluginConfig:{}", pluginConfig); + BootstrapCore bootstrapCore = new BootstrapCore(Collections.emptyList()); - PlainClassLoaderHandler injector = new PlainClassLoaderHandler(pluginConfig); + PlainClassLoaderHandler injector = new PlainClassLoaderHandler(pluginConfig, bootstrapCore); final Class loggerClass = injector.injectClass(contextTypeMatchClassLoader, logger.getClass().getName()); logger.debug("ClassLoader{}", loggerClass.getClassLoader()); @@ -71,20 +70,11 @@ private ClassLoader createContextTypeMatchClassLoader(URL[] urlArray) throws Cla final ClassLoader classLoader = this.getClass().getClassLoader(); final Class aClass = (Class) classLoader.loadClass(CONTEXT_TYPE_MATCH_CLASS_LOADER); final Constructor constructor = aClass.getConstructor(ClassLoader.class); - ReflectionUtils.makeAccessible(constructor); - - final LibClass libClassFilter = new LibClass() { - @Override - public boolean onLoadClass(String clazzName) { - if (clazzName.startsWith(LOG4_IMPL)) { - logger.debug("Loading {}", clazzName); - return ON_LOAD_CLASS; - } - return DELEGATE_PARENT; - } - }; - - URLClassLoader testClassLoader = PinpointClassLoaderFactory.createClassLoader(urlArray, ClassLoader.getSystemClassLoader(), libClassFilter); + constructor.setAccessible(true); + + List lib = Collections.singletonList(LOG4_IMPL); + + ClassLoader testClassLoader = PinpointClassLoaderFactory.createClassLoader(this.getClass().getName(), urlArray, ClassLoader.getSystemClassLoader(), lib); final ClassLoader contextTypeMatchClassLoader = constructor.newInstance(testClassLoader); logger.debug("cl:{}",contextTypeMatchClassLoader); @@ -97,7 +87,7 @@ public boolean onLoadClass(String clazzName) { } - private URL getSampleJar(String className) { + private Plugin getMockPlugin(String className) throws IOException { ClassLoader cl = ClassLoaderUtils.getDefaultClassLoader(); Class clazz = null; try { @@ -105,16 +95,16 @@ private URL getSampleJar(String className) { } catch (ClassNotFoundException ex) { throw new RuntimeException(className + " class not found. Caused by:" + ex.getMessage(), ex); } - return getSampleJar(clazz); + return getMockPlugin(clazz); } - private URL getSampleJar(Class clazz) { - final CodeSource codeSource = clazz.getProtectionDomain().getCodeSource(); - final URL location = codeSource.getLocation(); + private Plugin getMockPlugin(Class clazz) throws IOException { - logger.debug("url:{}", location); + final URL location = CodeSourceUtils.getCodeLocation(clazz); - return location; + logger.debug("url:{}", location); + JarFile jarFile = new JarFile(location.getPath()); + return new JarPlugin(location, jarFile, Collections.emptyList(), Collections.emptyList()); } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandlerTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandlerTest.java new file mode 100644 index 000000000000..6dc1ae6b3d05 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandlerTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.classloading; + +import com.navercorp.pinpoint.common.plugin.JarPlugin; +import com.navercorp.pinpoint.profiler.plugin.ClassNameFilter; +import com.navercorp.pinpoint.profiler.plugin.PluginConfig; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; +import java.util.jar.JarFile; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author Woonduk Kang(emeroad) + */ +public class PlainClassLoaderHandlerTest { + + @Test + public void injectClass_bootstrapClass() { + PluginConfig pluginConfig = newPluginConfig(); + BootstrapCore bootstrapCore = new BootstrapCore(Collections.emptyList()); + + PlainClassLoaderHandler plainClassLoaderHandler = new PlainClassLoaderHandler(pluginConfig, bootstrapCore); + try { + plainClassLoaderHandler.injectClass(this.getClass().getClassLoader(), "com.navercorp.pinpoint.bootstrap.Test"); + Assert.fail(); + } catch (NullPointerException e) { + Assert.fail(); + } catch (Exception e) { + + } + } + +// @Test +// public void injectClass() { +// PluginConfig pluginConfig = newPluginConfig(); +// +// PlainClassLoaderHandler plainClassLoaderHandler = new PlainClassLoaderHandler(pluginConfig); +// plainClassLoaderHandler.injectClass(this.getClass().getClassLoader(), "java.lang.String"); +// +// } + + private PluginConfig newPluginConfig() { + JarPlugin plugin = mock(JarPlugin.class); + JarFile jarFile = mock(JarFile.class); + when(plugin.getJarFile()).thenReturn(jarFile); + + ClassNameFilter filter = new ClassNameFilter() { + @Override + public boolean accept(String className) { + return ClassNameFilter.ACCEPT; + } + }; + PluginConfig pluginConfig = new PluginConfig(plugin, filter); + return pluginConfig; + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadataTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadataTest.java index 3eb7a0e9d91c..f9986c6d8d7c 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadataTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadataTest.java @@ -29,7 +29,7 @@ public class DefaultInternalClassMetadataTest { @Test public void base() throws Exception { - DefaultInternalClassMetadata classMetadata = new DefaultInternalClassMetadata("java/lang/String", "java/lang/Object", Arrays.asList("java/lang/Comparable", "java/lang/Serializable"), Collections.EMPTY_LIST, false, false, false, false); + DefaultInternalClassMetadata classMetadata = new DefaultInternalClassMetadata("java/lang/String", "java/lang/Object", Arrays.asList("java/lang/Comparable", "java/lang/Serializable"), Collections.emptyList(), false, false, false, false); // name assertEquals("java/lang/String", classMetadata.getClassInternalName()); // super @@ -43,7 +43,7 @@ public void base() throws Exception { @Test public void interfaceNamesNull() throws Exception { - DefaultInternalClassMetadata classMetadata = new DefaultInternalClassMetadata("java/lang/String", "java/lang/Object", null, Collections.EMPTY_LIST, false, false, false, false); + DefaultInternalClassMetadata classMetadata = new DefaultInternalClassMetadata("java/lang/String", "java/lang/Object", null, Collections.emptyList(), false, false, false, false); assertEquals(0, classMetadata.getInterfaceInternalNames().size()); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReaderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReaderTest.java index 16bcee3792f6..8aa22f1a963f 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReaderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReaderTest.java @@ -18,6 +18,7 @@ import com.navercorp.pinpoint.common.util.ClassLoaderUtils; import com.navercorp.pinpoint.profiler.util.BytecodeUtils; import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.junit.Assert; import org.junit.Test; import java.lang.annotation.Annotation; @@ -39,9 +40,9 @@ public void getInternalClassMetadata() throws Exception { assertEquals(JavaAssistUtils.javaNameToJvmName(clazz.getName()), classMetadata.getClassInternalName()); // interfaces - for(Class interfacez : clazz.getInterfaces()) { + for (Class interfacez : clazz.getInterfaces()) { final String interfaceInternalName = JavaAssistUtils.javaNameToJvmName(interfacez.getName()); - classMetadata.getInterfaceInternalNames().contains(interfaceInternalName); + Assert.assertTrue(classMetadata.getInterfaceInternalNames().contains(interfaceInternalName)); } // super @@ -50,7 +51,7 @@ public void getInternalClassMetadata() throws Exception { // annotations for (Annotation annotation : clazz.getAnnotations()) { final String annotationInternalName = JavaAssistUtils.javaNameToJvmName(annotation.annotationType().getName()); - classMetadata.getAnnotationInternalNames().contains(annotationInternalName); + Assert.assertTrue(classMetadata.getAnnotationInternalNames().contains(annotationInternalName)); } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/scanner/ClassScannerFactoryTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/scanner/ClassScannerFactoryTest.java new file mode 100644 index 000000000000..05dbefa1c1c3 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/scanner/ClassScannerFactoryTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.instrument.scanner; + +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClassScannerFactoryTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void newScanner() { + + } + + @Test + public void hasClass_directory() { + + Class testClass = ClassScannerFactoryTest.class; + Scanner scanner = ClassScannerFactory.newScanner(testClass.getProtectionDomain(), this.getClass().getClassLoader()); + String fileName = JavaAssistUtils.javaClassNameToJvmResourceName(testClass.getName()); + boolean exist = scanner.exist(fileName); + scanner.close(); + Assert.assertTrue(exist); + } + + @Test + public void hasClass_Jar() { + Class testClass = Logger.class; + + Scanner scanner = ClassScannerFactory.newScanner(testClass.getProtectionDomain(), this.getClass().getClassLoader()); + String fileName = JavaAssistUtils.javaClassNameToJvmResourceName(testClass.getName()); + boolean exist = scanner.exist(fileName); + scanner.close(); + Assert.assertTrue(exist); + } + + @Test + public void hasClass_classLoader() { + Class testClass = String.class; + + Scanner scanner = ClassScannerFactory.newScanner(testClass.getProtectionDomain(), this.getClass().getClassLoader()); + String fileName = JavaAssistUtils.javaClassNameToJvmResourceName(testClass.getName()); + boolean exist = scanner.exist(fileName); + scanner.close(); + Assert.assertTrue(exist); + } + + @Test + public void hasClass_classLoader_notfound() { + Class testClass = String.class; + + Scanner scanner = ClassScannerFactory.newScanner(testClass.getProtectionDomain(), this.getClass().getClassLoader()); + String fileName = JavaAssistUtils.javaClassNameToJvmResourceName("test.Test"); + boolean exist = scanner.exist(fileName); + scanner.close(); + Assert.assertFalse(exist); + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/InterceptorTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/InterceptorTest.java deleted file mode 100644 index ae77d364bb5a..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/InterceptorTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.Arrays; - -import com.navercorp.pinpoint.profiler.util.LoaderUtils; -import javassist.CannotCompileException; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.Loader; -import javassist.NotFoundException; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; -import com.navercorp.pinpoint.bootstrap.interceptor.registry.DefaultInterceptorRegistryAdaptor; -import com.navercorp.pinpoint.bootstrap.interceptor.registry.InterceptorRegistry; - - -/** - * @author emeroad - */ -public class InterceptorTest { - - private final Logger logger = LoggerFactory.getLogger(InterceptorTest.class.getName()); - - private static DefaultInterceptorRegistryAdaptor INTERCEPTOR_REGISTRY_ADAPTOR; - @Before - public void setUp() throws Exception { - INTERCEPTOR_REGISTRY_ADAPTOR = new DefaultInterceptorRegistryAdaptor(); - InterceptorRegistry.bind(INTERCEPTOR_REGISTRY_ADAPTOR, null); - } - - @After - public void tearDown() throws Exception { - InterceptorRegistry.unbind(null); - INTERCEPTOR_REGISTRY_ADAPTOR = null; - } - - - // @Deprecated - @Test - public void interceptor() throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException, IOException, ClassNotFoundException, NoSuchMethodException { - AroundInterceptor aroundInterceptor = new AroundInterceptor() { - - @Override - public void before(Object target, Object[] args) { - logger.info("BEFORE target:" + target + " args:" + Arrays.toString(args)); - } - - @Override - public void after(Object target, Object[] args, Object result, Throwable throwable) { - logger.info("AFTER target: " + target + " args:" + Arrays.toString(args) + " result:" + result + " throwable:" + throwable); - } - }; - int interceptorId = INTERCEPTOR_REGISTRY_ADAPTOR.addInterceptor(aroundInterceptor); - - - final ClassPool classPool = new ClassPool(true); - CtClass throwable = classPool.get(Throwable.class.getName()); - - CtClass ctClass = classPool.get("com.navercorp.pinpoint.profiler.interceptor.JavaAssistTestObject"); - - final CtMethod hello = ctClass.getMethod("hello", "(Ljava/lang/String;)Ljava/lang/String;"); - logger.debug("longName:{}", hello.getLongName()); - logger.debug("name:{}", hello.getName()); - - String interceptorClassName = AroundInterceptor.class.getName(); - CtClass interceptor = classPool.get(interceptorClassName); - hello.addLocalVariable("interceptor", interceptor); - - CtClass object = classPool.get(Object.class.getName()); - hello.addLocalVariable("result", object); - -// hello.insertBefore("{ System.out.println(\"BEFORE\"); }"); - hello.insertBefore("{" + - "interceptor = (" + interceptorClassName + ") " + InterceptorRegistry.class.getName() + ".getInterceptor(" + interceptorId + ");" + - "interceptor.before(this, $args);" + - "}"); -// hello.addCatch("{" + -//// " interceptor.after(ctx);"+ -//// " AroundInterceptor a = (AroundInterceptor) " + InterceptorRegistry.class.getName() + ".getStaticInterceptor(\"a\");"+ -// " throw $e;" + -// "}", throwable); -// hello.insertAfter("{" + -// "interceptor.after(this, $args, ($w)$_, null); " + -// "}"); - -// hello.setBody(generatedAroundInterceptor("TestObject", "hello")); -// hello.setBody("{ System.out.println(\"ddd\"); }", ClassMap map ); -// hello.insertBefore(" System.out.println(\" BEFORE + \");"); -// hello.insertAfter(" System.out.println($_);"); -// hello.insertAfter(" System.out.println($r);"); -// hello.insertAfter(" System.out.println($w);"); -// hello.insertAfter(" System.out.println($sig);"); -// hello.insertAfter(" System.out.println($type);"); -// hello.insertAfter(" System.out.println($class);"); -// hello.instrument(new ExprEditor() { -// public void edit(MethodCall m) -// throws CannotCompileException -// { -// try { -// System.out.println("method call" + m.getMethod().getName()); -// } catch (NotFoundException e) { -// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. -// } -// String code = generatedAroundInterceptor("TestObject", "hello"); -// m.replace(code); -// } - - -// }); -// hello.addCatch("System.out.println(\"catch\"); throw $e;", throwable); - -// hello.setName("__hello"); -// CtMethod method = CtNewMethod.make("public void hello() { try {__hello(); } catch(Throwable th){throw th;}}", ctClass); - -// CtMethod method = CtNewMethod.make("public void hello() { System.out.println(\"ddd\"); } catch(Throwable th){throw th;}}", ctClass); -// ctClass.addMethod(method); - - -// ctClass.freeze(); -// ctClass.writeFile("./debug"); -// ctClass.debugWriteFile("./debug"); - Loader loader = LoaderUtils.createLoader(classPool); - loader.delegateLoadingOf("com.navercorp.pinpoint.bootstrap."); - - Class aClass = loader.loadClass(ctClass.getName()); - Object testObject = aClass.newInstance(); - - Method helloMethod = testObject.getClass().getDeclaredMethod("hello", String.class); - - try { - helloMethod.invoke(testObject, "hello~~"); - } catch (Exception e) { - Assert.fail(e.getMessage()); - } - -// o.hello(); - } - - public void println(StringBuilder sb, String out) { - sb.append("System.out.println(\"" + out.replace("\"", "\\\"") + "\");"); - } -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/JavaAssistTestObject.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/JavaAssistTestObject.java deleted file mode 100644 index afc4cae97bba..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/JavaAssistTestObject.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor; - -/** - * @author emeroad - */ -public class JavaAssistTestObject { - public String hello(String hello) { - return hello; - } -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/AspectWeaverClassTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/AspectWeaverClassTest.java deleted file mode 100644 index 69e2eecefe48..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/AspectWeaverClassTest.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci; - -import com.navercorp.pinpoint.profiler.instrument.aspect.AspectWeaverClass; - -import com.navercorp.pinpoint.profiler.util.LoaderUtils; -import javassist.*; - -import org.junit.Assert; -import org.junit.Test; - -import java.lang.reflect.Method; - -public class AspectWeaverClassTest { - - private final String ORIGINAL = "com.navercorp.pinpoint.profiler.interceptor.bci.mock.Original"; - private final String ORIGINAL_SUB = "com.navercorp.pinpoint.profiler.interceptor.bci.mock.OriginalSub"; - - private final String ASPECT = "com.navercorp.pinpoint.profiler.interceptor.bci.mock.TestAspect"; - private final String ASPECT_NO_EXTENTS = "com.navercorp.pinpoint.profiler.interceptor.bci.mock.TestAspect_NoExtents"; - private final String ASPECT_EXTENTS_SUB = "com.navercorp.pinpoint.profiler.interceptor.bci.mock.TestAspect_ExtentsSub"; - - private final String ERROR_ASPECT1 = "com.navercorp.pinpoint.profiler.interceptor.bci.mock.ErrorAspect"; - private final String ERROR_ASPECT2 = "com.navercorp.pinpoint.profiler.interceptor.bci.mock.ErrorAspect2"; - - private final String ERROR_ASPECT_INVALID_EXTENTS= "com.navercorp.pinpoint.profiler.interceptor.bci.mock.ErrorAspect_InvalidExtents"; - - public Object createAspect(String originalName, String aspectName) { - try { - ClassPool classPool = new ClassPool(true); - Loader loader = getLoader(classPool); - - CtClass ctOriginal = classPool.get(originalName); - CtClass ctAdvice = classPool.get(aspectName); - - AspectWeaverClass weaver = new AspectWeaverClass(); - - weaver.weaving(ctOriginal, ctAdvice); - - Class aClass = loader.loadClass(originalName); - return aClass.newInstance(); - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } - } - - private Loader getLoader(ClassPool pool) { - return LoaderUtils.createLoader(pool); - } - - private Object createDefaultAspect() { - return createAspect(ORIGINAL, ASPECT); - } - - @Test - public void testVoid() throws Exception { - - Object aspectObject = createDefaultAspect(); - - invoke(aspectObject, "testVoid"); - assertBeforeTouchCount(aspectObject, 1); - assertAfterTouchCount(aspectObject, 1); - - } - - - - - @Test - public void testInt() throws Exception { - - Object aspectObject = createDefaultAspect(); - - int returnValue = (Integer)invoke(aspectObject, "testInt"); - Assert.assertEquals(1, returnValue); - - assertBeforeTouchCount(aspectObject, 1); - assertAfterTouchCount(aspectObject, 1); - } - - - @Test - public void testString() throws Exception { - - Object aspectObject = createDefaultAspect(); - - String returnValue = (String) invoke(aspectObject, "testString"); - Assert.assertEquals(returnValue, "testString"); - - assertBeforeTouchCount(aspectObject, 1); - assertAfterTouchCount(aspectObject, 1); - } - - @Test - public void testUtilMethod() throws Exception { - - Object aspectObject = createDefaultAspect(); - - int returnValue = (Integer)invoke(aspectObject, "testUtilMethod"); - Assert.assertEquals(1, returnValue); - - assertBeforeTouchCount(aspectObject, 1); - assertAfterTouchCount(aspectObject, 1); - } - - @Test - public void testNoTouch() throws Exception { - - Object aspectObject = createDefaultAspect(); - - Object returnValue = invoke(aspectObject, "testNoTouch"); - Assert.assertEquals(null, returnValue); - - assertBeforeTouchCount(aspectObject, 0); - assertAfterTouchCount(aspectObject, 0); - } - - @Test - public void testInternalMethod() throws Exception { - - Object aspectObject = createDefaultAspect(); - - Object returnValue = invoke(aspectObject, "testInternalMethod"); - Assert.assertEquals(null, returnValue); - - assertBeforeTouchCount(aspectObject, 1); - assertAfterTouchCount(aspectObject, 1); - } - - @Test - public void testMethodCall() throws Exception { - - Object aspectObject = createDefaultAspect(); - - invoke(aspectObject, "testMethodCall"); - - } - - @Test(expected = Exception.class) - public void testSignatureMiss() throws Exception { - createAspect(ORIGINAL, ERROR_ASPECT1); - } - - @Test(expected = Exception.class) - public void testInternalTypeMiss() throws Exception { - - createAspect(ORIGINAL, ERROR_ASPECT2); - - } - - @Test - public void testNo_extents() throws Exception { - - Object aspectObject = createAspect(ORIGINAL, ASPECT_NO_EXTENTS); - - Object returnValue = invoke(aspectObject, "testVoid"); - Assert.assertEquals(null, returnValue); - - } - - @Test - public void testExtents_Sub() throws Exception { - - Object aspectObject = createAspect(ORIGINAL_SUB, ASPECT_EXTENTS_SUB); - - Object returnValue = invoke(aspectObject, "testVoid"); - Assert.assertEquals(null, returnValue); - - } - - @Test(expected = Exception.class) - public void testInvalid_extents() throws Exception { - - Object aspectObject = createAspect(ORIGINAL, ERROR_ASPECT_INVALID_EXTENTS); - - Object returnValue = invoke(aspectObject, "testVoid"); - Assert.assertEquals(null, returnValue); - - } - - - - - private Object invoke(Object o, String methodName, Object... args) { - try { - Class clazz = o.getClass(); - Method method = clazz.getMethod(methodName); - return method.invoke(o, args); - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } - } - - private void assertBeforeTouchCount(Object aspectObject, int count) { - int touchCount = (Integer)invoke(aspectObject, "getTouchBefore"); - Assert.assertEquals(touchCount, count); - } - - private void assertAfterTouchCount(Object aspectObject, int count) { - int touchCount = (Integer)invoke(aspectObject, "getTouchAfter"); - Assert.assertEquals(touchCount, count); - } - - -} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/HierarchyMultipleClassPoolTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/HierarchyMultipleClassPoolTest.java deleted file mode 100644 index c28a4cda5a2f..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/HierarchyMultipleClassPoolTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci; - -import javassist.CtClass; - -import org.junit.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.profiler.instrument.classpool.HierarchyMultipleClassPool; -import com.navercorp.pinpoint.profiler.instrument.classpool.NamedClassPool; - -import java.net.URL; -import java.net.URLClassLoader; - -public class HierarchyMultipleClassPoolTest { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - - @Test - public void testGetClassPool() throws Exception { - NamedClassPool cp = new NamedClassPool("test"); - HierarchyMultipleClassPool multipleClassPool = new HierarchyMultipleClassPool(cp); - ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); - - NamedClassPool classPool = multipleClassPool.getClassPool(systemClassLoader); - CtClass string = classPool.get("java.lang.String"); - logger.debug("{}", string); - } - - @Test - public void logSystemClassLoader() { - ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); - - logger.debug("classLoader system:{}", systemClassLoader); - - ClassLoader ext = systemClassLoader.getParent(); - logger.debug("classLoader ext:{}", ext); - - ClassLoader boot = ext.getParent(); - logger.debug("classLoader boot:{}", boot); - - logger.debug("boot:{}", String.class.getClassLoader()); - - logger.debug("system:{}", this.getClass().getClassLoader()); - } - - - @Test - public void testTestClass() throws Exception { - NamedClassPool pool = new NamedClassPool("test"); - pool.childFirstLookup = true; - - HierarchyMultipleClassPool multipleClassPool = new HierarchyMultipleClassPool(pool); - - ClassLoader classLoader = new URLClassLoader(new URL[0], ClassLoader.getSystemClassLoader()); - - multipleClassPool.getClassPool(classLoader); - - logger.debug("size {}", multipleClassPool.size()); - - for (NamedClassPool classPool1 : multipleClassPool.values()) { - logger.debug("classPool:{} name:{}", classPool1, classPool1.getName()); - } - - Assert.assertEquals(2, multipleClassPool.size()); - } - -} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/IsolateMultipleClassPoolTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/IsolateMultipleClassPoolTest.java deleted file mode 100644 index da68beb90db7..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/IsolateMultipleClassPoolTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci; - -import javassist.CtClass; - -import org.junit.Test; -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.navercorp.pinpoint.profiler.instrument.classpool.IsolateMultipleClassPool; -import com.navercorp.pinpoint.profiler.instrument.classpool.NamedClassPool; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Arrays; - - -public class IsolateMultipleClassPoolTest { - - private static final Logger logger = LoggerFactory.getLogger(IsolateMultipleClassPoolTest.class); - - private ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); - - private static final String TEST_CLASS = "org.slf4j.Logger"; - private static final URL TEST_JAR_URL = getLoggerUrl(); - - private URLClassLoader root = new URLClassLoader(new URL[0], systemClassLoader); - - private URLClassLoader child1 = new URLClassLoader(new URL[0], root); - - private URLClassLoader child2 = new URLClassLoader(new URL[] { TEST_JAR_URL }, systemClassLoader) { - @Override - public InputStream getResourceAsStream(String name) { - logger.debug("child2 getResourceAsStream() {}", name); - if (name.equals(TEST_CLASS)) { - final URL resource = findResource(name); - if (resource == null) { - return null; - } - try { - return resource.openStream(); - } catch (IOException e) { - return null; - } - } - return super.getResourceAsStream(name); - } - }; - - public static URL getLoggerUrl() { - URL location = Logger.class.getProtectionDomain().getCodeSource().getLocation(); - logger.debug("Slf4j url:{}", location); - return location; - } - - - @Test - public void testPoolSize() throws Exception { - - IsolateMultipleClassPool pool = new IsolateMultipleClassPool(); - - NamedClassPool systemPool = pool.getClassPool(systemClassLoader); - Assert.assertEquals(0, pool.size()); - pool.getClassPool(null); - Assert.assertEquals(0, pool.size()); - Assert.assertSame(systemPool, pool.getClassPool(systemClassLoader)); - - NamedClassPool child1Pool = pool.getClassPool(child1); - Assert.assertEquals(1, pool.size()); - NamedClassPool child1Pool_recheck = pool.getClassPool(child1); - Assert.assertEquals(1, pool.size()); - Assert.assertSame(child1Pool, child1Pool_recheck); - Assert.assertNotSame(systemPool, child1Pool); - - - NamedClassPool classPool2 = pool.getClassPool(child2); - Assert.assertEquals(2, pool.size()); - - pool.getClassPool(child2); - Assert.assertEquals(2, pool.size()); - Assert.assertNotSame(systemPool, classPool2); - - } - - - @Test - public void testGetClass() throws Exception { - - IsolateMultipleClassPool pool = new IsolateMultipleClassPool(); - - NamedClassPool systemPool = pool.getClassPool(systemClassLoader); - - String classname = "java.lang.String"; - CtClass systemString = systemPool.get(classname); - - - NamedClassPool childPool = pool.getClassPool(child1); - CtClass childPoolString = childPool.get("java.lang.String"); - - Assert.assertNotSame(systemString, childPoolString); - Assert.assertNotSame(systemString.getClassPool(), childPoolString.getClassPool()); - - CtClass testClass = childPool.get(this.getClass().getName()); - Assert.assertNotSame(systemString.getClassPool(), testClass.getClassPool()); - - NamedClassPool childPool2 = pool.getClassPool(child2); - CtClass testClass2 = childPool2.get(this.getClass().getName()); - Assert.assertNotSame(systemString.getClassPool(), testClass2.getClassPool()); - - CtClass testCtClass = childPool2.get(TEST_CLASS); - logger.debug("className:{}", Arrays.toString(testCtClass.getConstructors())); - - } - - @Test - public void testGetClass_childLookupFirst() throws Exception { - - IsolateMultipleClassPool pool = new IsolateMultipleClassPool(false, IsolateMultipleClassPool.EMPTY_EVENT_LISTENER, null); - - NamedClassPool systemPool = pool.getClassPool(systemClassLoader); - CtClass systemLogger = systemPool.get(TEST_CLASS); - - NamedClassPool rootPool = pool.getClassPool(root); - CtClass rootLogger = rootPool.get(TEST_CLASS); - Assert.assertSame(systemLogger, rootLogger); - - NamedClassPool childPool = pool.getClassPool(child1); - CtClass childLogger = childPool.get(TEST_CLASS); - Assert.assertSame(systemLogger, childLogger); - - NamedClassPool childPool2 = pool.getClassPool(child2); - CtClass child2Logger = childPool2.get(TEST_CLASS); - Assert.assertSame(systemLogger, child2Logger); - - } - - -} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/ReflectionTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/ReflectionTest.java deleted file mode 100644 index 97c875a8738b..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/ReflectionTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci; - -import javassist.*; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.Arrays; - -/** - * @author emeroad - */ -public class ReflectionTest { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private ClassPool pool = new ClassPool(); - - @Before - public void setUp() throws Exception { - pool.appendSystemPath(); - } - - @Test - public void test() throws NotFoundException { - Constructor[] constructors = String.class.getConstructors(); - for(Constructor c: constructors) { - logger.debug(c.getName()); - } - CtClass ctClass = pool.get("java.lang.String"); - CtConstructor[] constructors1 = ctClass.getConstructors(); - for(CtConstructor cc : constructors1) { - logger.debug(cc.getName()); - logger.debug(cc.getLongName()); - logger.debug(cc.getSignature()); - } - - - } - @Test - public void methodName() throws NotFoundException, ClassNotFoundException, NoSuchMethodException { - CtClass ctClass = pool.get("java.lang.String"); - - CtMethod subString = ctClass.getDeclaredMethod("substring", new CtClass[]{pool.get("int")}); - logger.debug("getLongName:{}", subString.getLongName()); - logger.debug("getName:{}", subString.getName()); - logger.debug("getDescriptor:{}", subString.getMethodInfo().getDescriptor()); - logger.debug("getDescriptor2:{}", subString.getMethodInfo2().getDescriptor()); - logger.debug("getSignature:{}", subString.getSignature()); - - - Method substring = String.class.getMethod("substring", int.class); - logger.debug(substring.toString()); - logger.debug(Arrays.toString(substring.getParameterTypes())); - } -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/ErrorAspect.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/ErrorAspect.java deleted file mode 100644 index 3ea20bfbe899..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/ErrorAspect.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci.mock; - -import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; - -/** - * @author emeroad - */ -@Aspect -public abstract class ErrorAspect { - - @PointCut - public void testSignatureMiss() { - __testVoid(); - } - - @JointPoint - abstract void __testVoid(); - - - - - - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/ErrorAspect2.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/ErrorAspect2.java deleted file mode 100644 index a1a00ba131b9..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/ErrorAspect2.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci.mock; - -import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; - -/** - * @author emeroad - */ -@Aspect -public abstract class ErrorAspect2 { - - @PointCut - public int testInternalTypeMiss() { - __testVoid(); - return 0; - } - - @JointPoint - abstract void __testVoid(); - - - - - - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/ErrorAspect_InvalidExtents.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/ErrorAspect_InvalidExtents.java deleted file mode 100644 index ac3870352581..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/ErrorAspect_InvalidExtents.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci.mock; - -import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; - -/** - * @author emeroad - */ -@Aspect -public abstract class ErrorAspect_InvalidExtents extends Thread { - - @PointCut - public void testVoid() { - __testVoid(); - } - - @JointPoint - abstract void __testVoid(); - - - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/Original.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/Original.java deleted file mode 100644 index 6bc227d539d0..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/Original.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci.mock; - -import java.util.Collections; -import java.util.Map; - -/** - * @author emeroad - */ -public class Original { - - public int touchVoid = 0; - public int touchInt = 0; - public int touchUtil = 0; - - public int touchBefore; - public int touchAfter; - - public void testVoid() { - touchVoid++; - } - - public int getTouchVoid() { - return touchVoid; - } - - public int testInt() { - return ++touchInt; - } - - public int getTouchInt() { - return touchInt; - } - - - public String testString() { - return "testString"; - } - - - public int testUtilMethod() { - return ++touchUtil; - } - - - - void touchBefore() { - touchBefore++; - } - - public int getTouchBefore() { - return touchBefore; - } - - void touchAfter() { - touchAfter++; - } - - public int getTouchAfter() { - return touchAfter; - } - - public void testNoTouch() { - - } - - - public void methodA() { - } - - public void methodB() { - - } - - - public void testInternalMethod() { - touchBefore(); - touchAfter(); - //super - String s = toString(); - } - - public int testSignatureMiss() { - return -1; - } - - public void testMethodCall() { - } - - public Map testGeneric() { - return Collections.emptyMap(); - } - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/OriginalSub.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/OriginalSub.java deleted file mode 100644 index a0819e535d51..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/OriginalSub.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci.mock; - -/** - * @author emeroad - */ -public class OriginalSub extends Original { - @Override - public void testVoid() { - } -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/TestAspect.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/TestAspect.java deleted file mode 100644 index a1746c89d386..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/TestAspect.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci.mock; - -import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; -import com.navercorp.pinpoint.common.util.BytesUtils; - -import java.util.Map; - -/** - * @author emeroad - */ -@Aspect -public abstract class TestAspect extends Original { - - @PointCut - public void testVoid() { - touchBefore(); - __testVoid(); - touchAfter(); - } - - @JointPoint - abstract void __testVoid(); - - - @PointCut - public int testInt() { - touchBefore(); - final int result = __testInt(); - touchAfter(); - return result; - } - - @JointPoint - abstract int __testInt(); - - - @PointCut - public String testString() { - touchBefore(); - String s = __testString(); - touchAfter(); - return s; - } - - @JointPoint - abstract String __testString(); - - @PointCut - public int testUtilMethod() { - touchBefore(); - int result = __testInt(); - utilMethod(); - touchAfter(); - return result; - } - - private String utilMethod() { - return "Util"; - } - - @PointCut - public void testNoTouch() { - __testVoid(); - } - - @PointCut - public void testInternalMethod() { - __testVoid(); - } - - @PointCut - public void testMethodCall() { - BytesUtils.toBytes("test"); - __testMethodCall(); - } - - @JointPoint - abstract void __testMethodCall(); - - @PointCut - public Map testGeneric() { - return null; - } - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/TestAspect_ExtentsSub.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/TestAspect_ExtentsSub.java deleted file mode 100644 index 6811b29da6d0..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/TestAspect_ExtentsSub.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci.mock; - -import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; - -/** - * @author emeroad - */ -@Aspect -public abstract class TestAspect_ExtentsSub extends OriginalSub { - - @PointCut - public void testVoid() { - touchBefore(); - __testVoid(); - touchAfter(); - } - - @JointPoint - abstract void __testVoid(); - - - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/TestAspect_NoExtents.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/TestAspect_NoExtents.java deleted file mode 100644 index 94b9167075db..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/interceptor/bci/mock/TestAspect_NoExtents.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.interceptor.bci.mock; - -import com.navercorp.pinpoint.bootstrap.instrument.aspect.Aspect; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.JointPoint; -import com.navercorp.pinpoint.bootstrap.instrument.aspect.PointCut; - - -/** - * @author emeroad - */ -@Aspect -public abstract class TestAspect_NoExtents { - - @PointCut - public void testVoid() { - __testVoid(); - } - - @JointPoint - abstract void __testVoid(); - - - -} diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/logging/Slf4jPLoggerAdapterTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/logging/Slf4jPLoggerAdapterTest.java new file mode 100644 index 000000000000..fb1f3c76983d --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/logging/Slf4jPLoggerAdapterTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.logging; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author jaehong.kim + */ +public class Slf4jPLoggerAdapterTest { + + @Test + public void getSimpleName() throws Exception { + assertEquals("int[]", Slf4jPLoggerAdapter.getSimpleName((new int[1]).getClass())); + assertEquals("Slf4jPLoggerAdapterTest$Dummy", Slf4jPLoggerAdapter.getSimpleName(Dummy.class)); + + Runnable r = new Runnable() { + @Override + public void run() { + } + }; + assertEquals("Slf4jPLoggerAdapterTest$1", Slf4jPLoggerAdapter.getSimpleName(r.getClass())); + } + + @Test + public void isSimpletype() { + assertTrue(Slf4jPLoggerAdapter.isSimpleType(new Integer(1))); + assertTrue(Slf4jPLoggerAdapter.isSimpleType(Boolean.TRUE)); + + // array, object + assertFalse(Slf4jPLoggerAdapter.isSimpleType(new int[1])); + assertFalse(Slf4jPLoggerAdapter.isSimpleType(new Dummy())); + } + + private class Dummy { + } + +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultApiMetaDataServiceTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultApiMetaDataServiceTest.java index 2b6a83b3a0a9..1ba4c662b12a 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultApiMetaDataServiceTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultApiMetaDataServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,19 +32,19 @@ public class DefaultApiMetaDataServiceTest { @Test public void cacheApi() throws Exception { - EnhancedDataSender dataSender = mock(EnhancedDataSender.class); - ApiMetaDataService apiMetaDataService = new DefaultApiMetaDataService("agentId", System.currentTimeMillis(), dataSender); + EnhancedDataSender dataSender = mock(EnhancedDataSender.class); + ApiMetaDataService apiMetaDataService = new DefaultApiMetaDataService(dataSender); MethodDescriptor methodDescriptor = new DefaultMethodDescriptor("clazz", "method", null, null); int first = apiMetaDataService.cacheApi(methodDescriptor); Assert.assertNotEquals("not exist", first, 0); - verify(dataSender, times(1)).request(any(TBase.class)); + verify(dataSender, times(1)).request(any(ApiMetaData.class)); int second = apiMetaDataService.cacheApi(methodDescriptor); Assert.assertEquals("check cache", first, second); - verify(dataSender, times(1)).request(any(TBase.class)); + verify(dataSender, times(1)).request(any(ApiMetaData.class)); } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultSqlMetaDataServiceTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultSqlMetaDataServiceTest.java index 111cf036706b..aa8e74925fc9 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultSqlMetaDataServiceTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultSqlMetaDataServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,10 @@ import com.navercorp.pinpoint.bootstrap.context.ParsingResult; import com.navercorp.pinpoint.profiler.sender.EnhancedDataSender; -import org.apache.thrift.TBase; import org.junit.Assert; import org.junit.Test; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -35,7 +34,7 @@ public class DefaultSqlMetaDataServiceTest { @Test public void cacheSql() throws Exception { final EnhancedDataSender dataSender = mock(EnhancedDataSender.class); - final SqlMetaDataService sqlMetaDataService = new DefaultSqlMetaDataService("agentId", System.currentTimeMillis(), dataSender, 100); + final SqlMetaDataService sqlMetaDataService = new DefaultSqlMetaDataService(dataSender, 100); final String sql = "select * from A"; final ParsingResult parsingResult = sqlMetaDataService.parseSql(sql); @@ -43,10 +42,10 @@ public void cacheSql() throws Exception { boolean newValue = sqlMetaDataService.cacheSql(parsingResult); Assert.assertTrue(newValue); - verify(dataSender, times(1)).request(any(TBase.class)); + verify(dataSender, times(1)).request(any(SqlMetaData.class)); boolean notNewValue = sqlMetaDataService.cacheSql(parsingResult); Assert.assertFalse(notNewValue); - verify(dataSender, times(1)).request(any(TBase.class)); + verify(dataSender, times(1)).request(any(SqlMetaData.class)); } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultStringMetaDataServiceTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultStringMetaDataServiceTest.java index 3a2c22bbaad0..078839e6331a 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultStringMetaDataServiceTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/metadata/DefaultStringMetaDataServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,19 +30,19 @@ public class DefaultStringMetaDataServiceTest { @Test public void cacheString() throws Exception { - EnhancedDataSender dataSender = mock(EnhancedDataSender.class); - StringMetaDataService stringMetaDataService = new DefaultStringMetaDataService("agentId", System.currentTimeMillis(), dataSender); + EnhancedDataSender dataSender = mock(EnhancedDataSender.class); + StringMetaDataService stringMetaDataService = new DefaultStringMetaDataService(dataSender); String str = "test"; int first = stringMetaDataService.cacheString(str); Assert.assertNotEquals("not exist", first, 0); - verify(dataSender, times(1)).request(any(TBase.class)); + verify(dataSender, times(1)).request(any(StringMetaData.class)); int second = stringMetaDataService.cacheString(str); Assert.assertEquals("check cache", first, second); - verify(dataSender, times(1)).request(any(TBase.class)); + verify(dataSender, times(1)).request(any(StringMetaData.class)); } } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/CollectJobTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/CollectJobTest.java index bc14c804ceb9..5b72fd73b4cb 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/CollectJobTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/CollectJobTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,26 +16,14 @@ package com.navercorp.pinpoint.profiler.monitor; -import com.navercorp.pinpoint.bootstrap.AgentOption; -import com.navercorp.pinpoint.bootstrap.DefaultAgentOption; -import com.navercorp.pinpoint.bootstrap.config.DefaultProfilerConfig; -import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig; -import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; -import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; -import com.navercorp.pinpoint.profiler.context.module.DefaultApplicationContext; -import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder; import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.sender.DataSender; -import com.navercorp.pinpoint.profiler.util.TestInterceptorRegistryBinder; import com.navercorp.pinpoint.thrift.dto.TAgentStat; import com.navercorp.pinpoint.thrift.dto.TAgentStatBatch; import org.junit.Test; import org.mockito.Mockito; -import java.lang.instrument.Instrumentation; -import java.net.URL; - -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; /** @@ -62,16 +50,5 @@ private AgentStatMetricCollector mockAgentStatMetricCollector() { return Mockito.mock(AgentStatMetricCollector.class); } - private DefaultApplicationContext newApplicationContext() { - ProfilerConfig profilerConfig = new DefaultProfilerConfig(); - InterceptorRegistryBinder binder = new TestInterceptorRegistryBinder(); - Instrumentation instrumentation = mock(Instrumentation.class); - AgentOption agentOption = new DefaultAgentOption(instrumentation, "mockAgent", "mockApplicationName", profilerConfig, new URL[0], - null, new DefaultServiceTypeRegistryService(), new DefaultAnnotationKeyRegistryService()); - - return new DefaultApplicationContext(agentOption, binder); - } - - } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/collector/response/DefaultResponseTimeMetricCollectorTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/collector/response/DefaultResponseTimeMetricCollectorTest.java index 678e9d84ed69..ffe7a85f5dfc 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/collector/response/DefaultResponseTimeMetricCollectorTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/collector/response/DefaultResponseTimeMetricCollectorTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.monitor.collector.response; +import com.navercorp.pinpoint.profiler.monitor.collector.AgentStatMetricCollector; import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeMetric; import com.navercorp.pinpoint.profiler.monitor.metric.response.ResponseTimeValue; import com.navercorp.pinpoint.thrift.dto.TResponseTime; @@ -62,7 +63,7 @@ public void setUp() { @Test public void defaultTest() throws Exception { - ResponseTimeMetricCollector responseTimeMetricCollector = new DefaultResponseTimeMetricCollector(responseTimeMetric); + AgentStatMetricCollector responseTimeMetricCollector = new DefaultResponseTimeMetricCollector(responseTimeMetric); TResponseTime collect = responseTimeMetricCollector.collect(); Assert.assertEquals(totalValue / COUNT, collect.getAvg()); @@ -70,7 +71,7 @@ public void defaultTest() throws Exception { @Test(expected = NullPointerException.class) public void throwNPETest() throws Exception { - ResponseTimeMetricCollector responseTimeMetricCollector = new DefaultResponseTimeMetricCollector(null); + AgentStatMetricCollector responseTimeMetricCollector = new DefaultResponseTimeMetricCollector(null); } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DefaultDataSourceMetricTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DefaultDataSourceMetricTest.java index 336da3b3a240..77afa823e1ff 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DefaultDataSourceMetricTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/datasource/DefaultDataSourceMetricTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,8 +21,6 @@ import com.navercorp.pinpoint.profiler.context.monitor.DataSourceMonitorRegistryService; import com.navercorp.pinpoint.profiler.context.monitor.DefaultDataSourceMonitorRegistryService; import com.navercorp.pinpoint.profiler.context.monitor.JdbcUrlParsingService; -import com.navercorp.pinpoint.thrift.dto.TDataSource; -import com.navercorp.pinpoint.thrift.dto.TDataSourceList; import org.apache.commons.lang3.RandomUtils; import org.junit.Assert; import org.junit.Test; @@ -49,7 +47,7 @@ public class DefaultDataSourceMetricTest { private JdbcUrlParsingService jdbcUrlParsingService; @Test - public void collectTest() throws Exception { + public void collectTest() { int createMockObjectSize = 10; DataSourceMonitorRegistryService dataSourceMonitorRegistryService = new DefaultDataSourceMonitorRegistryService(createMockObjectSize); @@ -58,11 +56,11 @@ public void collectTest() throws Exception { logger.debug("JdbcUrlParsingService:{}", jdbcUrlParsingService); DataSourceMetric dataSourceMetric = new DefaultDataSourceMetric(dataSourceMonitorRegistryService, jdbcUrlParsingService); - TDataSourceList collect = dataSourceMetric.dataSourceList(); - assertIdIsUnique(collect.getDataSourceList()); + List collect = dataSourceMetric.dataSourceList(); + assertIdIsUnique(collect); for (MockDataSourceMonitor dataSourceMonitor : mockDataSourceMonitors) { - assertContainsAndEquals(dataSourceMonitor, collect.getDataSourceList()); + assertContainsAndEquals(dataSourceMonitor, collect); } } @@ -77,18 +75,18 @@ private MockDataSourceMonitor[] createMockDataSourceMonitor(DataSourceMonitorReg return mockDataSourceMonitors; } - private void assertIdIsUnique(List dataSourceList) { + private void assertIdIsUnique(List dataSourceList) { Set idSet = new HashSet(); - for (TDataSource dataSource : dataSourceList) { + for (DataSource dataSource : dataSourceList) { idSet.add(dataSource.getId()); } Assert.assertEquals(dataSourceList.size(), idSet.size()); } - private void assertContainsAndEquals(DataSourceMonitor dataSourceMonitor, List dataSourceList) { - for (TDataSource dataSource : dataSourceList) { + private void assertContainsAndEquals(DataSourceMonitor dataSourceMonitor, List dataSourceList) { + for (DataSource dataSource : dataSourceList) { String url = dataSourceMonitor.getUrl(); if (url.equals(dataSource.getUrl())) { diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/DefaultMemoryMetricTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/DefaultMemoryMetricTest.java index eabf87027bed..11ea25a91c7a 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/DefaultMemoryMetricTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/monitor/metric/memory/DefaultMemoryMetricTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -34,8 +34,7 @@ public class DefaultMemoryMetricTest { @Test public void testJvmSupplied() { // Given - MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); - MemoryMetric memoryMetric = new DefaultMemoryMetric(memoryMXBean); + MemoryMetric memoryMetric = new DefaultMemoryMetric(); // When MemoryMetricSnapshot snapshot = memoryMetric.getSnapshot(); // Then @@ -44,20 +43,4 @@ public void testJvmSupplied() { Assert.assertTrue(snapshot.getNonHeapMax() >= -1); Assert.assertTrue(snapshot.getNonHeapUsed() > 0); } - - @Test - public void testNullMemoryUsage() { - // Given - MemoryMXBean memoryMXBean = mock(MemoryMXBean.class); - when(memoryMXBean.getHeapMemoryUsage()).thenReturn(null); - when(memoryMXBean.getNonHeapMemoryUsage()).thenReturn(null); - MemoryMetric memoryMetric = new DefaultMemoryMetric(memoryMXBean); - // When - MemoryMetricSnapshot snapshot = memoryMetric.getSnapshot(); - // Then - Assert.assertEquals(MemoryMetric.UNCOLLECTED_VALUE, snapshot.getHeapMax()); - Assert.assertEquals(MemoryMetric.UNCOLLECTED_VALUE, snapshot.getHeapUsed()); - Assert.assertEquals(MemoryMetric.UNCOLLECTED_VALUE, snapshot.getNonHeapMax()); - Assert.assertEquals(MemoryMetric.UNCOLLECTED_VALUE, snapshot.getNonHeapUsed()); - } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/AnnotatedInterceptorFactoryTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/AnnotatedInterceptorFactoryTest.java index afcd96c06cac..c0c8c8a4c7bc 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/AnnotatedInterceptorFactoryTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/AnnotatedInterceptorFactoryTest.java @@ -26,6 +26,7 @@ import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext; import com.navercorp.pinpoint.bootstrap.plugin.monitor.DataSourceMonitorRegistry; import com.navercorp.pinpoint.profiler.instrument.ScopeInfo; +import com.navercorp.pinpoint.profiler.interceptor.factory.ExceptionHandlerFactory; import com.navercorp.pinpoint.profiler.metadata.ApiMetaDataService; import org.junit.Before; import org.junit.Test; @@ -53,7 +54,9 @@ public class AnnotatedInterceptorFactoryTest { private final InstrumentClass instrumentClass = mock(InstrumentClass.class); private final InstrumentMethod instrumentMethod = mock(InstrumentMethod.class); private final MethodDescriptor descriptor = mock(MethodDescriptor.class); - + + private final ExceptionHandlerFactory exceptionHandlerFactory = new ExceptionHandlerFactory(false); + @Before public void setUp() { reset(traceContext, instrumentClass, instrumentMethod); @@ -72,7 +75,7 @@ public Class answer(InvocationOnMock invocation) throws Throwable { } private AnnotatedInterceptorFactory newAnnotatedInterceptorFactory() { - return new AnnotatedInterceptorFactory(profilerConfig, traceContext, dataSourceMonitorRegistry, apiMetaDataService, pluginContext, false); + return new AnnotatedInterceptorFactory(profilerConfig, traceContext, dataSourceMonitorRegistry, apiMetaDataService, pluginContext, exceptionHandlerFactory); } private ScopeInfo newEmptyScopeInfo() { diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/xml/transformer/ClassConditions.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/xml/transformer/ClassConditions.java index f4a8a5c735b3..85af9c04c1e8 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/xml/transformer/ClassConditions.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/xml/transformer/ClassConditions.java @@ -185,7 +185,7 @@ public HasClass(String name) { @Override public boolean check(InstrumentContext context, ClassLoader classLoader, InstrumentClass target) { - return context.exist(classLoader, name); + return context.exist(classLoader, name, null); } @Override diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/xml/transformer/DedicatedClassFileTransformer.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/xml/transformer/DedicatedClassFileTransformer.java index 94dfb75b5cd4..3bc5b4611386 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/xml/transformer/DedicatedClassFileTransformer.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/plugin/xml/transformer/DedicatedClassFileTransformer.java @@ -43,7 +43,7 @@ public DedicatedClassFileTransformer(InstrumentContext context, String targetCla @Override public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { try { - InstrumentClass target = context.getInstrumentClass(classLoader, className, classfileBuffer); + InstrumentClass target = context.getInstrumentClass(classLoader, className, protectionDomain, classfileBuffer); recipe.edit(classLoader, target); return target.toBytecode(); } catch (PinpointException e) { diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandServiceLocatorTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandServiceLocatorTest.java index 90abefcfaba2..84f0aaf13768 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandServiceLocatorTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/receiver/ProfilerCommandServiceLocatorTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,9 +19,6 @@ import com.navercorp.pinpoint.profiler.receiver.service.EchoService; import com.navercorp.pinpoint.rpc.packet.stream.StreamCode; import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelContext; -import com.navercorp.pinpoint.thrift.dto.TResult; -import com.navercorp.pinpoint.thrift.dto.command.TCommandEcho; -import com.navercorp.pinpoint.thrift.dto.command.TCommandTransfer; import com.navercorp.pinpoint.thrift.io.TCommandType; import org.apache.thrift.TBase; import org.junit.Assert; @@ -54,13 +51,13 @@ public void throwNullTest2() throws Exception { @Test(expected = NullPointerException.class) public void throwNullTest3() throws Exception { ProfilerCommandLocatorBuilder builder = new ProfilerCommandLocatorBuilder(); - builder.addService(null, null); + builder.addService((short) -1, null); } @Test(expected = NullPointerException.class) public void throwNullTest4() throws Exception { ProfilerCommandLocatorBuilder builder = new ProfilerCommandLocatorBuilder(); - builder.addService(TResult.class, null); + builder.addService(TCommandType.RESULT.getCode(), null); } @Test @@ -68,10 +65,10 @@ public void returnNullTest() throws Exception { ProfilerCommandLocatorBuilder builder = new ProfilerCommandLocatorBuilder(); ProfilerCommandServiceLocator commandServiceLocator = builder.build(); - Assert.assertNull(commandServiceLocator.getService(null)); - Assert.assertNull(commandServiceLocator.getSimpleService(null)); - Assert.assertNull(commandServiceLocator.getRequestService(null)); - Assert.assertNull(commandServiceLocator.getStreamService(null)); + Assert.assertNull(commandServiceLocator.getService((short) -1)); + Assert.assertNull(commandServiceLocator.getSimpleService((short) -1)); + Assert.assertNull(commandServiceLocator.getRequestService((short) -1)); + Assert.assertNull(commandServiceLocator.getStreamService((short) -1)); } @Test @@ -79,13 +76,13 @@ public void basicFunctionTest1() throws Exception { ProfilerCommandLocatorBuilder builder = new ProfilerCommandLocatorBuilder(); builder.addService(new EchoService()); builder.addService(new EchoService()); - ProfilerCommandServiceLocator commandServiceLocator = builder.build(); + DefaultProfilerCommandServiceLocator commandServiceLocator = (DefaultProfilerCommandServiceLocator) builder.build(); - TCommandEcho commandEcho = new TCommandEcho(); + short commandEcho = TCommandType.ECHO.getCode(); - Assert.assertEquals(1, commandServiceLocator.getCommandServiceClasses().size()); + Assert.assertEquals(1, commandServiceLocator.getCommandServiceSize()); Assert.assertEquals(1, commandServiceLocator.getCommandServiceCodes().size()); - Assert.assertTrue(commandServiceLocator.getCommandServiceCodes().contains(TCommandType.getType(commandEcho.getClass()).getCode())); + Assert.assertTrue(commandServiceLocator.getCommandServiceCodes().contains(commandEcho)); Assert.assertNotNull(commandServiceLocator.getService(commandEcho)); Assert.assertNotNull(commandServiceLocator.getRequestService(commandEcho)); @@ -98,15 +95,16 @@ public void basicFunctionTest1() throws Exception { public void basicFunctionTest2() throws Exception { ProfilerCommandLocatorBuilder builder = new ProfilerCommandLocatorBuilder(); builder.addService(new MockCommandServiceGroup()); - ProfilerCommandServiceLocator commandServiceLocator = builder.build(); + DefaultProfilerCommandServiceLocator commandServiceLocator = (DefaultProfilerCommandServiceLocator) builder.build(); + + short commandResult = TCommandType.RESULT.getCode(); - TResult commandResult = new TResult(); - TCommandTransfer commandTransfer = new TCommandTransfer(); + short commandTransfer = TCommandType.TRANSFER.getCode(); - Assert.assertEquals(2, commandServiceLocator.getCommandServiceClasses().size()); + Assert.assertEquals(2, commandServiceLocator.getCommandServiceSize()); Assert.assertEquals(2, commandServiceLocator.getCommandServiceCodes().size()); - Assert.assertTrue(commandServiceLocator.getCommandServiceCodes().contains(TCommandType.getType(commandResult.getClass()).getCode())); - Assert.assertTrue(commandServiceLocator.getCommandServiceCodes().contains(TCommandType.getType(commandTransfer.getClass()).getCode())); + Assert.assertTrue(commandServiceLocator.getCommandServiceCodes().contains(commandResult)); + Assert.assertTrue(commandServiceLocator.getCommandServiceCodes().contains(commandTransfer)); Assert.assertNotNull(commandServiceLocator.getService(commandResult)); Assert.assertNotNull(commandServiceLocator.getSimpleService(commandResult)); @@ -119,7 +117,7 @@ public void basicFunctionTest2() throws Exception { Assert.assertNull(commandServiceLocator.getRequestService(commandTransfer)); } - private static class MockSimpleCommandService implements ProfilerSimpleCommandService { + private static class MockSimpleCommandService implements ProfilerSimpleCommandService> { @Override public void simpleCommandService(TBase tbase) { @@ -127,22 +125,22 @@ public void simpleCommandService(TBase tbase) { } @Override - public Class getCommandClazz() { - return TResult.class; + public short getCommandServiceCode() { + return TCommandType.RESULT.getCode(); } } - private static class MockStreamCommandService implements ProfilerStreamCommandService { + private static class MockStreamCommandService implements ProfilerStreamCommandService> { @Override - public StreamCode streamCommandService(TBase tBase, ServerStreamChannelContext streamChannelContext) { + public StreamCode streamCommandService(TBase tBase, ServerStreamChannelContext streamChannelContext) { return StreamCode.OK; } @Override - public Class getCommandClazz() { - return TCommandTransfer.class; + public short getCommandServiceCode() { + return TCommandType.TRANSFER.getCode(); } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/BufferedUdpDataSenderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/BufferedUdpDataSenderTest.java deleted file mode 100644 index 1133ee894f61..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/BufferedUdpDataSenderTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.profiler.sender; - -import com.navercorp.pinpoint.common.util.ThreadMXBeanUtils; -import com.navercorp.pinpoint.profiler.sender.BufferedUdpDataSender; - -import org.junit.Assert; - -import org.junit.Test; - - -public class BufferedUdpDataSenderTest { - - @Test - public void testSendPacket() throws Exception { - - - - } - - @Test - public void testStop_StopFlushThread() throws Exception { - - final BufferedUdpDataSender sender = new BufferedUdpDataSender("localhost", 9999, "testUdpSender", 100); - - final String flushThreadName = sender.getFlushThreadName(); - - Assert.assertTrue(ThreadMXBeanUtils.findThreadName(flushThreadName)); - - sender.stop(); - - Assert.assertFalse(ThreadMXBeanUtils.findThreadName(flushThreadName)); - // ?? finally { send.stop() } - } -} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/CountingDataSender.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/CountingDataSender.java index 90083a1fe8c8..a2600e934034 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/CountingDataSender.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/CountingDataSender.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -22,14 +22,13 @@ import com.navercorp.pinpoint.rpc.ResponseMessage; import com.navercorp.pinpoint.rpc.client.PinpointClientReconnectEventListener; -import org.apache.thrift.TBase; import java.util.concurrent.atomic.AtomicInteger; /** * @author emeroad */ -public class CountingDataSender implements EnhancedDataSender { +public class CountingDataSender implements EnhancedDataSender { private final AtomicInteger requestCounter = new AtomicInteger(); private final AtomicInteger requestRetryCounter = new AtomicInteger(); @@ -41,19 +40,19 @@ public class CountingDataSender implements EnhancedDataSender { @Override - public boolean request(TBase data) { + public boolean request(Object data) { requestCounter.incrementAndGet(); return false; } @Override - public boolean request(TBase data, int retry) { + public boolean request(Object data, int retry) { requestRetryCounter.incrementAndGet(); return false; } @Override - public boolean request(TBase data, FutureListener listener) { + public boolean request(Object data, FutureListener listener) { return false; } @@ -68,7 +67,7 @@ public boolean removeReconnectEventListener(PinpointClientReconnectEventListener } @Override - public boolean send(TBase data) { + public boolean send(Object data) { senderCounter.incrementAndGet(); if (data instanceof Span) { this.spanCounter.incrementAndGet(); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/NioUdpDataSenderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/NioUdpDataSenderTest.java index 05b35d3aea29..2c67a6c78111 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/NioUdpDataSenderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/NioUdpDataSenderTest.java @@ -1,22 +1,29 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ package com.navercorp.pinpoint.profiler.sender; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.util.IOUtils; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessorV1; +import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import com.navercorp.pinpoint.profiler.context.thrift.SpanThriftMessageConverter; import com.navercorp.pinpoint.thrift.dto.TAgentInfo; import org.apache.commons.lang3.RandomStringUtils; import org.apache.thrift.TBase; @@ -55,23 +62,15 @@ public void setUp() throws SocketException { } @After - public void setDown() throws InterruptedException { - close(receiver); + public void setDown() { + IOUtils.closeQuietly(receiver); // port conflict happens when testcases run continuously so port number is increased. PORT = SocketUtils.findAvailableUdpPort(61112); } - private void close(DatagramSocket socket) { - if (socket == null) { - return; - } - socket.close(); - - } - @Test public void sendTest1() throws Exception { - NioUDPDataSender sender = new NioUDPDataSender("localhost", PORT, "test", 128, 1000, 1024 * 64 * 100); + NioUDPDataSender sender = newNioUdpDataSender(); int sendMessageCount = 10; TAgentInfo agentInfo = new TAgentInfo(); @@ -86,14 +85,22 @@ public void sendTest1() throws Exception { } } + private NioUDPDataSender newNioUdpDataSender() { + TransactionIdEncoder encoder = new DefaultTransactionIdEncoder("agentId", 0); + SpanPostProcessor spanPostProcessor = new SpanPostProcessorV1(); + MessageConverter> messageConverter = new SpanThriftMessageConverter("appName", "agentId", + 0, ServiceType.STAND_ALONE.getCode(), encoder, spanPostProcessor); + return new NioUDPDataSender("localhost", PORT, "test", 128, 1000, 1024 * 64 * 100, messageConverter); + } + @Test(expected = IOException.class) public void exceedMessageSendTest() throws InterruptedException, IOException { - String random = RandomStringUtils.randomAlphabetic(UdpDataSender.UDP_MAX_PACKET_LENGTH + 100); + String random = RandomStringUtils.randomAlphabetic(ThriftUdpMessageSerializer.UDP_MAX_PACKET_LENGTH + 100); TAgentInfo agentInfo = new TAgentInfo(); agentInfo.setAgentId(random); - NioUDPDataSender sender = new NioUDPDataSender("localhost", PORT, "test", 128, 1000, 1024 * 64 * 100); + NioUDPDataSender sender = newNioUdpDataSender(); sender.send(agentInfo); waitMessageReceived(1); @@ -104,7 +111,7 @@ private boolean sendMessage_getLimit(TBase tbase, long waitTimeMillis) throws In final AtomicBoolean limitCounter = new AtomicBoolean(false); final CountDownLatch latch = new CountDownLatch(1); - NioUDPDataSender sender = new NioUDPDataSender("localhost", PORT, "test", 128, 1000, 1024 * 64 * 100); + NioUDPDataSender sender = newNioUdpDataSender(); try { sender.send(tbase); latch.await(waitTimeMillis, TimeUnit.MILLISECONDS); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/RefreshStrategyTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/RefreshStrategyTest.java new file mode 100644 index 000000000000..a725d25e5d2c --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/RefreshStrategyTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.profiler.sender; + +import com.navercorp.pinpoint.rpc.client.SocketAddressProvider; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.verification.VerificationMode; + +import java.net.InetSocketAddress; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +/** + * @author Woonduk Kang(emeroad) + */ +@RunWith(MockitoJUnitRunner.class) +public class RefreshStrategyTest { + + @Mock + private SocketAddressProvider socketAddressProvider; + + @Before + public void setUp() throws Exception { + InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8080); + when(socketAddressProvider.resolve()).thenReturn(address); + } + + @Test + public void resolve_refresh() { + + UdpSocketAddressProvider refreshStrategy = new RefreshStrategy(socketAddressProvider, -1, 0); + // first lookup + refreshStrategy.resolve(); + // refresh lookup + refreshStrategy.resolve(); + + Mockito.verify(socketAddressProvider, times(2)).resolve(); + } + + @Test + public void resolve_norefresh() { + + UdpSocketAddressProvider refreshStrategy = new RefreshStrategy(socketAddressProvider, 10*1000, 0); + // first lookup + refreshStrategy.resolve(); + // refresh lookup + refreshStrategy.resolve(); + + Mockito.verify(socketAddressProvider, times(1)).resolve(); + } + + @Test + public void handlePortUnreachable_refresh() { + UdpSocketAddressProvider refreshStrategy = new RefreshStrategy(socketAddressProvider, 10*1000, -1); + // first lookup + refreshStrategy.resolve(); + refreshStrategy.handlePortUnreachable(); + // refresh lookup + refreshStrategy.resolve(); + + Mockito.verify(socketAddressProvider, times(2)).resolve(); + } + + @Test + public void handlePortUnreachable_norefresh() { + UdpSocketAddressProvider refreshStrategy = new RefreshStrategy(socketAddressProvider, 10*1000, 10*1000); + // first lookup + refreshStrategy.resolve(); + refreshStrategy.handlePortUnreachable(); + // refresh lookup + refreshStrategy.resolve(); + + Mockito.verify(socketAddressProvider, times(1)).resolve(); + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/SpanStreamSendDataSerializerTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/SpanStreamSendDataSerializerTest.java index 919d522895fe..8405ca0207c3 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/SpanStreamSendDataSerializerTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/SpanStreamSendDataSerializerTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,22 +18,17 @@ import com.navercorp.pinpoint.bootstrap.context.TraceId; import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactoryV1; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; -import com.navercorp.pinpoint.profiler.context.Span; -import com.navercorp.pinpoint.profiler.context.SpanChunk; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactory; -import com.navercorp.pinpoint.profiler.context.SpanEvent; -import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; -import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; import com.navercorp.pinpoint.thrift.dto.TSpan; import com.navercorp.pinpoint.thrift.dto.TSpanChunk; import com.navercorp.pinpoint.thrift.dto.TSpanEvent; import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; +import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.junit.Assert; import org.junit.Test; @@ -48,12 +43,10 @@ */ public class SpanStreamSendDataSerializerTest { + private final String applicationName = "applicationName"; private final String agentId = "agentId"; private final long agentStartTime = System.currentTimeMillis(); - private final TransactionIdEncoder encoder = new DefaultTransactionIdEncoder(agentId, agentStartTime); - - private final SpanChunkFactory spanChunkFactory - = new SpanChunkFactoryV1("applicationName", agentId, agentStartTime, ServiceType.STAND_ALONE, encoder); + private final ServiceType applicationServiceType = ServiceType.STAND_ALONE ; private TraceRoot newInternalTraceId() { @@ -70,7 +63,10 @@ public void spanStreamSendDataSerializerTest1() throws InterruptedException, TEx HeaderTBaseSerializerFactory factory = new HeaderTBaseSerializerFactory(); - SpanChunk spanChunk = spanChunkFactory.create(newInternalTraceId(), createSpanEventList(spanEventSize)); + TSpanChunk spanChunk = newSpanChunk(); + spanChunk.setSpanEventList(createSpanEventList(spanEventSize)); + +// spanChunkspanChunkFactory.create(newInternalTraceId(), createSpanEventList(spanEventSize)); PartitionedByteBufferLocator partitionedByteBufferLocator = serializer.serializeSpanChunkStream(factory.createSerializer(), spanChunk); Assert.assertEquals(spanEventSize + 1, partitionedByteBufferLocator.getPartitionedCount()); @@ -84,20 +80,29 @@ public void spanStreamSendDataSerializerTest1() throws InterruptedException, TEx byteBuffer.get(readBuffer); - Object o = deserializer.deserialize(readBuffer); - - if (o == null) { + Message> message = deserializer.deserialize(readBuffer); + TBase data = message.getData(); + if (data == null) { Assert.fail(); } if (i < spanEventSize) { - Assert.assertTrue(o instanceof TSpanEvent); + Assert.assertTrue(data instanceof TSpanEvent); } else { - Assert.assertTrue(o instanceof TSpanChunk); + Assert.assertTrue(data instanceof TSpanChunk); } } } + private TSpanChunk newSpanChunk() { + TSpanChunk tSpanChunk = new TSpanChunk(); + tSpanChunk.setApplicationName(applicationName); + tSpanChunk.setAgentId(agentId); + tSpanChunk.setAgentStartTime(agentStartTime); + tSpanChunk.setApplicationServiceType(applicationServiceType.getCode()); + return tSpanChunk; + } + @Test public void spanStreamSendDataSerializerTest2() throws InterruptedException, TException { int spanEventSize = 10; @@ -106,7 +111,7 @@ public void spanStreamSendDataSerializerTest2() throws InterruptedException, TEx HeaderTBaseSerializerFactory factory = new HeaderTBaseSerializerFactory(); - Span span = createSpan(createSpanEventList(spanEventSize)); + TSpan span = createSpan(createSpanEventList(spanEventSize)); PartitionedByteBufferLocator partitionedByteBufferLocator = serializer.serializeSpanStream(factory.createSerializer(), span); Assert.assertEquals(spanEventSize + 1, partitionedByteBufferLocator.getPartitionedCount()); @@ -120,43 +125,39 @@ public void spanStreamSendDataSerializerTest2() throws InterruptedException, TEx byteBuffer.get(readBuffer); - Object o = deserializer.deserialize(readBuffer); - - if (o == null) { + Message> message = deserializer.deserialize(readBuffer); + TBase data = message.getData(); + if (data == null) { Assert.fail(); } if (i < spanEventSize) { - Assert.assertTrue(o instanceof TSpanEvent); + Assert.assertTrue(data instanceof TSpanEvent); } else { - Assert.assertTrue(o instanceof TSpan); + Assert.assertTrue(data instanceof TSpan); } } } - private Span createSpan(List spanEventList) { - TraceRoot traceRoot = newInternalTraceId(); - - final Span span = new Span(traceRoot); - for (SpanEvent spanEvent : spanEventList) { + private TSpan createSpan(List spanEventList) { + final TSpan span = new TSpan(); + for (TSpanEvent spanEvent : spanEventList) { span.addToSpanEventList(spanEvent); } - span.setAgentId("agentId"); return span; } - private List createSpanEventList(int size) throws InterruptedException { + private List createSpanEventList(int size) throws InterruptedException { + + int elapsedTime = 0; - TraceRoot traceRoot = newInternalTraceId(); + List spanEventList = new ArrayList(size); - Span span = new Span(traceRoot); - List spanEventList = new ArrayList(size); for (int i = 0; i < size; i++) { - SpanEvent spanEvent = new SpanEvent(traceRoot); - spanEvent.markStartTime(); - Thread.sleep(1); - spanEvent.markAfterTime(); + TSpanEvent spanEvent = new TSpanEvent(); + spanEvent.setStartElapsed(elapsedTime++); + spanEvent.setEndElapsed(elapsedTime++); spanEventList.add(spanEvent); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/TcpDataSenderReconnectTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/TcpDataSenderReconnectTest.java index 40347d4fd8f9..5641e56326d2 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/TcpDataSenderReconnectTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/TcpDataSenderReconnectTest.java @@ -16,29 +16,19 @@ package com.navercorp.pinpoint.profiler.sender; -import com.navercorp.pinpoint.profiler.TestAwaitTaskUtils; -import com.navercorp.pinpoint.profiler.TestAwaitUtils; -import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; -import com.navercorp.pinpoint.rpc.packet.SendPacket; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.rpc.server.LoggingServerMessageListenerFactory; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import com.navercorp.pinpoint.thrift.dto.TApiMetaData; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.SocketUtils; -import java.net.InetSocketAddress; import java.util.Collections; -import java.util.Map; /** * @author emeroad @@ -47,59 +37,25 @@ public class TcpDataSenderReconnectTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public static final int PORT = SocketUtils.findAvailableTcpPort(50050); - public static final String HOST = "127.0.0.1"; - private final TestAwaitUtils awaitUtils = new TestAwaitUtils(100, 5000); - private int send; - - public PinpointServerAcceptor serverAcceptorStart() { - PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(); - serverAcceptor.setMessageListener(new ServerMessageListener() { - - @Override - public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { - logger.debug("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); - send++; - } - - @Override - public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - logger.debug("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); - } - - @Override - public HandshakeResponseCode handleHandshake(Map properties) { - return HandshakeResponseType.Success.DUPLEX_COMMUNICATION; - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - logger.debug("ping received packet:{}, remote:{}", pingPacket, pinpointServer); - } - }); - serverAcceptor.bind(HOST, PORT); - return serverAcceptor; - } - - @Test public void connectAndSend() throws InterruptedException { - PinpointServerAcceptor oldAcceptor = serverAcceptorStart(); + TestPinpointServerAcceptor oldTestPinpointServerAcceptor = new TestPinpointServerAcceptor(new LoggingServerMessageListenerFactory(true)); + int bindPort = oldTestPinpointServerAcceptor.bind(); PinpointClientFactory clientFactory = createPinpointClientFactory(); - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender sender = new TcpDataSender(address, clientFactory); - waitClientConnected(oldAcceptor); + TcpDataSender sender = new TcpDataSender(this.getClass().getName(), TestPinpointServerAcceptor.LOCALHOST, bindPort, clientFactory); + oldTestPinpointServerAcceptor.assertAwaitClientConnected(5000); - oldAcceptor.close(); + oldTestPinpointServerAcceptor.close(); waitClientDisconnected(sender); logger.debug("Server start------------------"); - PinpointServerAcceptor serverAcceptor = serverAcceptorStart(); - waitClientConnected(serverAcceptor); + TestPinpointServerAcceptor newTestPinpointServerAcceptor = new TestPinpointServerAcceptor(new LoggingServerMessageListenerFactory(true)); + newTestPinpointServerAcceptor.bind(bindPort); + newTestPinpointServerAcceptor.assertAwaitClientConnected(5000); logger.debug("sendMessage------------------"); sender.send(new TApiMetaData("test", System.currentTimeMillis(), 1, "TestApi")); @@ -108,13 +64,14 @@ public void connectAndSend() throws InterruptedException { logger.debug("sender stop------------------"); sender.stop(); - serverAcceptor.close(); + newTestPinpointServerAcceptor.close(); clientFactory.release(); } private PinpointClientFactory createPinpointClientFactory() { PinpointClientFactory clientFactory = new DefaultPinpointClientFactory(); - clientFactory.setTimeoutMillis(1000 * 5); + clientFactory.setWriteTimeoutMillis(1000 * 3); + clientFactory.setRequestTimeoutMillis(1000 * 5); clientFactory.setProperties(Collections.EMPTY_MAP); return clientFactory; @@ -131,15 +88,4 @@ public boolean checkCompleted() { Assert.assertTrue(pass); } - private void waitClientConnected(final PinpointServerAcceptor acceptor) { - boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - return !acceptor.getWritableSocketList().isEmpty(); - } - }); - - Assert.assertTrue(pass); - } - } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/TcpDataSenderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/TcpDataSenderTest.java index 4931cf87041d..9badc7e5bcd4 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/TcpDataSenderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/TcpDataSenderTest.java @@ -16,111 +16,52 @@ package com.navercorp.pinpoint.profiler.sender; -import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; -import com.navercorp.pinpoint.rpc.packet.SendPacket; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; import com.navercorp.pinpoint.thrift.dto.TApiMetaData; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.SocketUtils; -import java.net.InetSocketAddress; import java.util.Collections; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; /** * @author emeroad */ public class TcpDataSenderTest { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - public static final int PORT = SocketUtils.findAvailableTcpPort(50050); - public static final String HOST = "127.0.0.1"; - - private PinpointServerAcceptor serverAcceptor; - private CountDownLatch sendLatch; - - @Before - public void serverStart() { - serverAcceptor = new PinpointServerAcceptor(); - serverAcceptor.setMessageListener(new ServerMessageListener() { - - @Override - public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { - logger.debug("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); - if (sendLatch != null) { - sendLatch.countDown(); - } - } - - @Override - public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - logger.debug("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); - } - - @Override - public HandshakeResponseCode handleHandshake(Map arg0) { - return HandshakeResponseType.Success.DUPLEX_COMMUNICATION; - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - logger.debug("ping received packet:{}, remote:{}", pingPacket, pinpointServer); - } - }); - serverAcceptor.bind(HOST, PORT); - } - - @After - public void serverShutdown() { - if (serverAcceptor != null) { - serverAcceptor.close(); - } - } - @Test public void connectAndSend() throws InterruptedException { - this.sendLatch = new CountDownLatch(2); + TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX, true); + TestServerMessageListenerFactory.TestServerMessageListener serverMessageListener = testServerMessageListenerFactory.create(); + + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); PinpointClientFactory clientFactory = createPinpointClientFactory(); - InetSocketAddress address = new InetSocketAddress(HOST, PORT); - TcpDataSender sender = new TcpDataSender(address, clientFactory); + TcpDataSender sender = new TcpDataSender(this.getClass().getName(), TestPinpointServerAcceptor.LOCALHOST, bindPort, clientFactory); try { sender.send(new TApiMetaData("test", System.currentTimeMillis(), 1, "TestApi")); sender.send(new TApiMetaData("test", System.currentTimeMillis(), 1, "TestApi")); - - boolean received = sendLatch.await(1000, TimeUnit.MILLISECONDS); - Assert.assertTrue(received); + serverMessageListener.awaitAssertExpectedSendCount(2, 1000); } finally { sender.stop(); if (clientFactory != null) { clientFactory.release(); } + + testPinpointServerAcceptor.close(); } } private PinpointClientFactory createPinpointClientFactory() { PinpointClientFactory clientFactory = new DefaultPinpointClientFactory(); - clientFactory.setTimeoutMillis(1000 * 5); - clientFactory.setProperties(Collections.EMPTY_MAP); + clientFactory.setWriteTimeoutMillis(1000 * 3); + clientFactory.setRequestTimeoutMillis(1000 * 5); + clientFactory.setProperties(Collections.emptyMap()); return clientFactory; } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/UdpDataSenderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/UdpDataSenderTest.java index 55efb592a1f6..fa1b8fb77305 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/UdpDataSenderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/UdpDataSenderTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,8 +16,12 @@ package com.navercorp.pinpoint.profiler.sender; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.thrift.BypassMessageConverter; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; import com.navercorp.pinpoint.profiler.logging.Slf4jLoggerBinderInitializer; -import com.navercorp.pinpoint.profiler.sender.UdpDataSender; import com.navercorp.pinpoint.thrift.dto.TAgentInfo; import org.junit.Assert; @@ -37,6 +41,11 @@ * @author emeroad */ public class UdpDataSenderTest { + private static final String APP_NAME = "appName"; + private static final String AGENT_ID = "agentid"; + private static final int AGENT_START_TIME = 0; + private static final ServiceType APP_SERVICE_TYPE = ServiceType.STAND_ALONE; + private final int PORT = SocketUtils.findAvailableUdpPort(9009); @BeforeClass public static void before() { @@ -48,11 +57,15 @@ public static void after() { Slf4jLoggerBinderInitializer.afterClass(); } + private final TransactionIdEncoder transactionIdEncoder = new DefaultTransactionIdEncoder(AGENT_ID, AGENT_START_TIME); @Test public void sendAndFlushCheck() throws InterruptedException { - UdpDataSender sender = new UdpDataSender("localhost", PORT, "test", 128, 1000, 1024*64*100); + final MessageConverter> messageConverter = new BypassMessageConverter>(); + final MessageSerializer thriftMessageSerializer = new ThriftUdpMessageSerializer(messageConverter, ThriftUdpMessageSerializer.UDP_MAX_PACKET_LENGTH); + UdpDataSender sender = new UdpDataSender("localhost", PORT, "test", 128, 1000, 1024*64*100, + thriftMessageSerializer); TAgentInfo agentInfo = new TAgentInfo(); sender.send(agentInfo); @@ -85,7 +98,7 @@ public void sendAndFlushCheck() throws InterruptedException { @Test public void sendExceedData() throws InterruptedException { - String random = RandomStringUtils.randomAlphabetic(UdpDataSender.UDP_MAX_PACKET_LENGTH + 100); + String random = RandomStringUtils.randomAlphabetic(ThriftUdpMessageSerializer.UDP_MAX_PACKET_LENGTH + 100); TAgentInfo agentInfo = new TAgentInfo(); agentInfo.setAgentId(random); boolean limit = sendMessage_getLimit(agentInfo, 1000); @@ -98,16 +111,19 @@ public void sendExceedData() throws InterruptedException { private boolean sendMessage_getLimit(TBase tbase, long waitTimeMillis) throws InterruptedException { final AtomicBoolean limitCounter = new AtomicBoolean(false); final CountDownLatch latch = new CountDownLatch(1); - - UdpDataSender sender = new UdpDataSender("localhost", PORT, "test", 128, 1000, 1024*64*100) { + final MessageConverter> messageConverter = new BypassMessageConverter>(); + final MessageSerializer thriftMessageSerializer = new ThriftUdpMessageSerializer(messageConverter, ThriftUdpMessageSerializer.UDP_MAX_PACKET_LENGTH) { @Override protected boolean isLimit(int interBufferSize) { - boolean limit = super.isLimit(interBufferSize); + final boolean limit = super.isLimit(interBufferSize); limitCounter.set(limit); latch.countDown(); return limit; } }; + + UdpDataSender sender = new UdpDataSender("localhost", PORT, "test", 128, 1000, 1024*64*100, + thriftMessageSerializer); try { sender.send(tbase); latch.await(waitTimeMillis, TimeUnit.MILLISECONDS); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/UdpSocketTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/UdpSocketTest.java index d1f2e848565d..0e351b22543d 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/UdpSocketTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/UdpSocketTest.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.profiler.sender; +import com.navercorp.pinpoint.common.util.IOUtils; import org.junit.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,20 +55,12 @@ public void setUp() throws SocketException { @After public void setDown() throws InterruptedException { - close(sender); - close(receiver); + IOUtils.closeQuietly(sender); + IOUtils.closeQuietly(receiver); // port conflict happens when testcases run continuously so port number is increased. PORT = SocketUtils.findAvailableUdpPort(61112); } - private void close(DatagramSocket socket) { - if (socket == null) { - return; - } - socket.close(); - - } - private DatagramPacket newDatagramPacket(int size) { return new DatagramPacket(new byte[size], size); } @@ -143,7 +136,7 @@ public void testRemoteReceive() { } // @Test - public void testRemoteSend() throws IOException, InterruptedException { + public void testRemoteSend() throws IOException { DatagramSocket so = new DatagramSocket(); so.connect(new InetSocketAddress("10.66.18.78", PORT)); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/planer/SpanChunkStreamSendDataPlanerTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/planer/SpanChunkStreamSendDataPlanerTest.java index 7d9e41448c05..1b22e6aff429 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/planer/SpanChunkStreamSendDataPlanerTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/planer/SpanChunkStreamSendDataPlanerTest.java @@ -1,22 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.profiler.sender.planer; import com.navercorp.pinpoint.bootstrap.context.TraceId; import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactoryV1; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.profiler.context.SpanChunk; -import com.navercorp.pinpoint.profiler.context.SpanChunkFactory; import com.navercorp.pinpoint.profiler.context.SpanEvent; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessor; +import com.navercorp.pinpoint.profiler.context.compress.SpanPostProcessorV1; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; import com.navercorp.pinpoint.profiler.context.id.DefaultTransactionIdEncoder; import com.navercorp.pinpoint.profiler.context.id.TraceRoot; import com.navercorp.pinpoint.profiler.context.id.TransactionIdEncoder; +import com.navercorp.pinpoint.profiler.context.thrift.MessageConverter; +import com.navercorp.pinpoint.profiler.context.thrift.SpanThriftMessageConverter; import com.navercorp.pinpoint.profiler.sender.HeaderTBaseSerializerPoolFactory; import com.navercorp.pinpoint.profiler.sender.PartitionedByteBufferLocator; import com.navercorp.pinpoint.profiler.sender.SpanStreamSendData; import com.navercorp.pinpoint.profiler.sender.SpanStreamSendDataFactory; import com.navercorp.pinpoint.profiler.sender.SpanStreamSendDataSerializer; import com.navercorp.pinpoint.profiler.util.ObjectPool; +import com.navercorp.pinpoint.thrift.dto.TSpanChunk; import com.navercorp.pinpoint.thrift.dto.TSpanEvent; import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; @@ -37,23 +57,24 @@ public class SpanChunkStreamSendDataPlanerTest { + private final String applicationName = "applicationName"; private final String agentId = "agentId"; private final long agentStartTime = System.currentTimeMillis(); + private final ServiceType applicationServiceType = ServiceType.STAND_ALONE; private final TransactionIdEncoder encoder = new DefaultTransactionIdEncoder(agentId, agentStartTime); - private SpanChunkFactory spanChunkFactory; + private SpanPostProcessor spanPostProcessor = new SpanPostProcessorV1(); private TraceRoot traceRoot; + private MessageConverter> messageConverter = + new SpanThriftMessageConverter(applicationName, agentId, agentStartTime, applicationServiceType.getCode(), encoder, spanPostProcessor); private ObjectPool objectPool; @Before public void before() { - - HeaderTBaseSerializerPoolFactory serializerFactory = new HeaderTBaseSerializerPoolFactory(true, 1000, true); this.objectPool = new ObjectPool(serializerFactory, 16); - this.spanChunkFactory = new SpanChunkFactoryV1("applicationName", agentId, agentStartTime, ServiceType.STAND_ALONE, encoder); this.traceRoot = newTraceRoot(); } @@ -71,13 +92,14 @@ public void spanChunkStreamSendDataPlanerTest() throws Exception { HeaderTBaseSerializerFactory headerTBaseSerializerFactory = new HeaderTBaseSerializerFactory(); List originalSpanEventList = createSpanEventList(spanEventSize); - SpanChunk spanChunk = spanChunkFactory.create(this.traceRoot, originalSpanEventList); + SpanChunk spanChunk = new SpanChunk(traceRoot, originalSpanEventList); + TBase tSpanChunk = messageConverter.toMessage(spanChunk); - PartitionedByteBufferLocator partitionedByteBufferLocator = serializer.serializeSpanChunkStream(headerTBaseSerializerFactory.createSerializer(), spanChunk); + PartitionedByteBufferLocator partitionedByteBufferLocator = serializer.serializeSpanChunkStream(headerTBaseSerializerFactory.createSerializer(), (TSpanChunk) tSpanChunk); SpanStreamSendDataFactory factory = new SpanStreamSendDataFactory(100, 50, objectPool); List spanEventList = getSpanEventList(partitionedByteBufferLocator, factory); - partitionedByteBufferLocator = serializer.serializeSpanChunkStream(headerTBaseSerializerFactory.createSerializer(), spanChunk); + partitionedByteBufferLocator = serializer.serializeSpanChunkStream(headerTBaseSerializerFactory.createSerializer(), (TSpanChunk) tSpanChunk); factory = new SpanStreamSendDataFactory(objectPool); List spanEventList2 = getSpanEventList(partitionedByteBufferLocator, factory); @@ -85,16 +107,15 @@ public void spanChunkStreamSendDataPlanerTest() throws Exception { Assert.assertEquals(spanEventSize, spanEventList2.size()); } - private List createSpanEventList(int size) throws InterruptedException { + private List createSpanEventList(int size) { TraceRoot traceRoot = mock(TraceRoot.class); List spanEventList = new ArrayList(size); for (int i = 0; i < size; i++) { - SpanEvent spanEvent = new SpanEvent(traceRoot); + SpanEvent spanEvent = new SpanEvent(); spanEvent.markStartTime(); - Thread.sleep(1); - spanEvent.markAfterTime(); + spanEvent.setElapsedTime(1); spanEventList.add(spanEvent); } @@ -157,9 +178,10 @@ private List deserialize(byte[] data) throws TException { bb.get(component); HeaderTBaseDeserializer deserialize = new HeaderTBaseDeserializerFactory().createDeserializer(); - List> value = deserialize.deserializeList(component); + List>> value = deserialize.deserializeList(component); - for (TBase tbase : value) { + for (Message> request : value) { + TBase tbase = request.getData(); if (tbase instanceof TSpanEvent) { eventList.add((TSpanEvent) tbase); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/planer/SpanStreamSendDataPlanerTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/planer/SpanStreamSendDataPlanerTest.java index 4a0c95f1ed52..2f3d5071c99c 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/planer/SpanStreamSendDataPlanerTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/sender/planer/SpanStreamSendDataPlanerTest.java @@ -1,6 +1,23 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.navercorp.pinpoint.profiler.sender.planer; import com.navercorp.pinpoint.bootstrap.context.TraceId; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceRoot; import com.navercorp.pinpoint.profiler.context.id.DefaultTraceId; import com.navercorp.pinpoint.profiler.context.Span; @@ -12,6 +29,7 @@ import com.navercorp.pinpoint.profiler.sender.SpanStreamSendDataFactory; import com.navercorp.pinpoint.profiler.sender.SpanStreamSendDataSerializer; import com.navercorp.pinpoint.profiler.util.ObjectPool; +import com.navercorp.pinpoint.thrift.dto.TSpan; import com.navercorp.pinpoint.thrift.dto.TSpanEvent; import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; @@ -50,8 +68,8 @@ public void spanStreamSendDataPlanerTest() throws Exception { HeaderTBaseSerializerFactory headerTBaseSerializerFactory = new HeaderTBaseSerializerFactory(); - List originalSpanEventList = createSpanEventList(spanEventSize); - Span span = createSpan(originalSpanEventList); + List originalSpanEventList = createSpanEventList(spanEventSize); + TSpan span = createSpan(originalSpanEventList); PartitionedByteBufferLocator partitionedByteBufferLocator = serializer.serializeSpanStream(headerTBaseSerializerFactory.createSerializer(), span); SpanStreamSendDataFactory factory = new SpanStreamSendDataFactory(100, 50, objectPool); @@ -65,29 +83,27 @@ public void spanStreamSendDataPlanerTest() throws Exception { Assert.assertEquals(spanEventSize, spanEventList2.size()); } - private Span createSpan(List spanEventList) { + private TSpan createSpan(List spanEventList) { final String agentId = "agentId"; - TraceId traceId = new DefaultTraceId(agentId, 0, 1); - TraceRoot traceRoot = new DefaultTraceRoot(traceId, agentId, System.currentTimeMillis(), 0); - Span span = new Span(traceRoot); - for (SpanEvent spanEvent : spanEventList) { + + final TSpan span = new TSpan(); + span.setAgentId(agentId); + + for (TSpanEvent spanEvent : spanEventList) { span.addToSpanEventList(spanEvent); } - span.setAgentId("agentId"); + return span; } - private List createSpanEventList(int size) throws InterruptedException { - TraceRoot traceRoot = mock(TraceRoot.class); - - List spanEventList = new ArrayList(size); + private List createSpanEventList(int size) { + List spanEventList = new ArrayList(size); for (int i = 0; i < size; i++) { - SpanEvent spanEvent = new SpanEvent(traceRoot); - spanEvent.markStartTime(); - Thread.sleep(1); - spanEvent.markAfterTime(); + TSpanEvent spanEvent = new TSpanEvent(); + spanEvent.setStartElapsed(1); + spanEvent.setEndElapsed(2); spanEventList.add(spanEvent); } @@ -150,10 +166,10 @@ private List deserialize(byte[] data) throws TException { bb.get(component); HeaderTBaseDeserializer deserialize = new HeaderTBaseDeserializerFactory().createDeserializer(); - List> value = deserialize.deserializeList(component); - - for (TBase tbase : value) { + List>> value = deserialize.deserializeList(component); + for (Message> request : value) { + TBase tbase = request.getData(); if (tbase instanceof TSpanEvent) { eventList.add((TSpanEvent) tbase); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/BytecodeUtils.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/BytecodeUtils.java index 3d6bca2de411..bf38c7e5fd64 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/BytecodeUtils.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/BytecodeUtils.java @@ -1,60 +1,34 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ package com.navercorp.pinpoint.profiler.util; -import java.io.Closeable; +import com.navercorp.pinpoint.common.util.IOUtils; + import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.Method; /** * // TODO duplicate BytecodeUtils : com.navercorp.pinpoint.test.util.BytecodeUtils */ public final class BytecodeUtils { - private static final Method DEFINE_CLASS = getDefineClassMethod(); - private BytecodeUtils() { } - - private static Method getDefineClassMethod() { - try { - final Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); - method.setAccessible(true); - return method; - } catch (NoSuchMethodException e) { - // link error - throw new RuntimeException("defineClass not found. Error:" + e.getMessage(), e); - } catch (SecurityException e) { - // link error - throw new RuntimeException("defineClass error. Error:" + e.getMessage(), e); - } - } - - public static Class defineClass(ClassLoader classLoader, String className, byte[] classFile) { - try { - return (Class) DEFINE_CLASS.invoke(classLoader, className, classFile, 0, classFile.length); - } catch (Throwable ex) { - throw new RuntimeException("defineClass error. Caused:" + ex.getMessage(), ex); - } - } - public static byte[] getClassFile(ClassLoader classLoader, String className) { if (classLoader == null) { classLoader = ClassLoader.getSystemClassLoader(); @@ -63,78 +37,16 @@ public static byte[] getClassFile(ClassLoader classLoader, String className) { throw new NullPointerException("className must not be null"); } - final String classInternalName = JavaAssistUtils.javaNameToJvmName(className); - final InputStream is = classLoader.getResourceAsStream(classInternalName + ".class"); + final String classInternalName = JavaAssistUtils.javaClassNameToJvmResourceName(className); + final InputStream is = classLoader.getResourceAsStream(classInternalName); if (is == null) { throw new RuntimeException("No such class file: " + className); } - try { - return readClass(is, false); + return IOUtils.toByteArray(is); } catch (IOException e) { - throw new RuntimeException(e); - } finally { - close(is); - } - } - - /** - * COPY ASM method. reference : org.objectweb.asm.ClassReader - * - * Reads the bytecode of a class. - * - * @param is - * an input stream from which to read the class. - * @param close - * true to close the input stream after reading. - * @return the bytecode read from the given input stream. - * @throws IOException - * if a problem occurs during reading. - */ - public static byte[] readClass(final InputStream is, boolean close) - throws IOException { - if (is == null) { - throw new IOException("Class not found"); - } - try { - byte[] b = new byte[is.available()]; - int len = 0; - while (true) { - int n = is.read(b, len, b.length - len); - if (n == -1) { - if (len < b.length) { - byte[] c = new byte[len]; - System.arraycopy(b, 0, c, 0, len); - b = c; - } - return b; - } - len += n; - if (len == b.length) { - int last = is.read(); - if (last < 0) { - return b; - } - byte[] c = new byte[b.length + 1000]; - System.arraycopy(b, 0, c, 0, len); - c[len++] = (byte) last; - b = c; - } - } - } finally { - if (close) { - close(is); - } + throw new RuntimeException(classInternalName + " class read fail"); } } - private static void close(Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (IOException ignore) { - // skip - } - } - } } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JarReaderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JarReaderTest.java index 06514f5093fe..d72ea91505bf 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JarReaderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JarReaderTest.java @@ -17,6 +17,7 @@ package com.navercorp.pinpoint.profiler.util; +import com.navercorp.pinpoint.common.util.CodeSourceUtils; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; @@ -35,7 +36,8 @@ public class JarReaderTest { @Test public void read() throws Exception { - URL location = Logger.class.getProtectionDomain().getCodeSource().getLocation(); + URL location = CodeSourceUtils.getCodeLocation(Logger.class); + JarFile jarFile = new JarFile(location.getPath()); logger.debug("jarFile:{}", jarFile.getName()); @@ -51,7 +53,8 @@ public void read() throws Exception { @Test public void getInputStream() throws Exception { - URL location = Logger.class.getProtectionDomain().getCodeSource().getLocation(); + URL location = CodeSourceUtils.getCodeLocation(Logger.class); + JarFile jarFile = new JarFile(location.getPath()); JarReader jarReader = new JarReader(jarFile); Assert.assertNotNull(jarReader.getInputStream("org/slf4j/Logger.class")); diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtilsTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtilsTest.java index 403c689f22bc..b00d5d9f29fd 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtilsTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtilsTest.java @@ -16,16 +16,12 @@ package com.navercorp.pinpoint.profiler.util; -import javassist.*; - import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; @@ -37,26 +33,6 @@ public class JavaAssistUtilsTest { private static final String TEST_CLASS_NAME = "com.navercorp.pinpoint.profiler.util.JavaAssistUtilsTest"; private final Logger logger = LoggerFactory.getLogger(JavaAssistUtilsTest.class.getName()); - private ClassPool pool; - - @Before - public void setUp() throws Exception { - pool = new ClassPool(); - pool.appendSystemPath(); - } - - @Test - public void testGetParameterDescription() throws Exception { - CtClass ctClass = pool.get("java.lang.String"); - CtMethod substring = ctClass.getDeclaredMethod("substring", new CtClass[]{CtClass.intType}); - - String ctDescription = JavaAssistUtils.getParameterDescription(substring.getParameterTypes()); - logger.debug(ctDescription); - - String clsDescription = JavaAssistUtils.getParameterDescription(new Class[]{int.class}); - logger.debug(clsDescription); - Assert.assertEquals(ctDescription, clsDescription); - } @Test @@ -216,99 +192,6 @@ public void testParseParameterDescriptor_array() throws Exception { Assert.assertArrayEquals(JavaAssistUtils.parseParameterSignature("([[[I)"), new String[]{"int[][][]"}); } - public void getLineNumber_testAPI(String params) { - } - - @Test - public void testGetLineNumber() throws Exception { -// pool.appendClassPath(new ClassClassPath(AbstractHttpClient.class)); - CtClass ctClass = pool.get("com.navercorp.pinpoint.profiler.util.JavaAssistUtilsTest"); - CtClass params = pool.get("java.lang.String"); - // non-javadoc, see interface HttpClient -// public synchronized final HttpParams getParams() { -// if (defaultParams == null) { -// defaultParams = createHttpParams(); -// } -// return defaultParams; -// } - - CtMethod setParams = ctClass.getDeclaredMethod("getLineNumber_testAPI", new CtClass[]{params}); - int lineNumber = JavaAssistUtils.getLineNumber(setParams); - logger.debug("line:{}", lineNumber); - - logger.debug(setParams.getName()); - logger.debug(setParams.getLongName()); - - String[] paramName = JavaAssistUtils.getParameterVariableName(setParams); - logger.debug(Arrays.toString(paramName)); - Assert.assertEquals(paramName.length, 1); - Assert.assertEquals(paramName[0], "params"); - - String[] parameterType = JavaAssistUtils.parseParameterSignature(setParams.getSignature()); - String[] parameterType2 = JavaAssistUtils.getParameterType(setParams.getParameterTypes()); - logger.debug(Arrays.toString(parameterType)); - Assert.assertArrayEquals(parameterType, parameterType2); - - String s = ApiUtils.mergeParameterVariableNameDescription(parameterType, paramName); - logger.debug(s); - } - - public void testVariableNameError1_testAPI(boolean autoCommitFlag) { - logger.debug("testVariableNameError1_testAPI test api"); - } - - @Test - public void testVariableNameError1() throws Exception { - CtClass ctClass = pool.get(TEST_CLASS_NAME); - CtMethod setParams = ctClass.getDeclaredMethod("testVariableNameError1_testAPI", new CtClass[]{CtClass.booleanType}); - int lineNumber = JavaAssistUtils.getLineNumber(setParams); - logger.debug("line:{}", lineNumber); - - logger.debug(setParams.getName()); - logger.debug(setParams.getLongName()); - - String[] paramName = JavaAssistUtils.getParameterVariableName(setParams); - logger.debug(Arrays.toString(paramName)); - Assert.assertEquals(paramName.length, 1); - Assert.assertEquals(paramName[0], "autoCommitFlag"); - - String[] parameterType = JavaAssistUtils.parseParameterSignature(setParams.getSignature()); - String[] parameterType2 = JavaAssistUtils.getParameterType(setParams.getParameterTypes()); - logger.debug(Arrays.toString(parameterType)); - Assert.assertArrayEquals(parameterType, parameterType2); - - String s = ApiUtils.mergeParameterVariableNameDescription(parameterType, paramName); - logger.debug(s); - } - - public void testVariableNameError2_testAPI(String sql) { - logger.debug("testVariableNameError1_testAPI test api"); - } - - @Test - public void testVariableNameError2() throws Exception { - CtClass ctClass = pool.get(TEST_CLASS_NAME); - CtClass params = pool.get("java.lang.String"); - CtMethod setParams = ctClass.getDeclaredMethod("testVariableNameError2_testAPI", new CtClass[]{params}); - int lineNumber = JavaAssistUtils.getLineNumber(setParams); - - logger.debug(setParams.getName()); - logger.debug(setParams.getLongName()); - - String[] paramName = JavaAssistUtils.getParameterVariableName(setParams); - logger.debug(Arrays.toString(paramName)); - Assert.assertEquals(paramName.length, 1); - Assert.assertEquals(paramName[0], "sql"); - - String[] parameterType = JavaAssistUtils.parseParameterSignature(setParams.getSignature()); - String[] parameterType2 = JavaAssistUtils.getParameterType(setParams.getParameterTypes()); - logger.debug(Arrays.toString(parameterType)); - Assert.assertArrayEquals(parameterType, parameterType2); - - String s = ApiUtils.mergeParameterVariableNameDescription(parameterType, paramName); - logger.debug(s); - } - @Test public void testGetParameterDescription2() throws Exception { @@ -317,4 +200,9 @@ public void testGetParameterDescription2() throws Exception { Assert.assertEquals("(java.lang.String, java.lang.Integer)", clsDescription); } + @Test + public void testJavaClassNameToJvmResourceName() throws Exception { + Assert.assertEquals("java/lang/String.class", JavaAssistUtils.javaClassNameToJvmResourceName("java.lang.String")); + } + } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/LoaderUtils.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/LoaderUtils.java deleted file mode 100644 index 0ca903df46ad..000000000000 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/LoaderUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.navercorp.pinpoint.profiler.util; - -import javassist.ClassPool; -import javassist.Loader; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -/** - * TODO Duplicate : com.navercorp.pinpoint.test.util.LoaderUtils - * @author emeroad - */ -public final class LoaderUtils { - - private static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); - - private LoaderUtils() { - } - - public static Loader createLoader(final ClassPool classPool) { - if (classPool == null) { - throw new NullPointerException("classPool must not be null"); - } - Loader loader; - if (SECURITY_MANAGER != null) { - loader = AccessController.doPrivileged(new LoaderCreateAction(classPool)); - } else { - loader = new Loader(classPool); - } - loader.delegateLoadingOf("org.apache.log4j."); - return loader; - } - - static class LoaderCreateAction implements PrivilegedAction { - private final ClassPool classPool; - - public LoaderCreateAction(final ClassPool classPool) { - if (classPool == null) { - throw new NullPointerException("classPool must not be null"); - } - this.classPool = classPool; - } - - public Loader run() { - return new Loader(classPool); - } - } - -} diff --git a/quickstart/README.Win.en.md b/quickstart/README.Win.en.md index 4e2309c4eba0..5238034d5aab 100644 --- a/quickstart/README.Win.en.md +++ b/quickstart/README.Win.en.md @@ -3,7 +3,7 @@ ## Starting Download Pinpoint with `git clone https://github.com/naver/pinpoint.git` or [download](https://github.com/naver/pinpoint/archive/master.zip) the project as a zip file and unzip. -Install Pinpoint by running `mvnw.cmd install -Dmaven.test.skip=true` +Install Pinpoint by running `mvnw.cmd install -DskipTests=true` ### Install & Start HBase Download `HBase-1.0.x-bin.tar.gz` from [Apache download site](http://apache.mirror.cdnetworks.com/hbase/)) and unzip it to `quickstart\hbase` directory. diff --git a/quickstart/README.Win.ko.md b/quickstart/README.Win.ko.md index 9eb2db039f08..c4747b4497ba 100644 --- a/quickstart/README.Win.ko.md +++ b/quickstart/README.Win.ko.md @@ -5,7 +5,7 @@ Pinpoint는 공식적으로는 Linux와 OS X를 지원한다. 하지만 Pinpoint `git clone https://github.com/naver/pinpoint.git`로 Pinpoint를 다운로드 하거나 zip 파일로 프로젝트를 [다운로드](https://github.com/naver/pinpoint/archive/master.zip)하고 압축을 해제한다. -`mvnw.cmd install -Dmaven.test.skip=true`를 실행하여 Pinpoint를 설치한다. +`mvnw.cmd install -DskipTests=true`를 실행하여 Pinpoint를 설치한다. ### 설치 및 HBase 시작하기 **[Apache 다운로드 사이트](http://apache.mirror.cdnetworks.com/hbase/)에서 HBase 1.0.x 버전을 다운로드 받는다. diff --git a/quickstart/README.md b/quickstart/README.md index 8fe3fa977425..93a4ffd3241c 100644 --- a/quickstart/README.md +++ b/quickstart/README.md @@ -9,7 +9,7 @@ In order to build Pinpoint, the following requirements must be met: * JDK 6 installed ([jdk1.6.0_45](http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase6-419409.html#jdk-6u45-oth-JPR) recommended) * JDK 7 installed ([jdk1.7.0_80](http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javase7-521261.html#jdk-7u80-oth-JPR) recommended) * JDK 8 installed -* JAVA_HOME environment variable set to JDK 7+ home directory. +* JAVA_HOME environment variable set to JDK 8+ home directory. * JAVA_6_HOME environment variable set to JDK 6 home directory. * JAVA_7_HOME environment variable set to JDK 7 home directory. * JAVA_8_HOME environment variable set to JDK 8 home directory. @@ -20,7 +20,7 @@ QuickStart supports Linux, OSX, and Windows. ## Starting Download Pinpoint with `git clone https://github.com/naver/pinpoint.git` or [download](https://github.com/naver/pinpoint/archive/master.zip) the project as a zip file and unzip. -Install Pinpoint by running `./mvnw install -Dmaven.test.skip=true` +Install Pinpoint by running `./mvnw install -DskipTests=true` ### Install & Start HBase @@ -49,11 +49,11 @@ The following script downloads HBase standalone from [Apache download site](http Once the startup scripts are completed, the last 10 lines of the Tomcat log are tailed to the console: -**Collector** ![Collector quick start successful](../doc/img/ss_quickstart-collector-log.png) +**Collector** ![Collector quick start successful](../doc/images/ss_quickstart-collector-log.png) -**TestApp** ![TestApp quick start successful](../doc/img/ss_quickstart-testapp-log.png) +**TestApp** ![TestApp quick start successful](../doc/images/ss_quickstart-testapp-log.png) -**Web UI** ![Web quick start successful](../doc/img/ss_quickstart-web-log.png) +**Web UI** ![Web quick start successful](../doc/images/ss_quickstart-web-log.png) ### Check Status Once HBase and the 3 daemons are running, you may visit the following addresses to test out your very own Pinpoint instance. diff --git a/quickstart/agent/src/main/resources/pinpoint.config b/quickstart/agent/src/main/resources/pinpoint.config index 2081f0a4a992..7f9ddcd954f1 100644 --- a/quickstart/agent/src/main/resources/pinpoint.config +++ b/quickstart/agent/src/main/resources/pinpoint.config @@ -25,6 +25,10 @@ profiler.collector.tcp.port=9994 ########################################################### profiler.enable=true +# Application namespace +# Differentiate from external pinpoint agents. (e.g., com.pinpoint) +profiler.application.namespace= + # Interval (in milliseconds) at which agent stat data is collected. (default : 5000, min : 1000, max : 5000) profiler.jvm.stat.collect.interval=5000 # Number of agent stat data sent to the collector in a single batch. (default : 6) @@ -138,7 +142,8 @@ profiler.tomcat.bootstrap.main=org.apache.catalina.startup.Bootstrap profiler.tomcat.conditional.transform=false # Hide pinpoint headers. profiler.tomcat.hidepinpointheader=true -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.tomcat.excludeurl=/aa/test.html, /bb/exclude.html profiler.tomcat.tracerequestparam=true @@ -157,7 +162,8 @@ profiler.tomcat.tracerequestparam=true profiler.jetty.enable=true # Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. profiler.jetty.bootstrap.main=org.eclipse.jetty.start.Main -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.jetty.excludeurl= # Hide pinpoint headers. 9.x only profiler.jetty.hide-pinpoint-header=true @@ -182,7 +188,8 @@ profiler.jboss.bootstrap.main=org.jboss.modules.Main profiler.jboss.conditional.transform=true # Hide pinpoint headers. profiler.jboss.hidepinpointheader=true -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.jboss.excludeurl= # HTTP Request methods to exclude from tracing #profiler.jboss.excludemethod= @@ -199,7 +206,7 @@ profiler.jboss.tracerequestparam=true ########################################################### # Vert.x(Reliability and stability can not be guaranteed) # ########################################################### -profiler.vertx.enable=false +profiler.vertx.enable=true # Classes for detecting application server type. Comma separated list of fully qualified class names. Wildcard not supported. profiler.vertx.bootstrap.main=io.vertx.core.Starter # Track Vertx.runOnContext() & Vertx.executeBlocking(). @@ -208,10 +215,13 @@ profiler.vertx.handler.base-packages= # e.g. com.service.handler, com.server.http.handler # HTTP server -profiler.vertx.http.server.enable=false +profiler.vertx.http.server.enable=true +# Set HttpServerRequestHandler method name. The argument is io.vertx.core.http.HttpServerRequest. +profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.accept profiler.vertx.http.server.tracerequestparam=true profiler.vertx.http.server.hidepinpointheader=true -# URLs to exclude from tracing +# URLs to exclude from tracing. +# Support ant style pattern. e.g. /aa/*.html, /??/exclude.html profiler.vertx.http.server.excludeurl= # original IP address header # https://en.wikipedia.org/wiki/X-Forwarded-For @@ -224,7 +234,7 @@ profiler.vertx.http.server.excludeurl= #profiler.vertx.http.server.excludemethod= # HTTP client -profiler.vertx.http.client.enable=false +profiler.vertx.http.client.enable=true profiler.vertx.http.client.param=true profiler.vertx.http.client.cookie=true # When to dump cookies. Either ALWAYS or EXCEPTION. @@ -336,21 +346,18 @@ profiler.jdk.httpurlconnection=true # Ning Async HTTP Client # ########################################################### profiler.ning.asynchttpclient=true +# unsupported in 1.8.x, 1.9.x versions +profiler.ning.asynchttpclient.param=true + profiler.ning.asynchttpclient.cookie=true profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS profiler.ning.asynchttpclient.cookie.dumpsize=1024 profiler.ning.asynchttpclient.cookie.sampling.rate=1 + profiler.ning.asynchttpclient.entity=true profiler.ning.asynchttpclient.entity.dumptype=ALWAYS profiler.ning.asynchttpclient.entity.dumpsize=1024 profiler.ning.asynchttpclient.entity.sampling.rate=1 -# unsupported in 1.8.x, 1.9.x versions -profiler.ning.asynchttpclient.param=true -profiler.ning.asynchttpclient.param.dumptype=ALWAYS -profiler.ning.asynchttpclient.param.dumpsize=1024 - -profiler.ning.asynchttpclient.param.sampling.rate=1 - ########################################################### # LINE+ baseframework # @@ -438,6 +445,24 @@ profiler.spring.beans.1.class.pattern= profiler.spring.beans.1.annotation=org.springframework.stereotype.Controller,org.springframework.stereotype.Service,org.springframework.stereotype.Repository profiler.spring.beans.mark.error=false + +########################################################### +# spring @Async +########################################################### +profiler.spring.async.enable=true +# Add custom AsyncTaskExecutor classes. Comma separated list of fully qualified class names. Wildcard not supported. +# Default values +# org.springframework.scheduling.concurrent.ConcurrentTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.core.task.SimpleAsyncTaskExecutor +# org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor +# org.springframework.core.task.support.TaskExecutorAdapter +# org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +# org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler +# org.springframework.jca.work.WorkManagerTaskExecutor +# org.springframework.scheduling.commonj.WorkManagerTaskExecutor +profiler.spring.async.executor.class.names= + ########################################################### # log4j ########################################################### @@ -460,7 +485,7 @@ profiler.okhttp.cookie=false # When to dump cookies. Either ALWAYS or EXCEPTION. profiler.okhttp.cookie.dumptype=EXCEPTION # 1 out of n cookies will be sampled where n is the rate. (1: 100%) -profiler.okhttp.cookie.sampling.rate=10 +profiler.okhttp.cookie.sampling.rate=1 # enqueue operation profiler.okhttp.async=true @@ -505,4 +530,12 @@ profiler.hystrix=false ########################################################### # recommend netty plugin disable, when using VERTX. profiler.netty=false -profiler.netty.http=false \ No newline at end of file +profiler.netty.http=false + +########################################################### +# Hbase (Reliability and stability can not be guaranteed) +########################################################### +profiler.hbase.client.enable=true +profiler.hbase.client.admin.enable=true +profiler.hbase.client.table.enable=true +profiler.hbase.client.params.enable=false diff --git a/quickstart/bin/start-collector.sh b/quickstart/bin/start-collector.sh index 5cbea0a9c18b..912b6ea384c0 100755 --- a/quickstart/bin/start-collector.sh +++ b/quickstart/bin/start-collector.sh @@ -1,11 +1,5 @@ #!/usr/bin/env bash -UNAME=`uname` -OS_TYPE="linux"; -if [[ "$UNAME" == "Darwin" ]]; then - OS_TYPE="mac" -fi - this="${BASH_SOURCE-$0}" while [ -h "$this" ]; do ls=`ls -ld "$this"` @@ -44,6 +38,7 @@ CLOSE_WAIT_TIME=`expr $UNIT_TIME \* $CHECK_COUNT` PROPERTIES=`cat $CONF_DIR/$CONF_FILE 2>/dev/null` KEY_VERSION="quickstart.version" +KEY_CONTEXT_PATH="quickstart.collector.context.path" KEY_PORT="quickstart.collector.port" function func_read_properties @@ -118,56 +113,53 @@ function func_init_log function func_check_running_pinpoint_collector { - port=$( func_read_properties "$KEY_PORT" ) - - if [[ "$OS_TYPE" == 'mac' ]]; then - main_port_num=`lsof -p $pid | grep TCP | grep $port | wc -l ` - process_tcp_port_num=`lsof -p $pid | grep TCP | wc -l ` - process_udp_port_num=`lsof -p $pid | grep UDP | wc -l ` - else - main_port_num=`netstat -anp 2>/dev/null | grep $pid/java | grep tcp | grep $port | wc -l ` - process_tcp_port_num=`netstat -anp 2>/dev/null | grep $pid/java | grep tcp | wc -l ` - process_udp_port_num=`netstat -anp 2>/dev/null | grep $pid/java | grep udp | wc -l ` - fi - - if [[ $main_port_num -eq 1 && $process_tcp_port_num -ge 2 && $process_udp_port_num -ge 2 ]]; then - echo "true" - else - echo "false" - fi + context_path=$( func_read_properties "$KEY_CONTEXT_PATH" ) + if [ "$context_path" == "/" ]; then + context_path="" + fi + port=$( func_read_properties "$KEY_PORT" ) + check_url="http://localhost:$port$context_path/serverTime.pinpoint" + + process_status=`curl $check_url 2>/dev/null | grep 'currentServerTime'` + + if [ -z $process_status ]; then + echo "false" + else + echo "true" + fi } function func_start_pinpoint_collector { - version=$( func_read_properties "$KEY_VERSION" ) - pid=`nohup ${bin}/../../mvnw -f $COLLECTOR_DIR/pom.xml clean package tomcat7:run -D$IDENTIFIER -Dmaven.pinpoint.version=$version > $LOGS_DIR/$LOG_FILE 2>&1 & echo $!` - echo $pid > $PID_DIR/$PID_FILE - - echo "---$COLLECTOR_IDENTIFIER initialization started. pid=$pid.---" - - end_count=0 - check_running_pinpoint_collector=$( func_check_running_pinpoint_collector ) - while [ "$check_running_pinpoint_collector" == "false" ]; do - wait_time=`expr $end_count \* $UNIT_TIME` - echo "starting $COLLECTOR_IDENTIFIER. $wait_time /$CLOSE_WAIT_TIME sec(close wait limit)." - - if [ $end_count -ge $CHECK_COUNT ]; then - break - fi + version=$( func_read_properties "$KEY_VERSION" ) + pid=`nohup ${bin}/../../mvnw -f $COLLECTOR_DIR/pom.xml clean package tomcat7:run -D$IDENTIFIER -Dmaven.pinpoint.version=$version > $LOGS_DIR/$LOG_FILE 2>&1 & echo $!` + echo $pid > $PID_DIR/$PID_FILE - sleep $UNIT_TIME - end_count=`expr $end_count + 1` - - check_running_pinpoint_collector=$( func_check_running_pinpoint_collector ) - done + echo "---$COLLECTOR_IDENTIFIER initialization started. pid=$pid.---"g + + end_count=0 + check_running_pinpoint_collector=$( func_check_running_pinpoint_collector ) + while [ "$check_running_pinpoint_collector" == "false" ]; do + wait_time=`expr $end_count \* $UNIT_TIME` + echo "starting $COLLECTOR_IDENTIFIER. $wait_time /$CLOSE_WAIT_TIME sec(close wait limit)." - if [[ "$check_running_pinpoint_collector" == "true" ]]; then - echo "---$COLLECTOR_IDENTIFIER initialization completed. pid=$pid.---" - tail -f $LOGS_DIR/$LOG_FILE - else - echo "---$COLLECTOR_IDENTIFIER initialization failed. pid=$pid.---" - kill -9 $pid + if [ $end_count -ge $CHECK_COUNT ]; then + break fi + + sleep $UNIT_TIME + end_count=`expr $end_count + 1` + + check_running_pinpoint_collector=$( func_check_running_pinpoint_collector ) + done + + if [[ "$check_running_pinpoint_collector" == "true" ]]; then + echo "---$COLLECTOR_IDENTIFIER initialization completed. pid=$pid.---" + tail -f $LOGS_DIR/$LOG_FILE + else + echo "---$COLLECTOR_IDENTIFIER initialization failed. pid=$pid.---" + kill -9 $pid + fi } func_check_process diff --git a/quickstart/bin/start-testapp.sh b/quickstart/bin/start-testapp.sh index 1ad198c3edd5..4f0898fdaee6 100755 --- a/quickstart/bin/start-testapp.sh +++ b/quickstart/bin/start-testapp.sh @@ -48,6 +48,7 @@ CLOSE_WAIT_TIME=`expr $UNIT_TIME \* $CHECK_COUNT` PROPERTIES=`cat $CONF_DIR/$CONF_FILE 2>/dev/null` KEY_VERSION="quickstart.version" +KEY_CONTEXT_PATH="quickstart.testapp.context.path" KEY_PORT="quickstart.testapp.port" function func_read_properties @@ -141,14 +142,18 @@ function func_init_agent function func_start_pinpoint_testapp { - version=$( func_read_properties "$KEY_VERSION" ) + version=$( func_read_properties "$KEY_VERSION" ) maven_opt=$MAVEN_OPTS - pinpoint_agent=$AGENT_BOOTSTRAP_DIR/pinpoint-bootstrap-$version.jar + pinpoint_agent=$AGENT_BOOTSTRAP_DIR/pinpoint-bootstrap-$version.jar pinpoint_opt="-javaagent:$pinpoint_agent -Dpinpoint.agentId=test-agent -Dpinpoint.applicationName=TESTAPP" export MAVEN_OPTS=$pinpoint_opt + context_path=$( func_read_properties "$KEY_CONTEXT_PATH" ) + if [ "$context_path" == "/" ]; then + context_path="" + fi port=$( func_read_properties "$KEY_PORT" ) - check_url="http://localhost:"$port"/getCurrentTimestamp.pinpoint" + check_url="http://localhost:$port$context_path/getCurrentTimestamp.pinpoint" pid=`nohup ${bin}/../../mvnw -f $TESTAPP_DIR/pom.xml clean package tomcat7:run -D$IDENTIFIER -Dmaven.pinpoint.version=$version >> $LOGS_DIR/$LOG_FILE 2>&1 & echo $!` echo $pid > $PID_DIR/$PID_FILE diff --git a/quickstart/bin/start-web.sh b/quickstart/bin/start-web.sh index 6cacd05cfb37..177123e7eae7 100755 --- a/quickstart/bin/start-web.sh +++ b/quickstart/bin/start-web.sh @@ -38,6 +38,7 @@ CLOSE_WAIT_TIME=`expr $UNIT_TIME \* $CHECK_COUNT` PROPERTIES=`cat $CONF_DIR/$CONF_FILE 2>/dev/null` KEY_VERSION="quickstart.version" +KEY_CONTEXT_PATH="quickstart.web.context.path" KEY_PORT="quickstart.web.port" function func_read_properties @@ -111,37 +112,41 @@ function func_init_log function func_start_pinpoint_web { - version=$( func_read_properties "$KEY_VERSION" ) - port=$( func_read_properties "$KEY_PORT" ) - pid=`nohup ${bin}/../../mvnw -f $WEB_DIR/pom.xml clean package tomcat7:run -D$IDENTIFIER -Dmaven.pinpoint.version=$version > $LOGS_DIR/$LOG_FILE 2>&1 & echo $!` - check_url="http://localhost:"$port"/serverTime.pinpoint" - echo $pid > $PID_DIR/$PID_FILE - - echo "---$WEB_IDENTIFIER initialization started. pid=$pid.---" - - process_status=`curl $check_url 2>/dev/null | grep 'currentServerTime'` - end_count=0 - - while [ -z $process_status ]; do - wait_time=`expr $end_count \* $UNIT_TIME` - echo "starting $WEB_IDENTIFIER. $wait_time /$CLOSE_WAIT_TIME sec(close wait limit)." - - if [ $end_count -ge $CHECK_COUNT ]; then - break - fi - - sleep $UNIT_TIME - end_count=`expr $end_count + 1` - process_status=`curl $check_url 2>/dev/null | grep 'currentServerTime'` - done - - if [ -z $process_status ]; then - echo "---$WEB_IDENTIFIER initialization failed. pid=$pid.---" - kill -9 $pid - else - echo "---$WEB_IDENTIFIER initialization completed. pid=$pid.---" - tail -f $LOGS_DIR/$LOG_FILE - fi + version=$( func_read_properties "$KEY_VERSION" ) + context_path=$( func_read_properties "$KEY_CONTEXT_PATH" ) + if [ "$context_path" == "/" ]; then + context_path="" + fi + port=$( func_read_properties "$KEY_PORT" ) + pid=`nohup ${bin}/../../mvnw -f $WEB_DIR/pom.xml clean package tomcat7:run -D$IDENTIFIER -Dmaven.pinpoint.version=$version > $LOGS_DIR/$LOG_FILE 2>&1 & echo $!` + check_url="http://localhost:$port$context_path/serverTime.pinpoint" + echo $pid > $PID_DIR/$PID_FILE + + echo "---$WEB_IDENTIFIER initialization started. pid=$pid.---" + + process_status=`curl $check_url 2>/dev/null | grep 'currentServerTime'` + end_count=0 + + while [ -z $process_status ]; do + wait_time=`expr $end_count \* $UNIT_TIME` + echo "starting $WEB_IDENTIFIER. $wait_time /$CLOSE_WAIT_TIME sec(close wait limit)." + + if [ $end_count -ge $CHECK_COUNT ]; then + break + fi + + sleep $UNIT_TIME + end_count=`expr $end_count + 1` + process_status=`curl $check_url 2>/dev/null | grep 'currentServerTime'` + done + + if [ -z $process_status ]; then + echo "---$WEB_IDENTIFIER initialization failed. pid=$pid.---" + kill -9 $pid + else + echo "---$WEB_IDENTIFIER initialization completed. pid=$pid.---" + tail -f $LOGS_DIR/$LOG_FILE + fi } func_check_process diff --git a/quickstart/collector/src/main/resources/hbase.properties b/quickstart/collector/src/main/resources/hbase.properties index 6f09e79e7a9a..ed2fbcea6b67 100644 --- a/quickstart/collector/src/main/resources/hbase.properties +++ b/quickstart/collector/src/main/resources/hbase.properties @@ -5,6 +5,9 @@ hbase.client.port=2181 # hbase default:/hbase hbase.zookeeper.znode.parent=/hbase +# hbase namespace to use default:default +hbase.namespace=default + # hbase timeout option================================================================================== # hbase default:true hbase.ipc.client.tcpnodelay=true @@ -31,5 +34,5 @@ hbase.client.async.enable=false hbase.client.async.in.queuesize=10000 # periodic asyncPut ops flush time. default:100 hbase.client.async.flush.period.ms=100 -# the max number of the retry attempts before dropping the request. default:10 -hbase.client.async.max.retries.in.queue=10 \ No newline at end of file +# the max number of the retry attempts to insert queue before dropping the request. default:10000 +hbase.client.async.max.retries.in.queue=10000 \ No newline at end of file diff --git a/quickstart/conf/quickstart.properties b/quickstart/conf/quickstart.properties index f4fcf43e230a..681d764d5b80 100644 --- a/quickstart/conf/quickstart.properties +++ b/quickstart/conf/quickstart.properties @@ -1,6 +1,6 @@ # quickstart properties -quickstart.version=1.7.2-SNAPSHOT +quickstart.version=1.8.1-SNAPSHOT # quickstart-web properties quickstart.web.context.path=/ diff --git a/quickstart/testapp/pom.xml b/quickstart/testapp/pom.xml index 06c39cc196a0..5f233714076e 100644 --- a/quickstart/testapp/pom.xml +++ b/quickstart/testapp/pom.xml @@ -1,3 +1,19 @@ + + 4.0.0 @@ -110,19 +126,14 @@ org.apache.httpcomponents httpclient - 4.3.6 - - - org.apache.httpcomponents - httpcore - 4.3.3 + 4.5.6 com.fasterxml.jackson.core jackson-databind - 2.4.4 + 2.9.7 @@ -149,7 +160,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.5.1 + 3.8.0 ${jdk.version} ${jdk.version} @@ -162,7 +173,7 @@ org.apache.maven.plugins maven-war-plugin - 2.4 + 3.2.2 ${basedir}/target/deploy diff --git a/quickstart/testapp/src/main/webapp/WEB-INF/views/apis.jsp b/quickstart/testapp/src/main/webapp/WEB-INF/views/apis.jsp index 7b4a483c4b35..074a54f51c72 100644 --- a/quickstart/testapp/src/main/webapp/WEB-INF/views/apis.jsp +++ b/quickstart/testapp/src/main/webapp/WEB-INF/views/apis.jsp @@ -16,7 +16,7 @@
${apiMapping.key}
-
${api.mappedUri}
+
${api.mappedUri}
${api.description}
diff --git a/quickstart/web/src/main/resources/hbase.properties b/quickstart/web/src/main/resources/hbase.properties index ac1e4a555505..e2df640e99a5 100644 --- a/quickstart/web/src/main/resources/hbase.properties +++ b/quickstart/web/src/main/resources/hbase.properties @@ -2,6 +2,9 @@ hbase.client.host=localhost hbase.client.port=2181 +# hbase namespace to use default:default +hbase.namespace=default + # hbase timeout option================================================================================== # hbase default:true hbase.ipc.client.tcpnodelay=true diff --git a/quickstart/web/src/main/resources/log4j.xml b/quickstart/web/src/main/resources/log4j.xml index f051c504f4e5..edda859f72ce 100644 --- a/quickstart/web/src/main/resources/log4j.xml +++ b/quickstart/web/src/main/resources/log4j.xml @@ -1,4 +1,20 @@ + + @@ -54,7 +70,11 @@ - + + + + + diff --git a/quickstart/web/src/main/resources/pinpoint-web.properties b/quickstart/web/src/main/resources/pinpoint-web.properties index dd4e39aa2845..62273edece7b 100644 --- a/quickstart/web/src/main/resources/pinpoint-web.properties +++ b/quickstart/web/src/main/resources/pinpoint-web.properties @@ -28,6 +28,7 @@ config.sendUsage=true config.editUserInfo=true config.show.activeThread=true config.show.activeThreadDump=true +config.show.stackTraceOnError=true config.enable.activeThreadDump=true web.hbase.selectSpans.limit=500 @@ -35,21 +36,14 @@ web.hbase.selectAllSpans.limit=500 web.activethread.activeAgent.duration.days=7 -# server map link selector mode = v1 or v2 (default = v1) -web.servermap.selector.mode=v2 - -# server map link creator mode = serial or parallel (default = serial) -# only applicable when web.servermap.selector.mode=v2 -web.servermap.creator.mode=serial -web.servermap.creator.parallel.maxthreads=16 - -# server map builder mode = v1 or v2 (default = v1) -web.servermap.builder.mode=v2 - -# server map appender mode = serial or parallel (default = serial) -# only applicable when web.servermap.builder.mode=v2 -web.servermap.appender.mode=serial -web.servermap.appender.parallel.maxthreads=16 +# number of server map link select worker threads +web.servermap.creator.worker.threadSize=16 +# capacity of server map link select worker queue +web.servermap.creator.worker.queueSize=512 +# number of server node appender worker threads +web.servermap.appender.worker.threadSize=16 +# capacity of server node appender worker queue +web.servermap.appender.worker.queueSize=512 # see RFC 6454: The Web Origin Concept(https://tools.ietf.org/html/rfc6454) for more details # 1. Allow only same origin requests (value : websocket.allowedOrigins=) diff --git a/rpc/clover.license b/rpc/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/rpc/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + + @@ -7,7 +23,7 @@ com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-rpc @@ -65,4 +81,25 @@ + + + + + org.apache.maven.plugins + maven-jar-plugin + ${plugin.jar.version} + + + + false + + + test-jar + + + + + + + \ No newline at end of file diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/PinpointSocket.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/PinpointSocket.java index 32df078d80e1..3846ab3abf02 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/PinpointSocket.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/PinpointSocket.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -34,7 +34,6 @@ public interface PinpointSocket { Future request(byte[] payload); - void response(RequestPacket requestPacket, byte[] payload); void response(int requestId, byte[] payload); ClientStreamChannelContext openStream(byte[] payload, ClientStreamChannelMessageListener messageListener); diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/PipelineFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/PipelineFactory.java new file mode 100644 index 000000000000..d7d7c3823ea8 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/PipelineFactory.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc; + +import org.jboss.netty.channel.ChannelPipeline; + +/** + * @author Taejin Koo + */ +public interface PipelineFactory { + + ChannelPipeline newPipeline(); + +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientChannelFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientChannelFactory.java new file mode 100644 index 000000000000..6cfcbb12772d --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientChannelFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import com.navercorp.pinpoint.common.util.PinpointThreadFactory; +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.channel.socket.nio.BossPool; +import org.jboss.netty.channel.socket.nio.NioClientBossPool; +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +import org.jboss.netty.channel.socket.nio.NioWorkerPool; +import org.jboss.netty.channel.socket.nio.WorkerPool; +import org.jboss.netty.util.ThreadNameDeterminer; +import org.jboss.netty.util.Timer; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClientChannelFactory { + + public ChannelFactory createChannelFactory(int bossCount, int workerCount, Timer timer) { + ExecutorService boss = newCachedThreadPool("Pinpoint-Client-Boss"); + BossPool bossPool = new NioClientBossPool(boss, bossCount, timer, ThreadNameDeterminer.CURRENT); + + ExecutorService worker = newCachedThreadPool("Pinpoint-Client-Worker"); + WorkerPool workerPool = new NioWorkerPool(worker, workerCount, ThreadNameDeterminer.CURRENT); + return new NioClientSocketChannelFactory(bossPool, workerPool); + } + + private ExecutorService newCachedThreadPool(String threadName) { + ThreadFactory threadFactory = new PinpointThreadFactory(threadName, true); + return Executors.newCachedThreadPool(threadFactory); + } +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientCodecPipelineFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientCodecPipelineFactory.java new file mode 100644 index 000000000000..32d05bb82a7f --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientCodecPipelineFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + + +import com.navercorp.pinpoint.rpc.PipelineFactory; +import com.navercorp.pinpoint.rpc.codec.PacketDecoder; +import com.navercorp.pinpoint.rpc.codec.PacketEncoder; + +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.Channels; + +/** + * @author emeroad + * @author koo.taejin + */ +public class ClientCodecPipelineFactory implements PipelineFactory { + + public ClientCodecPipelineFactory() { + } + + @Override + public ChannelPipeline newPipeline() { + ChannelPipeline pipeline = Channels.pipeline(); + pipeline.addLast("encoder", new PacketEncoder()); + pipeline.addLast("decoder", new PacketDecoder()); + + return pipeline; + } +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientHandlerFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientHandlerFactory.java new file mode 100644 index 000000000000..5c1d4a8f532c --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientHandlerFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import org.jboss.netty.util.Timer; + +/** + * @author Woonduk Kang(emeroad) + */ +interface ClientHandlerFactory { + + PinpointClientHandler newClientHandler(ConnectionFactory connectionFactory, SocketAddressProvider remoteAddressProvider, Timer timer, boolean reconnect); +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientOption.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientOption.java new file mode 100644 index 000000000000..2c63347e107a --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ClientOption.java @@ -0,0 +1,139 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import com.navercorp.pinpoint.common.util.Assert; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ClientOption { + + // it's better to be a long value. even though keeping ping period from client to server short, + // disconnection between them dose not be detected quickly. + // rather keeping it from server to client short help detect disconnection as soon as possible. + static final long DEFAULT_PING_DELAY = 60 * 1000 * 5; + static final long DEFAULT_ENABLE_WORKER_PACKET_DELAY = 60 * 1000 * 1; + static final long DEFAULT_WRITE_TIMEOUT_MILLIS = 3 * 1000; + static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = 3 * 1000; + + private final long reconnectDelay; + private final long pingDelay; + private final long enableWorkerPacketDelay; + private final long writeTimeoutMillis; + private final long requestTimeoutMillis; + + private ClientOption(long reconnectDelay, long pingDelay, long enableWorkerPacketDelay, long writeTimeoutMillis, long requestTimeoutMillis) { + this.reconnectDelay = reconnectDelay; + this.pingDelay = pingDelay; + this.enableWorkerPacketDelay = enableWorkerPacketDelay; + this.writeTimeoutMillis = writeTimeoutMillis; + this.requestTimeoutMillis = requestTimeoutMillis; + } + + public long getReconnectDelay() { + return reconnectDelay; + } + + public long getPingDelay() { + return pingDelay; + } + + public long getEnableWorkerPacketDelay() { + return enableWorkerPacketDelay; + } + + public long getWriteTimeoutMillis() { + return writeTimeoutMillis; + } + + public long getRequestTimeoutMillis() { + return requestTimeoutMillis; + } + + @Override + public String toString() { + return "ClientOption{" + + "reconnectDelay=" + reconnectDelay + + ", pingDelay=" + pingDelay + + ", enableWorkerPacketDelay=" + enableWorkerPacketDelay + + ", writeTimeoutMillis=" + writeTimeoutMillis + + ", requestTimeoutMillis=" + requestTimeoutMillis + + '}'; + } + + public static class Builder { + private long reconnectDelay = 3 * 1000; + private long pingDelay = DEFAULT_PING_DELAY; + private long enableWorkerPacketDelay = DEFAULT_ENABLE_WORKER_PACKET_DELAY; + private long writeTimeoutMillis = DEFAULT_WRITE_TIMEOUT_MILLIS; + private long requestTimeoutMillis = DEFAULT_REQUEST_TIMEOUT_MILLIS; + + public long getReconnectDelay() { + return reconnectDelay; + } + + public void setReconnectDelay(long reconnectDelay) { + if (reconnectDelay < 0) { + throw new IllegalArgumentException("reconnectDelay cannot be a negative number"); + } + this.reconnectDelay = reconnectDelay; + } + + public long getPingDelay() { + return pingDelay; + } + + public void setPingDelay(long pingDelay) { + if (pingDelay < 0) { + throw new IllegalArgumentException("pingDelay cannot be a negative number"); + } + this.pingDelay = pingDelay; + } + + public long getEnableWorkerPacketDelay() { + return enableWorkerPacketDelay; + } + + public void setEnableWorkerPacketDelay(long enableWorkerPacketDelay) { + this.enableWorkerPacketDelay = enableWorkerPacketDelay; + } + + public long getWriteTimeoutMillis() { + return writeTimeoutMillis; + } + + public void setWriteTimeoutMillis(long writeTimeoutMillis) { + Assert.isTrue(writeTimeoutMillis >= 0, "writeTimeoutMillis cannot be a negative number"); + this.writeTimeoutMillis = writeTimeoutMillis; + } + + public long getRequestTimeoutMillis() { + return requestTimeoutMillis; + } + + public void setRequestTimeoutMillis(long requestTimeoutMillis) { + Assert.isTrue(requestTimeoutMillis >= 0, "requestTimeoutMillis cannot be a negative number"); + this.requestTimeoutMillis = requestTimeoutMillis; + } + + public ClientOption build() { + return new ClientOption(this.reconnectDelay, pingDelay, enableWorkerPacketDelay, writeTimeoutMillis, requestTimeoutMillis); + } + } + +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/Closed.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/Closed.java new file mode 100644 index 000000000000..e0f643a6c97b --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/Closed.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author Woonduk Kang(emeroad) + */ +public class Closed { + + private final AtomicBoolean close = new AtomicBoolean(false); + + public Closed() { + } + + public boolean isClosed() { + return close.get(); + } + + public boolean close() { + return close.compareAndSet(false, true); + } +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectFuture.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectFuture.java index d6b1be7ddf8e..0105ded3cbc2 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectFuture.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectFuture.java @@ -65,12 +65,13 @@ public boolean await(long timeout, TimeUnit timeUnit) throws InterruptedExceptio } public void awaitUninterruptibly() { - while (true) { + while (getResult() == null) { try { await(); return; } catch (InterruptedException e) { logger.debug(e.getMessage(), e); + Thread.currentThread().interrupt(); } } } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/Connection.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/Connection.java new file mode 100644 index 000000000000..652ffd4f2724 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/Connection.java @@ -0,0 +1,133 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.PinpointSocketException; +import com.navercorp.pinpoint.rpc.PipelineFactory; +import com.navercorp.pinpoint.rpc.util.TimerFactory; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelHandler; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.SimpleChannelHandler; +import org.jboss.netty.handler.timeout.WriteTimeoutHandler; +import org.jboss.netty.util.HashedWheelTimer; +import org.jboss.netty.util.Timer; + +import java.net.SocketAddress; +import java.util.concurrent.TimeUnit; + +/** + * @author Woonduk Kang(emeroad) + */ +public class Connection { + private final ConnectionFactory connectionFactory; + private final SocketOption socketOption; + + private final ChannelFactory channelFactory; + + private final ClientHandlerFactory clientHandlerFactory; + + private PinpointClientHandler pinpointClientHandler; + private ChannelFuture connectFuture; + + public Connection(ConnectionFactory connectionFactory, SocketOption socketOption, ChannelFactory channelFactory, ClientHandlerFactory clientHandlerFactory) { + this.connectionFactory = Assert.requireNonNull(connectionFactory, "connectionFactory must not be null"); + + this.socketOption = Assert.requireNonNull(socketOption, "socketOption must not be null"); + + this.channelFactory = Assert.requireNonNull(channelFactory, "channelFactory must not be null"); + this.clientHandlerFactory = Assert.requireNonNull(clientHandlerFactory, "clientHandlerFactory must not be null"); + } + + void connect(SocketAddressProvider remoteAddressProvider, boolean reconnect, PipelineFactory pipelineFactory) { + Assert.requireNonNull(remoteAddressProvider, "remoteAddress must not be null"); + + final ChannelPipeline pipeline = pipelineFactory.newPipeline(); + + Timer channelTimer = createTimer("Pinpoint-PinpointClientHandler-Timer"); + final ChannelHandler writeTimeout = new WriteTimeoutHandler(channelTimer, 3000, TimeUnit.MILLISECONDS); + pipeline.addLast("writeTimeout", writeTimeout); + + this.pinpointClientHandler = this.clientHandlerFactory.newClientHandler(connectionFactory, remoteAddressProvider, channelTimer, reconnect); + if (pinpointClientHandler instanceof SimpleChannelHandler) { + pipeline.addLast("socketHandler", (SimpleChannelHandler) this.pinpointClientHandler); + } else { + throw new IllegalArgumentException("invalid pinpointClientHandler"); + } + + final SocketAddress remoteAddress = remoteAddressProvider.resolve(); + this.connectFuture = connect0(remoteAddress, pipeline); + } + + private ChannelFuture connect0(SocketAddress remoteAddress, ChannelPipeline pipeline) { + final Channel channel = newChannel(pipeline); + // Connect. + return channel.connect(remoteAddress); + } + + private Channel newChannel(ChannelPipeline pipeline) { + // Set the options. + final Channel ch = this.channelFactory.newChannel(pipeline); + boolean success = false; + try { + ch.getConfig().setOptions(socketOption.toMap()); + success = true; + } finally { + if (!success) { + ch.close(); + } + } + return ch; + } + + + public ChannelFuture getConnectFuture() { + return connectFuture; + } + + public PinpointClientHandler getPinpointClientHandler() { + return pinpointClientHandler; + } + + private static Timer createTimer(String timerName) { + HashedWheelTimer timer = TimerFactory.createHashedWheelTimer(timerName, 100, TimeUnit.MILLISECONDS, 512); + timer.start(); + return timer; + } + + + private PinpointClientHandler awaitConnected0() { + ConnectFuture handlerConnectFuture = pinpointClientHandler.getConnectFuture(); + handlerConnectFuture.awaitUninterruptibly(); + + if (ConnectFuture.Result.FAIL == handlerConnectFuture.getResult()) { + SocketAddress remoteAddress = connectFuture.getChannel().getRemoteAddress(); + throw new PinpointSocketException("connect fail to " + remoteAddress + ".", connectFuture.getCause()); + } + + return pinpointClientHandler; + } + + public PinpointClient awaitConnected() { + PinpointClientHandler pinpointClientHandler = awaitConnected0(); + PinpointClient pinpointClient = new DefaultPinpointClient(pinpointClientHandler); + return pinpointClient; + } +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectionFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectionFactory.java new file mode 100644 index 000000000000..d052bb6a4375 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectionFactory.java @@ -0,0 +1,137 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.PipelineFactory; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelFutureListener; +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.Timer; +import org.jboss.netty.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.TimeUnit; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ConnectionFactory { + private final Timer connectTimer; + private final Closed closed; + private final ChannelFactory channelFactory; + private final ClientHandlerFactory clientHandlerFactory; + private final SocketOption socketOption; + private final ClientOption clientOption; + private final PipelineFactory pipelineFactory; + + ConnectionFactory(Timer connectTimer, Closed closed, ChannelFactory channelFactory, + SocketOption socketOption, ClientOption clientOption, ClientHandlerFactory clientHandlerFactory, PipelineFactory pipelineFactory) { + + this.connectTimer = Assert.requireNonNull(connectTimer, "connectTimer must not be null"); + this.closed = Assert.requireNonNull(closed, "release must not be null"); + + this.channelFactory = Assert.requireNonNull(channelFactory, "channelFactory must not be null"); + + this.socketOption = Assert.requireNonNull(socketOption, "option must not be null"); + this.clientOption = Assert.requireNonNull(clientOption, "connectTimer must not be null"); + this.clientHandlerFactory = Assert.requireNonNull(clientHandlerFactory, "clientHandlerFactory must not be null"); + this.pipelineFactory = Assert.requireNonNull(pipelineFactory, "pipelineFactory must not be null"); + } + + public boolean isClosed() { + return closed.isClosed(); + } + + public Connection connect(SocketAddressProvider remoteAddressProvider, boolean reconnect) { + Connection connection = new Connection(this, this.socketOption, this.channelFactory, clientHandlerFactory); + connection.connect(remoteAddressProvider, reconnect, pipelineFactory); + return connection; + } + + public void reconnect(final PinpointClient pinpointClient, final SocketAddressProvider socketAddressProvider) { + ConnectEvent connectEvent = new ConnectEvent(this, socketAddressProvider, pinpointClient); + this.connectTimer.newTimeout(connectEvent, clientOption.getReconnectDelay(), TimeUnit.MILLISECONDS); + } + + private static class ConnectEvent implements TimerTask { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final ConnectionFactory connectionFactory; + private final SocketAddressProvider socketAddressProvider; + + private final PinpointClient pinpointClient; + + + private ConnectEvent(ConnectionFactory connectionFactory, SocketAddressProvider socketAddressProvider, PinpointClient pinpointClient) { + this.connectionFactory = Assert.requireNonNull(connectionFactory, "connectionFactory must not be null"); + this.socketAddressProvider = Assert.requireNonNull(socketAddressProvider, "socketAddressProvider must not be null"); + this.pinpointClient = Assert.requireNonNull(pinpointClient, "pinpointClient must not be null"); + } + + @Override + public void run(Timeout timeout) { + if (timeout.isCancelled()) { + return; + } + + // Just return not to try reconnection when event has been fired but pinpointClient already closed. + if (pinpointClient.isClosed()) { + logger.debug("pinpointClient is already closed."); + return; + } + logger.warn("try reconnect. connectAddress:{}", socketAddressProvider); + + final Connection connection = connectionFactory.connect(socketAddressProvider, true); + + final PinpointClientHandler pinpointClientHandler = connection.getPinpointClientHandler(); + pinpointClientHandler.setPinpointClient(pinpointClient); + + ChannelFuture channelFuture = connection.getConnectFuture(); + channelFuture.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + Channel channel = future.getChannel(); + logger.info("reconnect success {}, {}", socketAddressProvider, channel); + pinpointClient.reconnectSocketHandler(pinpointClientHandler); + } else { + if (!pinpointClient.isClosed()) { + + /* + // comment out because exception message can be taken at exceptionCaught + if (logger.isWarnEnabled()) { + Throwable cause = future.getCause(); + logger.warn("reconnect fail. {} Caused:{}", socketAddress, cause.getMessage()); + } + */ + connectionFactory.reconnect(pinpointClient, socketAddressProvider); + } else { + logger.info("pinpointClient is closed. stop reconnect."); + } + } + } + }); + + + } + } +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectionFactoryProvider.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectionFactoryProvider.java new file mode 100644 index 000000000000..a4a4698c965b --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ConnectionFactoryProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.util.Timer; + +/** + * @author Taejin Koo + */ +public interface ConnectionFactoryProvider { + + /** + * it can be changed. + * If possible, do not implement below method. + */ + ConnectionFactory get(Timer connectTimer, Closed closed, ChannelFactory channelFactory, + SocketOption socketOption, ClientOption clientOption, ClientHandlerFactory clientHandlerFactory); + +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultConnectionFactoryProvider.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultConnectionFactoryProvider.java new file mode 100644 index 000000000000..622c863b6bf6 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultConnectionFactoryProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.PipelineFactory; +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.util.Timer; + +/** + * @author Taejin Koo + */ +public class DefaultConnectionFactoryProvider implements ConnectionFactoryProvider { + + private final PipelineFactory pipelineFactory; + + public DefaultConnectionFactoryProvider(PipelineFactory pipelineFactory) { + this.pipelineFactory = Assert.requireNonNull(pipelineFactory, "pipelineFactory must not be null"); + } + + @Override + public ConnectionFactory get(Timer connectTimer, Closed closed, ChannelFactory channelFactory, SocketOption socketOption, ClientOption clientOption, ClientHandlerFactory clientHandlerFactory) { + return new ConnectionFactory(connectTimer, closed, channelFactory, socketOption, clientOption, clientHandlerFactory, pipelineFactory); + } + +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClient.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClient.java index 3bf789710b81..8e0054993154 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClient.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,14 +47,8 @@ public class DefaultPinpointClient implements PinpointClient { private List reconnectEventListeners = new CopyOnWriteArrayList(); - public DefaultPinpointClient() { - this(new ReconnectStateClientHandler()); - } - - public DefaultPinpointClient(PinpointClientHandler pinpointClientHandler) { - Assert.requireNonNull(pinpointClientHandler, "pinpointClientHandler"); - - this.pinpointClientHandler = pinpointClientHandler; + public DefaultPinpointClient(PinpointClientHandler pinpointClientHandler) { + this.pinpointClientHandler = Assert.requireNonNull(pinpointClientHandler, "pinpointClientHandler"); pinpointClientHandler.setPinpointClient(this); } @@ -129,10 +123,6 @@ public Future request(byte[] bytes) { return pinpointClientHandler.request(bytes); } - @Override - public void response(RequestPacket requestPacket, byte[] payload) { - response(requestPacket.getRequestId(), payload); - } @Override public void response(int requestId, byte[] payload) { diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientFactory.java index 4309ff560fb3..b87a448c9ae0 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientFactory.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientFactory.java @@ -17,7 +17,6 @@ package com.navercorp.pinpoint.rpc.client; import com.navercorp.pinpoint.common.util.Assert; -import com.navercorp.pinpoint.common.util.PinpointThreadFactory; import com.navercorp.pinpoint.rpc.MessageListener; import com.navercorp.pinpoint.rpc.PinpointSocketException; import com.navercorp.pinpoint.rpc.StateChangeEventListener; @@ -27,20 +26,11 @@ import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelMessageListener; import com.navercorp.pinpoint.rpc.util.LoggerFactorySetup; import com.navercorp.pinpoint.rpc.util.TimerFactory; -import org.jboss.netty.bootstrap.ClientBootstrap; -import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; -import org.jboss.netty.channel.ChannelFutureListener; -import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.channel.ChannelPipelineException; -import org.jboss.netty.channel.socket.nio.NioClientBossPool; -import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; -import org.jboss.netty.channel.socket.nio.NioWorkerPool; import org.jboss.netty.util.HashedWheelTimer; -import org.jboss.netty.util.ThreadNameDeterminer; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; -import org.jboss.netty.util.TimerTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,11 +38,10 @@ import java.net.SocketAddress; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -62,27 +51,20 @@ public class DefaultPinpointClientFactory implements PinpointClientFactory { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public static final String CONNECT_TIMEOUT_MILLIS = "connectTimeoutMillis"; - private static final int DEFAULT_CONNECT_TIMEOUT = 5000; - private static final long DEFAULT_TIMEOUT_MILLIS = 3 * 1000; - private static final long DEFAULT_PING_DELAY = 60 * 1000 * 5; - private static final long DEFAULT_ENABLE_WORKER_PACKET_DELAY = 60 * 1000 * 1; - private final AtomicInteger socketId = new AtomicInteger(1); - private volatile boolean released; - private ClientBootstrap bootstrap; + private final Closed closed = new Closed(); + + private final ChannelFactory channelFactory; + private final SocketOption.Builder socketOptionBuilder; + private Map properties = Collections.emptyMap(); - private long reconnectDelay = 3 * 1000; private final Timer timer; - // it's better to be a long value. even though keeping ping period from client to server short, - // disconnection between them dose not be detected quickly. - // rather keeping it from server to client short help detect disconnection as soon as possible. - private long pingDelay = DEFAULT_PING_DELAY; - private long enableWorkerPacketDelay = DEFAULT_ENABLE_WORKER_PACKET_DELAY; - private long timeoutMillis = DEFAULT_TIMEOUT_MILLIS; + private final ConnectionFactoryProvider connectionFactoryProvider; + + private final ClientOption.Builder clientOptionBuilder = new ClientOption.Builder(); private ClusterOption clusterOption = ClusterOption.DISABLE_CLUSTER_OPTION; @@ -99,289 +81,172 @@ public DefaultPinpointClientFactory() { this(1, 1); } + public DefaultPinpointClientFactory(ConnectionFactoryProvider connectionFactoryProvider) { + this(1, 1, connectionFactoryProvider); + } + public DefaultPinpointClientFactory(int bossCount, int workerCount) { + this(bossCount, workerCount, new DefaultConnectionFactoryProvider(new ClientCodecPipelineFactory())); + } + + public DefaultPinpointClientFactory(int bossCount, int workerCount, ConnectionFactoryProvider connectionFactoryProvider) { if (bossCount < 1) { throw new IllegalArgumentException("bossCount is negative: " + bossCount); } // create a timer earlier because it is used for connectTimeout - Timer timer = createTimer(); - ClientBootstrap bootstrap = createBootStrap(bossCount, workerCount, timer); - setOptions(bootstrap); - addPipeline(bootstrap); - - this.bootstrap = bootstrap; - this.timer = timer; + this.timer = createTimer("Pinpoint-SocketFactory-Timer"); + final ClientChannelFactory channelFactory = new ClientChannelFactory(); + logger.debug("createBootStrap boss:{}, worker:{}", bossCount, workerCount); + this.channelFactory = channelFactory.createChannelFactory(bossCount, workerCount, timer); + this.socketOptionBuilder = new SocketOption.Builder(); + this.connectionFactoryProvider = Assert.requireNonNull(connectionFactoryProvider, "connectionFactoryProvider must not be null"); } - private Timer createTimer() { - HashedWheelTimer timer = TimerFactory.createHashedWheelTimer("Pinpoint-SocketFactory-Timer", 100, TimeUnit.MILLISECONDS, 512); + private static Timer createTimer(String timerName) { + HashedWheelTimer timer = TimerFactory.createHashedWheelTimer(timerName, 100, TimeUnit.MILLISECONDS, 512); timer.start(); return timer; } - private void addPipeline(ClientBootstrap bootstrap) { - PinpointClientPipelineFactory pinpointClientPipelineFactory = new PinpointClientPipelineFactory(this); - bootstrap.setPipelineFactory(pinpointClientPipelineFactory); - } - - private void setOptions(ClientBootstrap bootstrap) { - // connectTimeout - bootstrap.setOption(CONNECT_TIMEOUT_MILLIS, DEFAULT_CONNECT_TIMEOUT); - // read write timeout needed? isn't it needed because of nio? - - // tcp setting - bootstrap.setOption("tcpNoDelay", true); - bootstrap.setOption("keepAlive", true); - // buffer setting - bootstrap.setOption("sendBufferSize", 1024 * 64); - bootstrap.setOption("receiveBufferSize", 1024 * 64); - - } - public void setConnectTimeout(int connectTimeout) { - if (connectTimeout < 0) { - throw new IllegalArgumentException("connectTimeout cannot be a negative number"); - } - bootstrap.setOption(CONNECT_TIMEOUT_MILLIS, connectTimeout); + this.socketOptionBuilder.setConnectTimeout(connectTimeout); } public int getConnectTimeout() { - return (Integer) bootstrap.getOption(CONNECT_TIMEOUT_MILLIS); + return socketOptionBuilder.getConnectTimeout(); } public long getReconnectDelay() { - return reconnectDelay; + return clientOptionBuilder.getReconnectDelay(); } public void setReconnectDelay(long reconnectDelay) { - if (reconnectDelay < 0) { - throw new IllegalArgumentException("reconnectDelay cannot be a negative number"); - } - this.reconnectDelay = reconnectDelay; + this.clientOptionBuilder.setReconnectDelay(reconnectDelay); } public long getPingDelay() { - return pingDelay; + return this.clientOptionBuilder.getPingDelay(); } public void setPingDelay(long pingDelay) { - if (pingDelay < 0) { - throw new IllegalArgumentException("pingDelay cannot be a negative number"); - } - this.pingDelay = pingDelay; + this.clientOptionBuilder.setPingDelay(pingDelay); } public long getEnableWorkerPacketDelay() { - return enableWorkerPacketDelay; + return this.clientOptionBuilder.getEnableWorkerPacketDelay(); } public void setEnableWorkerPacketDelay(long enableWorkerPacketDelay) { - if (enableWorkerPacketDelay < 0) { - throw new IllegalArgumentException("EnableWorkerPacketDelay cannot be a negative number"); - } - this.enableWorkerPacketDelay = enableWorkerPacketDelay; + this.clientOptionBuilder.setEnableWorkerPacketDelay(enableWorkerPacketDelay); } - public long getTimeoutMillis() { - return timeoutMillis; + @Override + public long getWriteTimeoutMillis() { + return this.clientOptionBuilder.getWriteTimeoutMillis(); } - public void setTimeoutMillis(long timeoutMillis) { - if (timeoutMillis < 0) { - throw new IllegalArgumentException("timeoutMillis cannot be a negative number"); - } - this.timeoutMillis = timeoutMillis; + @Override + public void setWriteTimeoutMillis(long writeTimeoutMillis) { + this.clientOptionBuilder.setWriteTimeoutMillis(writeTimeoutMillis); } - private ClientBootstrap createBootStrap(int bossCount, int workerCount, Timer timer) { - // profiler, collector, - logger.debug("createBootStrap boss:{}, worker:{}", bossCount, workerCount); - NioClientSocketChannelFactory nioClientSocketChannelFactory = createChannelFactory(bossCount, workerCount, timer); - return new ClientBootstrap(nioClientSocketChannelFactory); + @Override + public long getRequestTimeoutMillis() { + return this.clientOptionBuilder.getRequestTimeoutMillis(); } - private NioClientSocketChannelFactory createChannelFactory(int bossCount, int workerCount, Timer timer) { - ExecutorService boss = Executors.newCachedThreadPool(new PinpointThreadFactory("Pinpoint-Client-Boss", true)); - NioClientBossPool bossPool = new NioClientBossPool(boss, bossCount, timer, ThreadNameDeterminer.CURRENT); - - ExecutorService worker = Executors.newCachedThreadPool(new PinpointThreadFactory("Pinpoint-Client-Worker", true)); - NioWorkerPool workerPool = new NioWorkerPool(worker, workerCount, ThreadNameDeterminer.CURRENT); - return new NioClientSocketChannelFactory(bossPool, workerPool); + @Override + public void setRequestTimeoutMillis(long requestTimeoutMillis) { + this.clientOptionBuilder.setRequestTimeoutMillis(requestTimeoutMillis); } public PinpointClient connect(String host, int port) throws PinpointSocketException { - InetSocketAddress connectAddress = new InetSocketAddress(host, port); - return connect(connectAddress); + SocketAddressProvider socketAddressProvider = new DnsSocketAddressProvider(host, port); + return connect(socketAddressProvider); } + @Deprecated public PinpointClient connect(InetSocketAddress connectAddress) throws PinpointSocketException { - ChannelFuture connectFuture = bootstrap.connect(connectAddress); - PinpointClientHandler pinpointClientHandler = getSocketHandler(connectFuture, connectAddress); - - PinpointClient pinpointClient = new DefaultPinpointClient(pinpointClientHandler); - traceSocket(pinpointClient); - return pinpointClient; + SocketAddressProvider socketAddressProvider = new StaticSocketAddressProvider(connectAddress); + return connect(socketAddressProvider); } - /* - trace mechanism is needed in case of calling close without closing socket - it is okay to make that later because this is a exceptional case. - */ - private void traceSocket(PinpointClient pinpointClient) { - + public PinpointClient connect(SocketAddressProvider socketAddressProvider) throws PinpointSocketException { + Connection connection = connectInternal(socketAddressProvider, false); + return connection.awaitConnected(); } - public PinpointClient scheduledConnect(String host, int port) { - InetSocketAddress connectAddress = new InetSocketAddress(host, port); - return scheduledConnect(connectAddress); - } - public PinpointClient scheduledConnect(InetSocketAddress connectAddress) { - PinpointClient pinpointClient = new DefaultPinpointClient(new ReconnectStateClientHandler()); - reconnect(pinpointClient, connectAddress); - return pinpointClient; + private Connection connectInternal(SocketAddressProvider socketAddressProvider, boolean reconnect) { + final ConnectionFactory connectionFactory = createConnectionFactory(); + return connectionFactory.connect(socketAddressProvider, reconnect); } - PinpointClientHandler getSocketHandler(ChannelFuture channelConnectFuture, SocketAddress address) { - if (address == null) { - throw new NullPointerException("address"); - } + private ConnectionFactory createConnectionFactory() { + final ClientOption clientOption = clientOptionBuilder.build(); + final ClusterOption clusterOption = ClusterOption.copy(this.clusterOption); - PinpointClientHandler pinpointClientHandler = getSocketHandler(channelConnectFuture.getChannel()); - pinpointClientHandler.setConnectSocketAddress(address); + final MessageListener messageListener = this.getMessageListener(SimpleMessageListener.INSTANCE); + final ServerStreamChannelMessageListener serverStreamChannelMessageListener = this.getServerStreamChannelMessageListener(DisabledServerStreamChannelMessageListener.INSTANCE); + final List stateChangeEventListeners = this.getStateChangeEventListeners(); - ConnectFuture handlerConnectFuture = pinpointClientHandler.getConnectFuture(); - handlerConnectFuture.awaitUninterruptibly(); + Map copyProperties = new HashMap(this.properties); + final HandshakerFactory handshakerFactory = new HandshakerFactory(socketId, copyProperties, clientOption, clusterOption); + final ClientHandlerFactory clientHandlerFactory = new DefaultPinpointClientHandlerFactory(clientOption, clusterOption, handshakerFactory, + messageListener, serverStreamChannelMessageListener, stateChangeEventListeners); - if (ConnectFuture.Result.FAIL == handlerConnectFuture.getResult()) { - throw new PinpointSocketException("connect fail to " + address + ".", channelConnectFuture.getCause()); - } + final SocketOption socketOption = this.socketOptionBuilder.build(); - return pinpointClientHandler; + return connectionFactoryProvider.get(timer, this.closed, this.channelFactory, socketOption, clientOption, clientHandlerFactory); } - public ChannelFuture reconnect(final SocketAddress remoteAddress) { - if (remoteAddress == null) { - throw new NullPointerException("remoteAddress"); - } - - ChannelPipeline pipeline; - final ClientBootstrap bootstrap = this.bootstrap; - try { - pipeline = bootstrap.getPipelineFactory().getPipeline(); - } catch (Exception e) { - throw new ChannelPipelineException("Failed to initialize a pipeline.", e); - } - PinpointClientHandler pinpointClientHandler = (DefaultPinpointClientHandler) pipeline.getLast(); - pinpointClientHandler.initReconnect(); - - - // Set the options. - Channel ch = bootstrap.getFactory().newChannel(pipeline); - boolean success = false; - try { - ch.getConfig().setOptions(bootstrap.getOptions()); - success = true; - } finally { - if (!success) { - ch.close(); - } - } - - // Connect. - return ch.connect(remoteAddress); + @Override + public PinpointClient scheduledConnect(String host, int port) { + SocketAddressProvider socketAddressProvider = new DnsSocketAddressProvider(host, port); + return scheduledConnect(socketAddressProvider); } - public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) { - return this.timer.newTimeout(task, delay, unit); + @Deprecated + public PinpointClient scheduledConnect(InetSocketAddress connectAddress) { + SocketAddressProvider socketAddressProvider = new StaticSocketAddressProvider(connectAddress); + return scheduledConnect(socketAddressProvider); } + @Override + public PinpointClient scheduledConnect(SocketAddressProvider socketAddressProvider) { + Assert.requireNonNull(socketAddressProvider, "socketAddressProvider must not be null"); - private PinpointClientHandler getSocketHandler(Channel channel) { - return (PinpointClientHandler) channel.getPipeline().getLast(); - } - - void reconnect(final PinpointClient pinpointClient, final SocketAddress socketAddress) { - DefaultPinpointClientFactory.ConnectEvent connectEvent = new DefaultPinpointClientFactory.ConnectEvent(pinpointClient, socketAddress); - timer.newTimeout(connectEvent, reconnectDelay, TimeUnit.MILLISECONDS); + PinpointClient pinpointClient = new DefaultPinpointClient(new ReconnectStateClientHandler()); + ConnectionFactory connectionFactory = createConnectionFactory(); + connectionFactory.reconnect(pinpointClient, socketAddressProvider); + return pinpointClient; } - private class ConnectEvent implements TimerTask { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - private final PinpointClient pinpointClient; - private final SocketAddress socketAddress; - - private ConnectEvent(PinpointClient pinpointClient, SocketAddress socketAddress) { - if (pinpointClient == null) { - throw new NullPointerException("pinpointClient must not be null"); - } - if (socketAddress == null) { - throw new NullPointerException("socketAddress must not be null"); - } - - this.pinpointClient = pinpointClient; - this.socketAddress = socketAddress; - } - @Override - public void run(Timeout timeout) { - if (timeout.isCancelled()) { - return; - } - - // Just return not to try reconnection when event has been fired but pinpointClient already closed. - if (pinpointClient.isClosed()) { - logger.debug("pinpointClient is already closed."); - return; - } - - logger.warn("try reconnect. connectAddress:{}", socketAddress); - final ChannelFuture channelFuture = reconnect(socketAddress); - Channel channel = channelFuture.getChannel(); - final PinpointClientHandler pinpointClientHandler = getSocketHandler(channel); - pinpointClientHandler.setConnectSocketAddress(socketAddress); - pinpointClientHandler.setPinpointClient(pinpointClient); - - channelFuture.addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (future.isSuccess()) { - Channel channel = future.getChannel(); - logger.info("reconnect success {}, {}", socketAddress, channel); - pinpointClient.reconnectSocketHandler(pinpointClientHandler); - } else { - if (!pinpointClient.isClosed()) { - - /* - // comment out because exception message can be taken at exceptionCaught - if (logger.isWarnEnabled()) { - Throwable cause = future.getCause(); - logger.warn("reconnect fail. {} Caused:{}", socketAddress, cause.getMessage()); - } - */ - reconnect(pinpointClient, socketAddress); - } else { - logger.info("pinpointClient is closed. stop reconnect."); - } - } - } - }); + @Deprecated + public ChannelFuture reconnect(final SocketAddress remoteAddress) { + if (!(remoteAddress instanceof InetSocketAddress)) { + throw new IllegalArgumentException("invalid remoteAddress:" + remoteAddress); } + SocketAddressProvider socketAddressProvider = new StaticSocketAddressProvider((InetSocketAddress) remoteAddress); + Connection connection = connectInternal(socketAddressProvider, true); + return connection.getConnectFuture(); } public void release() { - synchronized (this) { - if (released) { - return; - } - released = true; + if (this.closed.isClosed()) { + return; + } + if (!this.closed.close()) { + return; } - if (bootstrap != null) { - bootstrap.releaseExternalResources(); + + final ChannelFactory channelFactory = this.channelFactory; + if (channelFactory != null) { + channelFactory.releaseExternalResources(); } Set stop = this.timer.stop(); if (!stop.isEmpty()) { @@ -391,14 +256,10 @@ public void release() { // stop, cancel something? } - Map getProperties() { - return properties; - } - public void setProperties(Map agentProperties) { Assert.requireNonNull(properties, "agentProperties must not be null"); - this.properties = Collections.unmodifiableMap(agentProperties); + this.properties = new HashMap(agentProperties); } public ClusterOption getClusterOption() { @@ -457,11 +318,7 @@ public void addStateChangeEventListener(StateChangeEventListener stateChangeEven this.stateChangeEventListeners.add(stateChangeEventListener); } - boolean isReleased() { - return released; - } - - int issueNewSocketId() { + private int nextSocketId() { return socketId.getAndIncrement(); } } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientHandler.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientHandler.java index 371cd4e2338d..4905397e3e75 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientHandler.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientHandler.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.rpc.client; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.rpc.*; import com.navercorp.pinpoint.rpc.client.ConnectFuture.Result; import com.navercorp.pinpoint.rpc.cluster.ClusterOption; @@ -26,9 +27,7 @@ import com.navercorp.pinpoint.rpc.stream.*; import com.navercorp.pinpoint.rpc.util.ClassUtils; import com.navercorp.pinpoint.rpc.util.IDGenerator; -import com.navercorp.pinpoint.rpc.util.TimerFactory; import org.jboss.netty.channel.*; -import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; @@ -36,8 +35,7 @@ import org.slf4j.LoggerFactory; import java.net.SocketAddress; -import java.util.HashMap; -import java.util.Map; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -48,79 +46,66 @@ */ public class DefaultPinpointClientHandler extends SimpleChannelHandler implements PinpointClientHandler { - private static final long DEFAULT_PING_DELAY = 60 * 1000 * 5; - private static final long DEFAULT_TIMEOUT_MILLIS = 3 * 1000; - - private static final long DEFAULT_ENABLE_WORKER_PACKET_DELAY = 60 * 1000 * 1; - private static final int DEFAULT_ENABLE_WORKER_PACKET_RETRY_COUNT = Integer.MAX_VALUE; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final int socketId; private final AtomicInteger pingIdGenerator; private final PinpointClientHandlerState state; + private final SocketAddressProvider socketAddressProvider; private volatile Channel channel; - - private long timeoutMillis = DEFAULT_TIMEOUT_MILLIS; - private long pingDelay = DEFAULT_PING_DELAY; - - private int maxHandshakeCount = DEFAULT_ENABLE_WORKER_PACKET_RETRY_COUNT; - + + private final Timer channelTimer; - private final DefaultPinpointClientFactory clientFactory; - private SocketAddress connectSocketAddress; + private final ConnectionFactory connectionFactory; private volatile PinpointClient pinpointClient; private final MessageListener messageListener; private final ServerStreamChannelMessageListener serverStreamChannelMessageListener; - + private final RequestManager requestManager; private final ChannelFutureListener pingWriteFailFutureListener = new WriteFailFutureListener(this.logger, "ping write fail.", "ping write success."); private final ChannelFutureListener sendWriteFailFutureListener = new WriteFailFutureListener(this.logger, "send() write fail.", "send() write success."); private final ChannelFutureListener sendClosePacketFailFutureListener = new WriteFailFutureListener(this.logger, "sendClosedPacket() write fail.", "sendClosedPacket() write success."); - + private final PinpointClientHandshaker handshaker; - + private final ConnectFuture connectFuture = new ConnectFuture(); - - private final String objectUniqName; + private final String objectUniqName; + private final ClientOption clientOption; private final ClusterOption localClusterOption; - private ClusterOption remoteClusterOption = ClusterOption.DISABLE_CLUSTER_OPTION; - - public DefaultPinpointClientHandler(DefaultPinpointClientFactory clientFactory) { - this(clientFactory, DEFAULT_PING_DELAY, DEFAULT_ENABLE_WORKER_PACKET_DELAY, DEFAULT_TIMEOUT_MILLIS); - } + private volatile ClusterOption remoteClusterOption = ClusterOption.DISABLE_CLUSTER_OPTION; + + + public DefaultPinpointClientHandler(ConnectionFactory connectionFactory, SocketAddressProvider socketAddressProvider, PinpointClientHandshaker handshaker, + ClusterOption localClusterOption, ClientOption clientOption, + Timer channelTimer, + MessageListener messageListener, + ServerStreamChannelMessageListener serverStreamChannelMessageListener, + List stateChangeEventListeners) { + + this.connectionFactory = Assert.requireNonNull(connectionFactory, "clientFactory must not be null"); + this.socketAddressProvider = Assert.requireNonNull(socketAddressProvider, "socketAddressProvider must not be null"); + + this.channelTimer = Assert.requireNonNull(channelTimer, "channelTimer must not be null"); + this.requestManager = new RequestManager(channelTimer, clientOption.getRequestTimeoutMillis()); + this.clientOption = Assert.requireNonNull(clientOption, "clientOption must not be null"); + + + this.messageListener = Assert.requireNonNull(messageListener, "messageListener must not be null"); + this.serverStreamChannelMessageListener = Assert.requireNonNull(serverStreamChannelMessageListener, "serverStreamChannelMessageListener must not be null"); - public DefaultPinpointClientHandler(DefaultPinpointClientFactory clientFactory, long pingDelay, long handshakeRetryInterval, long timeoutMillis) { - if (clientFactory == null) { - throw new NullPointerException("pinpointClientFactory must not be null"); - } - - HashedWheelTimer timer = TimerFactory.createHashedWheelTimer("Pinpoint-PinpointClientHandler-Timer", 100, TimeUnit.MILLISECONDS, 512); - timer.start(); - - this.channelTimer = timer; - this.clientFactory = clientFactory; - this.requestManager = new RequestManager(timer, timeoutMillis); - this.pingDelay = pingDelay; - this.timeoutMillis = timeoutMillis; - - this.messageListener = clientFactory.getMessageListener(SimpleMessageListener.INSTANCE); - this.serverStreamChannelMessageListener = clientFactory.getServerStreamChannelMessageListener(DisabledServerStreamChannelMessageListener.INSTANCE); - this.objectUniqName = ClassUtils.simpleClassNameAndHashCodeString(this); - this.handshaker = new PinpointClientHandshaker(channelTimer, (int) handshakeRetryInterval, maxHandshakeCount); - - this.socketId = clientFactory.issueNewSocketId(); + this.handshaker = Assert.requireNonNull(handshaker, "handshaker must not be null"); + this.pingIdGenerator = new AtomicInteger(0); - this.state = new PinpointClientHandlerState(this, clientFactory.getStateChangeEventListeners()); + this.state = new PinpointClientHandlerState(this.objectUniqName, this, stateChangeEventListeners); + + this.localClusterOption = Assert.requireNonNull(localClusterOption, "clusterOption must not be null"); - this.localClusterOption = clientFactory.getClusterOption(); } public void setPinpointClient(PinpointClient pinpointClient) { @@ -130,17 +115,10 @@ public void setPinpointClient(PinpointClient pinpointClient) { this.pinpointClient = pinpointClient; } - public void setConnectSocketAddress(SocketAddress connectSocketAddress) { - if (connectSocketAddress == null) { - throw new NullPointerException("connectSocketAddress must not be null"); - } - this.connectSocketAddress = connectSocketAddress; - } - @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - Channel channel = e.getChannel(); - + final Channel channel = e.getChannel(); + logger.debug("{} channelOpen() started. channel:{}", objectUniqName, channel); this.channel = channel; @@ -148,42 +126,35 @@ public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws E @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - Channel channel = e.getChannel(); + final Channel channel = e.getChannel(); if ((null == channel) || (this.channel != channel)) { throw new IllegalArgumentException("Invalid channel variable. this.channel:" + this.channel + ", channel:" + channel + "."); } logger.info("{} channelConnected() started. channel:{}", objectUniqName, channel); - + SocketStateChangeResult stateChangeResult = state.toConnected(); if (!stateChangeResult.isChange()) { throw new IllegalStateException("Invalid state:" + stateChangeResult.getCurrentState()); } - + prepareChannel(channel); - + stateChangeResult = state.toRunWithoutHandshake(); if (!stateChangeResult.isChange()) { throw new IllegalStateException("Failed to execute channelConnected() method. Error:" + stateChangeResult); } - + registerPing(); - Map handshakeData = new HashMap(); - handshakeData.putAll(clientFactory.getProperties()); - handshakeData.put("socketId", socketId); - if (localClusterOption.isEnable()) { - handshakeData.put("cluster", localClusterOption.getProperties()); - } + handshaker.handshakeStart(channel); - handshaker.handshakeStart(channel, handshakeData); - connectFuture.setResult(Result.SUCCESS); - + logger.info("{} channelConnected() completed.", objectUniqName); } - + private void prepareChannel(Channel channel) { StreamChannelManager streamChannelManager = new StreamChannelManager(channel, IDGenerator.createOddIdGenerator(), serverStreamChannelMessageListener); @@ -194,7 +165,7 @@ private void prepareChannel(Channel channel) { @Override public void initReconnect() { logger.info("{} initReconnect() started.", objectUniqName); - + SocketStateChangeResult stateChangeResult = state.toBeingConnect(); if (!stateChangeResult.isChange()) { throw new IllegalStateException("Failed to execute initReconnect() method. Error:" + stateChangeResult); @@ -209,7 +180,7 @@ private void registerPing() { } private void newPingTimeout(TimerTask pingTask) { - this.channelTimer.newTimeout(pingTask, pingDelay, TimeUnit.MILLISECONDS); + this.channelTimer.newTimeout(pingTask, clientOption.getPingDelay(), TimeUnit.MILLISECONDS); } private class PingTask implements TimerTask { @@ -219,7 +190,7 @@ public void run(Timeout timeout) throws Exception { newPingTimeout(this); return; } - + if (state.isClosed()) { return; } @@ -265,9 +236,9 @@ public void send(byte[] bytes) { @Override public Future sendAsync(byte[] bytes) { ChannelFuture channelFuture = send0(bytes); - final ChannelWriteCompleteListenableFuture future = new ChannelWriteCompleteListenableFuture(timeoutMillis); + final ChannelWriteCompleteListenableFuture future = new ChannelWriteCompleteListenableFuture(clientOption.getWriteTimeoutMillis()); channelFuture.addListener(future); - return future ; + return future; } @Override @@ -289,12 +260,16 @@ public void response(int requestId, byte[] payload) { @Override public SocketAddress getRemoteAddress() { - return connectSocketAddress; + final Channel channel = this.channel; + if (channel == null) { + return null; + } + return channel.getRemoteAddress(); } private void await(ChannelFuture channelFuture) { try { - channelFuture.await(timeoutMillis, TimeUnit.MILLISECONDS); + channelFuture.await(clientOption.getWriteTimeoutMillis(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } @@ -340,20 +315,20 @@ public Future request(byte[] bytes) { throw new NullPointerException("bytes"); } - boolean isEnable = state.isEnableCommunication(); + final boolean isEnable = state.isEnableCommunication(); if (!isEnable) { DefaultFuture closedException = new DefaultFuture(); closedException.setFailure(new PinpointSocketException("invalid state:" + state.getCurrentStateCode() + " channel:" + channel)); return closedException; } - - RequestPacket request = new RequestPacket(bytes); - final ChannelWriteFailListenableFuture messageFuture = this.requestManager.register(request, this.timeoutMillis); + final int requestId = this.requestManager.nextRequestId(); + final RequestPacket request = new RequestPacket(requestId, bytes); + final ChannelWriteFailListenableFuture messageFuture = this.requestManager.register(request.getRequestId(), clientOption.getRequestTimeoutMillis()); write0(request, messageFuture); return messageFuture; } - + @Override public ClientStreamChannelContext openStream(byte[] payload, ClientStreamChannelMessageListener messageListener) { return openStream(payload, messageListener, null); @@ -406,7 +381,7 @@ public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Ex handleClosedPacket(e.getChannel()); return; case PacketType.CONTROL_HANDSHAKE_RESPONSE: - handleHandshakePacket((ControlHandshakeResponsePacket)message, e.getChannel()); + handleHandshakePacket((ControlHandshakeResponsePacket) message, e.getChannel()); return; default: logger.warn("{} messageReceived() failed. unexpectedMessage received:{} address:{}", objectUniqName, message, e.getRemoteAddress()); @@ -421,12 +396,12 @@ private void handleClosedPacket(Channel channel) { state.toBeingCloseByPeer(); } - + private void handleHandshakePacket(ControlHandshakeResponsePacket message, Channel channel) { boolean isCompleted = handshaker.handshakeComplete(message); logger.info("{} handleHandshakePacket() started. message:{}", objectUniqName, message); - + if (isCompleted) { HandshakeResponseCode code = handshaker.getHandshakeResult(); @@ -443,7 +418,7 @@ private void handleHandshakePacket(ControlHandshakeResponsePacket message, Chann } logger.info("{} handleHandshakePacket() completed. code:{}", channel, code); - } else if (handshaker.isFinished()){ + } else if (handshaker.isFinished()) { logger.warn("{} handleHandshakePacket() failed. Error:Handshake already completed."); } else { logger.warn("{} handleHandshakePacket() failed. Error:Handshake not yet started."); @@ -453,11 +428,16 @@ private void handleHandshakePacket(ControlHandshakeResponsePacket message, Chann @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { Throwable cause = e.getCause(); - + SocketStateCode currentStateCode = state.getCurrentStateCode(); if (currentStateCode == SocketStateCode.BEING_CONNECT) { // removed stackTrace when reconnect. so many logs. logger.info("{} exceptionCaught() occurred. state:{}, caused:{}.", objectUniqName, currentStateCode, cause.getMessage()); + } else if (currentStateCode == SocketStateCode.NONE) { + // If an exception occurs in the execute channel open operation. (caused : netty's resource is already shut downed. then connectFuture never can't set value.) + // it will rarely happen but it is likely to happen at the end of the process. + logger.warn("{} exceptionCaught() occurred. state:{}. Caused:{}", objectUniqName, currentStateCode, cause.getMessage(), cause); + connectFuture.setResult(Result.FAIL); } else { logger.warn("{} exceptionCaught() occurred. state:{}. Caused:{}", objectUniqName, currentStateCode, cause.getMessage(), cause); } @@ -481,14 +461,14 @@ private void ensureOpen() { if (state.isReconnect(currentStateCode)) { throw new PinpointSocketException("reconnecting..."); } - + throw new PinpointSocketException("Invalid socket state:" + currentStateCode); } // Calling this method on a closed PinpointClientHandler has no effect. public void close() { logger.debug("{} close() started.", objectUniqName); - + SocketStateCode currentStateCode = state.getCurrentStateCode(); if (currentStateCode.isRun()) { state.toBeingClose(); @@ -502,7 +482,7 @@ public void close() { logger.warn("Illegal State :{}.", currentStateCode); } } - + private void closeChannel() { Channel channel = this.channel; if (channel != null) { @@ -543,7 +523,7 @@ private void sendClosedPacket(Channel channel) { logger.debug("{} sendClosedPacket() failed. Error:channel already closed.", objectUniqName); return; } - + logger.debug("{} sendClosedPacket() started.", objectUniqName); ClientClosePacket clientClosePacket = new ClientClosePacket(); @@ -553,11 +533,11 @@ private void sendClosedPacket(Channel channel) { @Override public void channelClosed(final ChannelHandlerContext ctx, final ChannelStateEvent e) throws Exception { - logger.info("{} channelClosed() started.", objectUniqName); - + logger.info("{} channelClosed() started.", objectUniqName); + try { - boolean factoryReleased = clientFactory.isReleased(); - + boolean factoryReleased = connectionFactory.isClosed(); + boolean needReconnect = false; SocketStateCode currentStateCode = state.getCurrentStateCode(); if (currentStateCode == SocketStateCode.BEING_CLOSE_BY_CLIENT) { @@ -575,7 +555,7 @@ public void channelClosed(final ChannelHandlerContext ctx, final ChannelStateEve } if (needReconnect) { - clientFactory.reconnect(this.pinpointClient, this.connectSocketAddress); + reconnect(); } } finally { closeResources(); @@ -583,33 +563,34 @@ public void channelClosed(final ChannelHandlerContext ctx, final ChannelStateEve } } + private void reconnect() { + connectionFactory.reconnect(this.pinpointClient, this.socketAddressProvider); + } + private ChannelFuture write0(Object message) { - return write0(message, null); + return channel.write(message); } - + private ChannelFuture write0(Object message, ChannelFutureListener futureListener) { - ChannelFuture future = channel.write(message); - if (futureListener != null) { - future.addListener(futureListener); + if (futureListener == null) { + throw new NullPointerException("futureListener must not be null"); } - + ChannelFuture future = channel.write(message); + future.addListener(futureListener); return future; } - public Timer getChannelTimer() { - return channelTimer; - } @Override public ConnectFuture getConnectFuture() { return connectFuture; } - + @Override public SocketStateCode getCurrentStateCode() { return state.getCurrentStateCode(); } - + private PinpointClientHandlerContext getChannelContext(Channel channel) { if (channel == null) { throw new NullPointerException("channel must not be null"); @@ -637,14 +618,10 @@ public ClusterOption getRemoteClusterOption() { return remoteClusterOption; } - protected PinpointClient getPinpointClient() { + protected PinpointSocket getPinpointSocket() { return pinpointClient; } - protected String getObjectName() { - return objectUniqName; - } - @Override public String toString() { final StringBuilder sb = new StringBuilder(objectUniqName); diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientHandlerFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientHandlerFactory.java new file mode 100644 index 000000000000..9be10c7badc0 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DefaultPinpointClientHandlerFactory.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.MessageListener; +import com.navercorp.pinpoint.rpc.StateChangeEventListener; +import com.navercorp.pinpoint.rpc.cluster.ClusterOption; +import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelMessageListener; +import org.jboss.netty.util.Timer; + +import java.util.List; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultPinpointClientHandlerFactory implements ClientHandlerFactory { + + private final ClientOption clientOption; + private final ClusterOption clusterOption; + private final HandshakerFactory handshakerFactory; + + private final MessageListener messageListener; + private final ServerStreamChannelMessageListener serverStreamChannelMessageListener; + private final List stateChangeEventListeners; + + + public DefaultPinpointClientHandlerFactory(ClientOption clientOption, ClusterOption clusterOption, HandshakerFactory handshakerFactory, + MessageListener messageListener, + ServerStreamChannelMessageListener serverStreamChannelMessageListener, + List stateChangeEventListeners) { + + this.clientOption = Assert.requireNonNull(clientOption, "clientOption must not be null"); + this.clusterOption = Assert.requireNonNull(clusterOption, "clusterOption must not be null"); + this.handshakerFactory = Assert.requireNonNull(handshakerFactory, "handshakerFactory must not be null"); + + this.messageListener = Assert.requireNonNull(messageListener, "messageListener must not be null"); + this.serverStreamChannelMessageListener = Assert.requireNonNull(serverStreamChannelMessageListener, "serverStreamChannelMessageListener must not be null"); + this.stateChangeEventListeners = Assert.requireNonNull(stateChangeEventListeners, "stateChangeEventListeners must not be null"); + + + } + + + @Override + public PinpointClientHandler newClientHandler(ConnectionFactory connectionFactory, SocketAddressProvider remoteAddressProvider, Timer channelTimer, boolean reconnect) { + PinpointClientHandshaker handshaker = handshakerFactory.newHandShaker(channelTimer); + final DefaultPinpointClientHandler clientHandler = new DefaultPinpointClientHandler(connectionFactory, remoteAddressProvider, handshaker, + clusterOption, clientOption, channelTimer, + messageListener, + serverStreamChannelMessageListener, + stateChangeEventListeners + ); + + if (reconnect) { + clientHandler.initReconnect(); + } + return clientHandler; + } + + +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DnsSocketAddressProvider.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DnsSocketAddressProvider.java new file mode 100644 index 000000000000..25298a6764fa --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/DnsSocketAddressProvider.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; +import com.navercorp.pinpoint.common.plugin.util.HostAndPort; +import com.navercorp.pinpoint.common.util.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DnsSocketAddressProvider implements SocketAddressProvider{ + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final String host; + private final int port; + + private InetSocketAddress oldAddress; + + public DnsSocketAddressProvider(String host, int port) { + this.host = Assert.requireNonNull(host, "host must not be null"); + this.port = checkPort(port); + } + + private static int checkPort(int port) { + if (!HostAndPort.isValidPort(port)) { + throw new IllegalArgumentException("port out of range:" + port); + } + return port; + } + + + @Override + public InetSocketAddress resolve() { + try { + InetAddress inetAddress = getByName(host); + InetSocketAddress updateAddress = new InetSocketAddress(inetAddress, port); + + checkDnsUpdate(updateAddress); + + return updateAddress; + } catch (UnknownHostException e) { + logger.info("dns lookup fail. host:{}", host); + // expected UnknownHostException from tcp connect timing + return InetSocketAddress.createUnresolved(host, port); + // or return null; + } + } + + @VisibleForTesting + InetAddress getByName(String host) throws UnknownHostException { + return InetAddress.getByName(host); + } + + private void checkDnsUpdate(InetSocketAddress updateAddress) { + synchronized(this) { + final InetSocketAddress oldAddress = this.oldAddress; + if (oldAddress != null) { + if (!oldAddress.equals(updateAddress)) { + logger.info("host address updated, host:{} old:{}, update:{}", host, oldAddress, updateAddress); + } + } + this.oldAddress = updateAddress; + } + } + + @Override + public String toString() { + return "DnsSocketAddressProvider{" + + "host='" + host + '\'' + + ", port=" + port + + '}'; + } +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/HandshakerFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/HandshakerFactory.java new file mode 100644 index 000000000000..e19202a04cfa --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/HandshakerFactory.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.cluster.ClusterOption; +import org.jboss.netty.util.Timer; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HandshakerFactory { + + private static final int DEFAULT_ENABLE_WORKER_PACKET_RETRY_COUNT = Integer.MAX_VALUE; + + private int maxHandshakeCount = DEFAULT_ENABLE_WORKER_PACKET_RETRY_COUNT; + + + private final AtomicInteger socketId; + private final Map properties; + + private final ClusterOption clusterOption; + private final ClientOption clientOption; + + public HandshakerFactory(AtomicInteger socketId, Map properties, ClientOption clientOption, ClusterOption clusterOption) { + this.socketId = Assert.requireNonNull(socketId, "socketId must not be null"); + + this.clusterOption = Assert.requireNonNull(clusterOption, "clusterOption must not be null"); + this.clientOption = Assert.requireNonNull(clientOption, "clientOption must not be null"); + this.properties = Assert.requireNonNull(properties, "properties must not be null"); + } + + public PinpointClientHandshaker newHandShaker(Timer channelTimer) { + Map handshakeData = createHandShakeData(); + return new PinpointClientHandshaker(handshakeData, channelTimer, clientOption.getEnableWorkerPacketDelay(), maxHandshakeCount); + } + + + private Map createHandShakeData() { + + Map handshakeData = new HashMap(this.properties); + + final int socketId = nextSocketId(); + handshakeData.put("socketId", socketId); + + if (clusterOption.isEnable()) { + handshakeData.put("cluster", clusterOption.toMap()); + } + return handshakeData; + } + + private int nextSocketId() { + return socketId.getAndIncrement(); + } +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientFactory.java index 2464c9cfd261..6abcdd35b531 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientFactory.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientFactory.java @@ -53,21 +53,38 @@ public interface PinpointClientFactory { void setEnableWorkerPacketDelay(long enableWorkerPacketDelay); - long getTimeoutMillis(); + long getWriteTimeoutMillis(); - void setTimeoutMillis(long timeoutMillis); + void setWriteTimeoutMillis(long writeTimeoutMillis); + long getRequestTimeoutMillis(); + + void setRequestTimeoutMillis(long requestTimeoutMillis); PinpointClient connect(String host, int port) throws PinpointSocketException; - PinpointClient connect(InetSocketAddress connectAddress) throws PinpointSocketException; + PinpointClient connect(SocketAddressProvider socketAddressProvider) throws PinpointSocketException; + /** + * @deprecated Since 1.7.2 Use {@link #connect(String, int)} + */ + @Deprecated + PinpointClient connect(InetSocketAddress connectAddress) throws PinpointSocketException; PinpointClient scheduledConnect(String host, int port); - PinpointClient scheduledConnect(InetSocketAddress connectAddress); + PinpointClient scheduledConnect(SocketAddressProvider socketAddressProvider); + /** + * @deprecated Since 1.7.2 Use {@link #scheduledConnect(String, int)} + */ + @Deprecated + PinpointClient scheduledConnect(InetSocketAddress connectAddress); + /** + * @deprecated Since 1.7.2 Use {@link #scheduledConnect(String, int)} + */ + @Deprecated ChannelFuture reconnect(final SocketAddress remoteAddress); @@ -99,8 +116,5 @@ public interface PinpointClientFactory { void addStateChangeEventListener(StateChangeEventListener stateChangeEventListener); -// boolean isReleased(); -// -// int issueNewSocketId(); } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandler.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandler.java index f90ad7518759..5e4601ad1893 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandler.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandler.java @@ -30,8 +30,6 @@ */ public interface PinpointClientHandler { - void setConnectSocketAddress(SocketAddress address); - void initReconnect(); ConnectFuture getConnectFuture(); diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandlerState.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandlerState.java index 49a52aa52f41..6100f9cccf7c 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandlerState.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandlerState.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.rpc.client; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.StateChangeEventListener; import org.slf4j.Logger; @@ -34,12 +35,15 @@ public class PinpointClientHandlerState { private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final String objectName; private final DefaultPinpointClientHandler clientHandler; private final List stateChangeEventListeners; private final SocketState state; - - public PinpointClientHandlerState(DefaultPinpointClientHandler clientHandler, List stateChangeEventListeners) { + + public PinpointClientHandlerState(String objectName, DefaultPinpointClientHandler clientHandler, List stateChangeEventListeners) { + this.objectName = Assert.requireNonNull(objectName, "objectName must not be null"); + this.clientHandler = clientHandler; this.stateChangeEventListeners = stateChangeEventListeners; @@ -112,8 +116,7 @@ SocketStateChangeResult toErrorUnknown() { } private SocketStateChangeResult to(SocketStateCode nextState) { - String objectName = clientHandler.getObjectName(); - PinpointSocket pinpointSocket = clientHandler.getPinpointClient(); + PinpointSocket pinpointSocket = clientHandler.getPinpointSocket(); logger.debug("{} stateTo() started. to:{}", objectName, nextState); diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandshaker.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandshaker.java index 299beb0422e8..6f8a5c32a13b 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandshaker.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientHandshaker.java @@ -60,7 +60,7 @@ public class PinpointClientHandshaker { private final AtomicInteger handshakeCount; private final Timer handshakerTimer; - private final int retryInterval; + private final long retryInterval; private final int maxHandshakeCount; private final Object lock = new Object(); @@ -69,21 +69,24 @@ public class PinpointClientHandshaker { private final String id = ClassUtils.simpleClassNameAndHashCodeString(this); + private final Map handshakeData; - public PinpointClientHandshaker(Timer handshakerTimer, int retryInterval, int maxHandshakeCount) { - Assert.requireNonNull(handshakerTimer, "handshakerTimer must not be null."); + + public PinpointClientHandshaker(Map handshakeData, Timer handshakerTimer, long retryInterval, int maxHandshakeCount) { Assert.isTrue(retryInterval > 0, "retryInterval must greater than zero."); Assert.isTrue(maxHandshakeCount > 0, "maxHandshakeCount must greater than zero."); this.state = new AtomicInteger(STATE_INIT); - this.handshakerTimer = handshakerTimer; + this.handshakerTimer = Assert.requireNonNull(handshakerTimer, "handshakerTimer must not be null."); + this.handshakeData = Assert.requireNonNull(handshakeData, "handshakeData must not be null"); + this.retryInterval = retryInterval; this.maxHandshakeCount = maxHandshakeCount; - + this.handshakeCount = new AtomicInteger(0); } - public void handshakeStart(Channel channel, Map handshakeData) { + public void handshakeStart(Channel channel) { logger.info("{} handshakeStart() started. channel:{}", id, channel); if (channel == null) { @@ -103,7 +106,7 @@ public void handshakeStart(Channel channel, Map handshakeData) { HandshakeJob handshakeJob = null; try { - handshakeJob = createHandshakeJob(channel, handshakeData); + handshakeJob = createHandshakeJob(channel); } catch (Exception e) { logger.warn("{} create HandshakeJob failed. caused:{}", id, e.getMessage(), e); } @@ -119,9 +122,10 @@ public void handshakeStart(Channel channel, Map handshakeData) { logger.info("{} handshakeStart() completed. channel:{}, data:{}", id, channel, handshakeData); } - private HandshakeJob createHandshakeJob(Channel channel, Map handshakeData) throws ProtocolException { + private HandshakeJob createHandshakeJob(Channel channel) throws ProtocolException { byte[] payload = ControlMessageEncodingUtils.encode(handshakeData); - ControlHandshakePacket handshakePacket = new ControlHandshakePacket(payload); + + ControlHandshakePacket handshakePacket = new ControlHandshakePacket(0, payload); HandshakeJob handshakeJob = new HandshakeJob(channel, handshakePacket); return handshakeJob; diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientPipelineFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientPipelineFactory.java deleted file mode 100644 index 3c3315fa96f4..000000000000 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/PinpointClientPipelineFactory.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.rpc.client; - - -import com.navercorp.pinpoint.rpc.codec.PacketDecoder; -import com.navercorp.pinpoint.rpc.codec.PacketEncoder; - -import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.channel.ChannelPipelineFactory; -import org.jboss.netty.channel.Channels; -import org.jboss.netty.handler.timeout.WriteTimeoutHandler; - -import java.util.concurrent.TimeUnit; - -/** - * @author emeroad - * @author koo.taejin - */ -public class PinpointClientPipelineFactory implements ChannelPipelineFactory { - - private final DefaultPinpointClientFactory pinpointClientFactory; - - public PinpointClientPipelineFactory(DefaultPinpointClientFactory pinpointClientFactory) { - if (pinpointClientFactory == null) { - throw new NullPointerException("pinpointClientFactory must not be null"); - } - this.pinpointClientFactory = pinpointClientFactory; - } - - - @Override - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = Channels.pipeline(); - pipeline.addLast("encoder", new PacketEncoder()); - pipeline.addLast("decoder", new PacketDecoder()); - - long pingDelay = pinpointClientFactory.getPingDelay(); - long enableWorkerPacketDelay = pinpointClientFactory.getEnableWorkerPacketDelay(); - long timeoutMillis = pinpointClientFactory.getTimeoutMillis(); - - DefaultPinpointClientHandler defaultPinpointClientHandler = new DefaultPinpointClientHandler(pinpointClientFactory, pingDelay, enableWorkerPacketDelay, timeoutMillis); - pipeline.addLast("writeTimeout", new WriteTimeoutHandler(defaultPinpointClientHandler.getChannelTimer(), 3000, TimeUnit.MILLISECONDS)); - pipeline.addLast("socketHandler", defaultPinpointClientHandler); - - return pipeline; - } -} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ReconnectStateClientHandler.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ReconnectStateClientHandler.java index 94e867907d80..a9d97cadaaef 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ReconnectStateClientHandler.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/ReconnectStateClientHandler.java @@ -40,9 +40,6 @@ public class ReconnectStateClientHandler implements PinpointClientHandler { private volatile SocketStateCode state = SocketStateCode.BEING_CONNECT; - @Override - public void setConnectSocketAddress(SocketAddress connectSocketAddress) { - } @Override public void initReconnect() { diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/RequestManager.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/RequestManager.java index 2a84dfa38b6a..77b4596f1424 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/RequestManager.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/RequestManager.java @@ -79,8 +79,7 @@ public boolean fireFailure() { return failureEventHandler; } - - private void addTimeoutTask(long timeoutMillis, DefaultFuture future) { + private void addTimeoutTask(DefaultFuture future, long timeoutMillis) { if (future == null) { throw new NullPointerException("future"); } @@ -93,7 +92,7 @@ private void addTimeoutTask(long timeoutMillis, DefaultFuture future) { } } - private int getNextRequestId() { + public int nextRequestId() { return this.requestId.getAndIncrement(); } @@ -135,30 +134,54 @@ public void messageReceived(RequestPacket requestPacket, Channel channel) { logger.error("unexpectedMessage received:{} address:{}", requestPacket, channel.getRemoteAddress()); } - public ChannelWriteFailListenableFuture register(RequestPacket requestPacket) { - return register(requestPacket, defaultTimeoutMillis); + public ChannelWriteFailListenableFuture register(int requestId) { + return register(requestId, defaultTimeoutMillis); } - public ChannelWriteFailListenableFuture register(RequestPacket requestPacket, long timeoutMillis) { + public ChannelWriteFailListenableFuture register(int requestId, long timeoutMillis) { // shutdown check - final int requestId = getNextRequestId(); - requestPacket.setRequestId(requestId); - - final ChannelWriteFailListenableFuture future = new ChannelWriteFailListenableFuture(timeoutMillis); + final ChannelWriteFailListenableFuture responseFuture = new ChannelWriteFailListenableFuture(timeoutMillis); - final DefaultFuture old = this.requestMap.put(requestId, future); + final DefaultFuture old = this.requestMap.put(requestId, responseFuture); if (old != null) { throw new PinpointSocketException("unexpected error. old future exist:" + old + " id:" + requestId); } // when future fails, put a handle in order to remove a failed future in the requestMap. FailureEventHandler removeTable = createFailureEventHandler(requestId); - future.setFailureEventHandler(removeTable); + responseFuture.setFailureEventHandler(removeTable); - addTimeoutTask(timeoutMillis, future); - return future; + addTimeoutTask(responseFuture, timeoutMillis); + return responseFuture; } +// public ChannelWriteFailListenableFuture register(final int requestId, final long timeoutMillis) { +// // shutdown check +// final ChannelWriteFailListenableFuture responseFuture = new ChannelWriteFailListenableFuture(timeoutMillis) { +// @Override +// public void operationComplete(ChannelFuture future) throws Exception { +// fireWriteComplete(requestId, future, this, timeoutMillis); +// } +// }; +// return responseFuture; +// } +// +// private void fireWriteComplete(int requestId, ChannelFuture ioWriteFuture, DefaultFuture responseFuture, long timeoutMillis) { +// if (ioWriteFuture.isSuccess()) { +// final DefaultFuture old = requestMap.put(requestId, responseFuture); +// if (old != null) { +// PinpointSocketException pinpointSocketException = new PinpointSocketException("unexpected error. old responseFuture exist:" + old + " id:" + requestId); +// responseFuture.setFailure(pinpointSocketException); +// return; +// } else { +// FailureEventHandler removeTable = createFailureEventHandler(requestId); +// responseFuture.setFailureEventHandler(removeTable); +// addTimeoutTask(responseFuture, timeoutMillis); +// } +// } else { +// responseFuture.setFailure(ioWriteFuture.getCause()); +// } +// } public void close() { logger.debug("close()"); @@ -175,7 +198,7 @@ public void close() { // } int requestFailCount = 0; for (Map.Entry> entry : requestMap.entrySet()) { - if(entry.getValue().setFailure(closed)) { + if (entry.getValue().setFailure(closed)) { requestFailCount++; } } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SimpleMessageListener.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SimpleMessageListener.java index 6e7003fd8251..380da389d127 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SimpleMessageListener.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SimpleMessageListener.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -50,9 +50,9 @@ public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSo logger.info("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); if (echo) { - pinpointSocket.response(requestPacket, requestPacket.getPayload()); + pinpointSocket.response(requestPacket.getRequestId(), requestPacket.getPayload()); } else { - pinpointSocket.response(requestPacket, new byte[0]); + pinpointSocket.response(requestPacket.getRequestId(), new byte[0]); } } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SocketAddressProvider.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SocketAddressProvider.java new file mode 100644 index 000000000000..03f870eb0118 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SocketAddressProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import java.net.InetSocketAddress; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface SocketAddressProvider { + InetSocketAddress resolve(); +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SocketOption.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SocketOption.java new file mode 100644 index 000000000000..8bac3b45eabe --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/SocketOption.java @@ -0,0 +1,141 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Woonduk Kang(emeroad) + */ +public class SocketOption implements Cloneable { + + private static final String CONNECT_TIMEOUT_MILLIS = "connectTimeoutMillis"; + static final int DEFAULT_CONNECT_TIMEOUT = 5000; + + private final int connectTimeout; + private final boolean tcpNoDelay; + private final boolean keepAlive; + + private final int sendBufferSize; + private final int receiveBufferSize; + + private SocketOption(int connectTimeout, boolean tcpNoDelay, boolean keepAlive, int sendBufferSize, int receiveBufferSize) { + this.connectTimeout = connectTimeout; + this.tcpNoDelay = tcpNoDelay; + this.keepAlive = keepAlive; + this.sendBufferSize = sendBufferSize; + this.receiveBufferSize = receiveBufferSize; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public boolean isTcpNoDelay() { + return tcpNoDelay; + } + + + public boolean isKeepAlive() { + return keepAlive; + } + + + public int getSendBufferSize() { + return sendBufferSize; + } + + public int getReceiveBufferSize() { + return receiveBufferSize; + } + + public Map toMap() { + + final Map options = new HashMap(); + // connectTimeout + options.put(CONNECT_TIMEOUT_MILLIS, connectTimeout); + // read write timeout needed? isn't it needed because of nio? + + // tcp setting + options.put("tcpNoDelay", tcpNoDelay); + options.put("keepAlive", keepAlive); + // buffer setting + options.put("sendBufferSize", sendBufferSize); + options.put("receiveBufferSize", receiveBufferSize); + return options; + } + + public static class Builder { + private int connectTimeout = DEFAULT_CONNECT_TIMEOUT; + private boolean tcpNoDelay = true; + private boolean keepAlive = true; + + private int sendBufferSize = 1024*64; + private int receiveBufferSize = 1024 * 64; + + public Builder() { + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + if (connectTimeout < 0) { + throw new IllegalArgumentException("connectTimeout cannot be a negative number"); + } + this.connectTimeout = connectTimeout; + } + + public boolean isTcpNoDelay() { + return tcpNoDelay; + } + + public void setTcpNoDelay(boolean tcpNoDelay) { + this.tcpNoDelay = tcpNoDelay; + } + + public boolean isKeepAlive() { + return keepAlive; + } + + public void setKeepAlive(boolean keepAlive) { + this.keepAlive = keepAlive; + } + + public int getSendBufferSize() { + return sendBufferSize; + } + + public void setSendBufferSize(int sendBufferSize) { + this.sendBufferSize = sendBufferSize; + } + + public int getReceiveBufferSize() { + return receiveBufferSize; + } + + public void setReceiveBufferSize(int receiveBufferSize) { + this.receiveBufferSize = receiveBufferSize; + } + + public SocketOption build() { + return new SocketOption(this.connectTimeout, this.tcpNoDelay, this.keepAlive, this.sendBufferSize, this.receiveBufferSize); + } + } +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/StaticSocketAddressProvider.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/StaticSocketAddressProvider.java new file mode 100644 index 000000000000..007213b81d75 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/client/StaticSocketAddressProvider.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import com.navercorp.pinpoint.common.util.Assert; + +import java.net.InetSocketAddress; + +/** + * @author Woonduk Kang(emeroad) + */ +@Deprecated +public class StaticSocketAddressProvider implements SocketAddressProvider { + private final InetSocketAddress socketAddress; + + public StaticSocketAddressProvider(InetSocketAddress inetSocketAddress) { + this.socketAddress = Assert.requireNonNull(inetSocketAddress, "inetSocketAddress must not be null"); + } + + @Override + public InetSocketAddress resolve() { + return socketAddress; + } + + @Override + public String toString() { + return "StaticSocketAddressProvider{" + + "socketAddress=" + socketAddress + + '}'; + } +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/cluster/ClusterOption.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/cluster/ClusterOption.java index d84bb1db5757..beb9ef1f259d 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/cluster/ClusterOption.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/cluster/ClusterOption.java @@ -23,7 +23,7 @@ */ public class ClusterOption { - public static final ClusterOption DISABLE_CLUSTER_OPTION = new ClusterOption(false, "", Collections.EMPTY_LIST); + public static final ClusterOption DISABLE_CLUSTER_OPTION = new ClusterOption(false, "", Collections.emptyList()); private final boolean enable; private final String id; @@ -37,6 +37,10 @@ public ClusterOption(boolean enable, String id, Role role) { this(enable, id, Arrays.asList(role)); } + public ClusterOption(ClusterOption clusterOption) { + this(clusterOption.enable, clusterOption.id, new ArrayList(clusterOption.roles)); + } + public ClusterOption(boolean enable, String id, List roles) { this.enable = enable; this.id = id; @@ -55,7 +59,7 @@ public List getRoles() { return roles; } - public Map getProperties() { + public Map toMap() { if (!enable) { return Collections.emptyMap(); } @@ -81,4 +85,8 @@ public String toString() { sb.append('}'); return sb.toString(); } + + public static ClusterOption copy(ClusterOption clusterOption) { + return new ClusterOption(clusterOption.enable, clusterOption.id, clusterOption.roles); + } } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/BasicPacket.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/BasicPacket.java index fcb4ea4646b3..c07d09ee904b 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/BasicPacket.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/BasicPacket.java @@ -37,8 +37,4 @@ public byte[] getPayload() { return payload; } - public void setPayload(byte[] payload) { - this.payload = payload; - } - } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlHandshakePacket.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlHandshakePacket.java index 4bfda593b399..bc38c884d281 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlHandshakePacket.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlHandshakePacket.java @@ -22,15 +22,13 @@ /** * @author koo.taejin */ -public class ControlHandshakePacket extends ControlPacket { +public class ControlHandshakePacket extends BasicPacket { - public ControlHandshakePacket(byte[] payload) { - super(payload); - } + private final int requestId; public ControlHandshakePacket(int requestId, byte[] payload) { super(payload); - setRequestId(requestId); + this.requestId = requestId; } @Override @@ -38,6 +36,10 @@ public short getPacketType() { return PacketType.CONTROL_HANDSHAKE; } + public int getRequestId() { + return requestId; + } + @Override public ChannelBuffer toBuffer() { @@ -61,8 +63,7 @@ public static ControlHandshakePacket readBuffer(short packetType, ChannelBuffer if (payload == null) { return null; } - final ControlHandshakePacket helloPacket = new ControlHandshakePacket(payload.array()); - helloPacket.setRequestId(messageId); + final ControlHandshakePacket helloPacket = new ControlHandshakePacket(messageId, payload.array()); return helloPacket; } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlHandshakeResponsePacket.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlHandshakeResponsePacket.java index a8c25bfec584..7ead3b3e3317 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlHandshakeResponsePacket.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlHandshakeResponsePacket.java @@ -22,20 +22,18 @@ /** * @author koo.taejin */ -public class ControlHandshakeResponsePacket extends ControlPacket { +public class ControlHandshakeResponsePacket extends BasicPacket { public static final String CODE = "code"; public static final String SUB_CODE = "subCode"; public static final String CLUSTER = "cluster"; - - public ControlHandshakeResponsePacket(byte[] payload) { - super(payload); - } + private final int requestId;; + public ControlHandshakeResponsePacket(int requestId, byte[] payload) { super(payload); - setRequestId(requestId); + this.requestId = requestId; } @Override @@ -48,7 +46,7 @@ public ChannelBuffer toBuffer() { ChannelBuffer header = ChannelBuffers.buffer(2 + 4 + 4); header.writeShort(PacketType.CONTROL_HANDSHAKE_RESPONSE); - header.writeInt(getRequestId()); + header.writeInt(requestId); return PayloadPacket.appendPayload(header, payload); } @@ -66,8 +64,7 @@ public static ControlHandshakeResponsePacket readBuffer(short packetType, Channe if (payload == null) { return null; } - final ControlHandshakeResponsePacket helloPacket = new ControlHandshakeResponsePacket(payload.array()); - helloPacket.setRequestId(messageId); + final ControlHandshakeResponsePacket helloPacket = new ControlHandshakeResponsePacket(messageId, payload.array()); return helloPacket; } @@ -75,7 +72,7 @@ public static ControlHandshakeResponsePacket readBuffer(short packetType, Channe public String toString() { final StringBuilder sb = new StringBuilder(); sb.append(this.getClass().getSimpleName()); - sb.append("{requestId=").append(getRequestId()); + sb.append("{requestId=").append(requestId); sb.append(", "); if (payload == null) { sb.append("payload=null"); diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlPacket.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlPacket.java deleted file mode 100644 index 34d2b671b5da..000000000000 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ControlPacket.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.rpc.packet; - -/** - * @author koo.taejin - */ -public abstract class ControlPacket extends BasicPacket { - - private int requestId; - - public ControlPacket(byte[] payload) { - super(payload); - } - - public int getRequestId() { - return requestId; - } - - public void setRequestId(int requestId) { - this.requestId = requestId; - } - -} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/RequestPacket.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/RequestPacket.java index 5587bc9031fd..386c729d76c6 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/RequestPacket.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/RequestPacket.java @@ -24,14 +24,7 @@ */ public class RequestPacket extends BasicPacket { - private int requestId; - - public RequestPacket() { - } - - public RequestPacket(byte[] payload) { - super(payload); - } + private final int requestId; public RequestPacket(int requestId, byte[] payload) { super(payload); @@ -42,9 +35,6 @@ public int getRequestId() { return requestId; } - public void setRequestId(int requestId) { - this.requestId = requestId; - } @Override public short getPacketType() { @@ -77,8 +67,7 @@ public static RequestPacket readBuffer(short packetType, ChannelBuffer buffer) { if (payload == null) { return null; } - final RequestPacket requestPacket = new RequestPacket(payload.array()); - requestPacket.setRequestId(messageId); + final RequestPacket requestPacket = new RequestPacket(messageId, payload.array()); return requestPacket; } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ResponsePacket.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ResponsePacket.java index 52a1f39320ac..d8238c63392f 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ResponsePacket.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/packet/ResponsePacket.java @@ -23,14 +23,7 @@ * @author emeroad */ public class ResponsePacket extends BasicPacket { - private int requestId; - - public ResponsePacket() { - } - - public ResponsePacket(byte[] payload) { - super(payload); - } + private final int requestId; public ResponsePacket(int requestId, byte[] payload) { super(payload); @@ -41,10 +34,6 @@ public int getRequestId() { return requestId; } - public void setRequestId(int requestId) { - this.requestId = requestId; - } - @Override public short getPacketType() { return PacketType.APPLICATION_RESPONSE; @@ -74,9 +63,7 @@ public static ResponsePacket readBuffer(short packetType, ChannelBuffer buffer) if (payload == null) { return null; } - ResponsePacket responsePacket = new ResponsePacket(payload.array()); - responsePacket.setRequestId(messageId); - + ResponsePacket responsePacket = new ResponsePacket(messageId, payload.array()); return responsePacket; } diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/DefaultPinpointServer.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/DefaultPinpointServer.java index 63e74a5a3ed1..191c630050ff 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/DefaultPinpointServer.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/DefaultPinpointServer.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -205,15 +205,11 @@ public Future request(byte[] payload) { throw new IllegalStateException("Request fail. Error: Illegal State. pinpointServer:" + toString()); } - RequestPacket requestPacket = new RequestPacket(payload); - ChannelWriteFailListenableFuture messageFuture = this.requestManager.register(requestPacket); - write0(requestPacket, messageFuture); - return messageFuture; - } - - @Override - public void response(RequestPacket requestPacket, byte[] payload) { - response(requestPacket.getRequestId(), payload); + final int requestId = this.requestManager.nextRequestId(); + RequestPacket requestPacket = new RequestPacket(requestId, payload); + ChannelWriteFailListenableFuture responseFuture = this.requestManager.register(requestPacket.getRequestId()); + write0(requestPacket, responseFuture); + return responseFuture; } @Override @@ -388,20 +384,24 @@ private void handleHandshake(ControlHandshakePacket handshakePacket) { logger.info("{} handleHandshake() started. requestId:{}, data:{}", objectUniqName, requestId, handshakeData); HandshakeResponseCode responseCode = messageListener.handleHandshake(handshakeData); - boolean isFirst = setChannelProperties(handshakeData); - if (isFirst) { - if (HandshakeResponseCode.DUPLEX_COMMUNICATION == responseCode) { - this.remoteClusterOption = getClusterOption(handshakeData); - state.toRunDuplex(); - } else if (HandshakeResponseCode.SIMPLEX_COMMUNICATION == responseCode || HandshakeResponseCode.SUCCESS == responseCode) { - state.toRunSimplex(); + if (responseCode != null) { + boolean isFirst = setChannelProperties(handshakeData); + if (isFirst) { + if (HandshakeResponseCode.DUPLEX_COMMUNICATION == responseCode) { + this.remoteClusterOption = getClusterOption(handshakeData); + state.toRunDuplex(); + } else if (HandshakeResponseCode.SIMPLEX_COMMUNICATION == responseCode || HandshakeResponseCode.SUCCESS == responseCode) { + state.toRunSimplex(); + } } - } - Map responseData = createHandshakeResponse(responseCode, isFirst); - sendHandshakeResponse0(requestId, responseData); - - logger.info("{} handleHandshake() completed(isFirst:{}). requestId:{}, responseCode:{}", objectUniqName, isFirst, requestId, responseCode); + Map responseData = createHandshakeResponse(responseCode, isFirst); + sendHandshakeResponse0(requestId, responseData); + + logger.info("{} handleHandshake() completed(isFirst:{}). requestId:{}, responseCode:{}", objectUniqName, isFirst, requestId, responseCode); + } else { + logger.info("{} to execute handleHandshake() is not ready", objectUniqName); + } } private ClusterOption getClusterOption(Map handshakeResponse) { @@ -498,29 +498,32 @@ private void writePong(Channel channel) { } private Map createHandshakeResponse(HandshakeResponseCode responseCode, boolean isFirst) { - HandshakeResponseCode createdCode = null; - if (isFirst) { - createdCode = responseCode; - } else { - if (HandshakeResponseCode.DUPLEX_COMMUNICATION == responseCode) { - createdCode = HandshakeResponseCode.ALREADY_DUPLEX_COMMUNICATION; - } else if (HandshakeResponseCode.SIMPLEX_COMMUNICATION == responseCode) { - createdCode = HandshakeResponseCode.ALREADY_SIMPLEX_COMMUNICATION; - } else { - createdCode = responseCode; - } - } + final HandshakeResponseCode createdCode = getHandshakeResponseCode(responseCode, isFirst); Map result = new HashMap(); result.put(ControlHandshakeResponsePacket.CODE, createdCode.getCode()); result.put(ControlHandshakeResponsePacket.SUB_CODE, createdCode.getSubCode()); if (localClusterOption.isEnable()) { - result.put(ControlHandshakeResponsePacket.CLUSTER, localClusterOption.getProperties()); + Map clusterOption = localClusterOption.toMap(); + result.put(ControlHandshakeResponsePacket.CLUSTER, clusterOption); } return result; } + private HandshakeResponseCode getHandshakeResponseCode(HandshakeResponseCode responseCode, boolean isFirst) { + if (isFirst) { + return responseCode; + } + if (HandshakeResponseCode.DUPLEX_COMMUNICATION == responseCode) { + return HandshakeResponseCode.ALREADY_DUPLEX_COMMUNICATION; + } else if (HandshakeResponseCode.SIMPLEX_COMMUNICATION == responseCode) { + return HandshakeResponseCode.ALREADY_SIMPLEX_COMMUNICATION; + } + + return responseCode; + } + private void sendHandshakeResponse0(int requestId, Map data) { try { byte[] resultPayload = ControlMessageEncodingUtils.encode(data); @@ -540,7 +543,7 @@ private Map decodeHandshakePacket(ControlHandshakePacket message logger.warn(e.getMessage(), e); } - return Collections.EMPTY_MAP; + return Collections.emptyMap(); } public boolean isEnableCommunication() { diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/HealthCheckManager.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/HealthCheckManager.java index 0833679e92ca..25ccc6242b54 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/HealthCheckManager.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/HealthCheckManager.java @@ -41,8 +41,6 @@ public class HealthCheckManager { private static final PingSimplePacket PING_PACKET = PingSimplePacket.PING_PACKET; private static final PingPacket LEGACY_PING_PACKET = PingPacket.PING_PACKET; - private static final long MAXIMUM_WAITING_TIME_MILLIS = 30 * 60 * 1000; - private volatile boolean startMethodInvoked = false; private volatile boolean isStopped = false; @@ -53,10 +51,6 @@ public class HealthCheckManager { private final WriteFailFutureListener writeFailListener = new WriteFailFutureListener(logger, "ping write fail.", "ping write success."); - public HealthCheckManager(Timer healthCheckTimer, ChannelGroup channelGroup) { - this(healthCheckTimer, MAXIMUM_WAITING_TIME_MILLIS, channelGroup); - } - public HealthCheckManager(Timer timer, long waitTimeMillis, ChannelGroup channelGroup) { Assert.requireNonNull(timer, "timer must not be null"); Assert.isTrue(waitTimeMillis > 0, "waitTimeMillis is must greater than 0"); diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/LoggingServerMessageListenerFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/LoggingServerMessageListenerFactory.java new file mode 100644 index 000000000000..b96d87c647c5 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/LoggingServerMessageListenerFactory.java @@ -0,0 +1,89 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.server; + +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; +import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; +import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.rpc.packet.SendPacket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + * @author Taejin Koo + */ +public class LoggingServerMessageListenerFactory implements ServerMessageListenerFactory { + + private final boolean enableDuplex; + + public LoggingServerMessageListenerFactory() { + this(false); + } + + public LoggingServerMessageListenerFactory(boolean enableDuplex) { + this.enableDuplex = enableDuplex; + } + + @Override + public ServerMessageListener create() { + return new LoggingServerMessageListener(enableDuplex); + } + + + private static class LoggingServerMessageListener implements ServerMessageListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final boolean enableDuplex; + + public LoggingServerMessageListener(boolean enableDuplex) { + this.enableDuplex = enableDuplex; + } + + @Override + public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { + logger.info("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); + } + + @Override + public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { + logger.info("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); + pinpointSocket.response(requestPacket.getRequestId(), new byte[0]); + } + + @Override + public HandshakeResponseCode handleHandshake(Map properties) { + logger.info("handleHandshake properties:{}", properties); + + if (enableDuplex) { + return HandshakeResponseCode.DUPLEX_COMMUNICATION; + } else { + return HandshakeResponseCode.SIMPLEX_COMMUNICATION; + } + } + + @Override + public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { + logger.info("handlePing packet:{}, remote:{}", pingPacket, pinpointServer.getRemoteAddress()); + } + + } + +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/PinpointServerAcceptor.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/PinpointServerAcceptor.java index 3efabb6c43f0..a840b76708fe 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/PinpointServerAcceptor.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/PinpointServerAcceptor.java @@ -22,6 +22,7 @@ import com.navercorp.pinpoint.common.util.PinpointThreadFactory; import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.PinpointSocketException; +import com.navercorp.pinpoint.rpc.PipelineFactory; import com.navercorp.pinpoint.rpc.cluster.ClusterOption; import com.navercorp.pinpoint.rpc.packet.ServerClosePacket; import com.navercorp.pinpoint.rpc.server.handler.ServerStateChangeEventHandler; @@ -33,7 +34,9 @@ import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; +import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; @@ -62,9 +65,6 @@ public class PinpointServerAcceptor implements PinpointServerConfig { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private static final long DEFAULT_TIMEOUT_MILLIS = 3 * 1000; - private static final long CHANNEL_CLOSE_MAXIMUM_WAITING_TIME_MILLIS = 3 * 1000; - private static final int HEALTH_CHECK_INTERVAL_TIME_MILLIS = 5 * 60 * 1000; private static final int WORKER_COUNT = CpuUtils.workerCount(); private volatile boolean released; @@ -78,7 +78,8 @@ public class PinpointServerAcceptor implements PinpointServerConfig { private final PinpointServerChannelHandler nettyChannelHandler = new PinpointServerChannelHandler(); - private ServerMessageListener messageListener = SimpleServerMessageListener.SIMPLEX_INSTANCE; + private ServerMessageListenerFactory messageListenerFactory = new LoggingServerMessageListenerFactory(); + private ServerStreamChannelMessageListener serverStreamChannelMessageListener = DisabledServerStreamChannelMessageListener.INSTANCE; private List stateChangeEventHandler = new ArrayList(); @@ -87,35 +88,47 @@ public class PinpointServerAcceptor implements PinpointServerConfig { private final Timer requestManagerTimer; - private final ClusterOption clusterOption; + private final ServerOption serverOption; - private long defaultRequestTimeout = DEFAULT_TIMEOUT_MILLIS; + private final PipelineFactory pipelineFactory; static { LoggerFactorySetup.setupSlf4jLoggerFactory(); } public PinpointServerAcceptor() { - this(ClusterOption.DISABLE_CLUSTER_OPTION, ChannelFilter.BYPASS); + this(ServerOption.getDefaultServerOption(), ChannelFilter.BYPASS); } public PinpointServerAcceptor(ChannelFilter channelConnectedFilter) { - this(ClusterOption.DISABLE_CLUSTER_OPTION, channelConnectedFilter); + this(ServerOption.getDefaultServerOption(), channelConnectedFilter); + } + + public PinpointServerAcceptor(ChannelFilter channelConnectedFilter, PipelineFactory pipelineFactory) { + this(ServerOption.getDefaultServerOption(), channelConnectedFilter, pipelineFactory); + } + + public PinpointServerAcceptor(ServerOption serverOption, ChannelFilter channelConnectedFilter) { + this(serverOption, channelConnectedFilter, new ServerCodecPipelineFactory()); } - public PinpointServerAcceptor(ClusterOption clusterOption, ChannelFilter channelConnectedFilter) { + public PinpointServerAcceptor(ServerOption serverOption, ChannelFilter channelConnectedFilter, PipelineFactory pipelineFactory) { ServerBootstrap bootstrap = createBootStrap(1, WORKER_COUNT); setOptions(bootstrap); - addPipeline(bootstrap); this.bootstrap = bootstrap; + this.serverOption = Assert.requireNonNull(serverOption, "serverOption must not be null"); + logger.info("serverOption : {}", serverOption); + this.healthCheckTimer = TimerFactory.createHashedWheelTimer("PinpointServerSocket-HealthCheckTimer", 50, TimeUnit.MILLISECONDS, 512); - this.healthCheckManager = new HealthCheckManager(healthCheckTimer, channelGroup); + this.healthCheckManager = new HealthCheckManager(healthCheckTimer, serverOption.getHealthCheckPacketWaitTimeMillis(), channelGroup); this.requestManagerTimer = TimerFactory.createHashedWheelTimer("PinpointServerSocket-RequestManager", 50, TimeUnit.MILLISECONDS, 512); - this.clusterOption = clusterOption; this.channelConnectedFilter = Assert.requireNonNull(channelConnectedFilter, "channelConnectedFilter must not be null"); + + this.pipelineFactory = Assert.requireNonNull(pipelineFactory, "pipelineFactory must not be null"); + addPipeline(bootstrap, pipelineFactory); } private ServerBootstrap createBootStrap(int bossCount, int workerCount) { @@ -145,9 +158,16 @@ private void setOptions(ServerBootstrap bootstrap) { // bootstrap.setOption("child.soLinger", 0); } - private void addPipeline(ServerBootstrap bootstrap) { - ServerPipelineFactory serverPipelineFactory = new ServerPipelineFactory(nettyChannelHandler); - bootstrap.setPipelineFactory(serverPipelineFactory); + private void addPipeline(ServerBootstrap bootstrap, final PipelineFactory pipelineFactory) { + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + @Override + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = pipelineFactory.newPipeline(); + pipeline.addLast("handler", nettyChannelHandler); + + return pipeline; + } + }); } @VisibleForTesting @@ -158,6 +178,20 @@ void setPipelineFactory(ChannelPipelineFactory channelPipelineFactory) { bootstrap.setPipelineFactory(channelPipelineFactory); } + @VisibleForTesting + public void setMessageHandler(final ChannelHandler messageHandler) { + Assert.requireNonNull(messageHandler, "messageHandler must not be null"); + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + @Override + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = pipelineFactory.newPipeline(); + pipeline.addLast("handler", messageHandler); + + return pipeline; + } + }); + } + public void bind(String host, int port) throws PinpointSocketException { InetSocketAddress bindAddress = new InetSocketAddress(host, port); bind(bindAddress); @@ -170,7 +204,7 @@ public void bind(InetSocketAddress bindAddress) throws PinpointSocketException { logger.info("bind() {}", bindAddress); this.serverChannel = bootstrap.bind(bindAddress); - healthCheckManager.start(HEALTH_CHECK_INTERVAL_TIME_MILLIS); + healthCheckManager.start(serverOption.getHealthCheckIntervalTimeMillis()); } private DefaultPinpointServer createPinpointServer(Channel channel) { @@ -180,23 +214,16 @@ private DefaultPinpointServer createPinpointServer(Channel channel) { @Override public long getDefaultRequestTimeout() { - return defaultRequestTimeout; + return serverOption.getRequestTimeoutMillis(); } - public void setDefaultRequestTimeout(long defaultRequestTimeout) { - this.defaultRequestTimeout = defaultRequestTimeout; - } - - @Override public ServerMessageListener getMessageListener() { - return messageListener; + return messageListenerFactory.create(); } - public void setMessageListener(ServerMessageListener messageListener) { - Assert.requireNonNull(messageListener, "messageListener must not be null"); - - this.messageListener = messageListener; + public void setMessageListenerFactory(ServerMessageListenerFactory messageListenerFactory) { + this.messageListenerFactory = Assert.requireNonNull(messageListenerFactory, "messageListenerFactory must not be null"); } @Override @@ -228,7 +255,7 @@ public Timer getRequestManagerTimer() { @Override public ClusterOption getClusterOption() { - return clusterOption; + return serverOption.getClusterOption(); } public void close() { @@ -245,7 +272,7 @@ public void close() { if (serverChannel != null) { ChannelFuture close = serverChannel.close(); - close.awaitUninterruptibly(CHANNEL_CLOSE_MAXIMUM_WAITING_TIME_MILLIS, TimeUnit.MILLISECONDS); + close.awaitUninterruptibly(serverOption.getServerCloseWaitTimeoutMillis(), TimeUnit.MILLISECONDS); serverChannel = null; } if (bootstrap != null) { diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/ServerCodecPipelineFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/ServerCodecPipelineFactory.java new file mode 100644 index 000000000000..e5763840f8c7 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/ServerCodecPipelineFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.server; + +import com.navercorp.pinpoint.rpc.PipelineFactory; +import com.navercorp.pinpoint.rpc.codec.PacketEncoder; +import com.navercorp.pinpoint.rpc.codec.ServerPacketDecoder; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.Channels; + +/** + * @author Taejin Koo + */ +public class ServerCodecPipelineFactory implements PipelineFactory { + + public ServerCodecPipelineFactory() { + } + + @Override + public ChannelPipeline newPipeline() { + ChannelPipeline pipeline = Channels.pipeline(); + + pipeline.addLast("decoder", new ServerPacketDecoder()); + pipeline.addLast("encoder", new PacketEncoder()); + + return pipeline; + } + +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/ServerMessageListenerFactory.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/ServerMessageListenerFactory.java new file mode 100644 index 000000000000..3ebe1d3617b4 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/ServerMessageListenerFactory.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.server; + +/** + * @author Taejin Koo + */ +public interface ServerMessageListenerFactory { + + T create(); + +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/ServerOption.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/ServerOption.java new file mode 100644 index 000000000000..4f65a84a0a70 --- /dev/null +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/ServerOption.java @@ -0,0 +1,142 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.server; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.cluster.ClusterOption; + +/** + * @author Taejin Koo + */ +public class ServerOption { + + private static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = 3 * 1000; + private static final long DEFAULT_SERVER_CLOSE_WAIT_TIMEOUT_MILLIS = 3 * 1000; + private static final long DEFAULT_HEALTH_CHECK_INTERVAL_TIME_MILLIS = 5 * 60 * 1000; + private static final long DEFAULT_HEALTH_CHECK_PACKET_WAIT_TIME_MILLIS = 30 * 60 * 1000; + private static final ClusterOption DEFAULT_CLUSTER_OPTION = ClusterOption.DISABLE_CLUSTER_OPTION; + + private static final ServerOption DEFAULT_INSTANCE = new ServerOption.Builder().build(); + + private final long requestTimeoutMillis; + private final long serverCloseWaitTimeoutMillis; + private final long healthCheckIntervalTimeMillis; + private final long healthCheckPacketWaitTimeMillis; + private final ClusterOption clusterOption; + + public static ServerOption getDefaultServerOption() { + return DEFAULT_INSTANCE; + } + + private ServerOption(long requestTimeoutMillis, long serverCloseWaitTimeoutMillis, long healthCheckIntervalTimeMillis, long healthCheckPacketWaitTimeMillis, ClusterOption clusterOption) { + this.requestTimeoutMillis = requestTimeoutMillis; + this.serverCloseWaitTimeoutMillis = serverCloseWaitTimeoutMillis; + this.healthCheckIntervalTimeMillis = healthCheckIntervalTimeMillis; + this.healthCheckPacketWaitTimeMillis = healthCheckPacketWaitTimeMillis; + this.clusterOption = clusterOption; + } + + public long getRequestTimeoutMillis() { + return requestTimeoutMillis; + } + + public long getServerCloseWaitTimeoutMillis() { + return serverCloseWaitTimeoutMillis; + } + + public long getHealthCheckIntervalTimeMillis() { + return healthCheckIntervalTimeMillis; + } + + public long getHealthCheckPacketWaitTimeMillis() { + return healthCheckPacketWaitTimeMillis; + } + + public ClusterOption getClusterOption() { + return clusterOption; + } + + @Override + public String toString() { + return "ServerOption{" + + "requestTimeoutMillis=" + requestTimeoutMillis + + ", serverCloseWaitTimeoutMillis=" + serverCloseWaitTimeoutMillis + + ", healthCheckIntervalTimeMillis=" + healthCheckIntervalTimeMillis + + ", healthCheckPacketWaitTimeMillis=" + healthCheckPacketWaitTimeMillis + + ", clusterOption=" + clusterOption + + '}'; + } + + public static class Builder { + + private long requestTimeoutMillis = DEFAULT_REQUEST_TIMEOUT_MILLIS; + private long serverCloseWaitTimeoutMillis = DEFAULT_SERVER_CLOSE_WAIT_TIMEOUT_MILLIS; + private long healthCheckIntervalTimeMillis = DEFAULT_HEALTH_CHECK_INTERVAL_TIME_MILLIS; + private long healthCheckPacketWaitTimeMillis = DEFAULT_HEALTH_CHECK_PACKET_WAIT_TIME_MILLIS; + private ClusterOption clusterOption = DEFAULT_CLUSTER_OPTION; + + public long getRequestTimeoutMillis() { + return requestTimeoutMillis; + } + + public void setRequestTimeoutMillis(long requestTimeoutMillis) { + Assert.isTrue(requestTimeoutMillis > 0, "requestTimeoutMillis cannot be a negative number"); + this.requestTimeoutMillis = requestTimeoutMillis; + } + + public long getServerCloseWaitTimeoutMillis() { + return serverCloseWaitTimeoutMillis; + } + + public void setServerCloseWaitTimeoutMillis(long serverCloseWaitTimeoutMillis) { + Assert.isTrue(serverCloseWaitTimeoutMillis > 0, "serverCloseWaitTimeoutMillis cannot be a negative number"); + this.serverCloseWaitTimeoutMillis = serverCloseWaitTimeoutMillis; + } + + public long getHealthCheckIntervalTimeMillis() { + return healthCheckIntervalTimeMillis; + } + + public void setHealthCheckIntervalTimeMillis(long healthCheckIntervalTimeMillis) { + Assert.isTrue(healthCheckIntervalTimeMillis > 0, "healthCheckIntervalTimeMillis cannot be a negative number"); + this.healthCheckIntervalTimeMillis = healthCheckIntervalTimeMillis; + } + + public long getHealthCheckPacketWaitTimeMillis() { + return healthCheckPacketWaitTimeMillis; + } + + public void setHealthCheckPacketWaitTimeMillis(long healthCheckPacketWaitTimeMillis) { + Assert.isTrue(healthCheckPacketWaitTimeMillis > 0, "healthCheckPacketWaitTimeMillis cannot be a negative number"); + this.healthCheckPacketWaitTimeMillis = healthCheckPacketWaitTimeMillis; + } + + public ClusterOption getClusterOption() { + return clusterOption; + } + + public void setClusterOption(ClusterOption clusterOption) { + this.clusterOption = Assert.requireNonNull(clusterOption, "clusterOption must not be null"); + } + + public ServerOption build() { + return new ServerOption(requestTimeoutMillis, serverCloseWaitTimeoutMillis, healthCheckIntervalTimeMillis, healthCheckPacketWaitTimeMillis, clusterOption); + } + + } + +} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/SimpleServerMessageListener.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/SimpleServerMessageListener.java deleted file mode 100644 index f8986fdfd246..000000000000 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/server/SimpleServerMessageListener.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.rpc.server; - -import com.navercorp.pinpoint.rpc.client.SimpleMessageListener; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Map; - -/** - * @author emeroad - */ -public class SimpleServerMessageListener extends SimpleMessageListener implements ServerMessageListener { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - public static final SimpleServerMessageListener SIMPLEX_INSTANCE = new SimpleServerMessageListener(HandshakeResponseType.Success.SIMPLEX_COMMUNICATION); - public static final SimpleServerMessageListener DUPLEX_INSTANCE = new SimpleServerMessageListener(HandshakeResponseType.Success.DUPLEX_COMMUNICATION); - - public static final SimpleServerMessageListener SIMPLEX_ECHO_INSTANCE = new SimpleServerMessageListener(true, HandshakeResponseType.Success.SIMPLEX_COMMUNICATION); - public static final SimpleServerMessageListener DUPLEX_ECHO_INSTANCE = new SimpleServerMessageListener(true, HandshakeResponseType.Success.DUPLEX_COMMUNICATION); - - private final HandshakeResponseCode handshakeResponseCode; - - public SimpleServerMessageListener(HandshakeResponseCode handshakeResponseCode) { - this(false, handshakeResponseCode); - } - - public SimpleServerMessageListener(boolean echo, HandshakeResponseCode handshakeResponseCode) { - super(echo); - this.handshakeResponseCode = handshakeResponseCode; - } - - @Override - public HandshakeResponseCode handleHandshake(Map properties) { - logger.info("handleHandshake properties:{}", properties); - return handshakeResponseCode; - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - logger.info("handlePing packet:{}, remote:{}", pingPacket, pinpointServer.getRemoteAddress()); - } - -} diff --git a/rpc/src/main/java/com/navercorp/pinpoint/rpc/util/ClientFactoryUtils.java b/rpc/src/main/java/com/navercorp/pinpoint/rpc/util/ClientFactoryUtils.java index ddf842c32b7d..61383f99f967 100644 --- a/rpc/src/main/java/com/navercorp/pinpoint/rpc/util/ClientFactoryUtils.java +++ b/rpc/src/main/java/com/navercorp/pinpoint/rpc/util/ClientFactoryUtils.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.rpc.util; +import com.navercorp.pinpoint.common.util.Assert; import com.navercorp.pinpoint.rpc.PinpointSocketException; import com.navercorp.pinpoint.rpc.client.PinpointClient; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; @@ -31,11 +32,75 @@ public final class ClientFactoryUtils { private static final Logger LOGGER = LoggerFactory.getLogger(ClientFactoryUtils.class); + + public interface PinpointClientProvider { + PinpointClient get(); + } + + public static PinpointClientProvider newPinpointClientProvider(String host, int port, PinpointClientFactory clientFactory) { + return new DnsPinpointClientProvider(host, port, clientFactory); + } + + private static class DnsPinpointClientProvider implements PinpointClientProvider { + private final PinpointClientFactory clientFactory; + private final String host; + private final int port; + + public DnsPinpointClientProvider(String host, int port, PinpointClientFactory clientFactory) { + this.host = Assert.requireNonNull(host, "host must not be null"); + this.port = port; + this.clientFactory = Assert.requireNonNull(clientFactory, "clientFactory must not be null"); + } + + @Override + public PinpointClient get() { + return createPinpointClient(host, port, clientFactory); + } + } + public static PinpointClient createPinpointClient(String host, int port, PinpointClientFactory clientFactory) { - InetSocketAddress connectAddress = new InetSocketAddress(host, port); - return createPinpointClient(connectAddress, clientFactory); + + PinpointClient pinpointClient = null; + for (int i = 0; i < 3; i++) { + try { + pinpointClient = clientFactory.connect(host, port); + LOGGER.info("tcp connect success. remote:{}/{}", host, port); + return pinpointClient; + } catch (PinpointSocketException e) { + LOGGER.warn("tcp connect fail. remote:{}/{} try reconnect, retryCount:{}", host, port, i); + } + } + LOGGER.warn("change background tcp connect mode remote:{}/{} ", host, port); + pinpointClient = clientFactory.scheduledConnect(host, port); + + return pinpointClient; + } + + @Deprecated + public static PinpointClientProvider newPinpointClientProvider(InetSocketAddress inetSocketAddress, PinpointClientFactory clientFactory) { + return new StaticPinpointClientProvider(inetSocketAddress, clientFactory); + } + + @Deprecated + private static class StaticPinpointClientProvider implements PinpointClientProvider { + private final InetSocketAddress inetSocketAddress; + private final PinpointClientFactory clientFactory; + + public StaticPinpointClientProvider(InetSocketAddress inetSocketAddress, PinpointClientFactory clientFactory) { + this.inetSocketAddress = Assert.requireNonNull(inetSocketAddress, "host must not be null"); + this.clientFactory = Assert.requireNonNull(clientFactory, "clientFactory must not be null"); + } + + @Override + public PinpointClient get() { + return createPinpointClient(inetSocketAddress, clientFactory); + } } + /** + * @deprecated Since 1.7.2 Use {@link #createPinpointClient(String, int, PinpointClientFactory)} + */ + @Deprecated public static PinpointClient createPinpointClient(InetSocketAddress connectAddress, PinpointClientFactory clientFactory) { PinpointClient pinpointClient = null; for (int i = 0; i < 3; i++) { diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/DiscardServerHandler.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/DiscardServerHandler.java index 9a540648df4a..628bc5dc7f8d 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/DiscardServerHandler.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/DiscardServerHandler.java @@ -17,7 +17,6 @@ package com.navercorp.pinpoint.rpc; -import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,31 +28,35 @@ public class DiscardServerHandler extends SimpleChannelUpstreamHandler { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private long transferredBytes; - - public long getTransferredBytes() { - return transferredBytes; - } + private int messageReceivedCount = 0; @Override - public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { - if (e instanceof ChannelStateEvent) { - logger.debug("event:{}", e); + public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent event) throws Exception { + if (event instanceof ChannelStateEvent) { + logger.debug("event:{}", event); + } else if (event instanceof MessageEvent) { + messageReceived(ctx, (MessageEvent) event); } - } @Override - public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { - - transferredBytes += ((ChannelBuffer) e.getMessage()).readableBytes(); - logger.debug("messageReceived. meg:{} channel:{}", e.getMessage(), e.getChannel()); - logger.debug("transferredBytes. transferredBytes:{}", transferredBytes); + public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) { + messageReceivedCount++; + try { + logger.debug("messageReceived. meg:{} channel:{}", event.getMessage(), event.getChannel()); + } catch (Exception e) { + logger.warn("catch exception. message:{}", e.getMessage(), e); + } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { logger.warn("Unexpected exception from downstream. Caused:{}", e, e.getCause()); } + + public int getMessageReceivedCount() { + return messageReceivedCount; + } + } diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/TestAwaitTaskUtils.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/TestAwaitTaskUtils.java deleted file mode 100644 index ed628d6aefd0..000000000000 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/TestAwaitTaskUtils.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.rpc; - -/** - * @author Taejin Koo - */ -public interface TestAwaitTaskUtils { - - boolean checkCompleted(); - -} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/TestAwaitUtils.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/TestAwaitUtils.java deleted file mode 100644 index 8bd65dc3fa74..000000000000 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/TestAwaitUtils.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.rpc; - -import com.navercorp.pinpoint.common.util.StopWatch; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Taejin Koo - */ -public class TestAwaitUtils { - - private final static Logger LOGGER = LoggerFactory.getLogger(TestAwaitUtils.class); - - private final long waitUnitTime; - private final long maxWaitTime; - - public TestAwaitUtils(long waitUnitTime, long maxWaitTime) { - this.waitUnitTime = waitUnitTime; - this.maxWaitTime = maxWaitTime; - } - - public boolean await(TestAwaitTaskUtils awaitTaskUtils) { - return await(awaitTaskUtils, waitUnitTime, maxWaitTime); - } - - public static boolean await(TestAwaitTaskUtils awaitTaskUtils, long waitUnitTime, long maxWaitTime) { - StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - - while (true) { - try { - if (awaitTaskUtils.checkCompleted()) { - return true; - } - } catch (Exception e) { - LOGGER.warn(e.getMessage(), e); - } - - try { - Thread.sleep(waitUnitTime); - } catch (InterruptedException e) { - } - - if (stopWatch.stop() > maxWaitTime) { - return false; - } - } - } - -} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/ClientMessageListenerTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/ClientMessageListenerTest.java index bd4dd7c66ec0..aa794da5a9d6 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/ClientMessageListenerTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/ClientMessageListenerTest.java @@ -17,88 +17,73 @@ package com.navercorp.pinpoint.rpc.client; import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.TestAwaitTaskUtils; -import com.navercorp.pinpoint.rpc.TestAwaitUtils; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.SimpleServerMessageListener; import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils.EchoClientListener; +import com.navercorp.pinpoint.test.client.TestPinpointClient; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; -import org.springframework.util.SocketUtils; - -import java.io.IOException; -import java.util.List; /** * @author Taejin Koo */ public class ClientMessageListenerTest { - private static int bindPort; - private final TestAwaitUtils awaitUtils = new TestAwaitUtils(10, 1000); - - @BeforeClass - public static void setUp() throws IOException { - bindPort = SocketUtils.findAvailableTcpPort(); - } + private final TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX); @Test public void clientMessageListenerTest1() throws InterruptedException { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_INSTANCE); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); EchoClientListener echoMessageListener = new EchoClientListener(); - PinpointClientFactory clientSocketFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), echoMessageListener); - + TestPinpointClient testPinpointClient = new TestPinpointClient(echoMessageListener, PinpointRPCTestUtils.getParams()); try { - PinpointClient client = clientSocketFactory.connect("127.0.0.1", bindPort); - assertAvailableWritableSocket(serverAcceptor, 1); + testPinpointClient.connect(bindPort); + testPinpointServerAcceptor.assertAwaitClientConnected(1, 1000); - List writableServerList = serverAcceptor.getWritableSocketList(); - PinpointSocket writableServer = writableServerList.get(0); + PinpointSocket writableServer = testPinpointServerAcceptor.getConnectedPinpointSocketList().get(0); assertSendMessage(writableServer, "simple", echoMessageListener); assertRequestMessage(writableServer, "request", echoMessageListener); - - PinpointRPCTestUtils.close(client); } finally { - clientSocketFactory.release(); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } @Test public void clientMessageListenerTest2() throws InterruptedException { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_INSTANCE); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); - EchoClientListener echoMessageListener1 = PinpointRPCTestUtils.createEchoClientListener(); - PinpointClientFactory clientSocketFactory1 = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), echoMessageListener1); + TestServerMessageListenerFactory.TestServerMessageListener echoMessageListener1 = testServerMessageListenerFactory.create(); + TestPinpointClient testPinpointClient1 = new TestPinpointClient(echoMessageListener1, PinpointRPCTestUtils.getParams()); - EchoClientListener echoMessageListener2 = PinpointRPCTestUtils.createEchoClientListener(); - PinpointClientFactory clientSocketFactory2 = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), echoMessageListener2); + TestServerMessageListenerFactory.TestServerMessageListener echoMessageListener2 = testServerMessageListenerFactory.create(); + TestPinpointClient testPinpointClient2 = new TestPinpointClient(echoMessageListener2, PinpointRPCTestUtils.getParams()); try { - PinpointClient client = clientSocketFactory1.connect("127.0.0.1", bindPort); - PinpointClient client2 = clientSocketFactory2.connect("127.0.0.1", bindPort); - assertAvailableWritableSocket(serverAcceptor, 2); + testPinpointClient1.connect(bindPort); + testPinpointClient2.connect(bindPort); + testPinpointServerAcceptor.assertAwaitClientConnected(2, 1000); - List writableServerList = serverAcceptor.getWritableSocketList(); - PinpointSocket writableServer = writableServerList.get(0); + PinpointSocket writableServer = testPinpointServerAcceptor.getConnectedPinpointSocketList().get(0); assertRequestMessage(writableServer, "socket1", null); - PinpointSocket writableServer2 = writableServerList.get(1); + PinpointSocket writableServer2 = testPinpointServerAcceptor.getConnectedPinpointSocketList().get(1); assertRequestMessage(writableServer2, "socket2", null); - Assert.assertEquals(1, echoMessageListener1.getRequestPacketRepository().size()); - Assert.assertEquals(1, echoMessageListener2.getRequestPacketRepository().size()); - PinpointRPCTestUtils.close(client, client2); + echoMessageListener1.awaitAssertExpectedRequestCount(1, 0); + echoMessageListener2.awaitAssertExpectedRequestCount(1, 0); } finally { - clientSocketFactory1.release(); - clientSocketFactory2.release(); - - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient1.closeAll(); + testPinpointClient2.closeAll(); + testPinpointServerAcceptor.close(); } } @@ -124,15 +109,4 @@ private void assertRequestMessage(PinpointSocket writableServer, String message, } } - private void assertAvailableWritableSocket(final PinpointServerAcceptor serverAcceptor, final int expectedWritableSocketSize) { - boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - return serverAcceptor.getWritableSocketList().size() == expectedWritableSocketSize; - } - }); - - Assert.assertTrue(pass); - } - } diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/DnsSocketAddressProviderTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/DnsSocketAddressProviderTest.java new file mode 100644 index 000000000000..3cee9b7d2a62 --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/DnsSocketAddressProviderTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.client; + +import org.junit.Assert; +import org.junit.Test; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + + +/** + * @author Woonduk Kang(emeroad) + */ +public class DnsSocketAddressProviderTest { + + @Test + public void resolve_success() { + String hostName = "127.0.0.1"; + int port = 80; + DnsSocketAddressProvider localhost = new DnsSocketAddressProvider(hostName, port); + Assert.assertEquals(localhost.resolve(), new InetSocketAddress(hostName, port)); + Assert.assertEquals(localhost.resolve(), new InetSocketAddress(hostName, port)); + + } + + + @Test + public void resolve_fail() { + String hostName = "empty"; + int port = 80; + DnsSocketAddressProvider empty = new DnsSocketAddressProvider(hostName, port); + Assert.assertEquals(empty.resolve(), new InetSocketAddress(hostName, port)); + Assert.assertEquals(empty.resolve(), new InetSocketAddress(hostName, port)); + + } + + + /** + * check npe + */ + @Test + public void resolve_update() { + final String host1 = "127.0.0.1"; + final String host2 = "127.0.0.2"; + int port = 80; + DnsSocketAddressProvider empty = new DnsSocketAddressProvider("empty", port) { + private int i = 0; + @Override + InetAddress getByName(String host) throws UnknownHostException { + if (i == 0) { + i++; + return InetAddress.getByName(host1); + } else { + return InetAddress.getByName(host2); + } + } + }; + Assert.assertEquals(empty.resolve(), new InetSocketAddress(host1, port)); + Assert.assertEquals(empty.resolve(), new InetSocketAddress(host2, port)); + } +} \ No newline at end of file diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/HealthCheckTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/HealthCheckTest.java index 1bacd5cda62b..8d1f714b58b4 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/HealthCheckTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/HealthCheckTest.java @@ -21,216 +21,163 @@ import com.navercorp.pinpoint.rpc.packet.PingPacket; import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; import com.navercorp.pinpoint.rpc.packet.PingSimplePacket; -import com.navercorp.pinpoint.rpc.packet.PongPacket; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.util.IOUtils; -import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; +import com.navercorp.pinpoint.test.client.TestRawSocket; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; -import org.springframework.util.SocketUtils; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicBoolean; /** * @author Taejin Koo */ public class HealthCheckTest { - private static int bindPort; - - @BeforeClass - public static void setUp() throws IOException { - bindPort = SocketUtils.findAvailableTcpPort(); - } - @Test public void legacyHealthCheckTest1() throws Exception { - final AtomicBoolean pingHandled = new AtomicBoolean(false); + TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX, true); + TestServerMessageListenerFactory.TestServerMessageListener serverMessageListener = testServerMessageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new PinpointRPCTestUtils.EchoServerListener() { - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - pingHandled.compareAndSet(false, true); - } - }); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); - sendPingAndReceivePongPacket(socket, PingPacket.PING_PACKET); + testRawSocket.connect(bindPort); + sendPingAndReceivePongPacket(testRawSocket, PingPacket.PING_PACKET); } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } - Assert.assertFalse(pingHandled.get()); + Assert.assertFalse(serverMessageListener.hasReceivedPing()); } @Test public void legacyHealthCheckTest2() throws Exception { - final AtomicBoolean pingHandled = new AtomicBoolean(false); + TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX, true); + TestServerMessageListenerFactory.TestServerMessageListener serverMessageListener = testServerMessageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new PinpointRPCTestUtils.EchoServerListener() { - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - pingHandled.compareAndSet(false, true); - } - }); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); - sendPingAndReceivePongPacket(socket, new PingPacket(1, (byte) 1, (byte) 10)); + testRawSocket.connect(bindPort); + sendPingAndReceivePongPacket(testRawSocket, new PingPacket(1, (byte) 1, (byte) 10)); } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } - Assert.assertTrue(pingHandled.get()); + Assert.assertTrue(serverMessageListener.hasReceivedPing()); } @Test public void healthCheckTest() throws Exception { - final AtomicBoolean pingHandled = new AtomicBoolean(false); + TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX, true); + TestServerMessageListenerFactory.TestServerMessageListener serverMessageListener = testServerMessageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new PinpointRPCTestUtils.EchoServerListener() { - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - pingHandled.compareAndSet(false, true); - } - }); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); + testRawSocket.connect(bindPort); // RUN_WITHOUT_HANDSHAKE - sendPingAndReceivePongPacket(socket, new PingPayloadPacket(1, (byte) 1, (byte) 10)); + sendPingAndReceivePongPacket(testRawSocket, new PingPayloadPacket(1, (byte) 1, (byte) 10)); } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } - Assert.assertTrue(pingHandled.get()); + Assert.assertTrue(serverMessageListener.hasReceivedPing()); } @Test public void healthCheckSimplePingTest() throws Exception { - final AtomicBoolean pingHandled = new AtomicBoolean(false); + TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX, true); + TestServerMessageListenerFactory.TestServerMessageListener serverMessageListener = testServerMessageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new PinpointRPCTestUtils.EchoServerListener() { - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - pingHandled.compareAndSet(false, true); - } - }); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); - sendPingAndReceivePongPacket(socket, new PingSimplePacket()); + testRawSocket.connect(bindPort); + sendPingAndReceivePongPacket(testRawSocket, new PingSimplePacket()); Assert.fail(); } catch (Exception e) { } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } - Assert.assertFalse(pingHandled.get()); + Assert.assertFalse(serverMessageListener.hasReceivedPing()); } @Test public void stateSyncFailTest() throws Exception { - final AtomicBoolean pingHandled = new AtomicBoolean(false); + TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX, true); + TestServerMessageListenerFactory.TestServerMessageListener serverMessageListener = testServerMessageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new PinpointRPCTestUtils.EchoServerListener() { - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - pingHandled.compareAndSet(false, true); - } - }); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); boolean isSuccess = false; - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); + testRawSocket.connect(bindPort); - sendPingAndReceivePongPacket(socket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); - sendPingAndReceivePongPacket(socket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); - sendPingAndReceivePongPacket(socket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); - sendPingAndReceivePongPacket(socket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); + sendPingAndReceivePongPacket(testRawSocket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); + sendPingAndReceivePongPacket(testRawSocket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); + sendPingAndReceivePongPacket(testRawSocket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); + sendPingAndReceivePongPacket(testRawSocket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); isSuccess = true; - sendPingAndReceivePongPacket(socket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); + sendPingAndReceivePongPacket(testRawSocket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); Assert.fail(); } catch (Exception e) { Assert.assertTrue(isSuccess); } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } - Assert.assertFalse(pingHandled.get()); + Assert.assertFalse(serverMessageListener.hasReceivedPing()); } @Ignore @Test public void expiredHealthCheckTest() throws Exception { - final AtomicBoolean pingHandled = new AtomicBoolean(false); + TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX, true); + TestServerMessageListenerFactory.TestServerMessageListener serverMessageListener = testServerMessageListenerFactory.create(); - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new PinpointRPCTestUtils.EchoServerListener() { - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - pingHandled.compareAndSet(false, true); - } - }); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); + testRawSocket.connect(bindPort); Thread.sleep(35 * 60 * 1000); - sendPingAndReceivePongPacket(socket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); + sendPingAndReceivePongPacket(testRawSocket, new PingPayloadPacket(1, (byte) 1, (byte) 1)); Assert.fail(); } catch (Exception e) { } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } - Assert.assertFalse(pingHandled.get()); - } - - private void sendPingAndReceivePongPacket(Socket socket, Packet pingPacket) throws IOException, ProtocolException { - sendPingPacket(socket.getOutputStream(), pingPacket); - PongPacket pongPacket = readPongPacket(socket.getInputStream()); - Assert.assertNotNull(pongPacket); + Assert.assertFalse(serverMessageListener.hasReceivedPing()); } - private void sendPingPacket(OutputStream outputStream, Packet pingPacket) throws ProtocolException, IOException { - ByteBuffer bb = pingPacket.toBuffer().toByteBuffer(0, pingPacket.toBuffer().writerIndex()); - IOUtils.write(outputStream, bb.array()); - } - - - private PongPacket readPongPacket(InputStream inputStream) throws ProtocolException, IOException { - byte[] payload = IOUtils.read(inputStream, 50, 3000); - ChannelBuffer cb = ChannelBuffers.wrappedBuffer(payload); - - short packetType = cb.readShort(); - - PongPacket pongPacket = PongPacket.readBuffer(packetType, cb); - return pongPacket; + private void sendPingAndReceivePongPacket(TestRawSocket testRawSocket, Packet pingPacket) throws IOException, ProtocolException { + testRawSocket.sendPingPacket(pingPacket); + Assert.assertNotNull(testRawSocket.readPongPacket(3000)); } } diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/PinpointClientFactoryTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/PinpointClientFactoryTest.java index 206e344c49e9..910f44af7f25 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/PinpointClientFactoryTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/PinpointClientFactoryTest.java @@ -18,11 +18,11 @@ import com.navercorp.pinpoint.rpc.PinpointSocketException; import com.navercorp.pinpoint.rpc.TestByteUtils; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; -import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.SimpleServerMessageListener; import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import org.jboss.netty.channel.ChannelFuture; import org.junit.AfterClass; import org.junit.Assert; @@ -35,7 +35,6 @@ import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; -import java.util.concurrent.CountDownLatch; /** @@ -44,13 +43,10 @@ public class PinpointClientFactoryTest { private Logger logger = LoggerFactory.getLogger(this.getClass()); - private static int bindPort; - private static PinpointClientFactory clientFactory; + private static DefaultPinpointClientFactory clientFactory; @BeforeClass public static void setUp() throws IOException { - bindPort = SocketUtils.findAvailableTcpPort(); - clientFactory = new DefaultPinpointClientFactory(); clientFactory.setPingDelay(100); } @@ -65,7 +61,8 @@ public static void tearDown() { @Test public void connectFail() { try { - clientFactory.connect("127.0.0.1", bindPort); + int availableTcpPort = SocketUtils.findAvailableTcpPort(47000); + clientFactory.connect("127.0.0.1", availableTcpPort); Assert.fail(); } catch (PinpointSocketException e) { Assert.assertTrue(ConnectException.class.isInstance(e.getCause())); @@ -75,7 +72,8 @@ public void connectFail() { @Test public void reconnectFail() throws InterruptedException { // confirm simplified error message when api called. - InetSocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", bindPort); + int availableTcpPort = SocketUtils.findAvailableTcpPort(47000); + InetSocketAddress remoteAddress = new InetSocketAddress("127.0.0.1", availableTcpPort); ChannelFuture reconnect = clientFactory.reconnect(remoteAddress); reconnect.await(); Assert.assertFalse(reconnect.isSuccess()); @@ -86,51 +84,59 @@ public void reconnectFail() throws InterruptedException { @Test public void connect() throws IOException, InterruptedException { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(); + int bindPort = testPinpointServerAcceptor.bind(); try { PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); PinpointRPCTestUtils.close(client); } finally { - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @Test public void pingInternal() throws IOException, InterruptedException { - final CountDownLatch pingLatch = new CountDownLatch(1); - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new PinpointRPCTestUtils.EchoServerListener() { - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - pingLatch.countDown(); - } - }); + TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX, true); + final TestServerMessageListenerFactory.TestServerMessageListener serverMessageListener = testServerMessageListenerFactory.create(); + + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); try { PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); - pingLatch.await(); + + boolean await = TestAwaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return serverMessageListener.hasReceivedPing(); + } + }, 100, 3000); + Assert.assertTrue(await); PinpointRPCTestUtils.close(client); } finally { - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @Test public void ping() throws IOException, InterruptedException { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(); + int bindPort = testPinpointServerAcceptor.bind(); try { PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); client.sendPing(); PinpointRPCTestUtils.close(client); } finally { - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @Test public void pingAndRequestResponse() throws IOException, InterruptedException { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX)); + int bindPort = testPinpointServerAcceptor.bind(); try { PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); @@ -141,13 +147,14 @@ public void pingAndRequestResponse() throws IOException, InterruptedException { Assert.assertArrayEquals(randomByte, response); PinpointRPCTestUtils.close(client); } finally { - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @Test public void sendSync() throws IOException, InterruptedException { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(); + int bindPort = testPinpointServerAcceptor.bind(); try { PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); @@ -158,13 +165,14 @@ public void sendSync() throws IOException, InterruptedException { PinpointRPCTestUtils.close(client); } finally { - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @Test public void requestAndResponse() throws IOException, InterruptedException { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX)); + int bindPort = testPinpointServerAcceptor.bind(); try { PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); @@ -175,7 +183,7 @@ public void requestAndResponse() throws IOException, InterruptedException { Assert.assertArrayEquals(randomByte, response); PinpointRPCTestUtils.close(client); } finally { - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/PinpointClientStateTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/PinpointClientStateTest.java index 85f792779d2a..88a5787846aa 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/PinpointClientStateTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/PinpointClientStateTest.java @@ -17,45 +17,39 @@ package com.navercorp.pinpoint.rpc.client; import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.TestAwaitTaskUtils; -import com.navercorp.pinpoint.rpc.TestAwaitUtils; import com.navercorp.pinpoint.rpc.common.SocketStateCode; import com.navercorp.pinpoint.rpc.server.DefaultPinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; import org.springframework.util.SocketUtils; -import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.List; /** * @author Taejin Koo */ public class PinpointClientStateTest { - private static int bindPort; - + private final TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX); private final TestAwaitUtils awaitUtils = new TestAwaitUtils(100, 2000); - @BeforeClass - public static void setUp() throws IOException { - bindPort = SocketUtils.findAvailableTcpPort(); - } - @Test public void connectFailedStateTest() throws InterruptedException { PinpointClientFactory clientFactory = null; DefaultPinpointClientHandler handler = null; try { - clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - handler = connect(clientFactory); + int availableTcpPort = SocketUtils.findAvailableTcpPort(47000); + + clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), testServerMessageListenerFactory.create()); + handler = connect(clientFactory, availableTcpPort); assertHandlerState(SocketStateCode.CONNECT_FAILED, handler); } finally { @@ -66,14 +60,14 @@ public void connectFailedStateTest() throws InterruptedException { @Test public void closeStateTest() throws InterruptedException { - PinpointServerAcceptor serverAcceptor = null; + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); + PinpointClientFactory clientSocketFactory = null; DefaultPinpointClientHandler handler = null; try { - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, PinpointRPCTestUtils.createEchoServerListener()); - - clientSocketFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - handler = connect(clientSocketFactory); + clientSocketFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), testServerMessageListenerFactory.create()); + handler = connect(clientSocketFactory, bindPort); assertHandlerState(SocketStateCode.RUN_DUPLEX, handler); handler.close(); @@ -81,41 +75,41 @@ public void closeStateTest() throws InterruptedException { } finally { closeHandler(handler); closeSocketFactory(clientSocketFactory); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @Test public void closeByPeerStateTest() throws InterruptedException { - PinpointServerAcceptor serverAcceptor = null; + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); + PinpointClientFactory clientFactory = null; DefaultPinpointClientHandler handler = null; try { - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, PinpointRPCTestUtils.createEchoServerListener()); - - clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - handler = connect(clientFactory); + clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), testServerMessageListenerFactory.create()); + handler = connect(clientFactory, bindPort); assertHandlerState(SocketStateCode.RUN_DUPLEX, handler); - serverAcceptor.close(); + testPinpointServerAcceptor.close(); assertHandlerState(SocketStateCode.CLOSED_BY_SERVER, handler); } finally { closeHandler(handler); closeSocketFactory(clientFactory); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @Test public void unexpectedCloseStateTest() throws InterruptedException { - PinpointServerAcceptor serverAcceptor = null; + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); + PinpointClientFactory clientFactory = null; DefaultPinpointClientHandler handler = null; try { - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, PinpointRPCTestUtils.createEchoServerListener()); - - clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - handler = connect(clientFactory); + clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), testServerMessageListenerFactory.create()); + handler = connect(clientFactory, bindPort); assertHandlerState(SocketStateCode.RUN_DUPLEX, handler); clientFactory.release(); @@ -123,30 +117,29 @@ public void unexpectedCloseStateTest() throws InterruptedException { } finally { closeHandler(handler); closeSocketFactory(clientFactory); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @Test public void unexpectedCloseByPeerStateTest() throws InterruptedException { - PinpointServerAcceptor serverAcceptor = null; + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); + PinpointClientFactory clientFactory = null; DefaultPinpointClientHandler handler = null; try { - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, PinpointRPCTestUtils.createEchoServerListener()); - - clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - handler = connect(clientFactory); + clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), testServerMessageListenerFactory.create()); + handler = connect(clientFactory, bindPort); assertHandlerState(SocketStateCode.RUN_DUPLEX, handler); - List pinpointServerList = serverAcceptor.getWritableSocketList(); - PinpointSocket pinpointServer = pinpointServerList.get(0); + PinpointSocket pinpointServer = testPinpointServerAcceptor.getConnectedPinpointSocketList().get(0); ((DefaultPinpointServer) pinpointServer).stop(true); assertHandlerState(SocketStateCode.UNEXPECTED_CLOSE_BY_SERVER, handler); } finally { closeHandler(handler); closeSocketFactory(clientFactory); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @@ -161,9 +154,9 @@ public boolean checkCompleted() { Assert.assertTrue(passed); } - private DefaultPinpointClientHandler connect(PinpointClientFactory factory) { - ChannelFuture future = factory.reconnect(new InetSocketAddress("127.0.0.1", bindPort)); - PinpointClientHandler handler = getSocketHandler(future, new InetSocketAddress("127.0.0.1", bindPort)); + private DefaultPinpointClientHandler connect(PinpointClientFactory factory, int port) { + ChannelFuture future = factory.reconnect(new InetSocketAddress("127.0.0.1", port)); + PinpointClientHandler handler = getSocketHandler(future, new InetSocketAddress("127.0.0.1", port)); return (DefaultPinpointClientHandler) handler; } @@ -174,7 +167,6 @@ PinpointClientHandler getSocketHandler(ChannelFuture channelConnectFuture, Socke Channel channel = channelConnectFuture.getChannel(); PinpointClientHandler pinpointClientHandler = (PinpointClientHandler) channel.getPipeline().getLast(); - pinpointClientHandler.setConnectSocketAddress(address); return pinpointClientHandler; } diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/ReconnectTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/ReconnectTest.java index 9ad37fe65dbf..74a931b575cf 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/ReconnectTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/ReconnectTest.java @@ -19,13 +19,17 @@ import com.navercorp.pinpoint.rpc.Future; import com.navercorp.pinpoint.rpc.PinpointSocketException; import com.navercorp.pinpoint.rpc.ResponseMessage; -import com.navercorp.pinpoint.rpc.TestAwaitTaskUtils; -import com.navercorp.pinpoint.rpc.TestAwaitUtils; import com.navercorp.pinpoint.rpc.TestByteUtils; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.SimpleServerMessageListener; import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; -import org.junit.*; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.SocketUtils; @@ -44,19 +48,19 @@ public class ReconnectTest { private Logger logger = LoggerFactory.getLogger(this.getClass()); - private static int bindPort; private static PinpointClientFactory clientFactory; + private final TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX); + private final TestAwaitUtils awaitUtils = new TestAwaitUtils(100, 1000); @BeforeClass public static void setUp() throws IOException { - bindPort = SocketUtils.findAvailableTcpPort(); - clientFactory = new DefaultPinpointClientFactory(); clientFactory.setReconnectDelay(200); clientFactory.setPingDelay(100); - clientFactory.setTimeoutMillis(200); + clientFactory.setWriteTimeoutMillis(200); + clientFactory.setRequestTimeoutMillis(200); } @AfterClass @@ -66,14 +70,14 @@ public static void tearDown() { } } - @Test public void reconnect() throws IOException, InterruptedException { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(); + int bindPort = testPinpointServerAcceptor.bind(); final AtomicBoolean reconnectPerformed = new AtomicBoolean(false); - PinpointServerAcceptor newServerAcceptor = null; + TestPinpointServerAcceptor newTestPinpointServerAcceptor = null; try { PinpointClient client = clientFactory.connect("localhost", bindPort); client.addPinpointClientReconnectEventListener(new PinpointClientReconnectEventListener() { @@ -84,12 +88,13 @@ public void reconnectPerformed(PinpointClient client) { } }); - - PinpointRPCTestUtils.close(serverAcceptor); + + testPinpointServerAcceptor.close(); logger.debug("server.close"); assertClientDisconnected(client); - newServerAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + newTestPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + newTestPinpointServerAcceptor.bind(bindPort); logger.debug("bind server"); assertClientConnected(client); @@ -101,7 +106,7 @@ public void reconnectPerformed(PinpointClient client) { PinpointRPCTestUtils.close(client); } finally { - PinpointRPCTestUtils.close(newServerAcceptor); + TestPinpointServerAcceptor.staticClose(newTestPinpointServerAcceptor); } Assert.assertTrue(reconnectPerformed.get()); @@ -118,15 +123,17 @@ public void reconnectStressTest() throws IOException, InterruptedException { int threadCount = tbean.getThreadCount(); for (int i = 0; i < count; i++) { logger.debug((i + 1) + "th's start."); - - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(); + int bindPort = testPinpointServerAcceptor.bind(); + PinpointClient client = clientFactory.connect("localhost", bindPort); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); logger.debug("server.close"); assertClientDisconnected(client); - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); logger.debug("bind server"); assertClientConnected(client); @@ -137,7 +144,7 @@ public void reconnectStressTest() throws IOException, InterruptedException { Assert.assertArrayEquals(randomByte, response); PinpointRPCTestUtils.close(client); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } Thread.sleep(10000); @@ -151,11 +158,14 @@ public void scheduledConnect() throws IOException, InterruptedException { final PinpointClientFactory clientFactory = new DefaultPinpointClientFactory(); clientFactory.setReconnectDelay(200); PinpointClient client = null; - PinpointServerAcceptor serverAcceptor = null; + + TestPinpointServerAcceptor testPinpointServerAcceptor = null; try { - client = clientFactory.scheduledConnect("localhost", bindPort); + int availableTcpPort = SocketUtils.findAvailableTcpPort(47000); + client = clientFactory.scheduledConnect("localhost", availableTcpPort); - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + testPinpointServerAcceptor.bind(availableTcpPort); assertClientConnected(client); logger.debug("request server"); @@ -166,13 +176,14 @@ public void scheduledConnect() throws IOException, InterruptedException { } finally { PinpointRPCTestUtils.close(client); clientFactory.release(); - PinpointRPCTestUtils.close(serverAcceptor); + TestPinpointServerAcceptor.staticClose(testPinpointServerAcceptor); } } @Test public void scheduledConnectAndClosed() throws IOException, InterruptedException { - PinpointClient client = clientFactory.scheduledConnect("localhost", bindPort); + int availableTcpPort = SocketUtils.findAvailableTcpPort(47000); + PinpointClient client = clientFactory.scheduledConnect("localhost", availableTcpPort); logger.debug("close"); PinpointRPCTestUtils.close(client); @@ -180,7 +191,8 @@ public void scheduledConnectAndClosed() throws IOException, InterruptedException @Test public void scheduledConnectDelayAndClosed() throws IOException, InterruptedException { - PinpointClient client = clientFactory.scheduledConnect("localhost", bindPort); + int availableTcpPort = SocketUtils.findAvailableTcpPort(47000); + PinpointClient client = clientFactory.scheduledConnect("localhost", availableTcpPort); Thread.sleep(2000); logger.debug("close pinpoint client"); @@ -189,7 +201,8 @@ public void scheduledConnectDelayAndClosed() throws IOException, InterruptedExce @Test public void scheduledConnectStateTest() { - PinpointClient client = clientFactory.scheduledConnect("localhost", bindPort); + int availableTcpPort = SocketUtils.findAvailableTcpPort(47000); + PinpointClient client = clientFactory.scheduledConnect("localhost", availableTcpPort); client.send(new byte[10]); @@ -219,7 +232,9 @@ public void scheduledConnectStateTest() { @Test public void serverFirstClose() throws IOException, InterruptedException { // when abnormal case in which server has been closed first, confirm that a socket should be closed properly. - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(); + int bindPort = testPinpointServerAcceptor.bind(); + PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); byte[] randomByte = TestByteUtils.createRandomByte(10); @@ -231,7 +246,7 @@ public void serverFirstClose() throws IOException, InterruptedException { logger.debug("timeout.", e); } // close server by force - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); assertClientDisconnected(client); PinpointRPCTestUtils.close(client); } @@ -239,12 +254,13 @@ public void serverFirstClose() throws IOException, InterruptedException { @Test public void serverCloseAndWrite() throws IOException, InterruptedException { // when abnormal case in which server has been closed first, confirm that a client socket should be closed properly. - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(); + int bindPort = testPinpointServerAcceptor.bind(); PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); // just close server and request - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); byte[] randomByte = TestByteUtils.createRandomByte(10); Future response = client.request(randomByte); diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/RequestManagerTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/RequestManagerTest.java index b2d0f4a8114b..0549c3e6a89c 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/RequestManagerTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/client/RequestManagerTest.java @@ -18,11 +18,13 @@ import com.navercorp.pinpoint.rpc.DefaultFuture; import com.navercorp.pinpoint.rpc.Future; -import com.navercorp.pinpoint.rpc.TestAwaitTaskUtils; -import com.navercorp.pinpoint.rpc.TestAwaitUtils; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import org.jboss.netty.util.HashedWheelTimer; +import org.jboss.netty.util.Timer; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,13 +38,27 @@ public class RequestManagerTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private Timer timer = getTimer(); + + @Before + public void setUp() throws Exception { + this.timer = getTimer(); + + } + + @After + public void tearDown() throws Exception { + if (this.timer != null) { + this.timer.stop(); + } + } + @Test public void testRegisterRequest() throws Exception { - HashedWheelTimer timer = getTimer(); RequestManager requestManager = new RequestManager(timer, 3000); try { - RequestPacket packet = new RequestPacket(new byte[0]); - final Future future = requestManager.register(packet, 50); + final int requestId = requestManager.nextRequestId(); + final Future future = requestManager.register(requestId, 50); TestAwaitUtils.await(new TestAwaitTaskUtils() { @Override @@ -57,25 +73,23 @@ public boolean checkCompleted() { logger.debug(future.getCause().getMessage()); } finally { requestManager.close(); - timer.stop(); } } + @Test public void testRemoveMessageFuture() throws Exception { - HashedWheelTimer timer = getTimer(); RequestManager requestManager = new RequestManager(timer, 3000); try { - RequestPacket packet = new RequestPacket(1, new byte[0]); - DefaultFuture future = requestManager.register(packet, 2000); + int requestId = requestManager.nextRequestId(); + DefaultFuture future = requestManager.register(requestId, 2000); future.setFailure(new RuntimeException()); - Future nullFuture = requestManager.removeMessageFuture(packet.getRequestId()); + Future nullFuture = requestManager.removeMessageFuture(requestId); Assert.assertNull(nullFuture); } finally { requestManager.close(); - timer.stop(); } } @@ -84,12 +98,7 @@ private HashedWheelTimer getTimer() { return new HashedWheelTimer(10, TimeUnit.MICROSECONDS); } - // @Test - public void testTimerStartTiming() throws InterruptedException { - HashedWheelTimer timer = new HashedWheelTimer(1000, TimeUnit.MILLISECONDS); - timer.start(); - timer.stop(); - } + @Test public void testClose() throws Exception { diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/codec/TestCodec.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/codec/TestCodec.java new file mode 100644 index 000000000000..3642a4bf3096 --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/codec/TestCodec.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.codec; + +import com.navercorp.pinpoint.rpc.packet.Packet; +import com.navercorp.pinpoint.rpc.packet.PacketType; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; + +/** + * @author Taejin Koo + */ +public class TestCodec { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestCodec.class); + + private static final ServerPacketDecoder SERVER_PACKET_DECODER = new ServerPacketDecoder(); + + public static byte[] encodePacket(Packet packet) { + ByteBuffer bb = packet.toBuffer().toByteBuffer(0, packet.toBuffer().writerIndex()); + return bb.array(); + } + + public static Packet decodePacket(byte[] payload) { + Packet packet = null; + try { + packet = (Packet) SERVER_PACKET_DECODER.decode(null, null, ChannelBuffers.wrappedBuffer(payload)); + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + + if (packet == null) { + try { + ChannelBuffer channelBuffer = ChannelBuffers.wrappedBuffer(payload); + final short packetType = channelBuffer.readShort(); + if (packetType == PacketType.CONTROL_PONG) { + return (Packet) SERVER_PACKET_DECODER.readPong(PacketType.CONTROL_PONG, channelBuffer); + } + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + } + + return packet; + } + +} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/ControlPacketServerTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/ControlPacketServerTest.java index 3713261e8b80..6fa02d5aa2d7 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/ControlPacketServerTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/ControlPacketServerTest.java @@ -16,35 +16,15 @@ package com.navercorp.pinpoint.rpc.server; -import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.control.ProtocolException; -import com.navercorp.pinpoint.rpc.packet.ControlHandshakePacket; -import com.navercorp.pinpoint.rpc.packet.ControlHandshakeResponsePacket; -import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; -import com.navercorp.pinpoint.rpc.packet.ResponsePacket; -import com.navercorp.pinpoint.rpc.packet.SendPacket; -import com.navercorp.pinpoint.rpc.util.ControlMessageEncodingUtils; -import com.navercorp.pinpoint.rpc.util.IOUtils; import com.navercorp.pinpoint.rpc.util.MapUtils; import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; +import com.navercorp.pinpoint.test.client.TestRawSocket; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.SocketUtils; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.nio.ByteBuffer; import java.util.Collections; import java.util.Map; @@ -53,75 +33,69 @@ */ public class ControlPacketServerTest { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private static int bindPort; - - @BeforeClass - public static void setUp() throws IOException { - bindPort = SocketUtils.findAvailableTcpPort(); - } - // Test for being possible to send messages in case of failure of registering packet ( return code : 2, lack of parameter) @Test public void registerAgentTest1() throws Exception { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new SimpleListener()); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(new HandshakeVerifyMessageListenerFactory()); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); + testRawSocket.connect(bindPort); - sendAndReceiveSimplePacket(socket); + sendAndReceiveSimplePacket(testRawSocket); - int code= sendAndReceiveRegisterPacket(socket); + int code= sendAndReceiveRegisterPacket(testRawSocket); Assert.assertEquals(2, code); - sendAndReceiveSimplePacket(socket); + sendAndReceiveSimplePacket(testRawSocket); } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } } // Test for being possible to send messages in case of success of registering packet ( return code : 0) @Test public void registerAgentTest2() throws Exception { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new SimpleListener()); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(new HandshakeVerifyMessageListenerFactory()); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); + testRawSocket.connect(bindPort); - sendAndReceiveSimplePacket(socket); + sendAndReceiveSimplePacket(testRawSocket); - int code= sendAndReceiveRegisterPacket(socket, PinpointRPCTestUtils.getParams()); + int code= sendAndReceiveRegisterPacket(testRawSocket, PinpointRPCTestUtils.getParams()); Assert.assertEquals(0, code); - sendAndReceiveSimplePacket(socket); + sendAndReceiveSimplePacket(testRawSocket); } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } } // when failure of registering and retrying to register, confirm to return same code ( return code : 2 @Test public void registerAgentTest3() throws Exception { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new SimpleListener()); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(new HandshakeVerifyMessageListenerFactory()); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); - int code = sendAndReceiveRegisterPacket(socket); + testRawSocket.connect(bindPort); + int code = sendAndReceiveRegisterPacket(testRawSocket); Assert.assertEquals(2, code); - code = sendAndReceiveRegisterPacket(socket); + code = sendAndReceiveRegisterPacket(testRawSocket); Assert.assertEquals(2, code); - sendAndReceiveSimplePacket(socket); + sendAndReceiveSimplePacket(testRawSocket); } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } } @@ -129,115 +103,43 @@ public void registerAgentTest3() throws Exception { // test 1) confirm to return success code, 2) confirm to return already success code. @Test public void registerAgentTest4() throws Exception { - PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, new SimpleListener()); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(new HandshakeVerifyMessageListenerFactory()); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); - sendAndReceiveSimplePacket(socket); + testRawSocket.connect(bindPort); - int code = sendAndReceiveRegisterPacket(socket, PinpointRPCTestUtils.getParams()); + sendAndReceiveSimplePacket(testRawSocket); + + int code = sendAndReceiveRegisterPacket(testRawSocket, PinpointRPCTestUtils.getParams()); Assert.assertEquals(0, code); - sendAndReceiveSimplePacket(socket); + sendAndReceiveSimplePacket(testRawSocket); - code = sendAndReceiveRegisterPacket(socket, PinpointRPCTestUtils.getParams()); + code = sendAndReceiveRegisterPacket(testRawSocket, PinpointRPCTestUtils.getParams()); Assert.assertEquals(1, code); - sendAndReceiveSimplePacket(socket); + sendAndReceiveSimplePacket(testRawSocket); } finally { - IOUtils.close(socket); - PinpointRPCTestUtils.close(serverAcceptor); + testRawSocket.close(); + testPinpointServerAcceptor.close(); } } - - private int sendAndReceiveRegisterPacket(Socket socket) throws ProtocolException, IOException { - return sendAndReceiveRegisterPacket(socket, Collections.emptyMap()); - } - - private int sendAndReceiveRegisterPacket(Socket socket, Map properties) throws ProtocolException, IOException { - sendRegisterPacket(socket.getOutputStream(), properties); - ControlHandshakeResponsePacket packet = receiveRegisterConfirmPacket(socket.getInputStream()); - Map result = (Map) ControlMessageEncodingUtils.decode(packet.getPayload()); - - return MapUtils.getInteger(result, "code", -1); - } - - private void sendAndReceiveSimplePacket(Socket socket) throws ProtocolException, IOException { - sendSimpleRequestPacket(socket.getOutputStream()); - ResponsePacket responsePacket = readSimpleResponsePacket(socket.getInputStream()); - Assert.assertNotNull(responsePacket); - } - - private void sendRegisterPacket(OutputStream outputStream, Map properties) throws ProtocolException, IOException { - byte[] payload = ControlMessageEncodingUtils.encode(properties); - ControlHandshakePacket packet = new ControlHandshakePacket(1, payload); - - ByteBuffer bb = packet.toBuffer().toByteBuffer(0, packet.toBuffer().writerIndex()); - IOUtils.write(outputStream, bb.array()); - } - - private void sendSimpleRequestPacket(OutputStream outputStream) throws ProtocolException, IOException { - RequestPacket packet = new RequestPacket(new byte[0]); - packet.setRequestId(10); - - ByteBuffer bb = packet.toBuffer().toByteBuffer(0, packet.toBuffer().writerIndex()); - IOUtils.write(outputStream, bb.array()); - } - - private ControlHandshakeResponsePacket receiveRegisterConfirmPacket(InputStream inputStream) throws ProtocolException, IOException { - - byte[] payload = IOUtils.read(inputStream, 50, 3000); - ChannelBuffer cb = ChannelBuffers.wrappedBuffer(payload); - - short packetType = cb.readShort(); - - ControlHandshakeResponsePacket packet = ControlHandshakeResponsePacket.readBuffer(packetType, cb); - return packet; + private int sendAndReceiveRegisterPacket(TestRawSocket testRawSocket) throws ProtocolException, IOException { + return sendAndReceiveRegisterPacket(testRawSocket, Collections.emptyMap()); } - private ResponsePacket readSimpleResponsePacket(InputStream inputStream) throws ProtocolException, IOException { - byte[] payload = IOUtils.read(inputStream, 50, 3000); - ChannelBuffer cb = ChannelBuffers.wrappedBuffer(payload); - - short packetType = cb.readShort(); - - ResponsePacket packet = ResponsePacket.readBuffer(packetType, cb); - return packet; + private int sendAndReceiveRegisterPacket(TestRawSocket testRawSocket, Map properties) throws ProtocolException, IOException { + testRawSocket.sendHandshakePacket(properties); + Map responseData = testRawSocket.readHandshakeResponseData(3000); + return MapUtils.getInteger(responseData, "code", -1); } - class SimpleListener implements ServerMessageListener { - - @Override - public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { - logger.debug("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); - } - - @Override - public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - logger.debug("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); - pinpointSocket.response(requestPacket, requestPacket.getPayload()); - } - - @Override - public HandshakeResponseCode handleHandshake(Map properties) { - if (properties == null) { - return HandshakeResponseType.ProtocolError.PROTOCOL_ERROR; - } - - boolean hasRequiredKeys = HandshakePropertyType.hasRequiredKeys(properties); - if (!hasRequiredKeys) { - return HandshakeResponseType.PropertyError.PROPERTY_ERROR; - } - - return HandshakeResponseType.Success.DUPLEX_COMMUNICATION; - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - } - + private void sendAndReceiveSimplePacket(TestRawSocket testRawSocket) throws ProtocolException, IOException { + testRawSocket.sendRequestPacket(); + Assert.assertNotNull(testRawSocket.readResponsePacket(3000)); } } diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/EventHandlerTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/EventHandlerTest.java index 41f55dfce577..9e95d6720c1e 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/EventHandlerTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/EventHandlerTest.java @@ -18,27 +18,17 @@ import com.navercorp.pinpoint.rpc.common.SocketStateCode; import com.navercorp.pinpoint.rpc.control.ProtocolException; -import com.navercorp.pinpoint.rpc.packet.ControlHandshakePacket; -import com.navercorp.pinpoint.rpc.packet.ControlHandshakeResponsePacket; -import com.navercorp.pinpoint.rpc.packet.RequestPacket; -import com.navercorp.pinpoint.rpc.packet.ResponsePacket; import com.navercorp.pinpoint.rpc.server.handler.ServerStateChangeEventHandler; -import com.navercorp.pinpoint.rpc.util.ControlMessageEncodingUtils; -import com.navercorp.pinpoint.rpc.util.IOUtils; import com.navercorp.pinpoint.rpc.util.MapUtils; import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; +import com.navercorp.pinpoint.test.client.TestRawSocket; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.util.SocketUtils; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.nio.ByteBuffer; import java.util.Map; /** @@ -47,6 +37,7 @@ public class EventHandlerTest { private static int bindPort; + private final TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX); @BeforeClass public static void setUp() throws IOException { @@ -60,21 +51,22 @@ public void registerAgentSuccessTest() throws Exception { PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(); serverAcceptor.addStateChangeEventHandler(eventHandler); - serverAcceptor.setMessageListener(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + serverAcceptor.setMessageListenerFactory(testServerMessageListenerFactory); serverAcceptor.bind("127.0.0.1", bindPort); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); - sendAndReceiveSimplePacket(socket); + testRawSocket.connect(bindPort); + + sendAndReceiveSimplePacket(testRawSocket); Assert.assertEquals(eventHandler.getCode(), SocketStateCode.RUN_WITHOUT_HANDSHAKE); - int code = sendAndReceiveRegisterPacket(socket, PinpointRPCTestUtils.getParams()); + int code = sendAndReceiveRegisterPacket(testRawSocket, PinpointRPCTestUtils.getParams()); Assert.assertEquals(eventHandler.getCode(), SocketStateCode.RUN_DUPLEX); - sendAndReceiveSimplePacket(socket); + sendAndReceiveSimplePacket(testRawSocket); } finally { - IOUtils.close(socket); + testRawSocket.close(); PinpointRPCTestUtils.close(serverAcceptor); } } @@ -85,70 +77,31 @@ public void registerAgentFailTest() throws Exception { PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(); serverAcceptor.addStateChangeEventHandler(eventHandler); - serverAcceptor.setMessageListener(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE); + serverAcceptor.setMessageListenerFactory(testServerMessageListenerFactory); serverAcceptor.bind("127.0.0.1", bindPort); - Socket socket = null; + TestRawSocket testRawSocket = new TestRawSocket(); try { - socket = new Socket("127.0.0.1", bindPort); - sendAndReceiveSimplePacket(socket); + testRawSocket.connect(bindPort); + + sendAndReceiveSimplePacket(testRawSocket); Assert.assertTrue(eventHandler.getErrorCount() > 0); } finally { - IOUtils.close(socket); + testRawSocket.close(); PinpointRPCTestUtils.close(serverAcceptor); } } - private int sendAndReceiveRegisterPacket(Socket socket, Map properties) throws ProtocolException, IOException { - sendRegisterPacket(socket.getOutputStream(), properties); - ControlHandshakeResponsePacket packet = receiveRegisterConfirmPacket(socket.getInputStream()); - Map result = (Map) ControlMessageEncodingUtils.decode(packet.getPayload()); - - return MapUtils.getInteger(result, "code", -1); - } - - private void sendAndReceiveSimplePacket(Socket socket) throws ProtocolException, IOException { - sendSimpleRequestPacket(socket.getOutputStream()); - ResponsePacket responsePacket = readSimpleResponsePacket(socket.getInputStream()); - Assert.assertNotNull(responsePacket); - } - - private void sendRegisterPacket(OutputStream outputStream, Map properties) throws ProtocolException, IOException { - byte[] payload = ControlMessageEncodingUtils.encode(properties); - ControlHandshakePacket packet = new ControlHandshakePacket(1, payload); - - ByteBuffer bb = packet.toBuffer().toByteBuffer(0, packet.toBuffer().writerIndex()); - IOUtils.write(outputStream, bb.array()); - } - - private void sendSimpleRequestPacket(OutputStream outputStream) throws ProtocolException, IOException { - RequestPacket packet = new RequestPacket(new byte[0]); - packet.setRequestId(10); - - ByteBuffer bb = packet.toBuffer().toByteBuffer(0, packet.toBuffer().writerIndex()); - IOUtils.write(outputStream, bb.array()); + private int sendAndReceiveRegisterPacket(TestRawSocket testRawSocket, Map properties) throws ProtocolException, IOException { + testRawSocket.sendHandshakePacket(properties); + Map responseData = testRawSocket.readHandshakeResponseData(3000); + return MapUtils.getInteger(responseData, "code", -1); } - private ControlHandshakeResponsePacket receiveRegisterConfirmPacket(InputStream inputStream) throws ProtocolException, IOException { - - byte[] payload = IOUtils.read(inputStream, 50, 3000); - ChannelBuffer cb = ChannelBuffers.wrappedBuffer(payload); - - short packetType = cb.readShort(); - - ControlHandshakeResponsePacket packet = ControlHandshakeResponsePacket.readBuffer(packetType, cb); - return packet; - } - - private ResponsePacket readSimpleResponsePacket(InputStream inputStream) throws ProtocolException, IOException { - byte[] payload = IOUtils.read(inputStream, 50, 3000); - ChannelBuffer cb = ChannelBuffers.wrappedBuffer(payload); - - short packetType = cb.readShort(); - - ResponsePacket packet = ResponsePacket.readBuffer(packetType, cb); - return packet; + private void sendAndReceiveSimplePacket(TestRawSocket testRawSocket) throws ProtocolException, IOException { + testRawSocket.sendRequestPacket(); + Assert.assertNotNull(testRawSocket.readResponsePacket(3000)); } class EventHandler implements ServerStateChangeEventHandler { diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/HandshakeTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/HandshakeTest.java index 218ca9d418a5..4a0db49f116e 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/HandshakeTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/HandshakeTest.java @@ -17,14 +17,13 @@ package com.navercorp.pinpoint.rpc.server; import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.TestAwaitTaskUtils; -import com.navercorp.pinpoint.rpc.TestAwaitUtils; -import com.navercorp.pinpoint.rpc.client.PinpointClient; -import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; import com.navercorp.pinpoint.rpc.client.PinpointClientHandshaker; import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; import com.navercorp.pinpoint.rpc.util.TimerFactory; +import com.navercorp.pinpoint.test.client.TestPinpointClient; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; import org.jboss.netty.util.Timer; import org.junit.AfterClass; import org.junit.Assert; @@ -32,10 +31,10 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.SocketUtils; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -44,17 +43,13 @@ public class HandshakeTest { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private static Timer timer = null; - - private static int bindPort; - - private final TestAwaitUtils awaitUtils = new TestAwaitUtils(50, 3000); + private final TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX); + private static Timer timer = null; @BeforeClass public static void setUp() throws IOException { timer = TimerFactory.createHashedWheelTimer(HandshakeTest.class.getSimpleName(), 100, TimeUnit.MILLISECONDS, 512); - bindPort = SocketUtils.findAvailableTcpPort(); } @AfterClass @@ -67,64 +62,42 @@ public static void tearDown() { // simple test @Test public void handshakeTest1() throws InterruptedException { - final PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_INSTANCE); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); - PinpointClientFactory clientFactory1 = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - PinpointClientFactory clientFactory2 = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), null); + TestPinpointClient testPinpointClient1 = new TestPinpointClient(testServerMessageListenerFactory.create(), PinpointRPCTestUtils.getParams()); + TestPinpointClient testPinpointClient2 = new TestPinpointClient(PinpointRPCTestUtils.getParams()); try { - PinpointClient client = clientFactory1.connect("127.0.0.1", bindPort); - PinpointClient client2 = clientFactory2.connect("127.0.0.1", bindPort); - - awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - List writableServerList = serverAcceptor.getWritableSocketList(); - return writableServerList.size() == 2; - } - }); + testPinpointClient1.connect(bindPort); + testPinpointClient2.connect(bindPort); - List writableServerList = serverAcceptor.getWritableSocketList(); - if (writableServerList.size() != 2) { - Assert.fail(); - } - - PinpointRPCTestUtils.close(client, client2); + testPinpointServerAcceptor.assertAwaitClientConnected(2, 3000); } finally { - clientFactory1.release(); - clientFactory2.release(); - - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient1.closeAll(); + testPinpointClient2.closeAll(); + testPinpointServerAcceptor.close(); } } @Test public void handshakeTest2() throws InterruptedException { - final PinpointServerAcceptor serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, SimpleServerMessageListener.DUPLEX_INSTANCE); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); Map params = PinpointRPCTestUtils.getParams(); - - PinpointClientFactory clientFactory1 = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - + TestPinpointClient testPinpointClient = new TestPinpointClient(testServerMessageListenerFactory.create(), params); try { - PinpointClient client = clientFactory1.connect("127.0.0.1", bindPort); - awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - List writableServerList = serverAcceptor.getWritableSocketList(); - return writableServerList.size() == 1; - } - }); + testPinpointClient.connect(bindPort); + testPinpointServerAcceptor.assertAwaitClientConnected(1, 3000); - PinpointSocket writableServer = getWritableServer("application", "agent", (Long) params.get(HandshakePropertyType.START_TIMESTAMP.getName()), serverAcceptor.getWritableSocketList()); + PinpointSocket writableServer = getWritableServer("application", "agent", (Long) params.get(HandshakePropertyType.START_TIMESTAMP.getName()), testPinpointServerAcceptor.getConnectedPinpointSocketList()); Assert.assertNotNull(writableServer); - writableServer = getWritableServer("application", "agent", (Long) params.get(HandshakePropertyType.START_TIMESTAMP.getName()) + 1, serverAcceptor.getWritableSocketList()); + writableServer = getWritableServer("application", "agent", (Long) params.get(HandshakePropertyType.START_TIMESTAMP.getName()) + 1, testPinpointServerAcceptor.getConnectedPinpointSocketList()); Assert.assertNull(writableServer); - - PinpointRPCTestUtils.close(client); } finally { - clientFactory1.release(); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } @@ -133,7 +106,8 @@ public void testExecuteCompleteWithoutStart() { int retryInterval = 100; int maxHandshakeCount = 10; - PinpointClientHandshaker handshaker = new PinpointClientHandshaker(timer, retryInterval, maxHandshakeCount); + Map emptyMap = Collections.emptyMap(); + PinpointClientHandshaker handshaker = new PinpointClientHandshaker(emptyMap, timer, retryInterval, maxHandshakeCount); handshaker.handshakeComplete(null); Assert.assertEquals(null, handshaker.getHandshakeResult()); @@ -146,7 +120,8 @@ public void testExecuteAbortWithoutStart() { int retryInterval = 100; int maxHandshakeCount = 10; - PinpointClientHandshaker handshaker = new PinpointClientHandshaker(timer, retryInterval, maxHandshakeCount); + Map emptyMap = Collections.emptyMap(); + PinpointClientHandshaker handshaker = new PinpointClientHandshaker(emptyMap, timer, retryInterval, maxHandshakeCount); handshaker.handshakeAbort(); Assert.assertTrue(handshaker.isFinished()); diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/HandshakeVerifyMessageListenerFactory.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/HandshakeVerifyMessageListenerFactory.java new file mode 100644 index 000000000000..45ff96a17640 --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/HandshakeVerifyMessageListenerFactory.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.server; + +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; +import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; +import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.rpc.packet.SendPacket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + * @author Taejin Koo + */ +public class HandshakeVerifyMessageListenerFactory implements ServerMessageListenerFactory { + + @Override + public ServerMessageListener create() { + return new HandshakeVerifyMessageListener(); + } + + private static class HandshakeVerifyMessageListener implements ServerMessageListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { + logger.debug("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); + } + + @Override + public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { + logger.debug("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); + pinpointSocket.response(requestPacket.getRequestId(), requestPacket.getPayload()); + } + + @Override + public HandshakeResponseCode handleHandshake(Map properties) { + if (properties == null) { + return HandshakeResponseType.ProtocolError.PROTOCOL_ERROR; + } + + boolean hasRequiredKeys = HandshakePropertyType.hasRequiredKeys(properties); + if (!hasRequiredKeys) { + return HandshakeResponseType.PropertyError.PROPERTY_ERROR; + } + + return HandshakeResponseType.Success.DUPLEX_COMMUNICATION; + } + + @Override + public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { + } + + } + +} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PinpointServerSocketTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PinpointServerSocketTest.java index 465cd246b9e9..3af9df0caec0 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PinpointServerSocketTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PinpointServerSocketTest.java @@ -16,41 +16,29 @@ package com.navercorp.pinpoint.rpc.server; -import java.io.IOException; -import java.net.Socket; - -import org.junit.BeforeClass; +import com.navercorp.pinpoint.rpc.DiscardServerHandler; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; import org.junit.Test; -import com.navercorp.pinpoint.rpc.DiscardPipelineFactory; -import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; -import org.springframework.util.SocketUtils; +import java.net.Socket; /** * @author emeroad */ public class PinpointServerSocketTest { - - private static int bindPort; - - @BeforeClass - public static void setUp() throws IOException { - bindPort = SocketUtils.findAvailableTcpPort(); - } - + @Test public void testBind() throws Exception { - PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(); - serverAcceptor.setPipelineFactory(new DiscardPipelineFactory()); - serverAcceptor.bind("127.0.0.1", bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(new DiscardServerHandler()); + int bindPort = testPinpointServerAcceptor.bind(); Socket socket = new Socket("127.0.0.1", bindPort); - socket.getOutputStream().write(new byte[10]); + socket.getOutputStream().write(new byte[0]); socket.getOutputStream().flush(); socket.close(); Thread.sleep(1000); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PinpointServerStateTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PinpointServerStateTest.java index 6634fcd207d0..b1ef42ba4e93 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PinpointServerStateTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PinpointServerStateTest.java @@ -17,180 +17,124 @@ package com.navercorp.pinpoint.rpc.server; import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.TestAwaitTaskUtils; -import com.navercorp.pinpoint.rpc.TestAwaitUtils; -import com.navercorp.pinpoint.rpc.client.PinpointClient; -import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; import com.navercorp.pinpoint.rpc.common.SocketStateCode; import com.navercorp.pinpoint.rpc.control.ProtocolException; -import com.navercorp.pinpoint.rpc.packet.ControlHandshakePacket; -import com.navercorp.pinpoint.rpc.util.ControlMessageEncodingUtils; -import com.navercorp.pinpoint.rpc.util.IOUtils; import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; -import org.jboss.netty.buffer.ChannelBuffer; +import com.navercorp.pinpoint.test.client.TestPinpointClient; +import com.navercorp.pinpoint.test.client.TestRawSocket; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; -import org.springframework.util.SocketUtils; import java.io.IOException; -import java.net.Socket; -import java.util.List; -import java.util.Map; /** * @author Taejin Koo */ public class PinpointServerStateTest { - private static int bindPort; - private final TestAwaitUtils awaitUtils = new TestAwaitUtils(100, 1000); - - @BeforeClass - public static void setUp() throws IOException { - bindPort = SocketUtils.findAvailableTcpPort(); - } + private final TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX); @Test - public void closeByPeerTest() throws InterruptedException { - PinpointServerAcceptor serverAcceptor = null; - PinpointClient client = null; - PinpointClientFactory clientFactory = null; - try { - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, PinpointRPCTestUtils.createEchoServerListener()); + public void closeByPeerTest() { + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); - clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - client = clientFactory.connect("127.0.0.1", bindPort); - assertAvailableWritableSocket(serverAcceptor); + TestPinpointClient testPinpointClient = new TestPinpointClient(testServerMessageListenerFactory.create(), PinpointRPCTestUtils.getParams()); + try { + int bindPort = testPinpointServerAcceptor.bind(); - List pinpointServerList = serverAcceptor.getWritableSocketList(); - PinpointSocket pinpointServer = pinpointServerList.get(0); + testPinpointClient.connect(bindPort); + testPinpointServerAcceptor.assertAwaitClientConnected(1000); + PinpointSocket pinpointServer = testPinpointServerAcceptor.getConnectedPinpointSocketList().get(0); if (pinpointServer instanceof PinpointServer) { Assert.assertEquals(SocketStateCode.RUN_DUPLEX, ((PinpointServer) pinpointServer).getCurrentStateCode()); - client.close(); - + testPinpointClient.disconnect(); assertPinpointServerState(SocketStateCode.CLOSED_BY_CLIENT, (PinpointServer) pinpointServer); } else { Assert.fail(); } - } finally { - PinpointRPCTestUtils.close(client); - if (clientFactory != null) { - clientFactory.release(); - } - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } @Test - public void closeTest() throws InterruptedException { - PinpointServerAcceptor serverAcceptor = null; - PinpointClient client = null; - PinpointClientFactory clientFactory = null; + public void closeTest() { + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + + TestPinpointClient testPinpointClient = new TestPinpointClient(testServerMessageListenerFactory.create(), PinpointRPCTestUtils.getParams()); try { - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, PinpointRPCTestUtils.createEchoServerListener()); + int bindPort = testPinpointServerAcceptor.bind(); - clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - client = clientFactory.connect("127.0.0.1", bindPort); - assertAvailableWritableSocket(serverAcceptor); + testPinpointClient.connect(bindPort); + testPinpointServerAcceptor.assertAwaitClientConnected(1000); - List pinpointServerList = serverAcceptor.getWritableSocketList(); - PinpointSocket pinpointServer = pinpointServerList.get(0); + PinpointSocket pinpointServer = testPinpointServerAcceptor.getConnectedPinpointSocketList().get(0); Assert.assertEquals(SocketStateCode.RUN_DUPLEX, ((PinpointServer) pinpointServer).getCurrentStateCode()); - serverAcceptor.close(); + testPinpointServerAcceptor.close(); assertPinpointServerState(SocketStateCode.CLOSED_BY_SERVER, (PinpointServer) pinpointServer); } finally { - PinpointRPCTestUtils.close(client); - if (clientFactory != null) { - clientFactory.release(); - } - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } @Test - public void unexpectedCloseByPeerTest() throws InterruptedException, IOException, ProtocolException { - PinpointServerAcceptor serverAcceptor = null; + public void unexpectedCloseByPeerTest() throws IOException, ProtocolException { + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); try { - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, PinpointRPCTestUtils.createEchoServerListener()); + int bindPort = testPinpointServerAcceptor.bind(); - Socket socket = new Socket("127.0.0.1", bindPort); - IOUtils.write(socket.getOutputStream(), createHandshakePayload(PinpointRPCTestUtils.getParams())); + TestRawSocket testRawSocket = new TestRawSocket(); + testRawSocket.connect(bindPort); - final PinpointServerAcceptor ImmutableServerAcceptor = serverAcceptor; - awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - return ImmutableServerAcceptor.getWritableSocketList().size() == 1; - } - }); + testRawSocket.sendHandshakePacket(PinpointRPCTestUtils.getParams()); + testPinpointServerAcceptor.assertAwaitClientConnected(1, 1000); - List pinpointServerList = serverAcceptor.getWritableSocketList(); - PinpointSocket pinpointServer = pinpointServerList.get(0); + PinpointSocket pinpointServer = testPinpointServerAcceptor.getConnectedPinpointSocketList().get(0); if (!(pinpointServer instanceof PinpointServer)) { - IOUtils.close(socket); + testRawSocket.close(); Assert.fail(); } Assert.assertEquals(SocketStateCode.RUN_DUPLEX, ((PinpointServer) pinpointServer).getCurrentStateCode()); - IOUtils.close(socket); + testRawSocket.close(); assertPinpointServerState(SocketStateCode.UNEXPECTED_CLOSE_BY_CLIENT, (PinpointServer) pinpointServer); } finally { - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointServerAcceptor.close(); } } @Test - public void unexpectedCloseTest() throws InterruptedException, IOException, ProtocolException { - PinpointServerAcceptor serverAcceptor = null; - PinpointClient client = null; - PinpointClientFactory clientFactory = null; - try { - serverAcceptor = PinpointRPCTestUtils.createPinpointServerFactory(bindPort, PinpointRPCTestUtils.createEchoServerListener()); + public void unexpectedCloseTest() { + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); - clientFactory = PinpointRPCTestUtils.createClientFactory(PinpointRPCTestUtils.getParams(), PinpointRPCTestUtils.createEchoClientListener()); - client = clientFactory.connect("127.0.0.1", bindPort); - assertAvailableWritableSocket(serverAcceptor); + TestPinpointClient testPinpointClient = new TestPinpointClient(testServerMessageListenerFactory.create(), PinpointRPCTestUtils.getParams()); + try { + int bindPort = testPinpointServerAcceptor.bind(); - List pinpointServerList = serverAcceptor.getWritableSocketList(); - PinpointSocket pinpointServer = pinpointServerList.get(0); + testPinpointClient.connect(bindPort); + testPinpointServerAcceptor.assertAwaitClientConnected(1000); + PinpointSocket pinpointServer = testPinpointServerAcceptor.getConnectedPinpointSocketList().get(0); Assert.assertEquals(SocketStateCode.RUN_DUPLEX, ((PinpointServer) pinpointServer).getCurrentStateCode()); ((DefaultPinpointServer) pinpointServer).stop(true); assertPinpointServerState(SocketStateCode.UNEXPECTED_CLOSE_BY_SERVER, (PinpointServer) pinpointServer); } finally { - PinpointRPCTestUtils.close(client); - if (clientFactory != null) { - clientFactory.release(); - } - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } - private byte[] createHandshakePayload(Map data) throws ProtocolException { - byte[] payload = ControlMessageEncodingUtils.encode(data); - ControlHandshakePacket handshakePacket = new ControlHandshakePacket(payload); - ChannelBuffer channelBuffer = handshakePacket.toBuffer(); - return channelBuffer.toByteBuffer().array(); - } - - private void assertAvailableWritableSocket(final PinpointServerAcceptor serverAcceptor) { - boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - return !serverAcceptor.getWritableSocketList().isEmpty(); - } - }); - - Assert.assertTrue(pass); - } - private void assertPinpointServerState(final SocketStateCode stateCode, final PinpointServer pinpointServer) { boolean passed = awaitUtils.await(new TestAwaitTaskUtils() { @Override @@ -202,5 +146,4 @@ public boolean checkCompleted() { Assert.assertTrue(passed); } - } diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PipelineFactoryTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PipelineFactoryTest.java new file mode 100644 index 000000000000..46b846af717e --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/server/PipelineFactoryTest.java @@ -0,0 +1,128 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.rpc.server; + +import com.navercorp.pinpoint.rpc.DiscardServerHandler; +import com.navercorp.pinpoint.rpc.PipelineFactory; +import com.navercorp.pinpoint.rpc.util.IOUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; +import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.handler.codec.frame.FrameDecoder; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.util.SocketUtils; + +import java.io.IOException; +import java.net.Socket; + +/** + * @author Taejin Koo + */ +public class PipelineFactoryTest { + + private static int bindPort; + + private static char START_KEY = '!'; + + @BeforeClass + public static void setUp() throws IOException { + bindPort = SocketUtils.findAvailableTcpPort(); + } + + @Test + public void testBind() throws Exception { + PinpointServerAcceptor serverAcceptor = null; + Socket socket = null; + try { + serverAcceptor = new PinpointServerAcceptor(ChannelFilter.BYPASS, new TestPipelineFactory()); + final DiscardServerHandler discardServerHandler = new DiscardServerHandler(); + serverAcceptor.setMessageHandler(discardServerHandler); + serverAcceptor.bind("127.0.0.1", bindPort); + + socket = new Socket("127.0.0.1", bindPort); + socket.getOutputStream().write((START_KEY + "Test").getBytes()); + socket.getOutputStream().flush(); + + boolean await = TestAwaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return discardServerHandler.getMessageReceivedCount() == 1; + } + }, 10, 100); + Assert.assertTrue(await); + + socket.getOutputStream().write(('@' + "Test").getBytes()); + socket.getOutputStream().flush(); + + await = TestAwaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return discardServerHandler.getMessageReceivedCount() == 2; + } + }, 10, 100); + Assert.assertFalse(await); + + } finally { + IOUtils.closeQuietly(socket); + + PinpointRPCTestUtils.close(serverAcceptor); + } + } + + private static class TestPipelineFactory implements PipelineFactory { + + @Override + public ChannelPipeline newPipeline() { + ChannelPipeline pipeline = Channels.pipeline(); + + pipeline.addLast("decoder", new FrameDecoder() { + @Override + protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { + byte b = buffer.readByte(); + + if (((char) b == START_KEY)) { + int availableSize = buffer.readableBytes(); + + byte[] data = new byte[availableSize]; + buffer.readBytes(data); + + return ChannelBuffers.wrappedBuffer(data); + } else { + //discard + int availableSize = buffer.readableBytes(); + + byte[] data = new byte[availableSize]; + buffer.readBytes(data); + + return null; + } + } + }); + + return pipeline; + } + } + +} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/stream/StreamChannelManagerTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/stream/StreamChannelManagerTest.java index aa9e195ad1d2..4f1262898a31 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/stream/StreamChannelManagerTest.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/stream/StreamChannelManagerTest.java @@ -16,25 +16,23 @@ package com.navercorp.pinpoint.rpc.stream; -import com.navercorp.pinpoint.common.util.CollectionUtils; -import com.navercorp.pinpoint.rpc.*; -import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; -import com.navercorp.pinpoint.rpc.client.PinpointClient; -import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.PinpointSocketException; +import com.navercorp.pinpoint.rpc.RecordedStreamChannelMessageListener; +import com.navercorp.pinpoint.rpc.TestByteUtils; import com.navercorp.pinpoint.rpc.client.SimpleMessageListener; import com.navercorp.pinpoint.rpc.packet.stream.StreamClosePacket; import com.navercorp.pinpoint.rpc.packet.stream.StreamCode; import com.navercorp.pinpoint.rpc.packet.stream.StreamCreateFailPacket; import com.navercorp.pinpoint.rpc.packet.stream.StreamCreatePacket; import com.navercorp.pinpoint.rpc.server.PinpointServer; -import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.ServerMessageListener; -import com.navercorp.pinpoint.rpc.server.SimpleServerMessageListener; -import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils; +import com.navercorp.pinpoint.test.client.TestPinpointClient; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; +import com.navercorp.pinpoint.test.server.TestServerMessageListenerFactory; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; -import org.springframework.util.SocketUtils; import java.io.IOException; import java.util.List; @@ -43,29 +41,23 @@ public class StreamChannelManagerTest { private final TestAwaitUtils awaitUtils = new TestAwaitUtils(10, 1000); - - private static int bindPort; - - @BeforeClass - public static void setUp() throws IOException { - bindPort = SocketUtils.findAvailableTcpPort(); - } + private final TestServerMessageListenerFactory testServerMessageListenerFactory = new TestServerMessageListenerFactory(TestServerMessageListenerFactory.HandshakeType.DUPLEX); // Client to Server Stream @Test public void streamSuccessTest1() throws IOException, InterruptedException { SimpleStreamBO bo = new SimpleStreamBO(); - PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, new ServerListener(bo)); - serverAcceptor.bind("localhost", bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory, new ServerListener(bo)); + int bindPort = testPinpointServerAcceptor.bind(); - PinpointClientFactory clientFactory = createSocketFactory(); + TestPinpointClient testPinpointClient = new TestPinpointClient(); try { - PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); + testPinpointClient.connect(bindPort); RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4); - ClientStreamChannelContext clientContext = client.openStream(new byte[0], clientListener); + ClientStreamChannelContext clientContext = testPinpointClient.openStream(new byte[0], clientListener); int sendCount = 4; for (int i = 0; i < sendCount; i++) { @@ -76,11 +68,9 @@ public void streamSuccessTest1() throws IOException, InterruptedException { Assert.assertEquals(sendCount, clientListener.getReceivedMessage().size()); clientContext.getStreamChannel().close(); - - PinpointRPCTestUtils.close(client); } finally { - clientFactory.release(); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } @@ -89,18 +79,18 @@ public void streamSuccessTest1() throws IOException, InterruptedException { public void streamSuccessTest2() throws IOException, InterruptedException { SimpleStreamBO bo = new SimpleStreamBO(); - PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, new ServerListener(bo)); - serverAcceptor.bind("localhost", bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory, new ServerListener(bo)); + int bindPort = testPinpointServerAcceptor.bind(); - PinpointClientFactory clientFactory = createSocketFactory(); + TestPinpointClient testPinpointClient = new TestPinpointClient(); try { - PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); + testPinpointClient.connect(bindPort); RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4); - ClientStreamChannelContext clientContext = client.openStream(new byte[0], clientListener); + ClientStreamChannelContext clientContext = testPinpointClient.openStream(new byte[0], clientListener); RecordedStreamChannelMessageListener clientListener2 = new RecordedStreamChannelMessageListener(8); - ClientStreamChannelContext clientContext2 = client.openStream(new byte[0], clientListener2); + ClientStreamChannelContext clientContext2 = testPinpointClient.openStream(new byte[0], clientListener2); int sendCount = 4; for (int i = 0; i < sendCount; i++) { @@ -122,34 +112,25 @@ public void streamSuccessTest2() throws IOException, InterruptedException { Assert.assertEquals(8, clientListener2.getReceivedMessage().size()); clientContext2.getStreamChannel().close(); - - PinpointRPCTestUtils.close(client); } finally { - clientFactory.release(); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } @Test public void streamSuccessTest3() throws IOException, InterruptedException { - final PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, null); - serverAcceptor.bind("localhost", bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); SimpleStreamBO bo = new SimpleStreamBO(); - PinpointClientFactory clientFactory = createSocketFactory(SimpleMessageListener.INSTANCE, new ServerListener(bo)); - + TestPinpointClient testPinpointClient = new TestPinpointClient(SimpleMessageListener.INSTANCE, new ServerListener(bo)); try { - PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); + testPinpointClient.connect(bindPort); + testPinpointServerAcceptor.assertAwaitClientConnected(1000); - awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - return CollectionUtils.hasLength(serverAcceptor.getWritableSocketList()); - } - }); - - List writableServerList = serverAcceptor.getWritableSocketList(); + List writableServerList = testPinpointServerAcceptor.getConnectedPinpointSocketList(); Assert.assertEquals(1, writableServerList.size()); PinpointSocket writableServer = writableServerList.get(0); @@ -171,37 +152,33 @@ public boolean checkCompleted() { } else { Assert.fail(); } - - PinpointRPCTestUtils.close(client); } finally { - clientFactory.release(); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } @Test public void streamClosedTest1() throws IOException, InterruptedException { - PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, null); - serverAcceptor.bind("localhost", bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); - PinpointClientFactory clientFactory = createSocketFactory(); + TestPinpointClient testPinpointClient = new TestPinpointClient(); try { - PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); + testPinpointClient.connect(bindPort); RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4); - ClientStreamChannelContext clientContext = client.openStream(new byte[0], clientListener); + ClientStreamChannelContext clientContext = testPinpointClient.openStream(new byte[0], clientListener); StreamCreateFailPacket createFailPacket = clientContext.getCreateFailPacket(); if (createFailPacket == null) { Assert.fail(); } clientContext.getStreamChannel().close(); - - PinpointRPCTestUtils.close(client); } finally { - clientFactory.release(); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } @@ -209,18 +186,16 @@ public void streamClosedTest1() throws IOException, InterruptedException { public void streamClosedTest2() throws IOException, InterruptedException { final SimpleStreamBO bo = new SimpleStreamBO(); - final PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, new ServerListener(bo)); - serverAcceptor.bind("localhost", bindPort); - - PinpointClientFactory clientFactory = createSocketFactory(); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory, new ServerListener(bo)); + int bindPort = testPinpointServerAcceptor.bind(); - PinpointClient client = null; + TestPinpointClient testPinpointClient = new TestPinpointClient(); try { - client = clientFactory.connect("127.0.0.1", bindPort); + testPinpointClient.connect(bindPort); RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4); - ClientStreamChannelContext clientContext = client.openStream(new byte[0], clientListener); + ClientStreamChannelContext clientContext = testPinpointClient.openStream(new byte[0], clientListener); Assert.assertEquals(1, bo.getStreamChannelContextSize()); clientContext.getStreamChannel().close(); @@ -234,9 +209,8 @@ public boolean checkCompleted() { Assert.assertEquals(0, bo.getStreamChannelContextSize()); } finally { - PinpointRPCTestUtils.close(client); - clientFactory.release(); - PinpointRPCTestUtils.close(serverAcceptor); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } } @@ -245,24 +219,17 @@ public boolean checkCompleted() { // ServerStreamChannel first close. @Test(expected = PinpointSocketException.class) public void streamClosedTest3() throws IOException, InterruptedException { - final PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, null); - serverAcceptor.bind("localhost", bindPort); + TestPinpointServerAcceptor testPinpointServerAcceptor = new TestPinpointServerAcceptor(testServerMessageListenerFactory); + int bindPort = testPinpointServerAcceptor.bind(); SimpleStreamBO bo = new SimpleStreamBO(); - PinpointClientFactory clientFactory = createSocketFactory(SimpleMessageListener.INSTANCE, new ServerListener(bo)); - - PinpointClient client = clientFactory.connect("127.0.0.1", bindPort); + TestPinpointClient testPinpointClient = new TestPinpointClient(SimpleMessageListener.INSTANCE, new ServerListener(bo)); + testPinpointClient.connect(bindPort); try { + testPinpointServerAcceptor.assertAwaitClientConnected(1000); - awaitUtils.await(new TestAwaitTaskUtils() { - @Override - public boolean checkCompleted() { - return CollectionUtils.hasLength(serverAcceptor.getWritableSocketList()); - } - }); - - List writableServerList = serverAcceptor.getWritableSocketList(); + List writableServerList = testPinpointServerAcceptor.getConnectedPinpointSocketList(); Assert.assertEquals(1, writableServerList.size()); PinpointSocket writableServer = writableServerList.get(0); @@ -272,7 +239,7 @@ public boolean checkCompleted() { ClientStreamChannelContext clientContext = ((PinpointServer)writableServer).openStream(new byte[0], clientListener); - StreamChannelContext streamChannelContext = client.findStreamChannel(2); + StreamChannelContext streamChannelContext = testPinpointClient.findStreamChannel(2); streamChannelContext.getStreamChannel().close(); @@ -286,38 +253,9 @@ public boolean checkCompleted() { } } finally { - PinpointRPCTestUtils.close(client); - clientFactory.release(); - PinpointRPCTestUtils.close(serverAcceptor); - } - } - - - private PinpointServerAcceptor createServerFactory(ServerMessageListener severMessageListener, ServerStreamChannelMessageListener serverStreamChannelMessageListener) { - PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(); - - if (severMessageListener != null) { - serverAcceptor.setMessageListener(severMessageListener); + testPinpointClient.closeAll(); + testPinpointServerAcceptor.close(); } - - if (serverStreamChannelMessageListener != null) { - serverAcceptor.setServerStreamChannelMessageListener(serverStreamChannelMessageListener); - } - - return serverAcceptor; - } - - private PinpointClientFactory createSocketFactory() { - PinpointClientFactory clientFactory = new DefaultPinpointClientFactory(); - return clientFactory; - } - - private PinpointClientFactory createSocketFactory(MessageListener messageListener, ServerStreamChannelMessageListener serverStreamChannelMessageListener) { - PinpointClientFactory clientFactory = new DefaultPinpointClientFactory(); - clientFactory.setMessageListener(messageListener); - clientFactory.setServerStreamChannelMessageListener(serverStreamChannelMessageListener); - - return clientFactory; } private void sendRandomBytes(SimpleStreamBO bo) { diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/IOUtils.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/IOUtils.java index 4d69fa0fc2b2..358f7639c34c 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/IOUtils.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/IOUtils.java @@ -16,8 +16,8 @@ package com.navercorp.pinpoint.rpc.util; -import com.navercorp.pinpoint.rpc.TestAwaitTaskUtils; -import com.navercorp.pinpoint.rpc.TestAwaitUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import java.io.IOException; import java.io.InputStream; @@ -65,19 +65,11 @@ public static void write(OutputStream outputStream, byte[] payload) throws IOExc } public static void close(Socket socket) throws IOException { - close(socket, false); + com.navercorp.pinpoint.common.util.IOUtils.close(socket); } - public static void close(Socket socket, boolean quietly) throws IOException { - if (socket != null) { - try { - socket.close(); - } catch (final IOException ioe) { - if (!quietly) { - throw ioe; - } - } - } + public static void closeQuietly(Socket socket) { + com.navercorp.pinpoint.common.util.IOUtils.closeQuietly(socket); } } diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/ListUtilsTest.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/ListUtilsTest.java deleted file mode 100644 index 33f6cbe2b0b6..000000000000 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/ListUtilsTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.rpc.util; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.Assert; - -import org.junit.Test; - -public class ListUtilsTest { - - @Test - public void addIfValueNotNullTest() { - List list = new ArrayList(); - - ListUtils.addIfValueNotNull(list, "firstString"); - ListUtils.addIfValueNotNull(list, null); - - Assert.assertEquals(1, list.size()); - } - - @Test - public void addAllIfAllValuesNotNullTest() { - List list = new ArrayList(); - - String[] values = {"firstString", null, "secondString"}; - - ListUtils.addAllIfAllValuesNotNull(list, values); - - Assert.assertEquals(0, list.size()); - } - - @Test - public void addAllExceptNullValueTest() { - List list = new ArrayList(); - - String[] values = {"firstString", null, "secondString"}; - - ListUtils.addAllExceptNullValue(list, values); - - Assert.assertEquals(2, list.size()); - } - -} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/PinpointRPCTestUtils.java b/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/PinpointRPCTestUtils.java index d266c128561b..6cd66f92b0c2 100644 --- a/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/PinpointRPCTestUtils.java +++ b/rpc/src/test/java/com/navercorp/pinpoint/rpc/util/PinpointRPCTestUtils.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -25,14 +25,9 @@ import com.navercorp.pinpoint.rpc.client.PinpointClient; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; import com.navercorp.pinpoint.rpc.packet.HandshakePropertyType; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; import com.navercorp.pinpoint.rpc.packet.RequestPacket; import com.navercorp.pinpoint.rpc.packet.SendPacket; -import com.navercorp.pinpoint.rpc.server.PinpointServer; import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.ServerMessageListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,22 +43,6 @@ public final class PinpointRPCTestUtils { private PinpointRPCTestUtils() { } - - public static PinpointServerAcceptor createPinpointServerFactory(int bindPort) { - return createPinpointServerFactory(bindPort, null); - } - - public static PinpointServerAcceptor createPinpointServerFactory(int bindPort, ServerMessageListener messageListener) { - PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(); - serverAcceptor.bind("127.0.0.1", bindPort); - - if (messageListener != null) { - serverAcceptor.setMessageListener(messageListener); - } - - return serverAcceptor; - } - public static void close(PinpointServerAcceptor serverAcceptor, PinpointServerAcceptor... serverAcceptors) { if (serverAcceptor != null) { serverAcceptor.close(); @@ -77,11 +56,7 @@ public static void close(PinpointServerAcceptor serverAcceptor, PinpointServerAc } } } - - public static PinpointClientFactory createClientFactory(Map param) { - return createClientFactory(param, null); - } - + public static PinpointClientFactory createClientFactory(Map param, MessageListener messageListener) { PinpointClientFactory clientFactory = new DefaultPinpointClientFactory(); clientFactory.setProperties(param); @@ -119,14 +94,6 @@ public static void close(PinpointClient client, PinpointClient... clients) { } } } - - public static EchoServerListener createEchoServerListener() { - return new EchoServerListener(); - } - - public static EchoClientListener createEchoClientListener() { - return new EchoClientListener(); - } public static Map getParams() { Map properties = new HashMap(); @@ -142,36 +109,6 @@ public static Map getParams() { return properties; } - public static class EchoServerListener implements ServerMessageListener { - private final List sendPacketRepository = new ArrayList(); - private final List requestPacketRepository = new ArrayList(); - - @Override - public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { - logger.debug("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); - sendPacketRepository.add(sendPacket); - } - - @Override - public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { - logger.debug("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); - - requestPacketRepository.add(requestPacket); - pinpointSocket.response(requestPacket, requestPacket.getPayload()); - } - - @Override - public HandshakeResponseCode handleHandshake(Map properties) { - logger.debug("handle Handshake {}", properties); - return HandshakeResponseType.Success.DUPLEX_COMMUNICATION; - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - } - - } - public static class EchoClientListener implements MessageListener { private final List sendPacketRepository = new ArrayList(); private final List requestPacketRepository = new ArrayList(); @@ -191,7 +128,7 @@ public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSo byte[] payload = requestPacket.getPayload(); logger.debug(new String(payload)); - pinpointSocket.response(requestPacket, payload); + pinpointSocket.response(requestPacket.getRequestId(), payload); } public List getSendPacketRepository() { diff --git a/rpc/src/test/java/com/navercorp/pinpoint/test/client/TestPinpointClient.java b/rpc/src/test/java/com/navercorp/pinpoint/test/client/TestPinpointClient.java new file mode 100644 index 000000000000..56992db95e5d --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/test/client/TestPinpointClient.java @@ -0,0 +1,130 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test.client; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.rpc.LoggingStateChangeEventListener; +import com.navercorp.pinpoint.rpc.MessageListener; +import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; +import com.navercorp.pinpoint.rpc.client.PinpointClient; +import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; +import com.navercorp.pinpoint.rpc.stream.ClientStreamChannelContext; +import com.navercorp.pinpoint.rpc.stream.ClientStreamChannelMessageListener; +import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelMessageListener; +import com.navercorp.pinpoint.rpc.stream.StreamChannelContext; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; + +import java.util.Collections; +import java.util.Map; + +/** + * @author Taejin Koo + */ +public class TestPinpointClient { + + private final PinpointClientFactory pinpointClientFactory; + private PinpointClient pinpointClient; + + public TestPinpointClient() { + this(Collections.EMPTY_MAP); + } + + public TestPinpointClient(Map param) { + this(null, param); + } + + public TestPinpointClient(MessageListener messageListener) { + this(messageListener, (ServerStreamChannelMessageListener) null); + } + + public TestPinpointClient(MessageListener messageListener, ServerStreamChannelMessageListener serverStreamChannelMessageListener) { + this(messageListener, serverStreamChannelMessageListener, Collections.EMPTY_MAP); + } + + public TestPinpointClient(MessageListener messageListener, Map param) { + this(messageListener, null, param); + } + + public TestPinpointClient(MessageListener messageListener, ServerStreamChannelMessageListener serverStreamChannelMessageListener, Map param) { + Assert.requireNonNull(param, "param must not be null"); + + PinpointClientFactory pinpointClientFactory = new DefaultPinpointClientFactory(); + pinpointClientFactory.setProperties(param); + pinpointClientFactory.addStateChangeEventListener(LoggingStateChangeEventListener.INSTANCE); + + if (messageListener != null) { + pinpointClientFactory.setMessageListener(messageListener); + } + + if (serverStreamChannelMessageListener != null) { + pinpointClientFactory.setServerStreamChannelMessageListener(serverStreamChannelMessageListener); + } + + this.pinpointClientFactory = pinpointClientFactory; + } + + public TestPinpointClient(PinpointClientFactory pinpointClientFactory) { + this.pinpointClientFactory = Assert.requireNonNull(pinpointClientFactory, "pinpointClientFactory must not be null"); + } + + public void connect(int port) { + connect(TestPinpointServerAcceptor.LOCALHOST, port); + } + + public void connect(String host, int port) { + this.pinpointClient = pinpointClientFactory.connect(host, port); + } + + public ClientStreamChannelContext openStream(byte[] payload, ClientStreamChannelMessageListener messageListener) { + Assert.requireNonNull(pinpointClient, "pinpointClient must not be null"); + return pinpointClient.openStream(payload, messageListener); + } + + public StreamChannelContext findStreamChannel(int streamChannelId) { + Assert.requireNonNull(pinpointClient, "pinpointClient must not be null"); + return pinpointClient.findStreamChannel(streamChannelId); + } + + public void disconnect() { + if (pinpointClient != null) { + pinpointClient.close(); + } + } + + public void releaseConnectionFactory() { + if (pinpointClientFactory != null) { + pinpointClientFactory.release(); + } + } + + public void closeAll() { + if (pinpointClient != null) { + pinpointClient.close(); + } + + if (pinpointClientFactory != null) { + pinpointClientFactory.release(); + } + } + + public static void staticCloseAll(TestPinpointClient pinpointClient) { + if (pinpointClient != null) { + pinpointClient.closeAll(); + } + } + +} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/test/client/TestRawSocket.java b/rpc/src/test/java/com/navercorp/pinpoint/test/client/TestRawSocket.java new file mode 100644 index 000000000000..e44a6b35d3d6 --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/test/client/TestRawSocket.java @@ -0,0 +1,89 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test.client; + +import com.navercorp.pinpoint.rpc.codec.TestCodec; +import com.navercorp.pinpoint.rpc.control.ProtocolException; +import com.navercorp.pinpoint.rpc.packet.ControlHandshakePacket; +import com.navercorp.pinpoint.rpc.packet.ControlHandshakeResponsePacket; +import com.navercorp.pinpoint.rpc.packet.Packet; +import com.navercorp.pinpoint.rpc.packet.PongPacket; +import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.rpc.packet.ResponsePacket; +import com.navercorp.pinpoint.rpc.util.ControlMessageEncodingUtils; +import com.navercorp.pinpoint.rpc.util.IOUtils; +import com.navercorp.pinpoint.test.server.TestPinpointServerAcceptor; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.Map; + +/** + * @author Taejin Koo + */ +public class TestRawSocket { + + private final Socket socket; + + public TestRawSocket() { + socket = new Socket(); + } + + public void connect(int port) throws IOException { + socket.connect(new InetSocketAddress(TestPinpointServerAcceptor.LOCALHOST, port)); + } + + + public void sendPingPacket(Packet pingPacket) throws ProtocolException, IOException { + byte[] payload = TestCodec.encodePacket(pingPacket); + IOUtils.write(socket.getOutputStream(), payload); + } + + public PongPacket readPongPacket(long maxWaitTIme) throws ProtocolException, IOException { + byte[] payload = IOUtils.read(socket.getInputStream(), 50, maxWaitTIme); + return (PongPacket) TestCodec.decodePacket(payload); + } + + public void sendRequestPacket() throws ProtocolException, IOException { + byte[] packet = TestCodec.encodePacket(new RequestPacket(10, new byte[0])); + IOUtils.write(socket.getOutputStream(), packet); + } + + public ResponsePacket readResponsePacket(long maxWaitTime) throws ProtocolException, IOException { + byte[] payload = IOUtils.read(socket.getInputStream(), 50, maxWaitTime); + return (ResponsePacket) TestCodec.decodePacket(payload); + } + + public void sendHandshakePacket(Map properties) throws ProtocolException, IOException { + byte[] payload = ControlMessageEncodingUtils.encode(properties); + byte[] packet = TestCodec.encodePacket(new ControlHandshakePacket(1, payload)); + IOUtils.write(socket.getOutputStream(), packet); + } + + public Map readHandshakeResponseData(long maxWaitTime) throws ProtocolException, IOException { + byte[] payload = IOUtils.read(socket.getInputStream(), 50, maxWaitTime); + ControlHandshakeResponsePacket responsePacket = (ControlHandshakeResponsePacket) TestCodec.decodePacket(payload); + Map result = (Map) ControlMessageEncodingUtils.decode(responsePacket.getPayload()); + return result; + } + + public void close() { + IOUtils.closeQuietly(socket); + } + +} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/test/server/TestPinpointServerAcceptor.java b/rpc/src/test/java/com/navercorp/pinpoint/test/server/TestPinpointServerAcceptor.java new file mode 100644 index 000000000000..2bfa5e95b6d0 --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/test/server/TestPinpointServerAcceptor.java @@ -0,0 +1,149 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test.server; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; +import com.navercorp.pinpoint.rpc.server.ServerMessageListenerFactory; +import com.navercorp.pinpoint.rpc.stream.ServerStreamChannelMessageListener; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; +import org.jboss.netty.channel.ChannelHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.SocketUtils; + +import java.util.List; + +/** + * @author Taejin Koo + */ +public class TestPinpointServerAcceptor { + + public static final String LOCALHOST = "localhost"; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final PinpointServerAcceptor serverAcceptor; + + public TestPinpointServerAcceptor() { + this((ServerMessageListenerFactory) null); + } + + public TestPinpointServerAcceptor(ServerMessageListenerFactory messageListenerFactory) { + this(messageListenerFactory, null); + } + + public TestPinpointServerAcceptor(ServerMessageListenerFactory messageListenerFactory, ServerStreamChannelMessageListener streamChannelMessageListener) { + this(messageListenerFactory, streamChannelMessageListener, null); + } + + public TestPinpointServerAcceptor(ChannelHandler messageHandler) { + this(null, null, messageHandler); + } + + public TestPinpointServerAcceptor(ServerMessageListenerFactory messageListenerFactory, ServerStreamChannelMessageListener streamChannelMessageListener, ChannelHandler messageHandler) { + PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor(); + + if (messageListenerFactory != null) { + serverAcceptor.setMessageListenerFactory(messageListenerFactory); + } + + if (streamChannelMessageListener != null) { + serverAcceptor.setServerStreamChannelMessageListener(streamChannelMessageListener); + } + + if (messageHandler != null) { + serverAcceptor.setMessageHandler(messageHandler); + } + + this.serverAcceptor = serverAcceptor; + } + + public int bind() { + int port = SocketUtils.findAvailableTcpPort(47000); + return bind(port); + } + + public int bind(int port) { + logger.info("bind port:{}", port); + serverAcceptor.bind(LOCALHOST, port); + return port; + } + + public void assertAwaitClientConnected(int maxWaitTime) { + boolean clientConnected = awaitClientConnected(maxWaitTime); + org.junit.Assert.assertTrue(clientConnected); + } + + public boolean awaitClientConnected(int maxWaitTime) { + Assert.isTrue(maxWaitTime > 100, "maxWaitTime must be greater than 100"); + + TestAwaitUtils awaitUtils = new TestAwaitUtils(100, maxWaitTime); + boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return !serverAcceptor.getWritableSocketList().isEmpty(); + } + }); + + return pass; + } + + public void assertAwaitClientConnected(int expectedConnectedClientCount, int maxWaitTime) { + boolean clientConnected = awaitClientConnected(expectedConnectedClientCount, maxWaitTime); + org.junit.Assert.assertTrue(clientConnected); + } + + public boolean awaitClientConnected(final int expectedConnectedClientCount, int maxWaitTime) { + Assert.isTrue(maxWaitTime > 100, "maxWaitTime must be greater than 100"); + + TestAwaitUtils awaitUtils = new TestAwaitUtils(100, maxWaitTime); + boolean pass = awaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return CollectionUtils.nullSafeSize(serverAcceptor.getWritableSocketList()) == expectedConnectedClientCount; + } + }); + + return pass; + } + + public int getConnectedClientCount() { + return CollectionUtils.nullSafeSize(serverAcceptor.getWritableSocketList()); + } + + public List getConnectedPinpointSocketList() { + return serverAcceptor.getWritableSocketList(); + } + + public void close() { + logger.info("close"); + if (serverAcceptor != null) { + serverAcceptor.close(); + } + } + + public static void staticClose(TestPinpointServerAcceptor testPinpointServerAcceptor) { + if (testPinpointServerAcceptor != null) { + testPinpointServerAcceptor.close(); + } + } + +} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/test/server/TestServerMessageListenerFactory.java b/rpc/src/test/java/com/navercorp/pinpoint/test/server/TestServerMessageListenerFactory.java new file mode 100644 index 000000000000..e058cebfad6b --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/test/server/TestServerMessageListenerFactory.java @@ -0,0 +1,193 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test.server; + +import com.navercorp.pinpoint.rpc.PinpointSocket; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; +import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; +import com.navercorp.pinpoint.rpc.packet.RequestPacket; +import com.navercorp.pinpoint.rpc.packet.SendPacket; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.rpc.server.ServerMessageListenerFactory; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +/** + * @author Taejin Koo + */ +public class TestServerMessageListenerFactory implements ServerMessageListenerFactory { + + public static enum HandshakeType { + SIMPLEX, + DUPLEX + } + + public static enum ResponseType { + NO_RESPONSE, + ECHO + } + + private final HandshakeType handshakeType; + private final ResponseType responseType; + + private final boolean singleton; + private final AtomicReference singletonReference = new AtomicReference(); + + public TestServerMessageListenerFactory() { + this(HandshakeType.SIMPLEX, ResponseType.ECHO); + } + + public TestServerMessageListenerFactory(HandshakeType handshakeType) { + this(handshakeType, ResponseType.ECHO, false); + } + + public TestServerMessageListenerFactory(HandshakeType handshakeType, boolean singleton) { + this(handshakeType, ResponseType.ECHO, singleton); + } + + public TestServerMessageListenerFactory(HandshakeType handshakeType, ResponseType responseType) { + this(handshakeType, responseType, false); + } + + public TestServerMessageListenerFactory(HandshakeType handshakeType, ResponseType responseType, boolean singleton) { + this.handshakeType = com.navercorp.pinpoint.common.util.Assert.requireNonNull(handshakeType, "handshakeType must not be null"); + this.responseType = com.navercorp.pinpoint.common.util.Assert.requireNonNull(responseType, "responseType must not be null"); + this.singleton = singleton; + } + + @Override + public TestServerMessageListener create() { + if (singleton) { + singletonReference.compareAndSet(null, new TestServerMessageListener(handshakeType, responseType)); + return singletonReference.get(); + } + + return new TestServerMessageListener(handshakeType, responseType); + } + + public static TestServerMessageListener create(HandshakeType handshakeType, ResponseType responseType) { + return new TestServerMessageListener(handshakeType, responseType); + } + + public static class TestServerMessageListener implements ServerMessageListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final AtomicInteger handleSendCount = new AtomicInteger(0); + private final AtomicInteger handleRequestCount = new AtomicInteger(0); + private final AtomicInteger handlePingCount = new AtomicInteger(0); + + private final HandshakeType handshakeType; + private final ResponseType responseType; + + public TestServerMessageListener(HandshakeType handshakeType, ResponseType responseType) { + this.handshakeType = com.navercorp.pinpoint.common.util.Assert.requireNonNull(handshakeType, "handshakeType must not be null"); + this.responseType = com.navercorp.pinpoint.common.util.Assert.requireNonNull(responseType, "responseType must not be null"); + } + + @Override + public void handleSend(SendPacket sendPacket, PinpointSocket pinpointSocket) { + handleSendCount.incrementAndGet(); + logger.info("handleSend packet:{}, remote:{}", sendPacket, pinpointSocket.getRemoteAddress()); + } + + @Override + public void handleRequest(RequestPacket requestPacket, PinpointSocket pinpointSocket) { + handleRequestCount.incrementAndGet(); + + logger.info("handleRequest packet:{}, remote:{}", requestPacket, pinpointSocket.getRemoteAddress()); + + if (responseType == ResponseType.ECHO) { + pinpointSocket.response(requestPacket.getRequestId(), requestPacket.getPayload()); + } + } + + @Override + public HandshakeResponseCode handleHandshake(Map properties) { + logger.info("handleHandshake properties:{}", properties); + + if (handshakeType == HandshakeType.DUPLEX) { + return HandshakeResponseCode.DUPLEX_COMMUNICATION; + } else { + return HandshakeResponseCode.SIMPLEX_COMMUNICATION; + } + } + + @Override + public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { + handlePingCount.incrementAndGet(); + + logger.info("handlePing packet:{}, remote:{}", pingPacket, pinpointServer.getRemoteAddress()); + } + + public void awaitAssertExpectedSendCount(final int expectedCount, long maxWaitTime) { + if (maxWaitTime > 100) { + TestAwaitUtils awaitUtils = new TestAwaitUtils(100, maxWaitTime); + Assert.assertTrue(awaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return expectedCount == handleSendCount.get(); + } + })); + } else { + Assert.assertTrue(expectedCount == handleSendCount.get()); + } + } + + public void awaitAssertExpectedRequestCount(final int expectedCount, long maxWaitTime) { + if (maxWaitTime > 100) { + TestAwaitUtils awaitUtils = new TestAwaitUtils(100, maxWaitTime); + Assert.assertTrue(awaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return expectedCount == handleRequestCount.get(); + } + })); + } else { + Assert.assertTrue(expectedCount == handleRequestCount.get()); + } + } + + public void awaitAssertExpectedPingCount(final int expectedCount, long maxWaitTime) { + if (maxWaitTime > 100) { + TestAwaitUtils awaitUtils = new TestAwaitUtils(100, maxWaitTime); + Assert.assertTrue(awaitUtils.await(new TestAwaitTaskUtils() { + @Override + public boolean checkCompleted() { + return expectedCount == handlePingCount.get(); + } + })); + } else { + Assert.assertTrue(expectedCount == handlePingCount.get()); + } + } + + public boolean hasReceivedPing() { + return handlePingCount.get() > 0; + } + + } + +} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/test/utils/TestAwaitTaskUtils.java b/rpc/src/test/java/com/navercorp/pinpoint/test/utils/TestAwaitTaskUtils.java new file mode 100644 index 000000000000..f04ce8fa3464 --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/test/utils/TestAwaitTaskUtils.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test.utils; + +/** + * @author Taejin Koo + */ +public interface TestAwaitTaskUtils { + + boolean checkCompleted(); + +} diff --git a/rpc/src/test/java/com/navercorp/pinpoint/test/utils/TestAwaitUtils.java b/rpc/src/test/java/com/navercorp/pinpoint/test/utils/TestAwaitUtils.java new file mode 100644 index 000000000000..666be19b45d5 --- /dev/null +++ b/rpc/src/test/java/com/navercorp/pinpoint/test/utils/TestAwaitUtils.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test.utils; + +import com.navercorp.pinpoint.common.util.StopWatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Taejin Koo + */ +public class TestAwaitUtils { + + private final static Logger LOGGER = LoggerFactory.getLogger(TestAwaitUtils.class); + + private final long waitUnitTime; + private final long maxWaitTime; + + public TestAwaitUtils(long waitUnitTime, long maxWaitTime) { + this.waitUnitTime = waitUnitTime; + this.maxWaitTime = maxWaitTime; + } + + public boolean await(TestAwaitTaskUtils awaitTaskUtils) { + return await(awaitTaskUtils, waitUnitTime, maxWaitTime); + } + + public static boolean await(TestAwaitTaskUtils awaitTaskUtils, long waitUnitTime, long maxWaitTime) { + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + while (true) { + try { + if (awaitTaskUtils.checkCompleted()) { + return true; + } + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + + try { + Thread.sleep(waitUnitTime); + } catch (InterruptedException e) { + } + + if (stopWatch.stop() > maxWaitTime) { + return false; + } + } + } + +} diff --git a/findbugs-exclude.xml b/spotbugs-exclude.xml similarity index 100% rename from findbugs-exclude.xml rename to spotbugs-exclude.xml diff --git a/test/clover.license b/test/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/test/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-test diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/AbstractPinpointPluginTestSuite.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/AbstractPinpointPluginTestSuite.java index d8e4304dd966..6192b85f94d3 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/AbstractPinpointPluginTestSuite.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/AbstractPinpointPluginTestSuite.java @@ -18,10 +18,8 @@ import java.io.File; import java.lang.management.ManagementFactory; -import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; -import java.security.CodeSource; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -108,9 +106,10 @@ protected String getJavaExecutable(int version) { } private String resolveTestClassLocation(Class testClass) { - CodeSource codeSource = testClass.getProtectionDomain().getCodeSource(); - URL testClassLocation = codeSource.getLocation(); - + final URL testClassLocation = CodeSourceUtils.getCodeLocation(testClass); + if (testClassLocation == null) { + throw new IllegalStateException(testClass + " url not found"); + } return toPathString(testClassLocation); } @@ -118,14 +117,16 @@ private List resolveRequiredLibraries() { List result = new ArrayList(); ClassLoader cl = getClass().getClassLoader(); - + while (true) { if (cl instanceof URLClassLoader) { - findRequiredLibraries(result, (URLClassLoader)cl); + URLClassLoader ucl = ((URLClassLoader) cl); + List requiredLibraries = findRequiredLibraries(ucl.getURLs()); + result.addAll(requiredLibraries); } - + cl = cl.getParent(); - + if (cl == null) { break; } @@ -135,8 +136,10 @@ private List resolveRequiredLibraries() { } - private void findRequiredLibraries(List result, URLClassLoader cl) { - outer: for (URL url : cl.getURLs()) { + private List findRequiredLibraries(URL[] urls) { + final List result = new ArrayList(); + outer: + for (URL url : urls) { for (String required : REQUIRED_CLASS_PATHS) { if (url.getFile().contains(required)) { result.add(toPathString(url)); @@ -145,14 +148,11 @@ private void findRequiredLibraries(List result, URLClassLoader cl) { } } } + return result; } private String toPathString(URL url) { - try { - return new File(url.toURI()).getAbsolutePath(); - } catch (URISyntaxException e) { - throw new RuntimeException("???", e); - } + return new File(url.getFile()).getAbsolutePath(); } private String resolveAgentPath(PinpointAgent agent) { diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/CodeSourceUtils.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/CodeSourceUtils.java new file mode 100644 index 000000000000..b9fe66ea9120 --- /dev/null +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/CodeSourceUtils.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.test.plugin; + +import java.net.URL; +import java.security.CodeSource; +import java.security.ProtectionDomain; + +/** + * @author Woonduk Kang(emeroad) + */ +class CodeSourceUtils { + + static URL getCodeLocation(Class clazz) { + if (clazz == null) { + throw new NullPointerException("clazz must not be null"); + } + + final ProtectionDomain protectionDomain = clazz.getProtectionDomain(); + final CodeSource codeSource = protectionDomain.getCodeSource(); + if (codeSource == null) { + return null; + } + return codeSource.getLocation(); + } +} diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTest.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTest.java index df78622169b2..cfe343f210cf 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTest.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/ForkedPinpointPluginTest.java @@ -103,7 +103,7 @@ private static ClassLoader getClassLoader(String agentType) throws MalformedURLE logger.debug("child-runner lib:" + url); } } - return new PluginTestClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader()); + return new PluginTestClassLoader(urls.toArray(new URL[0]), ClassLoader.getSystemClassLoader()); } return ClassLoader.getSystemClassLoader(); } diff --git a/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestStatement.java b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestStatement.java index 345bb5c76bfc..fe7e8cbf33f5 100644 --- a/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestStatement.java +++ b/test/src/main/java/com/navercorp/pinpoint/test/plugin/PinpointPluginTestStatement.java @@ -180,7 +180,7 @@ private String[] buildCommand() { list.add(mainClass); list.addAll(testCase.getAppArgs()); - return list.toArray(new String[list.size()]); + return list.toArray(new String[0]); } private List getDebugOptions() { diff --git a/thrift/build-thrift-linux.sh b/thrift/build-thrift-linux.sh index 01af096c274f..b6a8c9aace49 100755 --- a/thrift/build-thrift-linux.sh +++ b/thrift/build-thrift-linux.sh @@ -1,7 +1,29 @@ -mvn generate-sources -P with-thrift -Dmaven.test.skip -Dthrift.executable.path=./src/compiler/linux/thrift-0.10.0 +thrift_path="./src/compiler/linux/" +thrift_bin="thrift-0.10.0" -rc=$? -if [[ $rc != 0 ]] ; then - echo "BUILD FAILED $rc" - exit $rc -fi \ No newline at end of file +rc=0 +# check thrift binary +echo -n "Check Thrift binary... " +if ! [ -x "${thrift_path}${thrift_bin}" ]; then + echo "no Thrift binary in path ${thrift_path}" + ./install-thrift-linux.sh ${thrift_path} ${thrift_bin} + rc=$? +else + echo "ok" +fi + +if [ $rc -eq 0 ]; then + echo "INFO: Autogenerate source code with Thrift" + mvn generate-sources -P with-thrift -Dmaven.test.skip -Dthrift.executable.path=${thrift_path}${thrift_bin} + + rc=$? + if [[ $rc != 0 ]] ; then + echo "ERROR: BUILD FAILED $rc" + exit $rc + fi +else + echo "ERROR: Error occured when Thrift binary is prepared." + echo " Please check following link, install Thrift manually, and copy thrift binary to ${thrift_path}${thrift_bin}." + echo " https://thrift.apache.org/docs/BuildingFromSource" + exit 1 +fi diff --git a/thrift/clover.license b/thrift/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/thrift/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF&1` +if [ $? -eq 0 ]; then + echo "yes" + # Check Thrift version + echo -n "Check if Thrift version is ${tversion}... " + ${installed_path} --version 2>&1 | grep ${tversion} >/dev/null + if [ $? -eq 0 ]; then + echo "yes" + + # Copy Thrift binary to Thrift path + echo "INFO: Copy Thrift Binary to Pinpoint Thrift Path" + cp ${installed_path} ${tpath}${tbin} + + if [ $? -eq 0 ]; then + exit 0 + else + echo "ERROR: Thrift binary copy failed." + exit 1 + fi + + else + echo "no" + fi +else + echo "no" +fi + +# Check if Thrift is built but not copied to compiler path +echo -n "Check if Thrift is built but not copied to compiler path... " +if [ -x "thrift-${tversion}/compiler/cpp/thrift" ]; then + echo "yes" + + # Copy Thrift binary to Thrift path + echo "INFO: Copy Thrift Binary to Pinpoint Thrift Path" + cp thrift-${tversion}/compiler/cpp/thrift ${tpath}${tbin} + if [ $? -ne 0 ]; then + echo "ERROR: Thrift binary copy failed." + exit 1 + fi + + # cleanup + rm -rf thrift-${tversion} + if [ $? -ne 0 ]; then + echo "WARNING: Thrift build directory cleanup failed. Please remove it manually." + fi + exit 0 +else + echo "no" +fi + +# Check build environment +echo "INFO: Check Thrift installation environment" +if [ -f "/etc/os-release" ]; then + # Get Linux distribution name and version. + DIST_ID=`cat /etc/os-release | grep "^ID=" | awk -F "=" '{print $2;}' | tr -d '"'` + DIST_VERSION=`cat /etc/os-release | grep "^VERSION_ID=" | awk -F "=" '{print $2;}' | tr -d '"' | awk -F "." '{print $1;}'` + + echo "Linux distribution: ${DIST_ID}" + echo "Version: ${DIST_VERSION}" +else + echo "ERROR: This Linux distribution is not supported." + exit 1 +fi + +if [[ "${DIST_ID}" = "centos" || "${DIST_ID}" = "rhel" ]]; then + if ! [ "${DIST_VERSION}" -ge 7 ]; then + echo "ERROR: This Linux distribution version is not supported." + exit 1 + fi +else + echo "ERROR: This Linux distribution is not supported." + exit 1 +fi + +# Check pre-installed packages +echo "INFO: Check pre-installed packages" +pkg_count=0 +if [[ "${DIST_ID}" = "centos" || "${DIST_ID}" = "rhel" ]]; then + # Development Tools + echo -n "Check Development Tools installed... " + yum grouplist "Development Tools" installed 2>&1 | grep "Installed Groups:" >/dev/null + if [ $? -eq 0 ]; then + echo "yes" + else + echo "no" + pkg_arr[${pkg_count}]="Development Tools" + let "pkg_count += 1" + fi + + # ant + echo -n "Check ant installed... " + yum list ant installed 2>&1 | grep "Installed Packages" >/dev/null + if [ $? -eq 0 ]; then + echo "yes" + else + echo "no" + pkg_arr[${pkg_count}]="ant" + let "pkg_count += 1" + fi +fi + +# Install dependencies and pre-installed packages if needed +if [ ${pkg_count} -ne 0 ]; then + # If installation of pre-installed packages is required, get root privilege. + echo "Installation of pre-installed packages is required. Please enter password to get root privilege." + sudo test 1 + if [ $? -ne 0 ]; then + echo "ERROR: Authentication failed. Exit install script." + exit 1 + fi + + # Install dependencies and pre-installed packages + echo "INFO: Install Dependencies and Pre-installed Packages" + if [[ "${DIST_ID}" = "centos" || "${DIST_ID}" = "rhel" ]]; then + for pkg in "${pkg_arr[@]}" + do + echo "INFO: Install $pkg" + if [ "$pkg" = "Development Tools" ]; then + sudo yum groupinstall -y "Development Tools" + elif [ "$pkg" = "ant" ]; then + sudo yum install -y ant + fi + done + fi +fi + +# Get Thrift +# download thrift tarball from one of those apache mirrors to ${pinpoint-root}/thrift/src/compiler/linux +cd ${tpath} && wget -T 600 -w 1 -t 3 -c ${APACHE_MIRROR_URL}/thrift/${tversion}/thrift-${tversion}.tar.gz && cd - + +# Install Thrift +echo "INFO: Install Thrift" +tar zxf ${tpath}thrift-${tversion}.tar.gz +if [ $? -ne 0 ]; then + echo "ERROR: Thrift tarball decompression failed." + exit 1 +fi + +cd thrift-${tversion} +./configure +if [ $? -ne 0 ]; then + echo "ERROR: Thrift sourcecode configure failed." + exit 1 +fi + +make +if [ $? -ne 0 ]; then + echo "ERROR: Thrift sourcecode build failed." + exit 1 +fi +cd .. + +# Copy Thrift binary to Thrift path +echo "INFO: Copy Thrift Binary to Pinpoint Thrift Path" +cp thrift-${tversion}/compiler/cpp/thrift ${tpath}${tbin} +if [ $? -ne 0 ]; then + echo "ERROR: Thrift binary copy failed." + exit 1 +fi + +# cleanup +rm -rf thrift-${tversion} +if [ $? -ne 0 ]; then + echo "WARNING: Thrift build directory cleanup failed. Please remove it manually." +fi + +echo "INFO: Thrift install completed!" diff --git a/thrift/pom.xml b/thrift/pom.xml index 9359d0ca71fb..899b589f27f2 100644 --- a/thrift/pom.xml +++ b/thrift/pom.xml @@ -4,7 +4,7 @@ com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-thrift @@ -12,6 +12,10 @@ jar + + com.navercorp.pinpoint + pinpoint-commons + org.apache.thrift libthrift diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/header/ByteArrayHeaderReader.java b/thrift/src/main/java/com/navercorp/pinpoint/io/header/ByteArrayHeaderReader.java new file mode 100644 index 000000000000..d522d35fd38c --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/header/ByteArrayHeaderReader.java @@ -0,0 +1,133 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.header; + +import com.navercorp.pinpoint.common.buffer.Buffer; +import com.navercorp.pinpoint.common.buffer.OffsetFixedBuffer; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; +import com.navercorp.pinpoint.io.header.v2.HeaderV2; + + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Woonduk Kang(emeroad) + */ +public class ByteArrayHeaderReader implements HeaderReader { + + private final Buffer buffer; + + public ByteArrayHeaderReader(byte[] bytes) { + + this(checkBytes(bytes),0, bytes.length); + } + + public ByteArrayHeaderReader(byte[] bytes, final int startOffset, final int length) { + checkBytes(bytes); + this.buffer = new OffsetFixedBuffer(bytes, startOffset, length); + } + + private static byte[] checkBytes(byte[] bytes) { + if (bytes == null) { + throw new NullPointerException("bytes must not be null"); + } + return bytes; + } + + + public Header readHeader() { + final byte signature = buffer.readByte(); + if (signature != Header.SIGNATURE) { + throw new InvalidHeaderException("invalid signature :" + signature); + } + + final byte version = buffer.readByte(); + final short type = buffer.readShort(); + + if (version == HeaderV1.VERSION) { + return new HeaderV1(signature, version, type); + } + if (version == HeaderV2.VERSION) { + return new HeaderV2(signature, version, type); + } + + throw new InvalidHeaderException(String.format("invalid Header : signature(0x%02X), version(0x%02X)", signature, version)); + } + + public HeaderEntity readHeaderEntity(Header header) { + final byte version = header.getVersion(); + if (version == HeaderV1.VERSION) { + return HeaderEntity.EMPTY_HEADER_ENTITY; + } + if (version == HeaderV2.VERSION) { + return readHeaderEntity(); + } + + throw new InvalidHeaderException("invalid Header : " + header); + } + + private HeaderEntity readHeaderEntity() { + final short headerEntitySize = buffer.readShort(); + + if (headerEntitySize < 0 || headerEntitySize > HeaderV2.HEADER_ENTITY_COUNT_MAX_SIZE) { + throw new InvalidHeaderException("header entity count size is invalid. size : " + headerEntitySize); + } + if (headerEntitySize == 0) { + return HeaderEntity.EMPTY_HEADER_ENTITY; + } + + final Map headerEntity = new HashMap(headerEntitySize); + for (int i = 0 ; i < headerEntitySize ; i++ ) { + final String key = readString(); + final String value = readString(); + headerEntity.put(key, value); + } + return new HeaderEntity(headerEntity); + } + + private String readString() { + final short stringLength = buffer.readShort(); + if(!validCheck(stringLength)) { + throw new InvalidHeaderException("string length is invalid in header data. length : " + stringLength); + } + // rewind offset + buffer.setOffset(buffer.getOffset() - 2); + return buffer.read2PrefixedString(); + } + + private boolean validCheck(short length) { + if (length > HeaderV2.HEADER_ENTITY_STRING_MAX_LANGTH || length == 0) { + return false; + } + + return true; + } + + @Override + public int getOffset() { + return this.buffer.getOffset(); + } + + + @Override + public int getRemaining() { + return this.buffer.remaining(); + } + + +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/header/ByteArrayHeaderWriter.java b/thrift/src/main/java/com/navercorp/pinpoint/io/header/ByteArrayHeaderWriter.java new file mode 100644 index 000000000000..f273f470a3fb --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/header/ByteArrayHeaderWriter.java @@ -0,0 +1,128 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.io.header; + +import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; +import com.navercorp.pinpoint.io.header.v2.HeaderV2; +import org.apache.thrift.TException; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.Map; + +/** + * @author minwoo.jung + */ +public class ByteArrayHeaderWriter implements HeaderWriter { + + private static final Charset UTF_8 = Charset.forName("UTF-8"); + private final Header header; + private final AutomaticBuffer buffer; + private final HeaderEntity headerEntity; + + public ByteArrayHeaderWriter(Header header) { + if (header == null) { + throw new NullPointerException("header must not be null."); + } + + this.buffer = new AutomaticBuffer(4); + this.header = header; + this.headerEntity = HeaderEntity.EMPTY_HEADER_ENTITY; + } + + public ByteArrayHeaderWriter(Header header, HeaderEntity headerEntity) { + if (header == null) { + throw new NullPointerException("header must not be null."); + } + + this.buffer = new AutomaticBuffer(4); + this.header = header; + this.headerEntity = headerEntity; + } + + @Override + public byte[] writeHeader() { + byte version = header.getVersion(); + + try{ + if (version == HeaderV1.VERSION) { + writeHeaderV1(); + } else if (version == HeaderV2.VERSION) { + writeHeaderV2(); + } else { + throw new InvalidHeaderException("can not find header version. header : " + header); + } + } catch (Exception e) { + throw new InvalidHeaderException("can not write header. header : " + header, e); + } + + return buffer.getBuffer(); + } + + private void writeHeaderV1() throws TException { + writeHeaderPrefix(); + } + + private void writeHeaderPrefix() { + buffer.putByte(header.getSignature()); + buffer.putByte(header.getVersion()); + buffer.putShort(header.getType()); + } + + + private void writeHeaderV2() throws TException, UnsupportedEncodingException { + writeHeaderPrefix(); + writeHeaderEntity(); + } + + private void writeHeaderEntity() throws TException, UnsupportedEncodingException { + Map headerEntityData = headerEntity.getEntityAll(); + final int size = headerEntityData.size(); + if (size >= HeaderV2.HEADER_ENTITY_COUNT_MAX_SIZE) { + throw new InvalidHeaderException("header size is to big. size : " + size); + } + + buffer.putShort((short)size); + + if (size == 0) { + return; + } + for (Map.Entry entry : headerEntityData.entrySet()) { + writeString(entry.getKey()); + writeString(entry.getValue()); + } + } + + private void writeString(String value) { + if (!validCheck(value)) { + throw new InvalidHeaderException("string length is invalid in header data. value : " + value); + } + + byte[] valueBytes = value.getBytes(UTF_8); + buffer.put2PrefixedBytes(valueBytes); + } + + private boolean validCheck(String value) { + int length = value.length(); + + if (length > HeaderV2.HEADER_ENTITY_STRING_MAX_LANGTH || length == 0) { + return false; + } + + return true; + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/header/Header.java b/thrift/src/main/java/com/navercorp/pinpoint/io/header/Header.java new file mode 100644 index 000000000000..9bdde5a36c34 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/header/Header.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.header; + +import java.util.Map; + +/** + * @author emeroad + */ +public interface Header { + + byte SIGNATURE = (byte) 0xef; + + // signature + version + type size + int HEADER_PREFIX_SIZE = 4; + + byte getSignature(); + + byte getVersion(); + + short getType(); +} + diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/header/HeaderEntity.java b/thrift/src/main/java/com/navercorp/pinpoint/io/header/HeaderEntity.java new file mode 100644 index 000000000000..c109fea01aef --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/header/HeaderEntity.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.io.header; + +import java.util.Collections; +import java.util.Map; + +/** + * @author minwoo.jung + */ +public class HeaderEntity { + + public static final HeaderEntity EMPTY_HEADER_ENTITY = new HeaderEntity(Collections.emptyMap()); + + private final Map entity; + + public HeaderEntity(Map headerEntityData) { + if (headerEntityData == null) { + throw new NullPointerException("headerEntityData must not be null."); + } + + this.entity = Collections.unmodifiableMap(headerEntityData); + } + + public String getEntity(String key) { + return entity.get(key); + } + + public Map getEntityAll() { + return entity; + } + + @Override + public String toString() { + return "HeaderEntity{" + + "entity=" + entity + + '}'; + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/header/HeaderReader.java b/thrift/src/main/java/com/navercorp/pinpoint/io/header/HeaderReader.java new file mode 100644 index 000000000000..80d83b06333d --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/header/HeaderReader.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.header; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface HeaderReader { + Header readHeader(); + + HeaderEntity readHeaderEntity(Header header); + + int getOffset(); + + int getRemaining(); +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/header/HeaderWriter.java b/thrift/src/main/java/com/navercorp/pinpoint/io/header/HeaderWriter.java new file mode 100644 index 000000000000..0296eb02024a --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/header/HeaderWriter.java @@ -0,0 +1,23 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.io.header; + +/** + * @author minwoo.jung + */ +public interface HeaderWriter { + byte[] writeHeader(); +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/header/InvalidHeaderException.java b/thrift/src/main/java/com/navercorp/pinpoint/io/header/InvalidHeaderException.java new file mode 100644 index 000000000000..e85d19dd8823 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/header/InvalidHeaderException.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.io.header; + +/** + * @author minwoo.jung + */ +public class InvalidHeaderException extends RuntimeException { + + public InvalidHeaderException(String message) { + super(message); + } + + public InvalidHeaderException(String message, Throwable e) { + super(message, e); + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/header/v1/HeaderV1.java b/thrift/src/main/java/com/navercorp/pinpoint/io/header/v1/HeaderV1.java new file mode 100644 index 000000000000..cc4b43572ea0 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/header/v1/HeaderV1.java @@ -0,0 +1,71 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.io.header.v1; + +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.InvalidHeaderException; + +import java.util.Collections; +import java.util.Map; + +/** + * @author minwoo.jung + */ +final public class HeaderV1 implements Header { + + public static final byte VERSION = 0x10; + +// skip constant field +// private final byte signature; +// private final byte version; + private final short type; + + public HeaderV1(byte signature, byte version, short type) { + if (signature != Header.SIGNATURE) { + throw new InvalidHeaderException("invalid signature " + signature); + } + if (version != VERSION){ + throw new InvalidHeaderException("invalid version " + version); + } + this.type = type; + } + + public HeaderV1(short type) { + this.type = type; + } + + @Override + public byte getSignature() { + return Header.SIGNATURE; + } + + public byte getVersion() { + return VERSION; + } + + public short getType() { + return type; + } + + @Override + public String toString() { + return "Header{" + + "signature=" + SIGNATURE + + ", version=" + VERSION + + ", type=" + type + + '}'; + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/header/v2/HeaderV2.java b/thrift/src/main/java/com/navercorp/pinpoint/io/header/v2/HeaderV2.java new file mode 100644 index 000000000000..b9fdd64d9622 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/header/v2/HeaderV2.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.io.header.v2; + +import com.navercorp.pinpoint.io.header.Header; + +import java.util.Map; + +/** + * The type Header. + * + * @author minwoo.jung + */ +final public class HeaderV2 implements Header { + + public static final byte VERSION = 0x20; + + public static final int HEADER_ENTITY_COUNT_MAX_SIZE = 64; + public static final int HEADER_ENTITY_STRING_MAX_LANGTH = 1024; + + private final short type; + + public HeaderV2(byte signature, byte version, short type) { + if (signature != Header.SIGNATURE) { + throw new IllegalArgumentException("invalid signature " + signature); + } + if (version != VERSION){ + throw new IllegalArgumentException("invalid version " + version); + } + this.type = type; + } + + @Override + public byte getSignature() { + return SIGNATURE; + } + + @Override + public byte getVersion() { + return VERSION; + } + + @Override + public short getType() { + return type; + } + + @Override + public String toString() { + return "HeaderV2{" + + "signature=" + SIGNATURE + + ", version=" + VERSION + + ", type=" + type + + '}'; + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/AttributeMap.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/AttributeMap.java new file mode 100644 index 000000000000..ad02f02196aa --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/AttributeMap.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface AttributeMap { + + void setAttribute(Object key, Object value); + + Object getAttribute(Object key); +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/DefaultAttributeMap.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/DefaultAttributeMap.java new file mode 100644 index 000000000000..66d86bb21712 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/DefaultAttributeMap.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.request; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Woonduk Kang(emeroad) + */ +public abstract class DefaultAttributeMap implements AttributeMap { + + // lazy initialize + private Map attribute; + + protected Map getAttributeMap() { + if (attribute == null) { + attribute = new HashMap(); + } + return attribute; + } + + @Override + public void setAttribute(Object key, Object value) { + Map map = getAttributeMap(); + map.put(key, value); + } + + + @Override + public Object getAttribute(Object key) { + Map map = getAttributeMap(); + return map.get(key); + } + +} \ No newline at end of file diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/DefaultMessage.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/DefaultMessage.java new file mode 100644 index 000000000000..81e5a58c392b --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/DefaultMessage.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.request; + +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.HeaderEntity; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultMessage implements Message { + private final Header header; + private final HeaderEntity headerEntity; + private final T data; + + public DefaultMessage(Header header, HeaderEntity headerEntity, T data) { + if (header == null) { + throw new NullPointerException("header must not be null"); + } + if (headerEntity == null) { + throw new NullPointerException("headerEntity must not be null"); + } + + this.header = header; + this.headerEntity = headerEntity; + this.data = data; + } + + @Override + public Header getHeader() { + return header; + } + + @Override + public HeaderEntity getHeaderEntity() { + return headerEntity; + } + + @Override + public T getData() { + return data; + } + + @Override + public String toString() { + return "DefaultMessage{" + + "header=" + header + + ", headerEntity=" + headerEntity + + ", data=" + data + + '}'; + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/DefaultServerRequest.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/DefaultServerRequest.java new file mode 100644 index 000000000000..4c7e3f5530e2 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/DefaultServerRequest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.request; + +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.HeaderEntity; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultServerRequest extends DefaultAttributeMap implements ServerRequest { + + private final Message message; + private final String remoteAddress; + private final int remotePort; + + public DefaultServerRequest(Message message, String remoteAddress, int remotePort) { + if (message == null) { + throw new NullPointerException("message must not be null"); + } + if (remoteAddress == null) { + throw new NullPointerException("remoteAddress must not be null"); + } + this.message = message; + this.remoteAddress = remoteAddress; + this.remotePort = remotePort; + } + + + @Override + public Header getHeader() { + return message.getHeader(); + } + + @Override + public HeaderEntity getHeaderEntity() { + return message.getHeaderEntity(); + } + + @Override + public T getData() { + return message.getData(); + } + + @Override + public String getRemoteAddress() { + return remoteAddress; + } + + @Override + public int getRemotePort() { + return remotePort; + } + + @Override + public String toString() { + return "DefaultServerRequest{" + "message=" + message + ", remoteAddress='" + remoteAddress + '\'' + ", remotePort=" + remotePort + '}'; + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/EmptyMessage.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/EmptyMessage.java new file mode 100644 index 000000000000..f28d7cb5d71d --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/EmptyMessage.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.request; + +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.HeaderEntity; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; + +/** + * @author Woonduk Kang(emeroad) + */ +public class EmptyMessage implements Message { + public static final Message INSTANCE = new EmptyMessage(); + + private static final Header EMPTY_HEADER = new HeaderV1((short) -1); + + @Override + public Header getHeader() { + return EMPTY_HEADER; + } + + @Override + public HeaderEntity getHeaderEntity() { + return HeaderEntity.EMPTY_HEADER_ENTITY; + } + + @Override + public T getData() { + return null; + } + + public static Message emptyMessage() { + return INSTANCE; + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/FlinkRequest.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/FlinkRequest.java new file mode 100644 index 000000000000..aef26ea7581e --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/FlinkRequest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.io.request; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.io.header.HeaderEntity; +import org.apache.thrift.TBase; + +/** + * @author minwoo.jung + */ +public class FlinkRequest { + + private final HeaderEntity headerEntity; + private final TBase data; + + public FlinkRequest(HeaderEntity headerEntity, TBase data) { + this.headerEntity = Assert.requireNonNull(headerEntity, "headerEntity must not be null"); + this.data = Assert.requireNonNull(data, "data must not be null"); + } + + public HeaderEntity getHeaderEntity() { + return headerEntity; + } + + public TBase getData() { + return data; + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/Message.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/Message.java new file mode 100644 index 000000000000..bcd6f8425bc1 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/Message.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.request; + +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.HeaderEntity; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface Message { + Header getHeader(); + + HeaderEntity getHeaderEntity(); + + T getData(); +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/ServerRequest.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/ServerRequest.java new file mode 100644 index 000000000000..c933640a85aa --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/ServerRequest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.io.request; + +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.HeaderEntity; + +/** + * @author minwoo.jung + */ +public interface ServerRequest extends AttributeMap { + + Header getHeader(); + + HeaderEntity getHeaderEntity(); + + T getData(); + + String getRemoteAddress(); + + int getRemotePort(); +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/ServerResponse.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/ServerResponse.java new file mode 100644 index 000000000000..1b78bca36f2d --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/ServerResponse.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.request; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface ServerResponse { + void write(T message); +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/request/UnSupportedServerRequestTypeException.java b/thrift/src/main/java/com/navercorp/pinpoint/io/request/UnSupportedServerRequestTypeException.java new file mode 100644 index 000000000000..34ad28553bc4 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/request/UnSupportedServerRequestTypeException.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.io.request; + +/** + * @author minwoo.jung + */ +public class UnSupportedServerRequestTypeException extends RuntimeException { + + public UnSupportedServerRequestTypeException(String message) { + super(message); + } + + public UnSupportedServerRequestTypeException(String message, Throwable e) { + super(message, e); + } +} diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/AnnotationTranscoder.java b/thrift/src/main/java/com/navercorp/pinpoint/io/util/AnnotationTranscoder.java similarity index 77% rename from commons/src/main/java/com/navercorp/pinpoint/common/util/AnnotationTranscoder.java rename to thrift/src/main/java/com/navercorp/pinpoint/io/util/AnnotationTranscoder.java index 8e1569f1c86c..a48af4ca9182 100644 --- a/commons/src/main/java/com/navercorp/pinpoint/common/util/AnnotationTranscoder.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/util/AnnotationTranscoder.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,18 +14,26 @@ * limitations under the License. */ -package com.navercorp.pinpoint.common.util; +package com.navercorp.pinpoint.io.util; import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; import com.navercorp.pinpoint.common.buffer.Buffer; import com.navercorp.pinpoint.common.buffer.FixedBuffer; +import com.navercorp.pinpoint.common.util.BitFieldUtils; +import com.navercorp.pinpoint.common.util.BytesUtils; +import com.navercorp.pinpoint.common.util.IntBooleanIntBooleanValue; +import com.navercorp.pinpoint.common.util.IntStringStringValue; +import com.navercorp.pinpoint.common.util.IntStringValue; +import com.navercorp.pinpoint.common.util.LongIntIntByteByteStringValue; +import com.navercorp.pinpoint.common.util.StringStringValue; import com.navercorp.pinpoint.thrift.dto.TAnnotation; import com.navercorp.pinpoint.thrift.dto.TAnnotationValue; import com.navercorp.pinpoint.thrift.dto.TIntBooleanIntBooleanValue; import com.navercorp.pinpoint.thrift.dto.TIntStringStringValue; import com.navercorp.pinpoint.thrift.dto.TIntStringValue; import com.navercorp.pinpoint.thrift.dto.TLongIntIntByteByteStringValue; +import com.navercorp.pinpoint.thrift.dto.TStringStringValue; /** * @author emeroad @@ -53,6 +61,7 @@ public class AnnotationTranscoder { static final byte CODE_INT_STRING_STRING = 21; static final byte CODE_LONG_INT_INT_BYTE_BYTE_STRING = 22; static final byte CODE_INT_BOOLEAN_INT_BOOLEAN = 23; + static final byte CODE_STRING_STRING = 24; private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; @@ -99,6 +108,8 @@ public Object decode(final byte dataType, final byte[] data) { return decodeIntStringValue(data); case CODE_INT_STRING_STRING: return decodeIntStringStringValue(data); + case CODE_STRING_STRING: + return decodeStringStringValue(data); case CODE_LONG_INT_INT_BYTE_BYTE_STRING: return decodeLongIntIntByteByteStringValue(data); case CODE_INT_BOOLEAN_INT_BOOLEAN: @@ -137,6 +148,8 @@ public byte getTypeCode(Object o) { return CODE_INT_STRING; } else if (o instanceof TIntStringStringValue) { return CODE_INT_STRING_STRING; + } else if (o instanceof TStringStringValue) { + return CODE_STRING_STRING; } else if (o instanceof TLongIntIntByteByteStringValue) { return CODE_LONG_INT_INT_BYTE_BYTE_STRING; } else if (o instanceof TIntBooleanIntBooleanValue) { @@ -190,6 +203,8 @@ public byte[] encode(Object o, int typeCode) { return encodeIntStringValue(o); case CODE_INT_STRING_STRING: return encodeIntStringStringValue(o); + case CODE_STRING_STRING: + return encodeStringStringValue(o); case CODE_LONG_INT_INT_BYTE_BYTE_STRING: return encodeLongIntIntByteByteStringValue(o); case CODE_INT_BOOLEAN_INT_BOOLEAN: @@ -337,7 +352,71 @@ private byte[] encodeIntBooleanIntBooleanValue(Object o) { buffer.putBoolean(value.isBoolValue2()); return buffer.getBuffer(); } +// private Object decodeIntStringStringValue(byte[] data) { +// final Buffer buffer = new FixedBuffer(data); +// final int intValue = buffer.readSVInt(); +// final String stringValue1 = BytesUtils.toString(buffer.readPrefixedBytes()); +// final String stringValue2 = BytesUtils.toString(buffer.readPrefixedBytes()); +// return new IntStringStringValue(intValue, stringValue1, stringValue2); +// } +// +// private byte[] encodeIntStringStringValue(Object o) { +// final TIntStringStringValue tIntStringStringValue = (TIntStringStringValue) o; +// final int intValue = tIntStringStringValue.getIntValue(); +// final byte[] stringValue1 = BytesUtils.toBytes(tIntStringStringValue.getStringValue1()); +// final byte[] stringValue2 = BytesUtils.toBytes(tIntStringStringValue.getStringValue2()); +// // TODO increase by a more precise value +// final int bufferSize = getBufferSize(stringValue1, stringValue2, 4 + 8); +// final Buffer buffer = new AutomaticBuffer(bufferSize); +// buffer.putSVInt(intValue); +// buffer.putPrefixedBytes(stringValue1); +// buffer.putPrefixedBytes(stringValue2); +// return buffer.getBuffer(); +// } +// +// private int getBufferSize(byte[] stringValue1, byte[] stringValue2, int reserve) { +// int length = 0; +// if (stringValue1 != null) { +// length += stringValue1.length; +// } +// if (stringValue2 != null) { +// length += stringValue2.length; +// +// } +// return length + reserve; +// } +// + + private Object decodeStringStringValue(byte[] data) { + final Buffer buffer = new FixedBuffer(data); + final String stringValue1 = BytesUtils.toString(buffer.readPrefixedBytes()); + final String stringValue2 = BytesUtils.toString(buffer.readPrefixedBytes()); + return new StringStringValue(stringValue1, stringValue2); + } + + private byte[] encodeStringStringValue(Object o) { + final TStringStringValue tStringStringValue = (TStringStringValue) o; + final byte[] stringValue1 = BytesUtils.toBytes(tStringStringValue.getStringValue1()); + final byte[] stringValue2 = BytesUtils.toBytes(tStringStringValue.getStringValue2()); + // TODO increase by a more precise value + final int bufferSize = getBufferSize(stringValue1, stringValue2); + final Buffer buffer = new AutomaticBuffer(bufferSize); + buffer.putPrefixedBytes(stringValue1); + buffer.putPrefixedBytes(stringValue2); + return buffer.getBuffer(); + } + + private int getBufferSize(byte[] stringValue1, byte[] stringValue2) { + int length = 0; + if (stringValue1 != null) { + length += stringValue1.length; + } + if (stringValue2 != null) { + length += stringValue2.length; + } + return length; + } /** * Decode the string with the current character set. */ diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/util/BodyFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/io/util/BodyFactory.java new file mode 100644 index 000000000000..b22526308dc3 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/util/BodyFactory.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.util; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface BodyFactory { + + T getObject(); + +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/util/DefaultTypeLocator.java b/thrift/src/main/java/com/navercorp/pinpoint/io/util/DefaultTypeLocator.java new file mode 100644 index 000000000000..4ae449c876df --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/util/DefaultTypeLocator.java @@ -0,0 +1,105 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.util; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.apache.IntHashMap; +import com.navercorp.pinpoint.io.header.Header; + +import java.util.List; +import java.util.Map; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultTypeLocator implements TypeLocator { + + + private final IntHashMap> bodyFactoryMap; + private final Map, Header> bodyToHeaderMap; + private final DefaultTypeLocator.Entry, Header>[] bodyClassToHeaderArray; + private final IntHashMap
headerMap; + + DefaultTypeLocator(IntHashMap> bodyFactoryMap, Map, Header> bodyToHeaderMap, + IntHashMap
headerMap , List, Header>> bodyClassToHeaderList) { + this.bodyFactoryMap = Assert.requireNonNull(bodyFactoryMap, "bodyFactoryMap must not be null"); + this.bodyToHeaderMap = Assert.requireNonNull(bodyToHeaderMap, "bodyToHeaderMap must not be null"); + + this.headerMap = Assert.requireNonNull(headerMap , "headerMap must not be null"); + + Assert.requireNonNull(bodyClassToHeaderList, "bodyClassToHeaderList must not be null"); + this.bodyClassToHeaderArray = bodyClassToHeaderList.toArray(new Entry[0]); + } + + @Override + public T bodyLookup(short type) { + final BodyFactory bodyFactory = this.bodyFactoryMap.get(type); + if (bodyFactory != null) { + return bodyFactory.getObject(); + } + return null; + } + + @Override + public Header headerLookup(T body) { + if (body == null) { + throw new IllegalArgumentException("body must not be null"); + } + + for (Entry, Header> entry : bodyClassToHeaderArray) { + final Class bodyClass = entry.key; + if (bodyClass.isInstance(body)) { + return entry.value; + } + } + + return null; + } + + @Override + public Header headerLookup(short type) { + return this.headerMap.get(type); + } + + @Override + public boolean isSupport(short type) { + final BodyFactory bodyFactory = this.bodyFactoryMap.get(type); + if (bodyFactory != null) { + return true; + } + return false; + } + + @Override + public boolean isSupport(Class clazz) { + final Header header = bodyToHeaderMap.get(clazz); + if (header != null) { + return true; + } + return false; + } + + static class Entry { + private final K key; + private final V value; + + public Entry(K key, V value) { + this.key = key; + this.value = value; + } + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/util/HeaderFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/io/util/HeaderFactory.java new file mode 100644 index 000000000000..15c7dd4f4a17 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/util/HeaderFactory.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.util; + +import com.navercorp.pinpoint.io.header.Header; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface HeaderFactory { + Header newHeader(short type); +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/util/HeaderFactoryV1.java b/thrift/src/main/java/com/navercorp/pinpoint/io/util/HeaderFactoryV1.java new file mode 100644 index 000000000000..82c431c71d3a --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/util/HeaderFactoryV1.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.util; + +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; + +/** + * @author Woonduk Kang(emeroad) + */ +public class HeaderFactoryV1 implements HeaderFactory { + @Override + public Header newHeader(short type) { + Header header = new HeaderV1(type); + return header; + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/util/HeaderFactoryV2.java b/thrift/src/main/java/com/navercorp/pinpoint/io/util/HeaderFactoryV2.java new file mode 100644 index 000000000000..5a344fb11a58 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/util/HeaderFactoryV2.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.util; + +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.v2.HeaderV2; + +public class HeaderFactoryV2 implements HeaderFactory { + + @Override + public Header newHeader(short type) { + Header header = new HeaderV2(Header.SIGNATURE, HeaderV2.VERSION, type); + return header; + } + +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/util/TypeLocator.java b/thrift/src/main/java/com/navercorp/pinpoint/io/util/TypeLocator.java new file mode 100644 index 000000000000..08843b1e038b --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/util/TypeLocator.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.util; + +import com.navercorp.pinpoint.io.header.Header; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface TypeLocator { + T bodyLookup(short type); + + Header headerLookup(T body); + + Header headerLookup(short type); + + boolean isSupport(short type); + + boolean isSupport(Class clazz); + +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/io/util/TypeLocatorBuilder.java b/thrift/src/main/java/com/navercorp/pinpoint/io/util/TypeLocatorBuilder.java new file mode 100644 index 000000000000..c901f54ba0ad --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/io/util/TypeLocatorBuilder.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.util; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.common.util.apache.IntHashMap; +import com.navercorp.pinpoint.common.util.apache.IntHashMapUtils; +import com.navercorp.pinpoint.io.header.Header; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Woonduk Kang(emeroad) + */ +public class TypeLocatorBuilder { + + private final Map> bodyFactoryMap = new HashMap>(); + private final Map, Header> bodyClassToHeaderMap = new LinkedHashMap, Header>(); + + // private final IntHashMap> classMap = new IntHashMap>(); + private final Map headerMap = new HashMap(); + private final HeaderFactory headerFactory; + + public TypeLocatorBuilder() { + this(new HeaderFactoryV1()); + } + + public TypeLocatorBuilder(HeaderFactory headerFactory) { + this.headerFactory = Assert.requireNonNull(headerFactory, "headerFactory must not be null"); + } + + public void addBodyFactory(short type, BodyFactory bodyFactory) { + if (bodyFactory == null) { + throw new NullPointerException("bodyFactory must not be null"); + } + + final BodyFactory old = bodyFactoryMap.put((int) type, bodyFactory); + if (old != null) { + throw new IllegalStateException("duplicated type:" + type); + } + final Header header = this.headerFactory.newHeader(type); + final Header oldTypeHeader = headerMap.put((int) type, header); + if (oldTypeHeader != null) { + throw new IllegalStateException("duplicated type:" + type); + } + + final T object = bodyFactory.getObject(); + if (object != null) { + final Class bodyClass = object.getClass(); + // classMap.put(type, bodyClass); + final Header oldBodyClass = bodyClassToHeaderMap.put(bodyClass, header); + if (oldBodyClass != null) { + throw new IllegalStateException("duplicated type:" + type); + } + } + } + + public TypeLocator build() { + final IntHashMap> copyBodyFactoryMap = IntHashMapUtils.copy(bodyFactoryMap); + final Map, Header> copyBodyClassToHeaderMap = new IdentityHashMap, Header>(this.bodyClassToHeaderMap); + final IntHashMap
copyHeaderMap = IntHashMapUtils.copy(headerMap); + final List, Header>> bodyClassToHeaderList = toList(this.bodyClassToHeaderMap); + + TypeLocator typeLocator = new DefaultTypeLocator(copyBodyFactoryMap, copyBodyClassToHeaderMap, copyHeaderMap, bodyClassToHeaderList); + return typeLocator; + } + + private List, Header>> toList(Map, Header> bodyClassToHeaderMap) { + List, Header>> bodyClassToHeaderList = new ArrayList, Header>>(bodyClassToHeaderMap.size()); + for (Map.Entry, Header> mapEntry : bodyClassToHeaderMap.entrySet()) { + DefaultTypeLocator.Entry, Header> entry = new DefaultTypeLocator.Entry, Header>(mapEntry.getKey(), mapEntry.getValue()); + bodyClassToHeaderList.add(entry); + } + return bodyClassToHeaderList; + } + + +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentInfo.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentInfo.java index 7e5af07ced30..0da2b489721d 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentInfo.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentInfo.java @@ -7,7 +7,7 @@ package com.navercorp.pinpoint.thrift.dto; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-03-16") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2018-06-19") public class TAgentInfo implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TAgentInfo"); @@ -25,6 +25,7 @@ public class TAgentInfo implements org.apache.thrift.TBase byName = new java.util.HashMap(); @@ -102,6 +105,8 @@ public static _Fields findByThriftId(int fieldId) { return SERVER_META_DATA; case 30: // JVM_INFO return JVM_INFO; + case 40: // CONTAINER + return CONTAINER; default: return null; } @@ -147,8 +152,9 @@ public java.lang.String getFieldName() { private static final int __STARTTIMESTAMP_ISSET_ID = 2; private static final int __ENDTIMESTAMP_ISSET_ID = 3; private static final int __ENDSTATUS_ISSET_ID = 4; + private static final int __CONTAINER_ISSET_ID = 5; private byte __isset_bitfield = 0; - private static final _Fields optionals[] = {_Fields.END_TIMESTAMP,_Fields.END_STATUS,_Fields.SERVER_META_DATA,_Fields.JVM_INFO}; + private static final _Fields optionals[] = {_Fields.END_TIMESTAMP,_Fields.END_STATUS,_Fields.SERVER_META_DATA,_Fields.JVM_INFO,_Fields.CONTAINER}; public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); @@ -180,11 +186,15 @@ public java.lang.String getFieldName() { new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TServerMetaData.class))); tmpMap.put(_Fields.JVM_INFO, new org.apache.thrift.meta_data.FieldMetaData("jvmInfo", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TJvmInfo.class))); + tmpMap.put(_Fields.CONTAINER, new org.apache.thrift.meta_data.FieldMetaData("container", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BOOL))); metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TAgentInfo.class, metaDataMap); } public TAgentInfo() { + this.container = false; + } public TAgentInfo( @@ -252,6 +262,7 @@ public TAgentInfo(TAgentInfo other) { if (other.isSetJvmInfo()) { this.jvmInfo = new TJvmInfo(other.jvmInfo); } + this.container = other.container; } public TAgentInfo deepCopy() { @@ -279,6 +290,8 @@ public void clear() { this.endStatus = 0; this.serverMetaData = null; this.jvmInfo = null; + this.container = false; + } public java.lang.String getHostname() { @@ -598,6 +611,28 @@ public void setJvmInfoIsSet(boolean value) { } } + public boolean isContainer() { + return this.container; + } + + public void setContainer(boolean container) { + this.container = container; + setContainerIsSet(true); + } + + public void unsetContainer() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __CONTAINER_ISSET_ID); + } + + /** Returns true if field container is set (has been assigned a value) and false otherwise */ + public boolean isSetContainer() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __CONTAINER_ISSET_ID); + } + + public void setContainerIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __CONTAINER_ISSET_ID, value); + } + public void setFieldValue(_Fields field, java.lang.Object value) { switch (field) { case HOSTNAME: @@ -712,6 +747,14 @@ public void setFieldValue(_Fields field, java.lang.Object value) { } break; + case CONTAINER: + if (value == null) { + unsetContainer(); + } else { + setContainer((java.lang.Boolean)value); + } + break; + } } @@ -759,6 +802,9 @@ public java.lang.Object getFieldValue(_Fields field) { case JVM_INFO: return getJvmInfo(); + case CONTAINER: + return isContainer(); + } throw new java.lang.IllegalStateException(); } @@ -798,6 +844,8 @@ public boolean isSet(_Fields field) { return isSetServerMetaData(); case JVM_INFO: return isSetJvmInfo(); + case CONTAINER: + return isSetContainer(); } throw new java.lang.IllegalStateException(); } @@ -943,6 +991,15 @@ public boolean equals(TAgentInfo that) { return false; } + boolean this_present_container = true && this.isSetContainer(); + boolean that_present_container = true && that.isSetContainer(); + if (this_present_container || that_present_container) { + if (!(this_present_container && that_present_container)) + return false; + if (this.container != that.container) + return false; + } + return true; } @@ -1000,6 +1057,10 @@ public int hashCode() { if (isSetJvmInfo()) hashCode = hashCode * 8191 + jvmInfo.hashCode(); + hashCode = hashCode * 8191 + ((isSetContainer()) ? 131071 : 524287); + if (isSetContainer()) + hashCode = hashCode * 8191 + ((container) ? 131071 : 524287); + return hashCode; } @@ -1151,6 +1212,16 @@ public int compareTo(TAgentInfo other) { return lastComparison; } } + lastComparison = java.lang.Boolean.valueOf(isSetContainer()).compareTo(other.isSetContainer()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetContainer()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.container, other.container); + if (lastComparison != 0) { + return lastComparison; + } + } return 0; } @@ -1270,6 +1341,12 @@ public java.lang.String toString() { } first = false; } + if (isSetContainer()) { + if (!first) sb.append(", "); + sb.append("container:"); + sb.append(this.container); + first = false; + } sb.append(")"); return sb.toString(); } @@ -1435,6 +1512,14 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, TAgentInfo struct) org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; + case 40: // CONTAINER + if (schemeField.type == org.apache.thrift.protocol.TType.BOOL) { + struct.container = iprot.readBool(); + struct.setContainerIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } @@ -1516,6 +1601,11 @@ public void write(org.apache.thrift.protocol.TProtocol oprot, TAgentInfo struct) oprot.writeFieldEnd(); } } + if (struct.isSetContainer()) { + oprot.writeFieldBegin(CONTAINER_FIELD_DESC); + oprot.writeBool(struct.container); + oprot.writeFieldEnd(); + } oprot.writeFieldStop(); oprot.writeStructEnd(); } @@ -1576,7 +1666,10 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TAgentInfo struct) if (struct.isSetJvmInfo()) { optionals.set(13); } - oprot.writeBitSet(optionals, 14); + if (struct.isSetContainer()) { + optionals.set(14); + } + oprot.writeBitSet(optionals, 15); if (struct.isSetHostname()) { oprot.writeString(struct.hostname); } @@ -1619,12 +1712,15 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TAgentInfo struct) if (struct.isSetJvmInfo()) { struct.jvmInfo.write(oprot); } + if (struct.isSetContainer()) { + oprot.writeBool(struct.container); + } } @Override public void read(org.apache.thrift.protocol.TProtocol prot, TAgentInfo struct) throws org.apache.thrift.TException { org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; - java.util.BitSet incoming = iprot.readBitSet(14); + java.util.BitSet incoming = iprot.readBitSet(15); if (incoming.get(0)) { struct.hostname = iprot.readString(); struct.setHostnameIsSet(true); @@ -1683,6 +1779,10 @@ public void read(org.apache.thrift.protocol.TProtocol prot, TAgentInfo struct) t struct.jvmInfo.read(iprot); struct.setJvmInfoIsSet(true); } + if (incoming.get(14)) { + struct.container = iprot.readBool(); + struct.setContainerIsSet(true); + } } } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentStat.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentStat.java index 80204c1570cd..891d8c3e650e 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentStat.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentStat.java @@ -1,5 +1,5 @@ /** - * Autogenerated by Thrift Compiler (0.10.0) + * Autogenerated by Thrift Compiler (0.11.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -7,7 +7,7 @@ package com.navercorp.pinpoint.thrift.dto; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-06-16") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-03-26") public class TAgentStat implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TAgentStat"); @@ -22,6 +22,8 @@ public class TAgentStat implements org.apache.thrift.TBase byName = new java.util.HashMap(); @@ -90,6 +96,10 @@ public static _Fields findByThriftId(int fieldId) { return RESPONSE_TIME; case 70: // DEADLOCK return DEADLOCK; + case 80: // FILE_DESCRIPTOR + return FILE_DESCRIPTOR; + case 90: // DIRECT_BUFFER + return DIRECT_BUFFER; case 200: // METADATA return METADATA; default: @@ -136,7 +146,7 @@ public java.lang.String getFieldName() { private static final int __TIMESTAMP_ISSET_ID = 1; private static final int __COLLECTINTERVAL_ISSET_ID = 2; private byte __isset_bitfield = 0; - private static final _Fields optionals[] = {_Fields.AGENT_ID,_Fields.START_TIMESTAMP,_Fields.TIMESTAMP,_Fields.COLLECT_INTERVAL,_Fields.GC,_Fields.CPU_LOAD,_Fields.TRANSACTION,_Fields.ACTIVE_TRACE,_Fields.DATA_SOURCE_LIST,_Fields.RESPONSE_TIME,_Fields.DEADLOCK,_Fields.METADATA}; + private static final _Fields optionals[] = {_Fields.AGENT_ID,_Fields.START_TIMESTAMP,_Fields.TIMESTAMP,_Fields.COLLECT_INTERVAL,_Fields.GC,_Fields.CPU_LOAD,_Fields.TRANSACTION,_Fields.ACTIVE_TRACE,_Fields.DATA_SOURCE_LIST,_Fields.RESPONSE_TIME,_Fields.DEADLOCK,_Fields.FILE_DESCRIPTOR,_Fields.DIRECT_BUFFER,_Fields.METADATA}; public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); @@ -162,7 +172,11 @@ public java.lang.String getFieldName() { new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TResponseTime.class))); tmpMap.put(_Fields.DEADLOCK, new org.apache.thrift.meta_data.FieldMetaData("deadlock", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TDeadlock.class))); - tmpMap.put(_Fields.METADATA, new org.apache.thrift.meta_data.FieldMetaData("metadata", org.apache.thrift.TFieldRequirementType.OPTIONAL, + tmpMap.put(_Fields.FILE_DESCRIPTOR, new org.apache.thrift.meta_data.FieldMetaData("fileDescriptor", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT , "TFileDescriptor"))); + tmpMap.put(_Fields.DIRECT_BUFFER, new org.apache.thrift.meta_data.FieldMetaData("directBuffer", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TDirectBuffer.class))); + tmpMap.put(_Fields.METADATA, new org.apache.thrift.meta_data.FieldMetaData("metadata", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TAgentStat.class, metaDataMap); @@ -203,6 +217,12 @@ public TAgentStat(TAgentStat other) { if (other.isSetDeadlock()) { this.deadlock = new TDeadlock(other.deadlock); } + if (other.isSetFileDescriptor()) { + this.fileDescriptor = new TFileDescriptor(other.fileDescriptor); + } + if (other.isSetDirectBuffer()) { + this.directBuffer = new TDirectBuffer(other.directBuffer); + } if (other.isSetMetadata()) { this.metadata = other.metadata; } @@ -228,6 +248,8 @@ public void clear() { this.dataSourceList = null; this.responseTime = null; this.deadlock = null; + this.fileDescriptor = null; + this.directBuffer = null; this.metadata = null; } @@ -481,6 +503,52 @@ public void setDeadlockIsSet(boolean value) { } } + public TFileDescriptor getFileDescriptor() { + return this.fileDescriptor; + } + + public void setFileDescriptor(TFileDescriptor fileDescriptor) { + this.fileDescriptor = fileDescriptor; + } + + public void unsetFileDescriptor() { + this.fileDescriptor = null; + } + + /** Returns true if field fileDescriptor is set (has been assigned a value) and false otherwise */ + public boolean isSetFileDescriptor() { + return this.fileDescriptor != null; + } + + public void setFileDescriptorIsSet(boolean value) { + if (!value) { + this.fileDescriptor = null; + } + } + + public TDirectBuffer getDirectBuffer() { + return this.directBuffer; + } + + public void setDirectBuffer(TDirectBuffer directBuffer) { + this.directBuffer = directBuffer; + } + + public void unsetDirectBuffer() { + this.directBuffer = null; + } + + /** Returns true if field directBuffer is set (has been assigned a value) and false otherwise */ + public boolean isSetDirectBuffer() { + return this.directBuffer != null; + } + + public void setDirectBufferIsSet(boolean value) { + if (!value) { + this.directBuffer = null; + } + } + public java.lang.String getMetadata() { return this.metadata; } @@ -594,6 +662,22 @@ public void setFieldValue(_Fields field, java.lang.Object value) { } break; + case FILE_DESCRIPTOR: + if (value == null) { + unsetFileDescriptor(); + } else { + setFileDescriptor((TFileDescriptor)value); + } + break; + + case DIRECT_BUFFER: + if (value == null) { + unsetDirectBuffer(); + } else { + setDirectBuffer((TDirectBuffer)value); + } + break; + case METADATA: if (value == null) { unsetMetadata(); @@ -640,6 +724,12 @@ public java.lang.Object getFieldValue(_Fields field) { case DEADLOCK: return getDeadlock(); + case FILE_DESCRIPTOR: + return getFileDescriptor(); + + case DIRECT_BUFFER: + return getDirectBuffer(); + case METADATA: return getMetadata(); @@ -676,6 +766,10 @@ public boolean isSet(_Fields field) { return isSetResponseTime(); case DEADLOCK: return isSetDeadlock(); + case FILE_DESCRIPTOR: + return isSetFileDescriptor(); + case DIRECT_BUFFER: + return isSetDirectBuffer(); case METADATA: return isSetMetadata(); } @@ -796,6 +890,24 @@ public boolean equals(TAgentStat that) { return false; } + boolean this_present_fileDescriptor = true && this.isSetFileDescriptor(); + boolean that_present_fileDescriptor = true && that.isSetFileDescriptor(); + if (this_present_fileDescriptor || that_present_fileDescriptor) { + if (!(this_present_fileDescriptor && that_present_fileDescriptor)) + return false; + if (!this.fileDescriptor.equals(that.fileDescriptor)) + return false; + } + + boolean this_present_directBuffer = true && this.isSetDirectBuffer(); + boolean that_present_directBuffer = true && that.isSetDirectBuffer(); + if (this_present_directBuffer || that_present_directBuffer) { + if (!(this_present_directBuffer && that_present_directBuffer)) + return false; + if (!this.directBuffer.equals(that.directBuffer)) + return false; + } + boolean this_present_metadata = true && this.isSetMetadata(); boolean that_present_metadata = true && that.isSetMetadata(); if (this_present_metadata || that_present_metadata) { @@ -856,6 +968,14 @@ public int hashCode() { if (isSetDeadlock()) hashCode = hashCode * 8191 + deadlock.hashCode(); + hashCode = hashCode * 8191 + ((isSetFileDescriptor()) ? 131071 : 524287); + if (isSetFileDescriptor()) + hashCode = hashCode * 8191 + fileDescriptor.hashCode(); + + hashCode = hashCode * 8191 + ((isSetDirectBuffer()) ? 131071 : 524287); + if (isSetDirectBuffer()) + hashCode = hashCode * 8191 + directBuffer.hashCode(); + hashCode = hashCode * 8191 + ((isSetMetadata()) ? 131071 : 524287); if (isSetMetadata()) hashCode = hashCode * 8191 + metadata.hashCode(); @@ -981,6 +1101,26 @@ public int compareTo(TAgentStat other) { return lastComparison; } } + lastComparison = java.lang.Boolean.valueOf(isSetFileDescriptor()).compareTo(other.isSetFileDescriptor()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetFileDescriptor()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.fileDescriptor, other.fileDescriptor); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetDirectBuffer()).compareTo(other.isSetDirectBuffer()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetDirectBuffer()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.directBuffer, other.directBuffer); + if (lastComparison != 0) { + return lastComparison; + } + } lastComparison = java.lang.Boolean.valueOf(isSetMetadata()).compareTo(other.isSetMetadata()); if (lastComparison != 0) { return lastComparison; @@ -1108,6 +1248,26 @@ public java.lang.String toString() { } first = false; } + if (isSetFileDescriptor()) { + if (!first) sb.append(", "); + sb.append("fileDescriptor:"); + if (this.fileDescriptor == null) { + sb.append("null"); + } else { + sb.append(this.fileDescriptor); + } + first = false; + } + if (isSetDirectBuffer()) { + if (!first) sb.append(", "); + sb.append("directBuffer:"); + if (this.directBuffer == null) { + sb.append("null"); + } else { + sb.append(this.directBuffer); + } + first = false; + } if (isSetMetadata()) { if (!first) sb.append(", "); sb.append("metadata:"); @@ -1143,6 +1303,9 @@ public void validate() throws org.apache.thrift.TException { if (deadlock != null) { deadlock.validate(); } + if (directBuffer != null) { + directBuffer.validate(); + } } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { @@ -1276,6 +1439,24 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, TAgentStat struct) org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; + case 80: // FILE_DESCRIPTOR + if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { + struct.fileDescriptor = new TFileDescriptor(); + struct.fileDescriptor.read(iprot); + struct.setFileDescriptorIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 90: // DIRECT_BUFFER + if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { + struct.directBuffer = new TDirectBuffer(); + struct.directBuffer.read(iprot); + struct.setDirectBufferIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; case 200: // METADATA if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { struct.metadata = iprot.readString(); @@ -1368,6 +1549,20 @@ public void write(org.apache.thrift.protocol.TProtocol oprot, TAgentStat struct) oprot.writeFieldEnd(); } } + if (struct.fileDescriptor != null) { + if (struct.isSetFileDescriptor()) { + oprot.writeFieldBegin(FILE_DESCRIPTOR_FIELD_DESC); + struct.fileDescriptor.write(oprot); + oprot.writeFieldEnd(); + } + } + if (struct.directBuffer != null) { + if (struct.isSetDirectBuffer()) { + oprot.writeFieldBegin(DIRECT_BUFFER_FIELD_DESC); + struct.directBuffer.write(oprot); + oprot.writeFieldEnd(); + } + } if (struct.metadata != null) { if (struct.isSetMetadata()) { oprot.writeFieldBegin(METADATA_FIELD_DESC); @@ -1426,10 +1621,16 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TAgentStat struct) if (struct.isSetDeadlock()) { optionals.set(10); } - if (struct.isSetMetadata()) { + if (struct.isSetFileDescriptor()) { optionals.set(11); } - oprot.writeBitSet(optionals, 12); + if (struct.isSetDirectBuffer()) { + optionals.set(12); + } + if (struct.isSetMetadata()) { + optionals.set(13); + } + oprot.writeBitSet(optionals, 14); if (struct.isSetAgentId()) { oprot.writeString(struct.agentId); } @@ -1463,6 +1664,12 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TAgentStat struct) if (struct.isSetDeadlock()) { struct.deadlock.write(oprot); } + if (struct.isSetFileDescriptor()) { + struct.fileDescriptor.write(oprot); + } + if (struct.isSetDirectBuffer()) { + struct.directBuffer.write(oprot); + } if (struct.isSetMetadata()) { oprot.writeString(struct.metadata); } @@ -1471,7 +1678,7 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TAgentStat struct) @Override public void read(org.apache.thrift.protocol.TProtocol prot, TAgentStat struct) throws org.apache.thrift.TException { org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; - java.util.BitSet incoming = iprot.readBitSet(12); + java.util.BitSet incoming = iprot.readBitSet(14); if (incoming.get(0)) { struct.agentId = iprot.readString(); struct.setAgentIdIsSet(true); @@ -1524,6 +1731,16 @@ public void read(org.apache.thrift.protocol.TProtocol prot, TAgentStat struct) t struct.setDeadlockIsSet(true); } if (incoming.get(11)) { + struct.fileDescriptor = new TFileDescriptor(); + struct.fileDescriptor.read(iprot); + struct.setFileDescriptorIsSet(true); + } + if (incoming.get(12)) { + struct.directBuffer = new TDirectBuffer(); + struct.directBuffer.read(iprot); + struct.setDirectBufferIsSet(true); + } + if (incoming.get(13)) { struct.metadata = iprot.readString(); struct.setMetadataIsSet(true); } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentStatBatch.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentStatBatch.java index 3abc28c5fdde..eaaa00ae0fcf 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentStatBatch.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAgentStatBatch.java @@ -1,5 +1,5 @@ /** - * Autogenerated by Thrift Compiler (0.10.0) + * Autogenerated by Thrift Compiler (0.11.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -7,7 +7,7 @@ package com.navercorp.pinpoint.thrift.dto; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-03-16") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-02-12") public class TAgentStatBatch implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TAgentStatBatch"); @@ -495,14 +495,14 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, TAgentStatBatch str case 10: // AGENT_STATS if (schemeField.type == org.apache.thrift.protocol.TType.LIST) { { - org.apache.thrift.protocol.TList _list32 = iprot.readListBegin(); - struct.agentStats = new java.util.ArrayList(_list32.size); - TAgentStat _elem33; - for (int _i34 = 0; _i34 < _list32.size; ++_i34) + org.apache.thrift.protocol.TList _list40 = iprot.readListBegin(); + struct.agentStats = new java.util.ArrayList(_list40.size); + TAgentStat _elem41; + for (int _i42 = 0; _i42 < _list40.size; ++_i42) { - _elem33 = new TAgentStat(); - _elem33.read(iprot); - struct.agentStats.add(_elem33); + _elem41 = new TAgentStat(); + _elem41.read(iprot); + struct.agentStats.add(_elem41); } iprot.readListEnd(); } @@ -536,9 +536,9 @@ public void write(org.apache.thrift.protocol.TProtocol oprot, TAgentStatBatch st oprot.writeFieldBegin(AGENT_STATS_FIELD_DESC); { oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, struct.agentStats.size())); - for (TAgentStat _iter35 : struct.agentStats) + for (TAgentStat _iter43 : struct.agentStats) { - _iter35.write(oprot); + _iter43.write(oprot); } oprot.writeListEnd(); } @@ -581,9 +581,9 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TAgentStatBatch str if (struct.isSetAgentStats()) { { oprot.writeI32(struct.agentStats.size()); - for (TAgentStat _iter36 : struct.agentStats) + for (TAgentStat _iter44 : struct.agentStats) { - _iter36.write(oprot); + _iter44.write(oprot); } } } @@ -603,14 +603,14 @@ public void read(org.apache.thrift.protocol.TProtocol prot, TAgentStatBatch stru } if (incoming.get(2)) { { - org.apache.thrift.protocol.TList _list37 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, iprot.readI32()); - struct.agentStats = new java.util.ArrayList(_list37.size); - TAgentStat _elem38; - for (int _i39 = 0; _i39 < _list37.size; ++_i39) + org.apache.thrift.protocol.TList _list45 = new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, iprot.readI32()); + struct.agentStats = new java.util.ArrayList(_list45.size); + TAgentStat _elem46; + for (int _i47 = 0; _i47 < _list45.size; ++_i47) { - _elem38 = new TAgentStat(); - _elem38.read(iprot); - struct.agentStats.add(_elem38); + _elem46 = new TAgentStat(); + _elem46.read(iprot); + struct.agentStats.add(_elem46); } } struct.setAgentStatsIsSet(true); diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAnnotationValue.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAnnotationValue.java index ae4a6f221a7d..7d0b7238e4c2 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAnnotationValue.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TAnnotationValue.java @@ -1,5 +1,5 @@ /** - * Autogenerated by Thrift Compiler (0.10.0) + * Autogenerated by Thrift Compiler (0.11.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -21,6 +21,7 @@ public class TAnnotationValue extends org.apache.thrift.TUnion byName = new java.util.HashMap(); @@ -74,6 +76,8 @@ public static _Fields findByThriftId(int fieldId) { return LONG_INT_INT_BYTE_BYTE_STRING_VALUE; case 12: // INT_BOOLEAN_INT_BOOLEAN_VALUE return INT_BOOLEAN_INT_BOOLEAN_VALUE; + case 13: // STRING_STRING_VALUE + return STRING_STRING_VALUE; default: return null; } @@ -140,6 +144,8 @@ public java.lang.String getFieldName() { new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TLongIntIntByteByteStringValue.class))); tmpMap.put(_Fields.INT_BOOLEAN_INT_BOOLEAN_VALUE, new org.apache.thrift.meta_data.FieldMetaData("intBooleanIntBooleanValue", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TIntBooleanIntBooleanValue.class))); + tmpMap.put(_Fields.STRING_STRING_VALUE, new org.apache.thrift.meta_data.FieldMetaData("stringStringValue", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TStringStringValue.class))); metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TAnnotationValue.class, metaDataMap); } @@ -237,6 +243,12 @@ public static TAnnotationValue intBooleanIntBooleanValue(TIntBooleanIntBooleanVa return x; } + public static TAnnotationValue stringStringValue(TStringStringValue value) { + TAnnotationValue x = new TAnnotationValue(); + x.setStringStringValue(value); + return x; + } + @Override protected void checkType(_Fields setField, java.lang.Object value) throws java.lang.ClassCastException { @@ -301,6 +313,11 @@ protected void checkType(_Fields setField, java.lang.Object value) throws java.l break; } throw new java.lang.ClassCastException("Was expecting value of type TIntBooleanIntBooleanValue for field 'intBooleanIntBooleanValue', but got " + value.getClass().getSimpleName()); + case STRING_STRING_VALUE: + if (value instanceof TStringStringValue) { + break; + } + throw new java.lang.ClassCastException("Was expecting value of type TStringStringValue for field 'stringStringValue', but got " + value.getClass().getSimpleName()); default: throw new java.lang.IllegalArgumentException("Unknown field id " + setField); } @@ -423,6 +440,16 @@ protected java.lang.Object standardSchemeReadValue(org.apache.thrift.protocol.TP org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); return null; } + case STRING_STRING_VALUE: + if (field.type == STRING_STRING_VALUE_FIELD_DESC.type) { + TStringStringValue stringStringValue; + stringStringValue = new TStringStringValue(); + stringStringValue.read(iprot); + return stringStringValue; + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type); + return null; + } default: throw new java.lang.IllegalStateException("setField wasn't null, but didn't match any of the case statements!"); } @@ -483,6 +510,10 @@ protected void standardSchemeWriteValue(org.apache.thrift.protocol.TProtocol opr TIntBooleanIntBooleanValue intBooleanIntBooleanValue = (TIntBooleanIntBooleanValue)value_; intBooleanIntBooleanValue.write(oprot); return; + case STRING_STRING_VALUE: + TStringStringValue stringStringValue = (TStringStringValue)value_; + stringStringValue.write(oprot); + return; default: throw new java.lang.IllegalStateException("Cannot write union with unknown field " + setField_); } @@ -545,6 +576,11 @@ protected java.lang.Object tupleSchemeReadValue(org.apache.thrift.protocol.TProt intBooleanIntBooleanValue = new TIntBooleanIntBooleanValue(); intBooleanIntBooleanValue.read(iprot); return intBooleanIntBooleanValue; + case STRING_STRING_VALUE: + TStringStringValue stringStringValue; + stringStringValue = new TStringStringValue(); + stringStringValue.read(iprot); + return stringStringValue; default: throw new java.lang.IllegalStateException("setField wasn't null, but didn't match any of the case statements!"); } @@ -604,6 +640,10 @@ protected void tupleSchemeWriteValue(org.apache.thrift.protocol.TProtocol oprot) TIntBooleanIntBooleanValue intBooleanIntBooleanValue = (TIntBooleanIntBooleanValue)value_; intBooleanIntBooleanValue.write(oprot); return; + case STRING_STRING_VALUE: + TStringStringValue stringStringValue = (TStringStringValue)value_; + stringStringValue.write(oprot); + return; default: throw new java.lang.IllegalStateException("Cannot write union with unknown field " + setField_); } @@ -636,6 +676,8 @@ protected org.apache.thrift.protocol.TField getFieldDesc(_Fields setField) { return LONG_INT_INT_BYTE_BYTE_STRING_VALUE_FIELD_DESC; case INT_BOOLEAN_INT_BOOLEAN_VALUE: return INT_BOOLEAN_INT_BOOLEAN_VALUE_FIELD_DESC; + case STRING_STRING_VALUE: + return STRING_STRING_VALUE_FIELD_DESC; default: throw new java.lang.IllegalArgumentException("Unknown field id " + setField); } @@ -828,6 +870,20 @@ public void setIntBooleanIntBooleanValue(TIntBooleanIntBooleanValue value) { value_ = value; } + public TStringStringValue getStringStringValue() { + if (getSetField() == _Fields.STRING_STRING_VALUE) { + return (TStringStringValue)getFieldValue(); + } else { + throw new java.lang.RuntimeException("Cannot get field 'stringStringValue' because union is currently set to " + getFieldDesc(getSetField()).name); + } + } + + public void setStringStringValue(TStringStringValue value) { + if (value == null) throw new java.lang.NullPointerException(); + setField_ = _Fields.STRING_STRING_VALUE; + value_ = value; + } + public boolean isSetStringValue() { return setField_ == _Fields.STRING_VALUE; } @@ -888,6 +944,11 @@ public boolean isSetIntBooleanIntBooleanValue() { } + public boolean isSetStringStringValue() { + return setField_ == _Fields.STRING_STRING_VALUE; + } + + public boolean equals(java.lang.Object other) { if (other instanceof TAnnotationValue) { return equals((TAnnotationValue)other); diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TDirectBuffer.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TDirectBuffer.java new file mode 100644 index 000000000000..d5083386f99d --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TDirectBuffer.java @@ -0,0 +1,658 @@ +/** + * Autogenerated by Thrift Compiler (0.11.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package com.navercorp.pinpoint.thrift.dto; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-03-26") +public class TDirectBuffer implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TDirectBuffer"); + + private static final org.apache.thrift.protocol.TField DIRECT_COUNT_FIELD_DESC = new org.apache.thrift.protocol.TField("directCount", org.apache.thrift.protocol.TType.I64, (short)1); + private static final org.apache.thrift.protocol.TField DIRECT_MEMORY_USED_FIELD_DESC = new org.apache.thrift.protocol.TField("directMemoryUsed", org.apache.thrift.protocol.TType.I64, (short)2); + private static final org.apache.thrift.protocol.TField MAPPED_COUNT_FIELD_DESC = new org.apache.thrift.protocol.TField("mappedCount", org.apache.thrift.protocol.TType.I64, (short)3); + private static final org.apache.thrift.protocol.TField MAPPED_MEMORY_USED_FIELD_DESC = new org.apache.thrift.protocol.TField("mappedMemoryUsed", org.apache.thrift.protocol.TType.I64, (short)4); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new TDirectBufferStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new TDirectBufferTupleSchemeFactory(); + + private long directCount; // optional + private long directMemoryUsed; // optional + private long mappedCount; // optional + private long mappedMemoryUsed; // optional + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + DIRECT_COUNT((short)1, "directCount"), + DIRECT_MEMORY_USED((short)2, "directMemoryUsed"), + MAPPED_COUNT((short)3, "mappedCount"), + MAPPED_MEMORY_USED((short)4, "mappedMemoryUsed"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // DIRECT_COUNT + return DIRECT_COUNT; + case 2: // DIRECT_MEMORY_USED + return DIRECT_MEMORY_USED; + case 3: // MAPPED_COUNT + return MAPPED_COUNT; + case 4: // MAPPED_MEMORY_USED + return MAPPED_MEMORY_USED; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + private static final int __DIRECTCOUNT_ISSET_ID = 0; + private static final int __DIRECTMEMORYUSED_ISSET_ID = 1; + private static final int __MAPPEDCOUNT_ISSET_ID = 2; + private static final int __MAPPEDMEMORYUSED_ISSET_ID = 3; + private byte __isset_bitfield = 0; + private static final _Fields optionals[] = {_Fields.DIRECT_COUNT,_Fields.DIRECT_MEMORY_USED,_Fields.MAPPED_COUNT,_Fields.MAPPED_MEMORY_USED}; + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.DIRECT_COUNT, new org.apache.thrift.meta_data.FieldMetaData("directCount", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + tmpMap.put(_Fields.DIRECT_MEMORY_USED, new org.apache.thrift.meta_data.FieldMetaData("directMemoryUsed", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + tmpMap.put(_Fields.MAPPED_COUNT, new org.apache.thrift.meta_data.FieldMetaData("mappedCount", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + tmpMap.put(_Fields.MAPPED_MEMORY_USED, new org.apache.thrift.meta_data.FieldMetaData("mappedMemoryUsed", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TDirectBuffer.class, metaDataMap); + } + + public TDirectBuffer() { + } + + /** + * Performs a deep copy on other. + */ + public TDirectBuffer(TDirectBuffer other) { + __isset_bitfield = other.__isset_bitfield; + this.directCount = other.directCount; + this.directMemoryUsed = other.directMemoryUsed; + this.mappedCount = other.mappedCount; + this.mappedMemoryUsed = other.mappedMemoryUsed; + } + + public TDirectBuffer deepCopy() { + return new TDirectBuffer(this); + } + + @Override + public void clear() { + setDirectCountIsSet(false); + this.directCount = 0; + setDirectMemoryUsedIsSet(false); + this.directMemoryUsed = 0; + setMappedCountIsSet(false); + this.mappedCount = 0; + setMappedMemoryUsedIsSet(false); + this.mappedMemoryUsed = 0; + } + + public long getDirectCount() { + return this.directCount; + } + + public void setDirectCount(long directCount) { + this.directCount = directCount; + setDirectCountIsSet(true); + } + + public void unsetDirectCount() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __DIRECTCOUNT_ISSET_ID); + } + + /** Returns true if field directCount is set (has been assigned a value) and false otherwise */ + public boolean isSetDirectCount() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __DIRECTCOUNT_ISSET_ID); + } + + public void setDirectCountIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __DIRECTCOUNT_ISSET_ID, value); + } + + public long getDirectMemoryUsed() { + return this.directMemoryUsed; + } + + public void setDirectMemoryUsed(long directMemoryUsed) { + this.directMemoryUsed = directMemoryUsed; + setDirectMemoryUsedIsSet(true); + } + + public void unsetDirectMemoryUsed() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __DIRECTMEMORYUSED_ISSET_ID); + } + + /** Returns true if field directMemoryUsed is set (has been assigned a value) and false otherwise */ + public boolean isSetDirectMemoryUsed() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __DIRECTMEMORYUSED_ISSET_ID); + } + + public void setDirectMemoryUsedIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __DIRECTMEMORYUSED_ISSET_ID, value); + } + + public long getMappedCount() { + return this.mappedCount; + } + + public void setMappedCount(long mappedCount) { + this.mappedCount = mappedCount; + setMappedCountIsSet(true); + } + + public void unsetMappedCount() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __MAPPEDCOUNT_ISSET_ID); + } + + /** Returns true if field mappedCount is set (has been assigned a value) and false otherwise */ + public boolean isSetMappedCount() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __MAPPEDCOUNT_ISSET_ID); + } + + public void setMappedCountIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __MAPPEDCOUNT_ISSET_ID, value); + } + + public long getMappedMemoryUsed() { + return this.mappedMemoryUsed; + } + + public void setMappedMemoryUsed(long mappedMemoryUsed) { + this.mappedMemoryUsed = mappedMemoryUsed; + setMappedMemoryUsedIsSet(true); + } + + public void unsetMappedMemoryUsed() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __MAPPEDMEMORYUSED_ISSET_ID); + } + + /** Returns true if field mappedMemoryUsed is set (has been assigned a value) and false otherwise */ + public boolean isSetMappedMemoryUsed() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __MAPPEDMEMORYUSED_ISSET_ID); + } + + public void setMappedMemoryUsedIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __MAPPEDMEMORYUSED_ISSET_ID, value); + } + + public void setFieldValue(_Fields field, java.lang.Object value) { + switch (field) { + case DIRECT_COUNT: + if (value == null) { + unsetDirectCount(); + } else { + setDirectCount((java.lang.Long)value); + } + break; + + case DIRECT_MEMORY_USED: + if (value == null) { + unsetDirectMemoryUsed(); + } else { + setDirectMemoryUsed((java.lang.Long)value); + } + break; + + case MAPPED_COUNT: + if (value == null) { + unsetMappedCount(); + } else { + setMappedCount((java.lang.Long)value); + } + break; + + case MAPPED_MEMORY_USED: + if (value == null) { + unsetMappedMemoryUsed(); + } else { + setMappedMemoryUsed((java.lang.Long)value); + } + break; + + } + } + + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case DIRECT_COUNT: + return getDirectCount(); + + case DIRECT_MEMORY_USED: + return getDirectMemoryUsed(); + + case MAPPED_COUNT: + return getMappedCount(); + + case MAPPED_MEMORY_USED: + return getMappedMemoryUsed(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case DIRECT_COUNT: + return isSetDirectCount(); + case DIRECT_MEMORY_USED: + return isSetDirectMemoryUsed(); + case MAPPED_COUNT: + return isSetMappedCount(); + case MAPPED_MEMORY_USED: + return isSetMappedMemoryUsed(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that == null) + return false; + if (that instanceof TDirectBuffer) + return this.equals((TDirectBuffer)that); + return false; + } + + public boolean equals(TDirectBuffer that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_directCount = true && this.isSetDirectCount(); + boolean that_present_directCount = true && that.isSetDirectCount(); + if (this_present_directCount || that_present_directCount) { + if (!(this_present_directCount && that_present_directCount)) + return false; + if (this.directCount != that.directCount) + return false; + } + + boolean this_present_directMemoryUsed = true && this.isSetDirectMemoryUsed(); + boolean that_present_directMemoryUsed = true && that.isSetDirectMemoryUsed(); + if (this_present_directMemoryUsed || that_present_directMemoryUsed) { + if (!(this_present_directMemoryUsed && that_present_directMemoryUsed)) + return false; + if (this.directMemoryUsed != that.directMemoryUsed) + return false; + } + + boolean this_present_mappedCount = true && this.isSetMappedCount(); + boolean that_present_mappedCount = true && that.isSetMappedCount(); + if (this_present_mappedCount || that_present_mappedCount) { + if (!(this_present_mappedCount && that_present_mappedCount)) + return false; + if (this.mappedCount != that.mappedCount) + return false; + } + + boolean this_present_mappedMemoryUsed = true && this.isSetMappedMemoryUsed(); + boolean that_present_mappedMemoryUsed = true && that.isSetMappedMemoryUsed(); + if (this_present_mappedMemoryUsed || that_present_mappedMemoryUsed) { + if (!(this_present_mappedMemoryUsed && that_present_mappedMemoryUsed)) + return false; + if (this.mappedMemoryUsed != that.mappedMemoryUsed) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetDirectCount()) ? 131071 : 524287); + if (isSetDirectCount()) + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(directCount); + + hashCode = hashCode * 8191 + ((isSetDirectMemoryUsed()) ? 131071 : 524287); + if (isSetDirectMemoryUsed()) + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(directMemoryUsed); + + hashCode = hashCode * 8191 + ((isSetMappedCount()) ? 131071 : 524287); + if (isSetMappedCount()) + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(mappedCount); + + hashCode = hashCode * 8191 + ((isSetMappedMemoryUsed()) ? 131071 : 524287); + if (isSetMappedMemoryUsed()) + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(mappedMemoryUsed); + + return hashCode; + } + + @Override + public int compareTo(TDirectBuffer other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.valueOf(isSetDirectCount()).compareTo(other.isSetDirectCount()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetDirectCount()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.directCount, other.directCount); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetDirectMemoryUsed()).compareTo(other.isSetDirectMemoryUsed()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetDirectMemoryUsed()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.directMemoryUsed, other.directMemoryUsed); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetMappedCount()).compareTo(other.isSetMappedCount()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetMappedCount()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.mappedCount, other.mappedCount); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetMappedMemoryUsed()).compareTo(other.isSetMappedMemoryUsed()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetMappedMemoryUsed()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.mappedMemoryUsed, other.mappedMemoryUsed); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("TDirectBuffer("); + boolean first = true; + + if (isSetDirectCount()) { + sb.append("directCount:"); + sb.append(this.directCount); + first = false; + } + if (isSetDirectMemoryUsed()) { + if (!first) sb.append(", "); + sb.append("directMemoryUsed:"); + sb.append(this.directMemoryUsed); + first = false; + } + if (isSetMappedCount()) { + if (!first) sb.append(", "); + sb.append("mappedCount:"); + sb.append(this.mappedCount); + first = false; + } + if (isSetMappedMemoryUsed()) { + if (!first) sb.append(", "); + sb.append("mappedMemoryUsed:"); + sb.append(this.mappedMemoryUsed); + first = false; + } + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. + __isset_bitfield = 0; + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class TDirectBufferStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TDirectBufferStandardScheme getScheme() { + return new TDirectBufferStandardScheme(); + } + } + + private static class TDirectBufferStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, TDirectBuffer struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // DIRECT_COUNT + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.directCount = iprot.readI64(); + struct.setDirectCountIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // DIRECT_MEMORY_USED + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.directMemoryUsed = iprot.readI64(); + struct.setDirectMemoryUsedIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 3: // MAPPED_COUNT + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.mappedCount = iprot.readI64(); + struct.setMappedCountIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 4: // MAPPED_MEMORY_USED + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.mappedMemoryUsed = iprot.readI64(); + struct.setMappedMemoryUsedIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, TDirectBuffer struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.isSetDirectCount()) { + oprot.writeFieldBegin(DIRECT_COUNT_FIELD_DESC); + oprot.writeI64(struct.directCount); + oprot.writeFieldEnd(); + } + if (struct.isSetDirectMemoryUsed()) { + oprot.writeFieldBegin(DIRECT_MEMORY_USED_FIELD_DESC); + oprot.writeI64(struct.directMemoryUsed); + oprot.writeFieldEnd(); + } + if (struct.isSetMappedCount()) { + oprot.writeFieldBegin(MAPPED_COUNT_FIELD_DESC); + oprot.writeI64(struct.mappedCount); + oprot.writeFieldEnd(); + } + if (struct.isSetMappedMemoryUsed()) { + oprot.writeFieldBegin(MAPPED_MEMORY_USED_FIELD_DESC); + oprot.writeI64(struct.mappedMemoryUsed); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class TDirectBufferTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TDirectBufferTupleScheme getScheme() { + return new TDirectBufferTupleScheme(); + } + } + + private static class TDirectBufferTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, TDirectBuffer struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetDirectCount()) { + optionals.set(0); + } + if (struct.isSetDirectMemoryUsed()) { + optionals.set(1); + } + if (struct.isSetMappedCount()) { + optionals.set(2); + } + if (struct.isSetMappedMemoryUsed()) { + optionals.set(3); + } + oprot.writeBitSet(optionals, 4); + if (struct.isSetDirectCount()) { + oprot.writeI64(struct.directCount); + } + if (struct.isSetDirectMemoryUsed()) { + oprot.writeI64(struct.directMemoryUsed); + } + if (struct.isSetMappedCount()) { + oprot.writeI64(struct.mappedCount); + } + if (struct.isSetMappedMemoryUsed()) { + oprot.writeI64(struct.mappedMemoryUsed); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, TDirectBuffer struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(4); + if (incoming.get(0)) { + struct.directCount = iprot.readI64(); + struct.setDirectCountIsSet(true); + } + if (incoming.get(1)) { + struct.directMemoryUsed = iprot.readI64(); + struct.setDirectMemoryUsedIsSet(true); + } + if (incoming.get(2)) { + struct.mappedCount = iprot.readI64(); + struct.setMappedCountIsSet(true); + } + if (incoming.get(3)) { + struct.mappedMemoryUsed = iprot.readI64(); + struct.setMappedMemoryUsedIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } +} + diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TFileDescriptor.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TFileDescriptor.java new file mode 100644 index 000000000000..c25b352453fa --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TFileDescriptor.java @@ -0,0 +1,365 @@ +/** + * Autogenerated by Thrift Compiler (0.11.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package com.navercorp.pinpoint.thrift.dto; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-02-12") +public class TFileDescriptor implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TFileDescriptor"); + + private static final org.apache.thrift.protocol.TField OPEN_FILE_DESCRIPTOR_COUNT_FIELD_DESC = new org.apache.thrift.protocol.TField("openFileDescriptorCount", org.apache.thrift.protocol.TType.I64, (short)1); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new TFileDescriptorStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new TFileDescriptorTupleSchemeFactory(); + + private long openFileDescriptorCount; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + OPEN_FILE_DESCRIPTOR_COUNT((short)1, "openFileDescriptorCount"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // OPEN_FILE_DESCRIPTOR_COUNT + return OPEN_FILE_DESCRIPTOR_COUNT; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + private static final int __OPENFILEDESCRIPTORCOUNT_ISSET_ID = 0; + private byte __isset_bitfield = 0; + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.OPEN_FILE_DESCRIPTOR_COUNT, new org.apache.thrift.meta_data.FieldMetaData("openFileDescriptorCount", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TFileDescriptor.class, metaDataMap); + } + + public TFileDescriptor() { + } + + public TFileDescriptor( + long openFileDescriptorCount) + { + this(); + this.openFileDescriptorCount = openFileDescriptorCount; + setOpenFileDescriptorCountIsSet(true); + } + + /** + * Performs a deep copy on other. + */ + public TFileDescriptor(TFileDescriptor other) { + __isset_bitfield = other.__isset_bitfield; + this.openFileDescriptorCount = other.openFileDescriptorCount; + } + + public TFileDescriptor deepCopy() { + return new TFileDescriptor(this); + } + + @Override + public void clear() { + setOpenFileDescriptorCountIsSet(false); + this.openFileDescriptorCount = 0; + } + + public long getOpenFileDescriptorCount() { + return this.openFileDescriptorCount; + } + + public void setOpenFileDescriptorCount(long openFileDescriptorCount) { + this.openFileDescriptorCount = openFileDescriptorCount; + setOpenFileDescriptorCountIsSet(true); + } + + public void unsetOpenFileDescriptorCount() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __OPENFILEDESCRIPTORCOUNT_ISSET_ID); + } + + /** Returns true if field openFileDescriptorCount is set (has been assigned a value) and false otherwise */ + public boolean isSetOpenFileDescriptorCount() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __OPENFILEDESCRIPTORCOUNT_ISSET_ID); + } + + public void setOpenFileDescriptorCountIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __OPENFILEDESCRIPTORCOUNT_ISSET_ID, value); + } + + public void setFieldValue(_Fields field, java.lang.Object value) { + switch (field) { + case OPEN_FILE_DESCRIPTOR_COUNT: + if (value == null) { + unsetOpenFileDescriptorCount(); + } else { + setOpenFileDescriptorCount((java.lang.Long)value); + } + break; + + } + } + + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case OPEN_FILE_DESCRIPTOR_COUNT: + return getOpenFileDescriptorCount(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case OPEN_FILE_DESCRIPTOR_COUNT: + return isSetOpenFileDescriptorCount(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that == null) + return false; + if (that instanceof TFileDescriptor) + return this.equals((TFileDescriptor)that); + return false; + } + + public boolean equals(TFileDescriptor that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_openFileDescriptorCount = true; + boolean that_present_openFileDescriptorCount = true; + if (this_present_openFileDescriptorCount || that_present_openFileDescriptorCount) { + if (!(this_present_openFileDescriptorCount && that_present_openFileDescriptorCount)) + return false; + if (this.openFileDescriptorCount != that.openFileDescriptorCount) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(openFileDescriptorCount); + + return hashCode; + } + + @Override + public int compareTo(TFileDescriptor other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.valueOf(isSetOpenFileDescriptorCount()).compareTo(other.isSetOpenFileDescriptorCount()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetOpenFileDescriptorCount()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.openFileDescriptorCount, other.openFileDescriptorCount); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("TFileDescriptor("); + boolean first = true; + + sb.append("openFileDescriptorCount:"); + sb.append(this.openFileDescriptorCount); + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. + __isset_bitfield = 0; + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class TFileDescriptorStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TFileDescriptorStandardScheme getScheme() { + return new TFileDescriptorStandardScheme(); + } + } + + private static class TFileDescriptorStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, TFileDescriptor struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // OPEN_FILE_DESCRIPTOR_COUNT + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.openFileDescriptorCount = iprot.readI64(); + struct.setOpenFileDescriptorCountIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, TFileDescriptor struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + oprot.writeFieldBegin(OPEN_FILE_DESCRIPTOR_COUNT_FIELD_DESC); + oprot.writeI64(struct.openFileDescriptorCount); + oprot.writeFieldEnd(); + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class TFileDescriptorTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TFileDescriptorTupleScheme getScheme() { + return new TFileDescriptorTupleScheme(); + } + } + + private static class TFileDescriptorTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, TFileDescriptor struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetOpenFileDescriptorCount()) { + optionals.set(0); + } + oprot.writeBitSet(optionals, 1); + if (struct.isSetOpenFileDescriptorCount()) { + oprot.writeI64(struct.openFileDescriptorCount); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, TFileDescriptor struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(1); + if (incoming.get(0)) { + struct.openFileDescriptorCount = iprot.readI64(); + struct.setOpenFileDescriptorCountIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } +} + diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TSpanEvent.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TSpanEvent.java index cffd592f8dfc..9d371a4e7153 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TSpanEvent.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TSpanEvent.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * Autogenerated by Thrift Compiler (0.10.0) * @@ -7,7 +23,7 @@ package com.navercorp.pinpoint.thrift.dto; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-03-16") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2018-09-28") public class TSpanEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TSpanEvent"); @@ -206,6 +222,8 @@ public java.lang.String getFieldName() { } public TSpanEvent() { + this.startElapsed = 0; + this.endElapsed = 0; this.depth = -1; @@ -275,8 +293,8 @@ public void clear() { this.spanId = 0; setSequenceIsSet(false); this.sequence = 0; - setStartElapsedIsSet(false); this.startElapsed = 0; + this.endElapsed = 0; this.rpc = null; @@ -388,23 +406,28 @@ public void setEndElapsedIsSet(boolean value) { __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __ENDELAPSED_ISSET_ID, value); } + @Deprecated public java.lang.String getRpc() { return this.rpc; } + @Deprecated public void setRpc(java.lang.String rpc) { this.rpc = rpc; } + @Deprecated public void unsetRpc() { this.rpc = null; } /** Returns true if field rpc is set (has been assigned a value) and false otherwise */ + @Deprecated public boolean isSetRpc() { return this.rpc != null; } + @Deprecated public void setRpcIsSet(boolean value) { if (!value) { this.rpc = null; diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TStringStringValue.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TStringStringValue.java new file mode 100644 index 000000000000..2b533e70df41 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/TStringStringValue.java @@ -0,0 +1,475 @@ +/** + * Autogenerated by Thrift Compiler (0.11.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package com.navercorp.pinpoint.thrift.dto; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-07-23") +public class TStringStringValue implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TStringStringValue"); + + private static final org.apache.thrift.protocol.TField STRING_VALUE1_FIELD_DESC = new org.apache.thrift.protocol.TField("stringValue1", org.apache.thrift.protocol.TType.STRING, (short)1); + private static final org.apache.thrift.protocol.TField STRING_VALUE2_FIELD_DESC = new org.apache.thrift.protocol.TField("stringValue2", org.apache.thrift.protocol.TType.STRING, (short)2); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new TStringStringValueStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new TStringStringValueTupleSchemeFactory(); + + private java.lang.String stringValue1; // required + private java.lang.String stringValue2; // optional + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + STRING_VALUE1((short)1, "stringValue1"), + STRING_VALUE2((short)2, "stringValue2"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // STRING_VALUE1 + return STRING_VALUE1; + case 2: // STRING_VALUE2 + return STRING_VALUE2; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + private static final _Fields optionals[] = {_Fields.STRING_VALUE2}; + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.STRING_VALUE1, new org.apache.thrift.meta_data.FieldMetaData("stringValue1", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + tmpMap.put(_Fields.STRING_VALUE2, new org.apache.thrift.meta_data.FieldMetaData("stringValue2", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TStringStringValue.class, metaDataMap); + } + + public TStringStringValue() { + } + + public TStringStringValue( + java.lang.String stringValue1) + { + this(); + this.stringValue1 = stringValue1; + } + + /** + * Performs a deep copy on other. + */ + public TStringStringValue(TStringStringValue other) { + if (other.isSetStringValue1()) { + this.stringValue1 = other.stringValue1; + } + if (other.isSetStringValue2()) { + this.stringValue2 = other.stringValue2; + } + } + + public TStringStringValue deepCopy() { + return new TStringStringValue(this); + } + + @Override + public void clear() { + this.stringValue1 = null; + this.stringValue2 = null; + } + + public java.lang.String getStringValue1() { + return this.stringValue1; + } + + public void setStringValue1(java.lang.String stringValue1) { + this.stringValue1 = stringValue1; + } + + public void unsetStringValue1() { + this.stringValue1 = null; + } + + /** Returns true if field stringValue1 is set (has been assigned a value) and false otherwise */ + public boolean isSetStringValue1() { + return this.stringValue1 != null; + } + + public void setStringValue1IsSet(boolean value) { + if (!value) { + this.stringValue1 = null; + } + } + + public java.lang.String getStringValue2() { + return this.stringValue2; + } + + public void setStringValue2(java.lang.String stringValue2) { + this.stringValue2 = stringValue2; + } + + public void unsetStringValue2() { + this.stringValue2 = null; + } + + /** Returns true if field stringValue2 is set (has been assigned a value) and false otherwise */ + public boolean isSetStringValue2() { + return this.stringValue2 != null; + } + + public void setStringValue2IsSet(boolean value) { + if (!value) { + this.stringValue2 = null; + } + } + + public void setFieldValue(_Fields field, java.lang.Object value) { + switch (field) { + case STRING_VALUE1: + if (value == null) { + unsetStringValue1(); + } else { + setStringValue1((java.lang.String)value); + } + break; + + case STRING_VALUE2: + if (value == null) { + unsetStringValue2(); + } else { + setStringValue2((java.lang.String)value); + } + break; + + } + } + + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case STRING_VALUE1: + return getStringValue1(); + + case STRING_VALUE2: + return getStringValue2(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case STRING_VALUE1: + return isSetStringValue1(); + case STRING_VALUE2: + return isSetStringValue2(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that == null) + return false; + if (that instanceof TStringStringValue) + return this.equals((TStringStringValue)that); + return false; + } + + public boolean equals(TStringStringValue that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_stringValue1 = true && this.isSetStringValue1(); + boolean that_present_stringValue1 = true && that.isSetStringValue1(); + if (this_present_stringValue1 || that_present_stringValue1) { + if (!(this_present_stringValue1 && that_present_stringValue1)) + return false; + if (!this.stringValue1.equals(that.stringValue1)) + return false; + } + + boolean this_present_stringValue2 = true && this.isSetStringValue2(); + boolean that_present_stringValue2 = true && that.isSetStringValue2(); + if (this_present_stringValue2 || that_present_stringValue2) { + if (!(this_present_stringValue2 && that_present_stringValue2)) + return false; + if (!this.stringValue2.equals(that.stringValue2)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetStringValue1()) ? 131071 : 524287); + if (isSetStringValue1()) + hashCode = hashCode * 8191 + stringValue1.hashCode(); + + hashCode = hashCode * 8191 + ((isSetStringValue2()) ? 131071 : 524287); + if (isSetStringValue2()) + hashCode = hashCode * 8191 + stringValue2.hashCode(); + + return hashCode; + } + + @Override + public int compareTo(TStringStringValue other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.valueOf(isSetStringValue1()).compareTo(other.isSetStringValue1()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetStringValue1()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.stringValue1, other.stringValue1); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetStringValue2()).compareTo(other.isSetStringValue2()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetStringValue2()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.stringValue2, other.stringValue2); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("TStringStringValue("); + boolean first = true; + + sb.append("stringValue1:"); + if (this.stringValue1 == null) { + sb.append("null"); + } else { + sb.append(this.stringValue1); + } + first = false; + if (isSetStringValue2()) { + if (!first) sb.append(", "); + sb.append("stringValue2:"); + if (this.stringValue2 == null) { + sb.append("null"); + } else { + sb.append(this.stringValue2); + } + first = false; + } + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class TStringStringValueStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TStringStringValueStandardScheme getScheme() { + return new TStringStringValueStandardScheme(); + } + } + + private static class TStringStringValueStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, TStringStringValue struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // STRING_VALUE1 + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.stringValue1 = iprot.readString(); + struct.setStringValue1IsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // STRING_VALUE2 + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.stringValue2 = iprot.readString(); + struct.setStringValue2IsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, TStringStringValue struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.stringValue1 != null) { + oprot.writeFieldBegin(STRING_VALUE1_FIELD_DESC); + oprot.writeString(struct.stringValue1); + oprot.writeFieldEnd(); + } + if (struct.stringValue2 != null) { + if (struct.isSetStringValue2()) { + oprot.writeFieldBegin(STRING_VALUE2_FIELD_DESC); + oprot.writeString(struct.stringValue2); + oprot.writeFieldEnd(); + } + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class TStringStringValueTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TStringStringValueTupleScheme getScheme() { + return new TStringStringValueTupleScheme(); + } + } + + private static class TStringStringValueTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, TStringStringValue struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetStringValue1()) { + optionals.set(0); + } + if (struct.isSetStringValue2()) { + optionals.set(1); + } + oprot.writeBitSet(optionals, 2); + if (struct.isSetStringValue1()) { + oprot.writeString(struct.stringValue1); + } + if (struct.isSetStringValue2()) { + oprot.writeString(struct.stringValue2); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, TStringStringValue struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(2); + if (incoming.get(0)) { + struct.stringValue1 = iprot.readString(); + struct.setStringValue1IsSet(true); + } + if (incoming.get(1)) { + struct.stringValue2 = iprot.readString(); + struct.setStringValue2IsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } +} + diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentInfo.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentInfo.java index bab01d0ebb5f..9d5395e7cbbf 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentInfo.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentInfo.java @@ -7,7 +7,7 @@ package com.navercorp.pinpoint.thrift.dto.flink; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-09-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2018-06-19") public class TFAgentInfo implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TFAgentInfo"); @@ -25,6 +25,7 @@ public class TFAgentInfo implements org.apache.thrift.TBase byName = new java.util.HashMap(); @@ -102,6 +105,8 @@ public static _Fields findByThriftId(int fieldId) { return SERVER_META_DATA; case 30: // JVM_INFO return JVM_INFO; + case 40: // CONTAINER + return CONTAINER; default: return null; } @@ -147,8 +152,9 @@ public java.lang.String getFieldName() { private static final int __STARTTIMESTAMP_ISSET_ID = 2; private static final int __ENDTIMESTAMP_ISSET_ID = 3; private static final int __ENDSTATUS_ISSET_ID = 4; + private static final int __CONTAINER_ISSET_ID = 5; private byte __isset_bitfield = 0; - private static final _Fields optionals[] = {_Fields.END_TIMESTAMP,_Fields.END_STATUS,_Fields.SERVER_META_DATA,_Fields.JVM_INFO}; + private static final _Fields optionals[] = {_Fields.END_TIMESTAMP,_Fields.END_STATUS,_Fields.SERVER_META_DATA,_Fields.JVM_INFO,_Fields.CONTAINER}; public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); @@ -180,11 +186,15 @@ public java.lang.String getFieldName() { new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TFServerMetaData.class))); tmpMap.put(_Fields.JVM_INFO, new org.apache.thrift.meta_data.FieldMetaData("jvmInfo", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TFJvmInfo.class))); + tmpMap.put(_Fields.CONTAINER, new org.apache.thrift.meta_data.FieldMetaData("container", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BOOL))); metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TFAgentInfo.class, metaDataMap); } public TFAgentInfo() { + this.container = false; + } public TFAgentInfo( @@ -252,6 +262,7 @@ public TFAgentInfo(TFAgentInfo other) { if (other.isSetJvmInfo()) { this.jvmInfo = new TFJvmInfo(other.jvmInfo); } + this.container = other.container; } public TFAgentInfo deepCopy() { @@ -279,6 +290,8 @@ public void clear() { this.endStatus = 0; this.serverMetaData = null; this.jvmInfo = null; + this.container = false; + } public java.lang.String getHostname() { @@ -598,6 +611,28 @@ public void setJvmInfoIsSet(boolean value) { } } + public boolean isContainer() { + return this.container; + } + + public void setContainer(boolean container) { + this.container = container; + setContainerIsSet(true); + } + + public void unsetContainer() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __CONTAINER_ISSET_ID); + } + + /** Returns true if field container is set (has been assigned a value) and false otherwise */ + public boolean isSetContainer() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __CONTAINER_ISSET_ID); + } + + public void setContainerIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __CONTAINER_ISSET_ID, value); + } + public void setFieldValue(_Fields field, java.lang.Object value) { switch (field) { case HOSTNAME: @@ -712,6 +747,14 @@ public void setFieldValue(_Fields field, java.lang.Object value) { } break; + case CONTAINER: + if (value == null) { + unsetContainer(); + } else { + setContainer((java.lang.Boolean)value); + } + break; + } } @@ -759,6 +802,9 @@ public java.lang.Object getFieldValue(_Fields field) { case JVM_INFO: return getJvmInfo(); + case CONTAINER: + return isContainer(); + } throw new java.lang.IllegalStateException(); } @@ -798,6 +844,8 @@ public boolean isSet(_Fields field) { return isSetServerMetaData(); case JVM_INFO: return isSetJvmInfo(); + case CONTAINER: + return isSetContainer(); } throw new java.lang.IllegalStateException(); } @@ -943,6 +991,15 @@ public boolean equals(TFAgentInfo that) { return false; } + boolean this_present_container = true && this.isSetContainer(); + boolean that_present_container = true && that.isSetContainer(); + if (this_present_container || that_present_container) { + if (!(this_present_container && that_present_container)) + return false; + if (this.container != that.container) + return false; + } + return true; } @@ -1000,6 +1057,10 @@ public int hashCode() { if (isSetJvmInfo()) hashCode = hashCode * 8191 + jvmInfo.hashCode(); + hashCode = hashCode * 8191 + ((isSetContainer()) ? 131071 : 524287); + if (isSetContainer()) + hashCode = hashCode * 8191 + ((container) ? 131071 : 524287); + return hashCode; } @@ -1151,6 +1212,16 @@ public int compareTo(TFAgentInfo other) { return lastComparison; } } + lastComparison = java.lang.Boolean.valueOf(isSetContainer()).compareTo(other.isSetContainer()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetContainer()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.container, other.container); + if (lastComparison != 0) { + return lastComparison; + } + } return 0; } @@ -1270,6 +1341,12 @@ public java.lang.String toString() { } first = false; } + if (isSetContainer()) { + if (!first) sb.append(", "); + sb.append("container:"); + sb.append(this.container); + first = false; + } sb.append(")"); return sb.toString(); } @@ -1435,6 +1512,14 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, TFAgentInfo struct) org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; + case 40: // CONTAINER + if (schemeField.type == org.apache.thrift.protocol.TType.BOOL) { + struct.container = iprot.readBool(); + struct.setContainerIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; default: org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } @@ -1516,6 +1601,11 @@ public void write(org.apache.thrift.protocol.TProtocol oprot, TFAgentInfo struct oprot.writeFieldEnd(); } } + if (struct.isSetContainer()) { + oprot.writeFieldBegin(CONTAINER_FIELD_DESC); + oprot.writeBool(struct.container); + oprot.writeFieldEnd(); + } oprot.writeFieldStop(); oprot.writeStructEnd(); } @@ -1576,7 +1666,10 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TFAgentInfo struct) if (struct.isSetJvmInfo()) { optionals.set(13); } - oprot.writeBitSet(optionals, 14); + if (struct.isSetContainer()) { + optionals.set(14); + } + oprot.writeBitSet(optionals, 15); if (struct.isSetHostname()) { oprot.writeString(struct.hostname); } @@ -1619,12 +1712,15 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TFAgentInfo struct) if (struct.isSetJvmInfo()) { struct.jvmInfo.write(oprot); } + if (struct.isSetContainer()) { + oprot.writeBool(struct.container); + } } @Override public void read(org.apache.thrift.protocol.TProtocol prot, TFAgentInfo struct) throws org.apache.thrift.TException { org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; - java.util.BitSet incoming = iprot.readBitSet(14); + java.util.BitSet incoming = iprot.readBitSet(15); if (incoming.get(0)) { struct.hostname = iprot.readString(); struct.setHostnameIsSet(true); @@ -1683,6 +1779,10 @@ public void read(org.apache.thrift.protocol.TProtocol prot, TFAgentInfo struct) struct.jvmInfo.read(iprot); struct.setJvmInfoIsSet(true); } + if (incoming.get(14)) { + struct.container = iprot.readBool(); + struct.setContainerIsSet(true); + } } } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentStat.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentStat.java index 0761e2514a36..55c6b58b7501 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentStat.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentStat.java @@ -1,5 +1,5 @@ /** - * Autogenerated by Thrift Compiler (0.10.0) + * Autogenerated by Thrift Compiler (0.11.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -7,7 +7,7 @@ package com.navercorp.pinpoint.thrift.dto.flink; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-09-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-03-27") public class TFAgentStat implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TFAgentStat"); @@ -21,6 +21,8 @@ public class TFAgentStat implements org.apache.thrift.TBase byName = new java.util.HashMap(); @@ -85,6 +91,10 @@ public static _Fields findByThriftId(int fieldId) { return DATA_SOURCE_LIST; case 60: // RESPONSE_TIME return RESPONSE_TIME; + case 80: // FILE_DESCRIPTOR + return FILE_DESCRIPTOR; + case 90: // DIRECT_BUFFER + return DIRECT_BUFFER; case 200: // METADATA return METADATA; default: @@ -131,7 +141,7 @@ public java.lang.String getFieldName() { private static final int __TIMESTAMP_ISSET_ID = 1; private static final int __COLLECTINTERVAL_ISSET_ID = 2; private byte __isset_bitfield = 0; - private static final _Fields optionals[] = {_Fields.AGENT_ID,_Fields.START_TIMESTAMP,_Fields.TIMESTAMP,_Fields.COLLECT_INTERVAL,_Fields.GC,_Fields.CPU_LOAD,_Fields.TRANSACTION,_Fields.ACTIVE_TRACE,_Fields.DATA_SOURCE_LIST,_Fields.RESPONSE_TIME,_Fields.METADATA}; + private static final _Fields optionals[] = {_Fields.AGENT_ID,_Fields.START_TIMESTAMP,_Fields.TIMESTAMP,_Fields.COLLECT_INTERVAL,_Fields.GC,_Fields.CPU_LOAD,_Fields.TRANSACTION,_Fields.ACTIVE_TRACE,_Fields.DATA_SOURCE_LIST,_Fields.RESPONSE_TIME,_Fields.FILE_DESCRIPTOR,_Fields.DIRECT_BUFFER,_Fields.METADATA}; public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; static { java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); @@ -155,7 +165,11 @@ public java.lang.String getFieldName() { new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT , "TFDataSourceList"))); tmpMap.put(_Fields.RESPONSE_TIME, new org.apache.thrift.meta_data.FieldMetaData("responseTime", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TFResponseTime.class))); - tmpMap.put(_Fields.METADATA, new org.apache.thrift.meta_data.FieldMetaData("metadata", org.apache.thrift.TFieldRequirementType.OPTIONAL, + tmpMap.put(_Fields.FILE_DESCRIPTOR, new org.apache.thrift.meta_data.FieldMetaData("fileDescriptor", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT , "TFFileDescriptor"))); + tmpMap.put(_Fields.DIRECT_BUFFER, new org.apache.thrift.meta_data.FieldMetaData("directBuffer", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, TFDirectBuffer.class))); + tmpMap.put(_Fields.METADATA, new org.apache.thrift.meta_data.FieldMetaData("metadata", org.apache.thrift.TFieldRequirementType.OPTIONAL, new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TFAgentStat.class, metaDataMap); @@ -193,6 +207,12 @@ public TFAgentStat(TFAgentStat other) { if (other.isSetResponseTime()) { this.responseTime = new TFResponseTime(other.responseTime); } + if (other.isSetFileDescriptor()) { + this.fileDescriptor = new TFFileDescriptor(other.fileDescriptor); + } + if (other.isSetDirectBuffer()) { + this.directBuffer = new TFDirectBuffer(other.directBuffer); + } if (other.isSetMetadata()) { this.metadata = other.metadata; } @@ -217,6 +237,8 @@ public void clear() { this.activeTrace = null; this.dataSourceList = null; this.responseTime = null; + this.fileDescriptor = null; + this.directBuffer = null; this.metadata = null; } @@ -447,6 +469,52 @@ public void setResponseTimeIsSet(boolean value) { } } + public TFFileDescriptor getFileDescriptor() { + return this.fileDescriptor; + } + + public void setFileDescriptor(TFFileDescriptor fileDescriptor) { + this.fileDescriptor = fileDescriptor; + } + + public void unsetFileDescriptor() { + this.fileDescriptor = null; + } + + /** Returns true if field fileDescriptor is set (has been assigned a value) and false otherwise */ + public boolean isSetFileDescriptor() { + return this.fileDescriptor != null; + } + + public void setFileDescriptorIsSet(boolean value) { + if (!value) { + this.fileDescriptor = null; + } + } + + public TFDirectBuffer getDirectBuffer() { + return this.directBuffer; + } + + public void setDirectBuffer(TFDirectBuffer directBuffer) { + this.directBuffer = directBuffer; + } + + public void unsetDirectBuffer() { + this.directBuffer = null; + } + + /** Returns true if field directBuffer is set (has been assigned a value) and false otherwise */ + public boolean isSetDirectBuffer() { + return this.directBuffer != null; + } + + public void setDirectBufferIsSet(boolean value) { + if (!value) { + this.directBuffer = null; + } + } + public java.lang.String getMetadata() { return this.metadata; } @@ -552,6 +620,22 @@ public void setFieldValue(_Fields field, java.lang.Object value) { } break; + case FILE_DESCRIPTOR: + if (value == null) { + unsetFileDescriptor(); + } else { + setFileDescriptor((TFFileDescriptor)value); + } + break; + + case DIRECT_BUFFER: + if (value == null) { + unsetDirectBuffer(); + } else { + setDirectBuffer((TFDirectBuffer)value); + } + break; + case METADATA: if (value == null) { unsetMetadata(); @@ -595,6 +679,12 @@ public java.lang.Object getFieldValue(_Fields field) { case RESPONSE_TIME: return getResponseTime(); + case FILE_DESCRIPTOR: + return getFileDescriptor(); + + case DIRECT_BUFFER: + return getDirectBuffer(); + case METADATA: return getMetadata(); @@ -629,6 +719,10 @@ public boolean isSet(_Fields field) { return isSetDataSourceList(); case RESPONSE_TIME: return isSetResponseTime(); + case FILE_DESCRIPTOR: + return isSetFileDescriptor(); + case DIRECT_BUFFER: + return isSetDirectBuffer(); case METADATA: return isSetMetadata(); } @@ -740,6 +834,24 @@ public boolean equals(TFAgentStat that) { return false; } + boolean this_present_fileDescriptor = true && this.isSetFileDescriptor(); + boolean that_present_fileDescriptor = true && that.isSetFileDescriptor(); + if (this_present_fileDescriptor || that_present_fileDescriptor) { + if (!(this_present_fileDescriptor && that_present_fileDescriptor)) + return false; + if (!this.fileDescriptor.equals(that.fileDescriptor)) + return false; + } + + boolean this_present_directBuffer = true && this.isSetDirectBuffer(); + boolean that_present_directBuffer = true && that.isSetDirectBuffer(); + if (this_present_directBuffer || that_present_directBuffer) { + if (!(this_present_directBuffer && that_present_directBuffer)) + return false; + if (!this.directBuffer.equals(that.directBuffer)) + return false; + } + boolean this_present_metadata = true && this.isSetMetadata(); boolean that_present_metadata = true && that.isSetMetadata(); if (this_present_metadata || that_present_metadata) { @@ -796,6 +908,14 @@ public int hashCode() { if (isSetResponseTime()) hashCode = hashCode * 8191 + responseTime.hashCode(); + hashCode = hashCode * 8191 + ((isSetFileDescriptor()) ? 131071 : 524287); + if (isSetFileDescriptor()) + hashCode = hashCode * 8191 + fileDescriptor.hashCode(); + + hashCode = hashCode * 8191 + ((isSetDirectBuffer()) ? 131071 : 524287); + if (isSetDirectBuffer()) + hashCode = hashCode * 8191 + directBuffer.hashCode(); + hashCode = hashCode * 8191 + ((isSetMetadata()) ? 131071 : 524287); if (isSetMetadata()) hashCode = hashCode * 8191 + metadata.hashCode(); @@ -911,6 +1031,26 @@ public int compareTo(TFAgentStat other) { return lastComparison; } } + lastComparison = java.lang.Boolean.valueOf(isSetFileDescriptor()).compareTo(other.isSetFileDescriptor()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetFileDescriptor()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.fileDescriptor, other.fileDescriptor); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetDirectBuffer()).compareTo(other.isSetDirectBuffer()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetDirectBuffer()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.directBuffer, other.directBuffer); + if (lastComparison != 0) { + return lastComparison; + } + } lastComparison = java.lang.Boolean.valueOf(isSetMetadata()).compareTo(other.isSetMetadata()); if (lastComparison != 0) { return lastComparison; @@ -1028,6 +1168,26 @@ public java.lang.String toString() { } first = false; } + if (isSetFileDescriptor()) { + if (!first) sb.append(", "); + sb.append("fileDescriptor:"); + if (this.fileDescriptor == null) { + sb.append("null"); + } else { + sb.append(this.fileDescriptor); + } + first = false; + } + if (isSetDirectBuffer()) { + if (!first) sb.append(", "); + sb.append("directBuffer:"); + if (this.directBuffer == null) { + sb.append("null"); + } else { + sb.append(this.directBuffer); + } + first = false; + } if (isSetMetadata()) { if (!first) sb.append(", "); sb.append("metadata:"); @@ -1060,6 +1220,9 @@ public void validate() throws org.apache.thrift.TException { if (responseTime != null) { responseTime.validate(); } + if (directBuffer != null) { + directBuffer.validate(); + } } private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { @@ -1184,6 +1347,24 @@ public void read(org.apache.thrift.protocol.TProtocol iprot, TFAgentStat struct) org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); } break; + case 80: // FILE_DESCRIPTOR + if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { + struct.fileDescriptor = new TFFileDescriptor(); + struct.fileDescriptor.read(iprot); + struct.setFileDescriptorIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 90: // DIRECT_BUFFER + if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { + struct.directBuffer = new TFDirectBuffer(); + struct.directBuffer.read(iprot); + struct.setDirectBufferIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; case 200: // METADATA if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { struct.metadata = iprot.readString(); @@ -1269,6 +1450,20 @@ public void write(org.apache.thrift.protocol.TProtocol oprot, TFAgentStat struct oprot.writeFieldEnd(); } } + if (struct.fileDescriptor != null) { + if (struct.isSetFileDescriptor()) { + oprot.writeFieldBegin(FILE_DESCRIPTOR_FIELD_DESC); + struct.fileDescriptor.write(oprot); + oprot.writeFieldEnd(); + } + } + if (struct.directBuffer != null) { + if (struct.isSetDirectBuffer()) { + oprot.writeFieldBegin(DIRECT_BUFFER_FIELD_DESC); + struct.directBuffer.write(oprot); + oprot.writeFieldEnd(); + } + } if (struct.metadata != null) { if (struct.isSetMetadata()) { oprot.writeFieldBegin(METADATA_FIELD_DESC); @@ -1324,10 +1519,16 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TFAgentStat struct) if (struct.isSetResponseTime()) { optionals.set(9); } - if (struct.isSetMetadata()) { + if (struct.isSetFileDescriptor()) { optionals.set(10); } - oprot.writeBitSet(optionals, 11); + if (struct.isSetDirectBuffer()) { + optionals.set(11); + } + if (struct.isSetMetadata()) { + optionals.set(12); + } + oprot.writeBitSet(optionals, 13); if (struct.isSetAgentId()) { oprot.writeString(struct.agentId); } @@ -1358,6 +1559,12 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TFAgentStat struct) if (struct.isSetResponseTime()) { struct.responseTime.write(oprot); } + if (struct.isSetFileDescriptor()) { + struct.fileDescriptor.write(oprot); + } + if (struct.isSetDirectBuffer()) { + struct.directBuffer.write(oprot); + } if (struct.isSetMetadata()) { oprot.writeString(struct.metadata); } @@ -1366,7 +1573,7 @@ public void write(org.apache.thrift.protocol.TProtocol prot, TFAgentStat struct) @Override public void read(org.apache.thrift.protocol.TProtocol prot, TFAgentStat struct) throws org.apache.thrift.TException { org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; - java.util.BitSet incoming = iprot.readBitSet(11); + java.util.BitSet incoming = iprot.readBitSet(13); if (incoming.get(0)) { struct.agentId = iprot.readString(); struct.setAgentIdIsSet(true); @@ -1414,6 +1621,16 @@ public void read(org.apache.thrift.protocol.TProtocol prot, TFAgentStat struct) struct.setResponseTimeIsSet(true); } if (incoming.get(10)) { + struct.fileDescriptor = new TFFileDescriptor(); + struct.fileDescriptor.read(iprot); + struct.setFileDescriptorIsSet(true); + } + if (incoming.get(11)) { + struct.directBuffer = new TFDirectBuffer(); + struct.directBuffer.read(iprot); + struct.setDirectBufferIsSet(true); + } + if (incoming.get(12)) { struct.metadata = iprot.readString(); struct.setMetadataIsSet(true); } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentStatBatch.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentStatBatch.java index 5cc45c7d6665..aff6854f6f39 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentStatBatch.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFAgentStatBatch.java @@ -1,5 +1,5 @@ /** - * Autogenerated by Thrift Compiler (0.10.0) + * Autogenerated by Thrift Compiler (0.11.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -7,7 +7,7 @@ package com.navercorp.pinpoint.thrift.dto.flink; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.10.0)", date = "2017-09-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-02-12") public class TFAgentStatBatch implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TFAgentStatBatch"); diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFDirectBuffer.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFDirectBuffer.java new file mode 100644 index 000000000000..6a688711ea0d --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFDirectBuffer.java @@ -0,0 +1,658 @@ +/** + * Autogenerated by Thrift Compiler (0.11.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package com.navercorp.pinpoint.thrift.dto.flink; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-03-23") +public class TFDirectBuffer implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TFDirectBuffer"); + + private static final org.apache.thrift.protocol.TField DIRECT_COUNT_FIELD_DESC = new org.apache.thrift.protocol.TField("directCount", org.apache.thrift.protocol.TType.I64, (short)1); + private static final org.apache.thrift.protocol.TField DIRECT_MEMORY_USED_FIELD_DESC = new org.apache.thrift.protocol.TField("directMemoryUsed", org.apache.thrift.protocol.TType.I64, (short)2); + private static final org.apache.thrift.protocol.TField MAPPED_COUNT_FIELD_DESC = new org.apache.thrift.protocol.TField("mappedCount", org.apache.thrift.protocol.TType.I64, (short)3); + private static final org.apache.thrift.protocol.TField MAPPED_MEMORY_USED_FIELD_DESC = new org.apache.thrift.protocol.TField("mappedMemoryUsed", org.apache.thrift.protocol.TType.I64, (short)4); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new TFDirectBufferStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new TFDirectBufferTupleSchemeFactory(); + + private long directCount; // optional + private long directMemoryUsed; // optional + private long mappedCount; // optional + private long mappedMemoryUsed; // optional + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + DIRECT_COUNT((short)1, "directCount"), + DIRECT_MEMORY_USED((short)2, "directMemoryUsed"), + MAPPED_COUNT((short)3, "mappedCount"), + MAPPED_MEMORY_USED((short)4, "mappedMemoryUsed"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // DIRECT_COUNT + return DIRECT_COUNT; + case 2: // DIRECT_MEMORY_USED + return DIRECT_MEMORY_USED; + case 3: // MAPPED_COUNT + return MAPPED_COUNT; + case 4: // MAPPED_MEMORY_USED + return MAPPED_MEMORY_USED; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + private static final int __DIRECTCOUNT_ISSET_ID = 0; + private static final int __DIRECTMEMORYUSED_ISSET_ID = 1; + private static final int __MAPPEDCOUNT_ISSET_ID = 2; + private static final int __MAPPEDMEMORYUSED_ISSET_ID = 3; + private byte __isset_bitfield = 0; + private static final _Fields optionals[] = {_Fields.DIRECT_COUNT,_Fields.DIRECT_MEMORY_USED,_Fields.MAPPED_COUNT,_Fields.MAPPED_MEMORY_USED}; + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.DIRECT_COUNT, new org.apache.thrift.meta_data.FieldMetaData("directCount", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + tmpMap.put(_Fields.DIRECT_MEMORY_USED, new org.apache.thrift.meta_data.FieldMetaData("directMemoryUsed", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + tmpMap.put(_Fields.MAPPED_COUNT, new org.apache.thrift.meta_data.FieldMetaData("mappedCount", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + tmpMap.put(_Fields.MAPPED_MEMORY_USED, new org.apache.thrift.meta_data.FieldMetaData("mappedMemoryUsed", org.apache.thrift.TFieldRequirementType.OPTIONAL, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TFDirectBuffer.class, metaDataMap); + } + + public TFDirectBuffer() { + } + + /** + * Performs a deep copy on other. + */ + public TFDirectBuffer(TFDirectBuffer other) { + __isset_bitfield = other.__isset_bitfield; + this.directCount = other.directCount; + this.directMemoryUsed = other.directMemoryUsed; + this.mappedCount = other.mappedCount; + this.mappedMemoryUsed = other.mappedMemoryUsed; + } + + public TFDirectBuffer deepCopy() { + return new TFDirectBuffer(this); + } + + @Override + public void clear() { + setDirectCountIsSet(false); + this.directCount = 0; + setDirectMemoryUsedIsSet(false); + this.directMemoryUsed = 0; + setMappedCountIsSet(false); + this.mappedCount = 0; + setMappedMemoryUsedIsSet(false); + this.mappedMemoryUsed = 0; + } + + public long getDirectCount() { + return this.directCount; + } + + public void setDirectCount(long directCount) { + this.directCount = directCount; + setDirectCountIsSet(true); + } + + public void unsetDirectCount() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __DIRECTCOUNT_ISSET_ID); + } + + /** Returns true if field directCount is set (has been assigned a value) and false otherwise */ + public boolean isSetDirectCount() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __DIRECTCOUNT_ISSET_ID); + } + + public void setDirectCountIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __DIRECTCOUNT_ISSET_ID, value); + } + + public long getDirectMemoryUsed() { + return this.directMemoryUsed; + } + + public void setDirectMemoryUsed(long directMemoryUsed) { + this.directMemoryUsed = directMemoryUsed; + setDirectMemoryUsedIsSet(true); + } + + public void unsetDirectMemoryUsed() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __DIRECTMEMORYUSED_ISSET_ID); + } + + /** Returns true if field directMemoryUsed is set (has been assigned a value) and false otherwise */ + public boolean isSetDirectMemoryUsed() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __DIRECTMEMORYUSED_ISSET_ID); + } + + public void setDirectMemoryUsedIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __DIRECTMEMORYUSED_ISSET_ID, value); + } + + public long getMappedCount() { + return this.mappedCount; + } + + public void setMappedCount(long mappedCount) { + this.mappedCount = mappedCount; + setMappedCountIsSet(true); + } + + public void unsetMappedCount() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __MAPPEDCOUNT_ISSET_ID); + } + + /** Returns true if field mappedCount is set (has been assigned a value) and false otherwise */ + public boolean isSetMappedCount() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __MAPPEDCOUNT_ISSET_ID); + } + + public void setMappedCountIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __MAPPEDCOUNT_ISSET_ID, value); + } + + public long getMappedMemoryUsed() { + return this.mappedMemoryUsed; + } + + public void setMappedMemoryUsed(long mappedMemoryUsed) { + this.mappedMemoryUsed = mappedMemoryUsed; + setMappedMemoryUsedIsSet(true); + } + + public void unsetMappedMemoryUsed() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __MAPPEDMEMORYUSED_ISSET_ID); + } + + /** Returns true if field mappedMemoryUsed is set (has been assigned a value) and false otherwise */ + public boolean isSetMappedMemoryUsed() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __MAPPEDMEMORYUSED_ISSET_ID); + } + + public void setMappedMemoryUsedIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __MAPPEDMEMORYUSED_ISSET_ID, value); + } + + public void setFieldValue(_Fields field, java.lang.Object value) { + switch (field) { + case DIRECT_COUNT: + if (value == null) { + unsetDirectCount(); + } else { + setDirectCount((java.lang.Long)value); + } + break; + + case DIRECT_MEMORY_USED: + if (value == null) { + unsetDirectMemoryUsed(); + } else { + setDirectMemoryUsed((java.lang.Long)value); + } + break; + + case MAPPED_COUNT: + if (value == null) { + unsetMappedCount(); + } else { + setMappedCount((java.lang.Long)value); + } + break; + + case MAPPED_MEMORY_USED: + if (value == null) { + unsetMappedMemoryUsed(); + } else { + setMappedMemoryUsed((java.lang.Long)value); + } + break; + + } + } + + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case DIRECT_COUNT: + return getDirectCount(); + + case DIRECT_MEMORY_USED: + return getDirectMemoryUsed(); + + case MAPPED_COUNT: + return getMappedCount(); + + case MAPPED_MEMORY_USED: + return getMappedMemoryUsed(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case DIRECT_COUNT: + return isSetDirectCount(); + case DIRECT_MEMORY_USED: + return isSetDirectMemoryUsed(); + case MAPPED_COUNT: + return isSetMappedCount(); + case MAPPED_MEMORY_USED: + return isSetMappedMemoryUsed(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that == null) + return false; + if (that instanceof TFDirectBuffer) + return this.equals((TFDirectBuffer)that); + return false; + } + + public boolean equals(TFDirectBuffer that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_directCount = true && this.isSetDirectCount(); + boolean that_present_directCount = true && that.isSetDirectCount(); + if (this_present_directCount || that_present_directCount) { + if (!(this_present_directCount && that_present_directCount)) + return false; + if (this.directCount != that.directCount) + return false; + } + + boolean this_present_directMemoryUsed = true && this.isSetDirectMemoryUsed(); + boolean that_present_directMemoryUsed = true && that.isSetDirectMemoryUsed(); + if (this_present_directMemoryUsed || that_present_directMemoryUsed) { + if (!(this_present_directMemoryUsed && that_present_directMemoryUsed)) + return false; + if (this.directMemoryUsed != that.directMemoryUsed) + return false; + } + + boolean this_present_mappedCount = true && this.isSetMappedCount(); + boolean that_present_mappedCount = true && that.isSetMappedCount(); + if (this_present_mappedCount || that_present_mappedCount) { + if (!(this_present_mappedCount && that_present_mappedCount)) + return false; + if (this.mappedCount != that.mappedCount) + return false; + } + + boolean this_present_mappedMemoryUsed = true && this.isSetMappedMemoryUsed(); + boolean that_present_mappedMemoryUsed = true && that.isSetMappedMemoryUsed(); + if (this_present_mappedMemoryUsed || that_present_mappedMemoryUsed) { + if (!(this_present_mappedMemoryUsed && that_present_mappedMemoryUsed)) + return false; + if (this.mappedMemoryUsed != that.mappedMemoryUsed) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetDirectCount()) ? 131071 : 524287); + if (isSetDirectCount()) + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(directCount); + + hashCode = hashCode * 8191 + ((isSetDirectMemoryUsed()) ? 131071 : 524287); + if (isSetDirectMemoryUsed()) + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(directMemoryUsed); + + hashCode = hashCode * 8191 + ((isSetMappedCount()) ? 131071 : 524287); + if (isSetMappedCount()) + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(mappedCount); + + hashCode = hashCode * 8191 + ((isSetMappedMemoryUsed()) ? 131071 : 524287); + if (isSetMappedMemoryUsed()) + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(mappedMemoryUsed); + + return hashCode; + } + + @Override + public int compareTo(TFDirectBuffer other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.valueOf(isSetDirectCount()).compareTo(other.isSetDirectCount()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetDirectCount()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.directCount, other.directCount); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetDirectMemoryUsed()).compareTo(other.isSetDirectMemoryUsed()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetDirectMemoryUsed()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.directMemoryUsed, other.directMemoryUsed); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetMappedCount()).compareTo(other.isSetMappedCount()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetMappedCount()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.mappedCount, other.mappedCount); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetMappedMemoryUsed()).compareTo(other.isSetMappedMemoryUsed()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetMappedMemoryUsed()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.mappedMemoryUsed, other.mappedMemoryUsed); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("TFDirectBuffer("); + boolean first = true; + + if (isSetDirectCount()) { + sb.append("directCount:"); + sb.append(this.directCount); + first = false; + } + if (isSetDirectMemoryUsed()) { + if (!first) sb.append(", "); + sb.append("directMemoryUsed:"); + sb.append(this.directMemoryUsed); + first = false; + } + if (isSetMappedCount()) { + if (!first) sb.append(", "); + sb.append("mappedCount:"); + sb.append(this.mappedCount); + first = false; + } + if (isSetMappedMemoryUsed()) { + if (!first) sb.append(", "); + sb.append("mappedMemoryUsed:"); + sb.append(this.mappedMemoryUsed); + first = false; + } + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. + __isset_bitfield = 0; + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class TFDirectBufferStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TFDirectBufferStandardScheme getScheme() { + return new TFDirectBufferStandardScheme(); + } + } + + private static class TFDirectBufferStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, TFDirectBuffer struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // DIRECT_COUNT + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.directCount = iprot.readI64(); + struct.setDirectCountIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // DIRECT_MEMORY_USED + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.directMemoryUsed = iprot.readI64(); + struct.setDirectMemoryUsedIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 3: // MAPPED_COUNT + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.mappedCount = iprot.readI64(); + struct.setMappedCountIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 4: // MAPPED_MEMORY_USED + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.mappedMemoryUsed = iprot.readI64(); + struct.setMappedMemoryUsedIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, TFDirectBuffer struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.isSetDirectCount()) { + oprot.writeFieldBegin(DIRECT_COUNT_FIELD_DESC); + oprot.writeI64(struct.directCount); + oprot.writeFieldEnd(); + } + if (struct.isSetDirectMemoryUsed()) { + oprot.writeFieldBegin(DIRECT_MEMORY_USED_FIELD_DESC); + oprot.writeI64(struct.directMemoryUsed); + oprot.writeFieldEnd(); + } + if (struct.isSetMappedCount()) { + oprot.writeFieldBegin(MAPPED_COUNT_FIELD_DESC); + oprot.writeI64(struct.mappedCount); + oprot.writeFieldEnd(); + } + if (struct.isSetMappedMemoryUsed()) { + oprot.writeFieldBegin(MAPPED_MEMORY_USED_FIELD_DESC); + oprot.writeI64(struct.mappedMemoryUsed); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class TFDirectBufferTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TFDirectBufferTupleScheme getScheme() { + return new TFDirectBufferTupleScheme(); + } + } + + private static class TFDirectBufferTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, TFDirectBuffer struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetDirectCount()) { + optionals.set(0); + } + if (struct.isSetDirectMemoryUsed()) { + optionals.set(1); + } + if (struct.isSetMappedCount()) { + optionals.set(2); + } + if (struct.isSetMappedMemoryUsed()) { + optionals.set(3); + } + oprot.writeBitSet(optionals, 4); + if (struct.isSetDirectCount()) { + oprot.writeI64(struct.directCount); + } + if (struct.isSetDirectMemoryUsed()) { + oprot.writeI64(struct.directMemoryUsed); + } + if (struct.isSetMappedCount()) { + oprot.writeI64(struct.mappedCount); + } + if (struct.isSetMappedMemoryUsed()) { + oprot.writeI64(struct.mappedMemoryUsed); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, TFDirectBuffer struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(4); + if (incoming.get(0)) { + struct.directCount = iprot.readI64(); + struct.setDirectCountIsSet(true); + } + if (incoming.get(1)) { + struct.directMemoryUsed = iprot.readI64(); + struct.setDirectMemoryUsedIsSet(true); + } + if (incoming.get(2)) { + struct.mappedCount = iprot.readI64(); + struct.setMappedCountIsSet(true); + } + if (incoming.get(3)) { + struct.mappedMemoryUsed = iprot.readI64(); + struct.setMappedMemoryUsedIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } +} + diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFDirectBufferType.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFDirectBufferType.java new file mode 100644 index 000000000000..818efbd11f3b --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFDirectBufferType.java @@ -0,0 +1,44 @@ +/** + * Autogenerated by Thrift Compiler (0.11.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package com.navercorp.pinpoint.thrift.dto.flink; + + +public enum TFDirectBufferType implements org.apache.thrift.TEnum { + UNKNOWN(0), + DIRECT(1), + MAPPED(2); + + private final int value; + + private TFDirectBufferType(int value) { + this.value = value; + } + + /** + * Get the integer value of this enum value, as defined in the Thrift IDL. + */ + public int getValue() { + return value; + } + + /** + * Find a the enum type by its integer value, as defined in the Thrift IDL. + * @return null if the value is not found. + */ + public static TFDirectBufferType findByValue(int value) { + switch (value) { + case 0: + return UNKNOWN; + case 1: + return DIRECT; + case 2: + return MAPPED; + default: + return null; + } + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFFileDescriptor.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFFileDescriptor.java new file mode 100644 index 000000000000..0013380aae37 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/dto/flink/TFFileDescriptor.java @@ -0,0 +1,365 @@ +/** + * Autogenerated by Thrift Compiler (0.11.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package com.navercorp.pinpoint.thrift.dto.flink; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-02-12") +public class TFFileDescriptor implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TFFileDescriptor"); + + private static final org.apache.thrift.protocol.TField OPEN_FILE_DESCRIPTOR_COUNT_FIELD_DESC = new org.apache.thrift.protocol.TField("openFileDescriptorCount", org.apache.thrift.protocol.TType.I64, (short)1); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new TFFileDescriptorStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new TFFileDescriptorTupleSchemeFactory(); + + private long openFileDescriptorCount; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + OPEN_FILE_DESCRIPTOR_COUNT((short)1, "openFileDescriptorCount"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // OPEN_FILE_DESCRIPTOR_COUNT + return OPEN_FILE_DESCRIPTOR_COUNT; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + private static final int __OPENFILEDESCRIPTORCOUNT_ISSET_ID = 0; + private byte __isset_bitfield = 0; + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.OPEN_FILE_DESCRIPTOR_COUNT, new org.apache.thrift.meta_data.FieldMetaData("openFileDescriptorCount", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TFFileDescriptor.class, metaDataMap); + } + + public TFFileDescriptor() { + } + + public TFFileDescriptor( + long openFileDescriptorCount) + { + this(); + this.openFileDescriptorCount = openFileDescriptorCount; + setOpenFileDescriptorCountIsSet(true); + } + + /** + * Performs a deep copy on other. + */ + public TFFileDescriptor(TFFileDescriptor other) { + __isset_bitfield = other.__isset_bitfield; + this.openFileDescriptorCount = other.openFileDescriptorCount; + } + + public TFFileDescriptor deepCopy() { + return new TFFileDescriptor(this); + } + + @Override + public void clear() { + setOpenFileDescriptorCountIsSet(false); + this.openFileDescriptorCount = 0; + } + + public long getOpenFileDescriptorCount() { + return this.openFileDescriptorCount; + } + + public void setOpenFileDescriptorCount(long openFileDescriptorCount) { + this.openFileDescriptorCount = openFileDescriptorCount; + setOpenFileDescriptorCountIsSet(true); + } + + public void unsetOpenFileDescriptorCount() { + __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __OPENFILEDESCRIPTORCOUNT_ISSET_ID); + } + + /** Returns true if field openFileDescriptorCount is set (has been assigned a value) and false otherwise */ + public boolean isSetOpenFileDescriptorCount() { + return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __OPENFILEDESCRIPTORCOUNT_ISSET_ID); + } + + public void setOpenFileDescriptorCountIsSet(boolean value) { + __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __OPENFILEDESCRIPTORCOUNT_ISSET_ID, value); + } + + public void setFieldValue(_Fields field, java.lang.Object value) { + switch (field) { + case OPEN_FILE_DESCRIPTOR_COUNT: + if (value == null) { + unsetOpenFileDescriptorCount(); + } else { + setOpenFileDescriptorCount((java.lang.Long)value); + } + break; + + } + } + + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case OPEN_FILE_DESCRIPTOR_COUNT: + return getOpenFileDescriptorCount(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case OPEN_FILE_DESCRIPTOR_COUNT: + return isSetOpenFileDescriptorCount(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that == null) + return false; + if (that instanceof TFFileDescriptor) + return this.equals((TFFileDescriptor)that); + return false; + } + + public boolean equals(TFFileDescriptor that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_openFileDescriptorCount = true; + boolean that_present_openFileDescriptorCount = true; + if (this_present_openFileDescriptorCount || that_present_openFileDescriptorCount) { + if (!(this_present_openFileDescriptorCount && that_present_openFileDescriptorCount)) + return false; + if (this.openFileDescriptorCount != that.openFileDescriptorCount) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + org.apache.thrift.TBaseHelper.hashCode(openFileDescriptorCount); + + return hashCode; + } + + @Override + public int compareTo(TFFileDescriptor other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.valueOf(isSetOpenFileDescriptorCount()).compareTo(other.isSetOpenFileDescriptorCount()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetOpenFileDescriptorCount()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.openFileDescriptorCount, other.openFileDescriptorCount); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("TFFileDescriptor("); + boolean first = true; + + sb.append("openFileDescriptorCount:"); + sb.append(this.openFileDescriptorCount); + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor. + __isset_bitfield = 0; + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class TFFileDescriptorStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TFFileDescriptorStandardScheme getScheme() { + return new TFFileDescriptorStandardScheme(); + } + } + + private static class TFFileDescriptorStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, TFFileDescriptor struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // OPEN_FILE_DESCRIPTOR_COUNT + if (schemeField.type == org.apache.thrift.protocol.TType.I64) { + struct.openFileDescriptorCount = iprot.readI64(); + struct.setOpenFileDescriptorCountIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, TFFileDescriptor struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + oprot.writeFieldBegin(OPEN_FILE_DESCRIPTOR_COUNT_FIELD_DESC); + oprot.writeI64(struct.openFileDescriptorCount); + oprot.writeFieldEnd(); + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class TFFileDescriptorTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public TFFileDescriptorTupleScheme getScheme() { + return new TFFileDescriptorTupleScheme(); + } + } + + private static class TFFileDescriptorTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, TFFileDescriptor struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetOpenFileDescriptorCount()) { + optionals.set(0); + } + oprot.writeBitSet(optionals, 1); + if (struct.isSetOpenFileDescriptorCount()) { + oprot.writeI64(struct.openFileDescriptorCount); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, TFFileDescriptor struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(1); + if (incoming.get(0)) { + struct.openFileDescriptorCount = iprot.readI64(); + struct.setOpenFileDescriptorCountIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } +} + diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventHeaderTBaseDeserializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventHeaderTBaseDeserializerFactory.java index bd829f295b07..6319c250e953 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventHeaderTBaseDeserializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventHeaderTBaseDeserializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,8 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; +import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; @@ -26,7 +28,7 @@ public class AgentEventHeaderTBaseDeserializerFactory implements DeserializerFac private static final TProtocolFactory DEFAULT_PROTOCOL_FACTORY = new TCompactProtocol.Factory(); private final TProtocolFactory protocolFactory; - private final TBaseLocator locator = new AgentEventTBaseLocator(); + private final TypeLocator> locator = AgentEventTBaseLocator.getTypeLocator(); public AgentEventHeaderTBaseDeserializerFactory() { this(DEFAULT_PROTOCOL_FACTORY); diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventHeaderTBaseSerializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventHeaderTBaseSerializerFactory.java index 1debf23670ec..1489fc41164e 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventHeaderTBaseSerializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventHeaderTBaseSerializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; @@ -27,7 +28,7 @@ public class AgentEventHeaderTBaseSerializerFactory implements SerializerFactory public static final int DEFAULT_SERIALIZER_MAX_SIZE = 1024 * 64; - private final TBaseLocator tBaseLocator; + private final TypeLocator> tBaseLocator; private final SerializerFactory factory; public AgentEventHeaderTBaseSerializerFactory() { @@ -35,7 +36,7 @@ public AgentEventHeaderTBaseSerializerFactory() { } public AgentEventHeaderTBaseSerializerFactory(int outputStreamSize) { - TBaseLocator agentEventTBaseLocator = new AgentEventTBaseLocator(); + TypeLocator> agentEventTBaseLocator = AgentEventTBaseLocator.getTypeLocator(); TProtocolFactory protocolFactory = new TCompactProtocol.Factory(); HeaderTBaseSerializerFactory serializerFactory = new HeaderTBaseSerializerFactory(true, outputStreamSize, protocolFactory, agentEventTBaseLocator); @@ -51,8 +52,8 @@ public HeaderTBaseSerializer createSerializer() { @Override public boolean isSupport(Object target) { - if (target instanceof TBase) { - return tBaseLocator.isSupport((Class) target.getClass()); + if (target instanceof TBase) { + return tBaseLocator.isSupport((Class>) target.getClass()); } return false; diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventTBaseLocator.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventTBaseLocator.java index 9afb93682f2f..1f892f8260ca 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventTBaseLocator.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/AgentEventTBaseLocator.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,11 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; +import com.navercorp.pinpoint.io.util.BodyFactory; +import com.navercorp.pinpoint.io.util.TypeLocator; +import com.navercorp.pinpoint.io.util.TypeLocatorBuilder; import com.navercorp.pinpoint.thrift.dto.TDeadlock; import org.apache.thrift.TBase; import org.apache.thrift.TException; @@ -23,66 +28,30 @@ /** * @author Taejin Koo */ -public class AgentEventTBaseLocator implements TBaseLocator { +public class AgentEventTBaseLocator { private static final short DEADLOCK = 910; - private static final Header DEADLOCK_HEADER = createHeader(DEADLOCK); - private static Header createHeader(short type) { - Header header = new Header(); - header.setType(type); - return header; - } - - @Override - public TBase tBaseLookup(short type) throws TException { - switch (type) { - case DEADLOCK: - return new TDeadlock(); - } - throw new TException("Unsupported type:" + type); - } + private static final TypeLocator> typeLocator = build(); - public Header headerLookup(TBase tbase) throws TException { - if (tbase == null) { - throw new IllegalArgumentException("tbase must not be null"); - } - if (tbase instanceof TDeadlock) { - return DEADLOCK_HEADER; - } + public static TypeLocator>build() { - throw new TException("Unsupported Type" + tbase.getClass()); + TypeLocatorBuilder> builder = new TypeLocatorBuilder>(); + addBodyFactory(builder); + return builder.build(); } - @Override - public boolean isSupport(short type) { - try { - tBaseLookup(type); - return true; - } catch (TException ignore) { - // skip - } - - return false; - } - - @Override - public boolean isSupport(Class clazz) { - if (clazz.equals(TDeadlock.class)) { - return true; - } - - return false; - } + public static void addBodyFactory(TypeLocatorBuilder> builder) { + builder.addBodyFactory(DEADLOCK, new BodyFactory>() { + @Override + public TBase getObject() { + return new TDeadlock(); + } + }); - @Override - public Header getChunkHeader() { - return null; } - @Override - public boolean isChunkHeader(short type) { - return false; + public static TypeLocator> getTypeLocator() { + return typeLocator; } - } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializer.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializer.java index a6953f26bd9a..681f1183600f 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializer.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializer.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,6 +19,9 @@ import java.io.ByteArrayOutputStream; import java.util.List; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.apache.thrift.protocol.TProtocol; @@ -42,7 +45,7 @@ public class ChunkHeaderBufferedTBaseSerializer { // span event list serialized buffer private final TBaseStream eventStream; // header - private final TBaseLocator locator; + private final TypeLocator> locator; private final TProtocolFactory protocolFactory; private final ByteArrayOutputStreamTransport transport; @@ -53,7 +56,7 @@ public class ChunkHeaderBufferedTBaseSerializer { // flush handler private ChunkHeaderBufferedTBaseSerializerFlushHandler flushHandler; - public ChunkHeaderBufferedTBaseSerializer(final ByteArrayOutputStream out, final TProtocolFactory protocolFactory, final TBaseLocator locator) { + public ChunkHeaderBufferedTBaseSerializer(final ByteArrayOutputStream out, final TProtocolFactory protocolFactory, final TypeLocator> locator) { transport = new ByteArrayOutputStreamTransport(out); eventStream = new TBaseStream(protocolFactory); @@ -124,8 +127,12 @@ private void write(final TBase base, final String fieldName, final List base) throws TException { writeChunkHeader(protocol); // write header - writeHeader(protocol, locator.headerLookup(base)); + final Header header = locator.headerLookup(base); + if (header == null) { + throw new TException("header must not be null base:" + base); + } + HeaderUtils.writeHeader(protocol, header); base.write(protocol); @@ -163,22 +174,14 @@ private void writeChunkHeader(TProtocol protocol) throws TException { } // write chunk header - writeHeader(protocol, locator.getChunkHeader()); + HeaderUtils.writeHeader(protocol, locator.headerLookup(DefaultTBaseLocator.CHUNK)); writeChunkHeader = true; } - private void writeHeader(final TProtocol protocol, final Header header) throws TException { - protocol.writeByte(header.getSignature()); - protocol.writeByte(header.getVersion()); - short type = header.getType(); - protocol.writeByte(BytesUtils.writeShort1(type)); - protocol.writeByte(BytesUtils.writeShort2(type)); - } - // flush & clear public void flush() throws TException { synchronized (transport) { - if (flushHandler != null && transport.getBufferPosition() > Header.HEADER_SIZE) { + if (flushHandler != null && transport.getBufferPosition() > Header.HEADER_PREFIX_SIZE) { flushHandler.handle(transport.getBuffer(), 0, transport.getBufferPosition()); } transport.flush(); diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializerFactory.java index 02dc1c8a3b32..c7f2cfbb366e 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; @@ -33,24 +34,24 @@ public final class ChunkHeaderBufferedTBaseSerializerFactory implements Serializ private static final int DEFAULT_STREAM_SIZE = 1024 * 8; private static final boolean DEFAULT_AUTO_EXPAND = true; - private static final TBaseLocator DEFAULT_TBASE_LOCATOR = new DefaultTBaseLocator(); + private static final TypeLocator> DEFAULT_TBASE_LOCATOR = DefaultTBaseLocator.getTypeLocator(); private static final TProtocolFactory DEFAULT_PROTOCOL_FACTORY = new TCompactProtocol.Factory(); private final boolean safetyGuaranteed; private final int outputStreamSize; private final boolean autoExpand; private final TProtocolFactory protocolFactory; - private final TBaseLocator locator; + private final TypeLocator> locator; public ChunkHeaderBufferedTBaseSerializerFactory() { this(DEFAULT_SAFE_GUARANTEED, DEFAULT_STREAM_SIZE, DEFAULT_PROTOCOL_FACTORY, DEFAULT_TBASE_LOCATOR); } - public ChunkHeaderBufferedTBaseSerializerFactory(boolean safetyGuaranteed, int outputStreamSize, TProtocolFactory protocolFactory, TBaseLocator locator) { + public ChunkHeaderBufferedTBaseSerializerFactory(boolean safetyGuaranteed, int outputStreamSize, TProtocolFactory protocolFactory, TypeLocator> locator) { this(safetyGuaranteed, outputStreamSize, DEFAULT_AUTO_EXPAND, protocolFactory, locator); } - public ChunkHeaderBufferedTBaseSerializerFactory(boolean safetyGuaranteed, int outputStreamSize, boolean autoExpand, TProtocolFactory protocolFactory, TBaseLocator locator) { + public ChunkHeaderBufferedTBaseSerializerFactory(boolean safetyGuaranteed, int outputStreamSize, boolean autoExpand, TProtocolFactory protocolFactory, TypeLocator> locator) { this.safetyGuaranteed = safetyGuaranteed; this.outputStreamSize = outputStreamSize; this.autoExpand = autoExpand; @@ -70,7 +71,7 @@ public TProtocolFactory getProtocolFactory() { return protocolFactory; } - public TBaseLocator getLocator() { + public TypeLocator> getLocator() { return locator; } @@ -88,8 +89,8 @@ public ChunkHeaderBufferedTBaseSerializer createSerializer() { @Override public boolean isSupport(Object target) { - if (target instanceof TBase) { - return locator.isSupport((Class) target.getClass()); + if (target instanceof TBase) { + return locator.isSupport((Class>) target.getClass()); } return false; diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializer.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializer.java index f2adceef1de0..906363f4edfb 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializer.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializer.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,8 +17,14 @@ package com.navercorp.pinpoint.thrift.io; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import com.navercorp.pinpoint.io.header.*; +import com.navercorp.pinpoint.io.request.DefaultMessage; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.io.request.ServerRequest; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.apache.thrift.protocol.TProtocol; @@ -34,80 +40,96 @@ public class ChunkHeaderTBaseDeserializer { private final TProtocol protocol; private final TMemoryInputTransport trans; - private final TBaseLocator locator; + private final TypeLocator> locator; - ChunkHeaderTBaseDeserializer(TProtocolFactory protocolFactory, TBaseLocator locator) { + ChunkHeaderTBaseDeserializer(TProtocolFactory protocolFactory, TypeLocator> locator) { this.trans = new TMemoryInputTransport(); this.protocol = protocolFactory.getProtocol(trans); this.locator = locator; } - public List> deserialize(byte[] bytes, int offset, int length) throws TException { - List> list = new ArrayList>(); + public List>> deserialize(byte[] bytes, int offset, int length) throws TException { + try { trans.reset(bytes, offset, length); - final Header header = readHeader(); - if(header == null) { - return list; - } - - if (locator.isChunkHeader(header.getType())) { - TBase base; - while ((base = deserialize()) != null) { - list.add(base); + Header header = readHeader(); + + if (locator.isSupport(header.getType())) { + + List>> list = new ArrayList>>(); + + while (trans.getBytesRemainingInBuffer() > 0) { + final Message> request = readInternal(); + list.add(request); + } + return list; + } else { - TBase base = deserialize(); - if (base != null) { - list.add(base); + final Message> request = readInternal(); + if (request == null) { + return Collections.emptyList(); } + List>> list = new ArrayList>>(); + list.add(request); + return list; } - } finally { trans.clear(); protocol.reset(); } - return list; } - private TBase deserialize() throws TException { - final Header header = readHeader(); - if (header == null) { - return null; - } + private Message> readInternal() throws TException { + final HeaderReader reader = newHeaderReader(); + final Header header = readHeader(reader); + final HeaderEntity headerEntity = readHeaderEntity(reader, header); + skipHeaderOffset(reader); - final int validate = validate(header); - TBase base = locator.tBaseLookup(header.getType()); + final TBase base = locator.bodyLookup(header.getType()); + if (base == null) { + throw new TException("base must not be null type:" + header.getType()); + } base.read(protocol); - return base; + return new DefaultMessage>(header, headerEntity, base); } - private int validate(Header header) throws TException { - final byte signature = header.getSignature(); - final int result = HeaderUtils.validateSignature(signature); - if (result == HeaderUtils.FAIL) { - throw new TException("Invalid Signature:" + header); - } - return result; + private Header readHeader() throws TException { + HeaderReader reader = newHeaderReader(); + Header header = readHeader(reader); + skipHeaderOffset(reader); + return header; } - private Header readHeader() throws TException { - if (trans.getBytesRemainingInBuffer() < Header.HEADER_SIZE) { - return null; - } - final byte signature = protocol.readByte(); - final byte version = protocol.readByte(); - final byte type1 = protocol.readByte(); - final byte type2 = protocol.readByte(); - final short type = bytesToShort(type1, type2); - return new Header(signature, version, type); + private void skipHeaderOffset(HeaderReader reader) { + trans.reset(trans.getBuffer(), reader.getOffset(), reader.getRemaining()); } - private short bytesToShort(final byte byte1, final byte byte2) { - return (short) (((byte1 & 0xff) << 8) | ((byte2 & 0xff))); + private ByteArrayHeaderReader newHeaderReader() { + byte[] buffer = trans.getBuffer(); + int bufferPosition = trans.getBufferPosition(); + int bytesRemainingInBuffer = trans.getBytesRemainingInBuffer(); + return new ByteArrayHeaderReader(buffer, bufferPosition, bytesRemainingInBuffer); } + + private Header readHeader(HeaderReader reader) throws TException { + try { + return reader.readHeader(); + } catch (InvalidHeaderException e) { + throw new TException("invalid header Caused by:" + e.getMessage(), e); + } + } + + private HeaderEntity readHeaderEntity(HeaderReader reader, Header header) throws TException { + try { + return reader.readHeaderEntity(header); + } catch (InvalidHeaderException e) { + throw new TException("invalid headerEntity Caused by:" + e.getMessage(), e); + } + } + } \ No newline at end of file diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializerFactory.java index f4c12885b227..4830ea4782a7 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,8 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; +import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; @@ -24,20 +26,20 @@ */ public final class ChunkHeaderTBaseDeserializerFactory implements DeserializerFactory { - private static final TBaseLocator DEFAULT_TBASE_LOCATOR = new DefaultTBaseLocator(); + private static final TypeLocator> DEFAULT_TBASE_LOCATOR = DefaultTBaseLocator.getTypeLocator(); private static final TProtocolFactory DEFAULT_PROTOCOL_FACTORY = new TCompactProtocol.Factory(); public static final ChunkHeaderTBaseDeserializerFactory DEFAULT_FACTORY = new ChunkHeaderTBaseDeserializerFactory(); private final TProtocolFactory protocolFactory; - private TBaseLocator locator; + private TypeLocator> locator; public ChunkHeaderTBaseDeserializerFactory() { this(DEFAULT_PROTOCOL_FACTORY, DEFAULT_TBASE_LOCATOR); } - public TBaseLocator getLocator() { + public TypeLocator> getLocator() { return locator; } @@ -45,7 +47,7 @@ public TProtocolFactory getProtocolFactory() { return protocolFactory; } - public ChunkHeaderTBaseDeserializerFactory(TProtocolFactory protocolFactory, TBaseLocator locator) { + public ChunkHeaderTBaseDeserializerFactory(TProtocolFactory protocolFactory, TypeLocator> locator) { if (protocolFactory == null) { throw new NullPointerException("protocolFactory must not be null"); } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/CommandHeaderTBaseDeserializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/CommandHeaderTBaseDeserializerFactory.java index 2ad03272427d..7f1516ef3d8b 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/CommandHeaderTBaseDeserializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/CommandHeaderTBaseDeserializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,8 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; +import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; @@ -29,7 +31,7 @@ public final class CommandHeaderTBaseDeserializerFactory implements Deserializer private final DeserializerFactory factory; public CommandHeaderTBaseDeserializerFactory() { - TBaseLocator commandTbaseLocator = new TCommandRegistry(Arrays.asList(TCommandType.values())); + TypeLocator> commandTbaseLocator = TCommandRegistry.build(Arrays.asList(TCommandType.values())); TProtocolFactory protocolFactory = new TCompactProtocol.Factory(); HeaderTBaseDeserializerFactory deserializerFactory = new HeaderTBaseDeserializerFactory(protocolFactory, commandTbaseLocator); diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/CommandHeaderTBaseSerializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/CommandHeaderTBaseSerializerFactory.java index 0e3c7916e077..12f6252376cb 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/CommandHeaderTBaseSerializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/CommandHeaderTBaseSerializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; @@ -29,7 +30,7 @@ public final class CommandHeaderTBaseSerializerFactory implements SerializerFact public static final int DEFAULT_SERIALIZER_MAX_SIZE = 1024 * 64; - private final TBaseLocator tBaseLocator; + private final TypeLocator> tBaseLocator; private final SerializerFactory factory; public CommandHeaderTBaseSerializerFactory() { @@ -37,7 +38,7 @@ public CommandHeaderTBaseSerializerFactory() { } public CommandHeaderTBaseSerializerFactory(int outputStreamSize) { - TBaseLocator commandTbaseLocator = new TCommandRegistry(Arrays.asList(TCommandType.values())); + TypeLocator> commandTbaseLocator = TCommandRegistry.build(Arrays.asList(TCommandType.values())); TProtocolFactory protocolFactory = new TCompactProtocol.Factory(); HeaderTBaseSerializerFactory serializerFactory = new HeaderTBaseSerializerFactory(true, outputStreamSize, protocolFactory, commandTbaseLocator); @@ -53,8 +54,8 @@ public HeaderTBaseSerializer createSerializer() { @Override public boolean isSupport(Object target) { - if (target instanceof TBase) { - return tBaseLocator.isSupport((Class) target.getClass()); + if (target instanceof TBase) { + return tBaseLocator.isSupport((Class>) target.getClass()); } return false; diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/DefaultTBaseLocator.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/DefaultTBaseLocator.java index 13dc0a6b25a1..2333b9a3cb1d 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/DefaultTBaseLocator.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/DefaultTBaseLocator.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,11 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; +import com.navercorp.pinpoint.io.util.BodyFactory; +import com.navercorp.pinpoint.io.util.TypeLocator; +import com.navercorp.pinpoint.io.util.TypeLocatorBuilder; import org.apache.thrift.TBase; import org.apache.thrift.TException; @@ -30,6 +35,8 @@ import com.navercorp.pinpoint.thrift.dto.TSqlMetaData; import com.navercorp.pinpoint.thrift.dto.TStringMetaData; +import java.lang.reflect.Constructor; + /** * @author emeroad * @author koo.taejin @@ -38,174 +45,135 @@ * @author jaehong.kim * - add CHUNK_HEADER */ -class DefaultTBaseLocator implements TBaseLocator { - - private static final short NETWORK_CHECK = 10; - private static final Header NETWORK_CHECK_HEADER = createHeader(NETWORK_CHECK); - - private static final short SPAN = 40; - private static final Header SPAN_HEADER = createHeader(SPAN); - - private static final short AGENT_INFO = 50; - private static final Header AGENT_INFO_HEADER = createHeader(AGENT_INFO); - - private static final short AGENT_STAT = 55; - private static final Header AGENT_STAT_HEADER = createHeader(AGENT_STAT); - private static final short AGENT_STAT_BATCH = 56; - private static final Header AGENT_STAT_BATCH_HEADER = createHeader(AGENT_STAT_BATCH); - - private static final short SPANCHUNK = 70; - private static final Header SPANCHUNK_HEADER = createHeader(SPANCHUNK); - - private static final short SPANEVENT = 80; - private static final Header SPANEVENT_HEADER = createHeader(SPANEVENT); - - private static final short SQLMETADATA = 300; - private static final Header SQLMETADATA_HEADER = createHeader(SQLMETADATA); - - private static final short APIMETADATA = 310; - private static final Header APIMETADATA_HEADER = createHeader(APIMETADATA); - - private static final short RESULT = 320; - private static final Header RESULT_HEADER = createHeader(RESULT); - - private static final short STRINGMETADATA = 330; - private static final Header STRINGMETADATA_HEADER = createHeader(STRINGMETADATA); - - private static final short CHUNK = 400; - private static final Header CHUNK_HEADER = createHeader(CHUNK); - - @Override - public TBase tBaseLookup(short type) throws TException { - switch (type) { - case SPAN: +public class DefaultTBaseLocator { + + public static final short NETWORK_CHECK = 10; + + public static final short SPAN = 40; + + public static final short AGENT_INFO = 50; + + + public static final short AGENT_STAT = 55; + + public static final short AGENT_STAT_BATCH = 56; + + public static final short SPANCHUNK = 70; + + public static final short SPANEVENT = 80; + + public static final short SQLMETADATA = 300; + + public static final short APIMETADATA = 310; + + public static final short RESULT = 320; + + public static final short STRINGMETADATA = 330; + + public static final short CHUNK = 400; + + private static final TypeLocator> typeLocator = build(); + + public static TypeLocator>build() { + + TypeLocatorBuilder> builder = new TypeLocatorBuilder>(); + addBodyFactory(builder); + return builder.build(); + } + + public static void addBodyFactory(TypeLocatorBuilder> builder) { + builder.addBodyFactory(SPAN, new BodyFactory>() { + @Override + public TBase getObject() { return new TSpan(); - case AGENT_INFO: + } + }); + + builder.addBodyFactory(AGENT_INFO, new BodyFactory>() { + @Override + public TBase getObject() { return new TAgentInfo(); - case AGENT_STAT: + } + }); + + builder.addBodyFactory(AGENT_STAT, new BodyFactory>() { + @Override + public TBase getObject() { return new TAgentStat(); - case AGENT_STAT_BATCH: + } + }); + + builder.addBodyFactory(AGENT_STAT_BATCH, new BodyFactory>() { + @Override + public TBase getObject() { return new TAgentStatBatch(); - case SPANCHUNK: + } + + }); + + builder.addBodyFactory(SPANCHUNK, new BodyFactory>() { + @Override + public TBase getObject() { return new TSpanChunk(); - case SPANEVENT: + } + + }); + + builder.addBodyFactory(SPANEVENT, new BodyFactory>() { + @Override + public TBase getObject() { return new TSpanEvent(); - case SQLMETADATA: + } + + }); + + builder.addBodyFactory(SQLMETADATA, new BodyFactory>() { + @Override + public TBase getObject() { return new TSqlMetaData(); - case APIMETADATA: + } + + }); + + builder.addBodyFactory(APIMETADATA, new BodyFactory>() { + @Override + public TBase getObject() { return new TApiMetaData(); - case RESULT: - return new TResult(); - case STRINGMETADATA: - return new TStringMetaData(); - case NETWORK_CHECK: - return new NetworkAvailabilityCheckPacket(); - } - throw new TException("Unsupported type:" + type); - } + } + }); - public Header headerLookup(TBase tbase) throws TException { - if (tbase == null) { - throw new IllegalArgumentException("tbase must not be null"); - } - if (tbase instanceof TSpan) { - return SPAN_HEADER; - } - if (tbase instanceof TSpanChunk) { - return SPANCHUNK_HEADER; - } - if (tbase instanceof TSpanEvent) { - return SPANEVENT_HEADER; - } - if (tbase instanceof TAgentInfo) { - return AGENT_INFO_HEADER; - } - if (tbase instanceof TAgentStat) { - return AGENT_STAT_HEADER; - } - if (tbase instanceof TAgentStatBatch) { - return AGENT_STAT_BATCH_HEADER; - } - if (tbase instanceof TSqlMetaData) { - return SQLMETADATA_HEADER; - } - if (tbase instanceof TApiMetaData) { - return APIMETADATA_HEADER; - } - if (tbase instanceof TResult) { - return RESULT_HEADER; - } - if (tbase instanceof TStringMetaData) { - return STRINGMETADATA_HEADER; - } - if (tbase instanceof NetworkAvailabilityCheckPacket) { - return NETWORK_CHECK_HEADER; - } - - throw new TException("Unsupported Type" + tbase.getClass()); - } - @Override - public boolean isSupport(short type) { - try { - tBaseLookup(type); - return true; - } catch (TException ignore) { - // skip - } + builder.addBodyFactory(RESULT, new BodyFactory>() { + @Override + public TBase getObject() { + return new TResult(); + } - return false; - } + }); - @Override - public boolean isSupport(Class clazz) { - if (clazz.equals(TSpan.class)) { - return true; - } - if (clazz.equals(TSpanChunk.class)) { - return true; - } - if (clazz.equals(TAgentInfo.class)) { - return true; - } - if (clazz.equals(TAgentStat.class)) { - return true; - } - if (clazz.equals(TAgentStatBatch.class)) { - return true; - } - if (clazz.equals(TSqlMetaData.class)) { - return true; - } - if (clazz.equals(TApiMetaData.class)) { - return true; - } - if (clazz.equals(TResult.class)) { - return true; - } - if (clazz.equals(TStringMetaData.class)) { - return true; - } - if (clazz.equals(NetworkAvailabilityCheckPacket.class)) { - return true; - } - - return false; - } - - private static Header createHeader(short type) { - Header header = new Header(); - header.setType(type); - return header; - } + builder.addBodyFactory(STRINGMETADATA, new BodyFactory>() { + @Override + public TBase getObject() { + return new TStringMetaData(); + } + }); - @Override - public Header getChunkHeader() { - return CHUNK_HEADER; + builder.addBodyFactory(NETWORK_CHECK, new BodyFactory>() { + @Override + public TBase getObject() { + return new NetworkAvailabilityCheckPacket(); + } + }); + + builder.addBodyFactory(CHUNK, new BodyFactory>() { + @Override + public TBase getObject() { + return null; + } + }); } - @Override - public boolean isChunkHeader(short type) { - return CHUNK == type; + public static TypeLocator> getTypeLocator() { + return typeLocator; } } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseDeserializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseDeserializerFactory.java index da61a7075db1..85d45760ef5c 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseDeserializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseDeserializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,11 +15,22 @@ */ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; +import org.apache.thrift.TBase; + /** * @author minwoo.jung */ public class FlinkHeaderTBaseDeserializerFactory implements DeserializerFactory { - private final HeaderTBaseDeserializerFactory headerTBaseDeserializerFactory = new HeaderTBaseDeserializerFactory(new FlinkTBaseLocator()); + private final HeaderTBaseDeserializerFactory headerTBaseDeserializerFactory; + + public FlinkHeaderTBaseDeserializerFactory(TypeLocator> flinkTBaseLocator) { + if (flinkTBaseLocator == null) { + throw new NullPointerException("flinkTBaseLocator must not be null."); + } + + this.headerTBaseDeserializerFactory = new HeaderTBaseDeserializerFactory(flinkTBaseLocator); + } @Override public HeaderTBaseDeserializer createDeserializer() { diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseSerializer.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseSerializer.java new file mode 100644 index 000000000000..0221e6567742 --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseSerializer.java @@ -0,0 +1,71 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.thrift.io; + +import com.navercorp.pinpoint.common.util.Assert; +import com.navercorp.pinpoint.io.header.*; +import com.navercorp.pinpoint.io.request.FlinkRequest; +import com.navercorp.pinpoint.io.util.TypeLocator; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.TIOStreamTransport; + +/** + * @author minwoo.jung + */ +public class FlinkHeaderTBaseSerializer { + + private final ResettableByteArrayOutputStream baos; + private final TProtocol protocol; + private final TypeLocator> locator; + + /** + * Create a new HeaderTBaseSerializer. + * + * @param bos + * @param protocolFactory + */ + public FlinkHeaderTBaseSerializer(ResettableByteArrayOutputStream bos, TProtocolFactory protocolFactory, TypeLocator> locator) { + this.baos = Assert.requireNonNull(bos, "ResettableByteArrayOutputStream must not be null."); + this.locator = Assert.requireNonNull(locator, "locator must not be null."); + + Assert.requireNonNull(protocolFactory, "TProtocolFactory must not be null."); + TIOStreamTransport transport = new TIOStreamTransport(bos); + this.protocol = protocolFactory.getProtocol(transport); + + + } + + public byte[] serialize(FlinkRequest flinkRequest) throws TException { + baos.reset(); + writeHeader(flinkRequest); + flinkRequest.getData().write(protocol); + return baos.toByteArray(); + } + + private void writeHeader(FlinkRequest flinkRequest) { + try { + Header header = locator.headerLookup(flinkRequest.getData()); + HeaderWriter headerWriter = new ByteArrayHeaderWriter(header, flinkRequest.getHeaderEntity()); + byte[] headerBytes = headerWriter.writeHeader(); + baos.write(headerBytes); + } catch (Exception e) { + throw new InvalidHeaderException("can not write header.", e); + } + } +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseSerializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseSerializerFactory.java index 4d233a4f257f..3eda2262ab2e 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseSerializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkHeaderTBaseSerializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,26 +15,36 @@ */ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; +import org.apache.thrift.protocol.TProtocolFactory; /** * @author minwoo.jung */ -public class FlinkHeaderTBaseSerializerFactory implements SerializerFactory { +public class FlinkHeaderTBaseSerializerFactory implements SerializerFactory { + private final TypeLocator> tBaseLocator; + private final HeaderTBaseSerializerFactory headerTBaseSerializerFactory; - private final TBaseLocator tBaseLocator = new FlinkTBaseLocator(); - private final HeaderTBaseSerializerFactory headerTBaseSerializerFactory = new HeaderTBaseSerializerFactory(tBaseLocator); + public FlinkHeaderTBaseSerializerFactory(TypeLocator> flinkTBaseLocator) { + if (flinkTBaseLocator == null) { + throw new NullPointerException("flinkTBaseLocator must not be null."); + } + tBaseLocator = flinkTBaseLocator; + headerTBaseSerializerFactory = new HeaderTBaseSerializerFactory(tBaseLocator); + } - @Override - public HeaderTBaseSerializer createSerializer() { - return headerTBaseSerializerFactory.createSerializer(); + public FlinkHeaderTBaseSerializer createSerializer() { + ResettableByteArrayOutputStream baos = headerTBaseSerializerFactory.createResettableByteArrayOutputStream(); + TProtocolFactory protocolFactory = headerTBaseSerializerFactory.getProtocolFactory(); + return new FlinkHeaderTBaseSerializer(baos, protocolFactory, tBaseLocator); } @Override public boolean isSupport(Object target) { - if (target instanceof TBase) { - return tBaseLocator.isSupport((Class) target.getClass()); + if (target instanceof TBase) { + return tBaseLocator.isSupport((Class>) target.getClass()); } return false; diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkTBaseLocator.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkTBaseLocator.java index 3ca3cbbc5844..a0f60457484a 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkTBaseLocator.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/FlinkTBaseLocator.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,73 +15,80 @@ */ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; +import com.navercorp.pinpoint.io.header.v2.HeaderV2; +import com.navercorp.pinpoint.io.util.BodyFactory; +import com.navercorp.pinpoint.io.util.HeaderFactory; +import com.navercorp.pinpoint.io.util.TypeLocator; +import com.navercorp.pinpoint.io.util.TypeLocatorBuilder; import com.navercorp.pinpoint.thrift.dto.flink.TFAgentStatBatch; import org.apache.thrift.TBase; -import org.apache.thrift.TException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; +import java.util.concurrent.ConcurrentHashMap; + /** * @author minwoo.jung */ -public class FlinkTBaseLocator implements TBaseLocator { +public class FlinkTBaseLocator { private Logger logger = LoggerFactory.getLogger(this.getClass()); - private static final short AGENT_STAT_BATCH = 1000; - private static final Header AGENT_STAT_BATCH_HEADER = createHeader(AGENT_STAT_BATCH); + public static final short AGENT_STAT_BATCH = 1000; - @Override - public TBase tBaseLookup(short type) throws TException { - switch (type) { - case AGENT_STAT_BATCH: - return new TFAgentStatBatch(); + private final byte version; + private final TypeLocator> typeLocator; + + public FlinkTBaseLocator(byte version) { + if (version != HeaderV1.VERSION && version != HeaderV2.VERSION) { + throw new IllegalArgumentException(String.format("could not select match header version. : 0x%02X", version)); } - throw new TException("Unsupported type:" + type); + this.version = version; + this.typeLocator = newTypeLocator(); } - @Override - public Header headerLookup(TBase tbase) throws TException { - if (tbase instanceof TFAgentStatBatch) { - return AGENT_STAT_BATCH_HEADER; - } + private TypeLocator> newTypeLocator() { + HeaderFactory headerFactory = new FlinkHeaderFactory(); + TypeLocatorBuilder> typeLocatorBuilder = new TypeLocatorBuilder>(headerFactory); + typeLocatorBuilder.addBodyFactory(AGENT_STAT_BATCH, new BodyFactory>() { + @Override + public TBase getObject() { + return new TFAgentStatBatch(); + } + }); - throw new TException("Unsupported Type" + tbase.getClass()); + return typeLocatorBuilder.build(); } - @Override - public boolean isSupport(short type) { - try { - tBaseLookup(type); - return true; - } catch (TException ignore) { - logger.warn("{} is not support type", type); - } - - return false; + public TypeLocator> getTypeLocator() { + return typeLocator; } - @Override - public boolean isSupport(Class clazz) { - if (clazz.equals(TFAgentStatBatch.class)) { - return true; + public class FlinkHeaderFactory implements HeaderFactory { + @Override + public Header newHeader(short type) { + return createHeader(type); } - return false; - } + private Header createHeader(short type) { + if (version == HeaderV1.VERSION) { + return createHeaderV1(type); + } else if (version == HeaderV2.VERSION) { + return createHeaderV2(type); + } - private static Header createHeader(short type) { - Header header = new Header(); - header.setType(type); - return header; - } + throw new IllegalArgumentException("unsupported Header version : " + version); + } - @Override - public Header getChunkHeader() { - return null; - } + private Header createHeaderV1(short type) { + return new HeaderV1(type); + } + + private Header createHeaderV2(short type) { + return new HeaderV2(Header.SIGNATURE, HeaderV2.VERSION, type); + } + }; - @Override - public boolean isChunkHeader(short type) { - return false; - } } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/Header.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/Header.java deleted file mode 100644 index bf8d9bc2028e..000000000000 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/Header.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.thrift.io; - -/** - * @author emeroad - */ -public class Header { - - public static final byte SIGNATURE = (byte) 0xef; - - public static final int HEADER_SIZE = 4; - - private byte signature = SIGNATURE; - private byte version = 0x10; - private short type = 0; - - public Header() { - } - - public Header(byte signature, byte version, short type) { - this.signature = signature; - this.version = version; - this.type = type; - } - - public byte getSignature() { - return signature; - } - - public void setSignature(byte signature) { - this.signature = signature; - } - - public byte getVersion() { - return version; - } - - public void setVersion(byte version) { - this.version = version; - } - - public short getType() { - return type; - } - - public void setType(short type) { - this.type = type; - } - - @Override - public String toString() { - return "Header{" + - "signature=" + signature + - ", version=" + version + - ", type=" + type + - '}'; - } -} - diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseDeserializer.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseDeserializer.java index f206455f8461..328ba65ff64d 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseDeserializer.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseDeserializer.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,6 +19,10 @@ import java.util.ArrayList; import java.util.List; +import com.navercorp.pinpoint.io.header.*; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.io.request.DefaultMessage; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.apache.thrift.protocol.TProtocol; @@ -36,7 +40,7 @@ public class HeaderTBaseDeserializer { private final TProtocol protocol; private final TMemoryInputTransport trans; - private final TBaseLocator locator; + private final TypeLocator> locator; /** * Create a new TDeserializer. It will use the TProtocol specified by the @@ -44,7 +48,7 @@ public class HeaderTBaseDeserializer { * * @param protocolFactory Factory to create a protocol */ - HeaderTBaseDeserializer(TProtocolFactory protocolFactory, TBaseLocator locator) { + HeaderTBaseDeserializer(TProtocolFactory protocolFactory, TypeLocator> locator) { this.trans = new TMemoryInputTransport(); this.protocol = protocolFactory.getProtocol(trans); this.locator = locator; @@ -55,72 +59,75 @@ public class HeaderTBaseDeserializer { * * @param bytes The array to read from */ - public TBase deserialize(byte[] bytes) throws TException { + public Message> deserialize(byte[] bytes) throws TException { + try { - trans.reset(bytes); - Header header = readHeader(); - final int validate = validate(header); - if (validate == HeaderUtils.OK) { - TBase base = locator.tBaseLookup(header.getType()); - base.read(protocol); - return base; - } - throw new IllegalStateException("invalid validate " + validate); + trans.reset(bytes, 0, bytes.length); + return readInternal(); } finally { trans.clear(); protocol.reset(); } } - - public List> deserializeList(byte[] buffer) throws TException { - List> tBaseList = new ArrayList>(); - - trans.reset(buffer); - try { - while (trans.getBytesRemainingInBuffer() > 0) { - Header header = readHeader(); - final int validate = validate(header); - if (validate == HeaderUtils.OK) { - TBase base = locator.tBaseLookup(header.getType()); - base.read(protocol); - tBaseList.add(base); - } else { - throw new IllegalStateException("invalid validate " + validate); - } - } - } catch (Exception e){ - logger.warn("failed to deserialize.", e); - return new ArrayList>(); - } finally { - trans.clear(); - protocol.reset(); + + private Message> readInternal() throws TException { + final HeaderReader reader = newHeaderReader(); + final Header header = readHeader(reader); + final HeaderEntity headerEntity = readHeaderEntity(reader, header); + skipHeaderOffset(reader); + + + final TBase base = locator.bodyLookup(header.getType()); + if (base == null) { + throw new TException("base must not be null type:" + header.getType()); } - - return tBaseList; + + base.read(protocol); + + return new DefaultMessage>(header, headerEntity, base); + } + + private void skipHeaderOffset(HeaderReader reader) { + trans.reset(trans.getBuffer(), reader.getOffset(), reader.getRemaining()); + } + + private HeaderReader newHeaderReader() { + byte[] buffer = trans.getBuffer(); + int bufferPosition = trans.getBufferPosition(); + int bytesRemainingInBuffer = trans.getBytesRemainingInBuffer(); + return new ByteArrayHeaderReader(buffer, bufferPosition, bytesRemainingInBuffer); } - private int validate(Header header) throws TException { - final byte signature = header.getSignature(); - final int result = HeaderUtils.validateSignature(signature); - if (result == HeaderUtils.FAIL) { - throw new TException("Invalid Signature:" + header); + private Header readHeader(HeaderReader reader) throws TException { + try { + return reader.readHeader(); + } catch (InvalidHeaderException e) { + throw new TException("invalid header Caused by:" + e.getMessage(), e); } - return result; } - private Header readHeader() throws TException { - final byte signature = protocol.readByte(); - final byte version = protocol.readByte(); - - // fixed size regardless protocol - final byte type1 = protocol.readByte(); - final byte type2 = protocol.readByte(); - final short type = bytesToShort(type1, type2); - return new Header(signature, version, type); + private HeaderEntity readHeaderEntity(HeaderReader reader, Header header) throws TException { + try { + return reader.readHeaderEntity(header); + } catch (InvalidHeaderException e) { + throw new TException("invalid headerEntity Caused by:" + e.getMessage(), e); + } } - private short bytesToShort(final byte byte1, final byte byte2) { - return (short) (((byte1 & 0xff) << 8) | ((byte2 & 0xff))); + public List>> deserializeList(byte[] buffer) throws TException { + final List>> tBaseList = new ArrayList>>(); + + try { + trans.reset(buffer, 0, buffer.length); + while (trans.getBytesRemainingInBuffer() > 0) { + final Message> tBase = readInternal(); + tBaseList.add(tBase); + } + } finally { + trans.clear(); + protocol.reset(); + } + return tBaseList; } } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseDeserializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseDeserializerFactory.java index bfdd13d383c8..bbd0e681c512 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseDeserializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseDeserializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,8 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; +import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; @@ -24,24 +26,24 @@ */ public final class HeaderTBaseDeserializerFactory implements DeserializerFactory { - private static final TBaseLocator DEFAULT_TBASE_LOCATOR = new DefaultTBaseLocator(); + private static final TypeLocator> DEFAULT_TBASE_LOCATOR = DefaultTBaseLocator.getTypeLocator(); private static final TProtocolFactory DEFAULT_PROTOCOL_FACTORY = new TCompactProtocol.Factory(); public static final HeaderTBaseDeserializerFactory DEFAULT_FACTORY = new HeaderTBaseDeserializerFactory(); private final TProtocolFactory protocolFactory; - private TBaseLocator locator; + private TypeLocator> locator; public HeaderTBaseDeserializerFactory() { this(DEFAULT_PROTOCOL_FACTORY, DEFAULT_TBASE_LOCATOR); } - public HeaderTBaseDeserializerFactory(TBaseLocator locator) { + public HeaderTBaseDeserializerFactory(TypeLocator> locator) { this(DEFAULT_PROTOCOL_FACTORY, locator); } - public TBaseLocator getLocator() { + public TypeLocator> getLocator() { return locator; } @@ -49,7 +51,7 @@ public TProtocolFactory getProtocolFactory() { return protocolFactory; } - public HeaderTBaseDeserializerFactory(TProtocolFactory protocolFactory, TBaseLocator locator) { + public HeaderTBaseDeserializerFactory(TProtocolFactory protocolFactory, TypeLocator> locator) { if (protocolFactory == null) { throw new NullPointerException("protocolFactory must not be null"); } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializer.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializer.java index a9ea28e61d20..bccc01f2a484 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializer.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializer.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,8 +17,15 @@ package com.navercorp.pinpoint.thrift.io; +import java.io.IOException; import java.io.UnsupportedEncodingException; +import com.navercorp.pinpoint.io.header.ByteArrayHeaderWriter; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.HeaderEntity; +import com.navercorp.pinpoint.io.header.HeaderWriter; +import com.navercorp.pinpoint.io.header.InvalidHeaderException; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.apache.thrift.protocol.TProtocol; @@ -30,18 +37,18 @@ * String. * copy->HeaderTBaseSerializer */ -public class HeaderTBaseSerializer { +public class HeaderTBaseSerializer implements TBaseSerializer { private static final String UTF8 = "UTF8"; private final ResettableByteArrayOutputStream baos; private final TProtocol protocol; - private final TBaseLocator locator; + private final TypeLocator> locator; /** * Create a new HeaderTBaseSerializer. */ - HeaderTBaseSerializer(ResettableByteArrayOutputStream bos, TProtocolFactory protocolFactory, TBaseLocator locator) { + HeaderTBaseSerializer(ResettableByteArrayOutputStream bos, TProtocolFactory protocolFactory, TypeLocator> locator) { this.baos = bos; TIOStreamTransport transport = new TIOStreamTransport(bos); this.protocol = protocolFactory.getProtocol(transport); @@ -56,17 +63,40 @@ public class HeaderTBaseSerializer { * @param base The object to serialize * @return Serialized object in byte[] format */ + @Override public byte[] serialize(TBase base) throws TException { - final Header header = locator.headerLookup(base); + return serialize(base, HeaderEntity.EMPTY_HEADER_ENTITY); + } + + @Override + public byte[] serialize(TBase base, HeaderEntity headerEntity) throws TException { baos.reset(); - writeHeader(header); + + writeHeader(base, headerEntity); base.write(protocol); return baos.toByteArray(); } - + + private void writeHeader(TBase base) { + writeHeader(base, HeaderEntity.EMPTY_HEADER_ENTITY); + } + + private void writeHeader(TBasebase, HeaderEntity headerEntity) { + try { + final Header header = locator.headerLookup(base); + if (header == null) { + throw new TException("header must not be null base:" + base); + } + HeaderWriter headerWriter = new ByteArrayHeaderWriter(header, headerEntity); + byte[] headerBytes = headerWriter.writeHeader(); + baos.write(headerBytes); + } catch (Exception e) { + throw new InvalidHeaderException("can not write header.", e); + } + } + public byte[] continueSerialize(TBase base) throws TException { - final Header header = locator.headerLookup(base); - writeHeader(header); + writeHeader(base); base.write(protocol); return baos.toByteArray(); } @@ -83,14 +113,6 @@ public int getInterBufferSize() { return baos.size(); } - private void writeHeader(Header header) throws TException { - protocol.writeByte(header.getSignature()); - protocol.writeByte(header.getVersion()); - // fixed size regardless protocol - short type = header.getType(); - protocol.writeByte(BytesUtils.writeShort1(type)); - protocol.writeByte(BytesUtils.writeShort2(type)); - } /** * Serialize the Thrift object into a Java string, using the UTF8 diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializer2.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializer2.java index db4fc263218d..56131701d1de 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializer2.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializer2.java @@ -1,22 +1,23 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.apache.thrift.protocol.TProtocol; @@ -36,9 +37,9 @@ public class HeaderTBaseSerializer2 { private final TOutputStreamTransport tOutputStreamTransport; private final TProtocol protocol; - private final TBaseLocator tBaseLocator; + private final TypeLocator> tBaseLocator; - public HeaderTBaseSerializer2(TProtocolFactory protocolFactory, TBaseLocator tBaseLocator) { + public HeaderTBaseSerializer2(TProtocolFactory protocolFactory, TypeLocator> tBaseLocator) { this.tOutputStreamTransport = new TOutputStreamTransport(); this.protocol = protocolFactory.getProtocol(tOutputStreamTransport); this.tBaseLocator = tBaseLocator; @@ -48,20 +49,16 @@ public void serialize(TBase base, OutputStream outputStream) throws TExcep tOutputStreamTransport.open(outputStream); try { final Header header = tBaseLocator.headerLookup(base); - writeHeader(header); + if (header == null) { + throw new TException("header must not be null base:" + base); + } + HeaderUtils.writeHeader(protocol, header); base.write(protocol); } finally { tOutputStreamTransport.close(); } } - private void writeHeader(Header header) throws TException { - protocol.writeByte(header.getSignature()); - protocol.writeByte(header.getVersion()); - // fixed size regardless protocol - short type = header.getType(); - protocol.writeByte(BytesUtils.writeShort1(type)); - protocol.writeByte(BytesUtils.writeShort2(type)); - } + } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerFactory.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerFactory.java index 38f1ad41c703..3c0ede7dd1e9 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerFactory.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; @@ -31,7 +32,7 @@ public final class HeaderTBaseSerializerFactory implements SerializerFactory> DEFAULT_TBASE_LOCATOR = DefaultTBaseLocator.getTypeLocator(); private static final TProtocolFactory DEFAULT_PROTOCOL_FACTORY = new TCompactProtocol.Factory(); public static final HeaderTBaseSerializerFactory DEFAULT_FACTORY = new HeaderTBaseSerializerFactory(); @@ -40,7 +41,7 @@ public final class HeaderTBaseSerializerFactory implements SerializerFactory> locator; public HeaderTBaseSerializerFactory() { this(DEFAULT_SAFE_GUARANTEED); @@ -50,7 +51,7 @@ public HeaderTBaseSerializerFactory(boolean safetyGuaranteed) { this(safetyGuaranteed, DEFAULT_STREAM_SIZE); } - public HeaderTBaseSerializerFactory(TBaseLocator locator) { + public HeaderTBaseSerializerFactory(TypeLocator> locator) { this(DEFAULT_SAFE_GUARANTEED, DEFAULT_STREAM_SIZE, DEFAULT_AUTO_EXPAND, DEFAULT_PROTOCOL_FACTORY, locator); } @@ -62,11 +63,11 @@ public HeaderTBaseSerializerFactory(boolean safetyGuaranteed, int outputStreamSi this(safetyGuaranteed, outputStreamSize, autoExpand, DEFAULT_PROTOCOL_FACTORY, DEFAULT_TBASE_LOCATOR); } - public HeaderTBaseSerializerFactory(boolean safetyGuaranteed, int outputStreamSize, TProtocolFactory protocolFactory, TBaseLocator locator) { + public HeaderTBaseSerializerFactory(boolean safetyGuaranteed, int outputStreamSize, TProtocolFactory protocolFactory, TypeLocator> locator) { this(safetyGuaranteed, outputStreamSize, DEFAULT_AUTO_EXPAND, protocolFactory, locator); } - public HeaderTBaseSerializerFactory(boolean safetyGuaranteed, int outputStreamSize, boolean autoExpand, TProtocolFactory protocolFactory, TBaseLocator locator) { + public HeaderTBaseSerializerFactory(boolean safetyGuaranteed, int outputStreamSize, boolean autoExpand, TProtocolFactory protocolFactory, TypeLocator> locator) { this.safetyGuaranteed = safetyGuaranteed; this.outputStreamSize = outputStreamSize; this.autoExpand = autoExpand; @@ -86,26 +87,30 @@ public TProtocolFactory getProtocolFactory() { return protocolFactory; } - public TBaseLocator getLocator() { + public TypeLocator> getLocator() { return locator; } @Override public HeaderTBaseSerializer createSerializer() { + ResettableByteArrayOutputStream baos = createResettableByteArrayOutputStream(); + return new HeaderTBaseSerializer(baos, protocolFactory, locator); + } + + public ResettableByteArrayOutputStream createResettableByteArrayOutputStream() { ResettableByteArrayOutputStream baos = null; if (safetyGuaranteed) { baos = new PinpointByteArrayOutputStream(outputStreamSize, autoExpand); } else { baos = new UnsafeByteArrayOutputStream(outputStreamSize, autoExpand); } - - return new HeaderTBaseSerializer(baos, protocolFactory, locator); + return baos; } @Override public boolean isSupport(Object target) { - if (target instanceof TBase) { - return locator.isSupport((Class) target.getClass()); + if (target instanceof TBase) { + return locator.isSupport((Class>) target.getClass()); } return false; diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerFactory2.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerFactory2.java index b0fdc98a6b58..9217099629ab 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerFactory2.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerFactory2.java @@ -1,22 +1,22 @@ /* - * Copyright 2016 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * */ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; @@ -27,10 +27,10 @@ public class HeaderTBaseSerializerFactory2 implements SerializerFactory { private static final TProtocolFactory DEFAULT_PROTOCOL_FACTORY = new TCompactProtocol.Factory(); - private static final TBaseLocator DEFAULT_TBASE_LOCATOR = new DefaultTBaseLocator(); + private static final TypeLocator> DEFAULT_TBASE_LOCATOR = DefaultTBaseLocator.getTypeLocator(); private final TProtocolFactory protocolFactory; - private final TBaseLocator tBaseLocator; + private final TypeLocator> tBaseLocator; public HeaderTBaseSerializerFactory2() { this(DEFAULT_PROTOCOL_FACTORY, DEFAULT_TBASE_LOCATOR); @@ -40,11 +40,11 @@ public HeaderTBaseSerializerFactory2(TProtocolFactory protocolFactory) { this(protocolFactory, DEFAULT_TBASE_LOCATOR); } - public HeaderTBaseSerializerFactory2(TBaseLocator tBaseLocator) { + public HeaderTBaseSerializerFactory2(TypeLocator> tBaseLocator) { this(DEFAULT_PROTOCOL_FACTORY, tBaseLocator); } - public HeaderTBaseSerializerFactory2(TProtocolFactory protocolFactory, TBaseLocator tBaseLocator) { + public HeaderTBaseSerializerFactory2(TProtocolFactory protocolFactory, TypeLocator> tBaseLocator) { this.protocolFactory = protocolFactory; this.tBaseLocator = tBaseLocator; } @@ -56,8 +56,8 @@ public HeaderTBaseSerializer2 createSerializer() { @Override public boolean isSupport(Object target) { - if (target instanceof TBase) { - return tBaseLocator.isSupport((Class) target.getClass()); + if (target instanceof TBase) { + return tBaseLocator.isSupport((Class>) target.getClass()); } return false; diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderUtils.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderUtils.java index 73d822b0362f..d4e91d9e9ad2 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderUtils.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/HeaderUtils.java @@ -16,6 +16,10 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TProtocol; + /** * @author emeroad */ @@ -27,9 +31,18 @@ private HeaderUtils() { } public static int validateSignature(byte signature) { - if (Header.SIGNATURE == signature) { + if (OK == signature) { return OK; } return FAIL; } + + public static void writeHeader(TProtocol protocol, Header header) throws TException { + protocol.writeByte(header.getSignature()); + protocol.writeByte(header.getVersion()); + // fixed size regardless protocol + short type = header.getType(); + protocol.writeByte(BytesUtils.writeShort1(type)); + protocol.writeByte(BytesUtils.writeShort2(type)); + } } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TBaseLocator.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TBaseLocator.java index 9ae961fbec93..585b88188575 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TBaseLocator.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TBaseLocator.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; import org.apache.thrift.TBase; import org.apache.thrift.TException; @@ -34,7 +35,9 @@ public interface TBaseLocator { boolean isSupport(Class clazz); + @Deprecated Header getChunkHeader(); + @Deprecated boolean isChunkHeader(short type); } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TBaseSerializer.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TBaseSerializer.java new file mode 100644 index 000000000000..a2e99815799c --- /dev/null +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TBaseSerializer.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.thrift.io; + +import com.navercorp.pinpoint.io.header.HeaderEntity; +import org.apache.thrift.TBase; +import org.apache.thrift.TException; + +/** + * @author Woonduk Kang(emeroad) + */ +public interface TBaseSerializer { + + byte[] serialize(TBase base) throws TException; + + byte[] serialize(TBase base, HeaderEntity headerEntity) throws TException; +} diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TCommandRegistry.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TCommandRegistry.java index d998091df830..7d5339e1e5c6 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TCommandRegistry.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TCommandRegistry.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,90 +16,38 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.util.BodyFactory; +import com.navercorp.pinpoint.io.util.TypeLocator; +import com.navercorp.pinpoint.io.util.TypeLocatorBuilder; import org.apache.thrift.TBase; import org.apache.thrift.TException; -import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; +import java.util.Map; +import java.util.Set; /** * @author koo.taejin */ -public class TCommandRegistry implements TBaseLocator { +public class TCommandRegistry { - private final ConcurrentHashMap commandTBaseRepository = new ConcurrentHashMap(); - public TCommandRegistry(TCommandTypeVersion version) { - this(version.getSupportCommandList()); + public static TypeLocator> build(TCommandTypeVersion version) { + return build(version.getSupportCommandList()); } + public static TypeLocator> build(List supportCommandList) { + TypeLocatorBuilder> builder = new TypeLocatorBuilder>(); - public TCommandRegistry(List supportCommandList) { - for (TCommandType type : supportCommandList) { - commandTBaseRepository.put(type.getCode(), type); + for (final TCommandType commandType : supportCommandList) { + builder.addBodyFactory(commandType.getCode(), commandType.getBodyFactory()); } - } - - @Override - public TBase tBaseLookup(short type) throws TException { - TCommandType commandTBaseType = commandTBaseRepository.get(type); - if (commandTBaseType == null) { - throw new TException("Unsupported type:" + type); - } - - return commandTBaseType.newObject(); - } - - @Override - public Header headerLookup(TBase tbase) throws TException { - if (tbase == null) { - throw new IllegalArgumentException("tbase must not be null"); - } - - // Should we preload commandTBaseList for performance? - Collection commandTBaseList = commandTBaseRepository.values(); - - for (TCommandType commandTBase : commandTBaseList) { - if (commandTBase.isInstanceOf(tbase)) { - return commandTBase.getHeader(); - } - } - - throw new TException("Unsupported Type" + tbase.getClass()); - } - - @Override - public boolean isSupport(short type) { - TCommandType commandTBaseType = commandTBaseRepository.get(type); - - if (commandTBaseType != null) { - return true; - } - - return false; - } - - @Override - public boolean isSupport(Class clazz) { - // Should we preload commandTBaseList for performance? - Collection commandTBaseList = commandTBaseRepository.values(); - - for (TCommandType commandTBase : commandTBaseList) { - if (commandTBase.getClazz().equals(clazz)) { - return true; - } - } - - return false; - } - - @Override - public Header getChunkHeader() { - return null; - } - @Override - public boolean isChunkHeader(short type) { - return false; + TypeLocator> typeLocator = builder.build(); + return typeLocator; } } diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TCommandType.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TCommandType.java index 41d8cc9d925a..82c425710166 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TCommandType.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/io/TCommandType.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.util.BodyFactory; import com.navercorp.pinpoint.thrift.dto.command.*; import org.apache.thrift.TBase; @@ -32,115 +33,112 @@ public enum TCommandType { // Using reflection would make code cleaner. // But it also makes it hard to handle exception, constructor and will show relatively low performance. - RESULT((short) 320, TResult.class) { + RESULT((short) 320, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TResult(); } - }, - TRANSFER((short) 700, TCommandTransfer.class) { + }), + + TRANSFER((short) 700, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCommandTransfer(); } - }, - TRANSFER_RESPONSE((short) 701, TCommandTransferResponse.class) { + }), + TRANSFER_RESPONSE((short) 701, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCommandTransferResponse(); } - }, - ECHO((short) 710, TCommandEcho.class) { + }), + + ECHO((short) 710, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCommandEcho(); } - }, - THREAD_DUMP((short) 720, TCommandThreadDump.class) { + }), + + THREAD_DUMP((short) 720, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCommandThreadDump(); } - }, - THREAD_DUMP_RESPONSE((short) 721, TCommandThreadDumpResponse.class) { + }), + THREAD_DUMP_RESPONSE((short) 721, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCommandThreadDumpResponse(); } - }, - ACTIVE_THREAD_COUNT((short) 730, TCmdActiveThreadCount.class) { + }), + + ACTIVE_THREAD_COUNT((short) 730, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCmdActiveThreadCount(); } - }, - ACTIVE_THREAD_COUNT_RESPONSE((short) 731, TCmdActiveThreadCountRes.class) { + }), + ACTIVE_THREAD_COUNT_RESPONSE((short) 731, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCmdActiveThreadCountRes(); } - }, - ACTIVE_THREAD_DUMP((short) 740, TCmdActiveThreadDump.class) { + }), + + ACTIVE_THREAD_DUMP((short) 740, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCmdActiveThreadDump(); } - }, - ACTIVE_THREAD_DUMP_RESPONSE((short) 741, TCmdActiveThreadDumpRes.class) { + }), + ACTIVE_THREAD_DUMP_RESPONSE((short) 741, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCmdActiveThreadDumpRes(); } - }, - ACTIVE_THREAD_LIGHT_DUMP((short) 750, TCmdActiveThreadLightDump.class) { + }), + + ACTIVE_THREAD_LIGHT_DUMP((short) 750, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCmdActiveThreadLightDump(); } - }, - ACTIVE_THREAD_LIGHT_DUMP_RESPONSE((short) 751, TCmdActiveThreadLightDumpRes.class) { + }), + ACTIVE_THREAD_LIGHT_DUMP_RESPONSE((short) 751, new BodyFactory>() { @Override - public TBase newObject() { + public TBase getObject() { return new TCmdActiveThreadLightDumpRes(); } - }; + }); private final short code; private final Class clazz; - private final Header header; + private final BodyFactory> bodyFactory; private static final Set TCOMMAND_TYPES = EnumSet.allOf(TCommandType.class); - private TCommandType(short code, Class clazz) { + + private TCommandType(short code, BodyFactory> bodyFactory) { this.code = code; - this.clazz = clazz; - this.header = createHeader(code); + this.bodyFactory = bodyFactory; + this.clazz = bodyFactory.getObject().getClass(); } public short getCode() { return code; } - public Class getClazz() { + public Class getClazz() { return clazz; } - protected boolean isInstanceOf(Object value) { - return this.clazz.isInstance(value); - } - - protected Header getHeader() { - return header; - } - - public abstract TBase newObject(); - private static Header createHeader(short code) { - Header header = new Header(); - header.setType(code); - return header; + public BodyFactory> getBodyFactory() { + return bodyFactory; } + @Deprecated public static TCommandType getType(Class clazz) { for (TCommandType commandType : TCOMMAND_TYPES) { if (commandType.getClazz() == clazz) { diff --git a/thrift/src/main/java/com/navercorp/pinpoint/thrift/util/SerializationUtils.java b/thrift/src/main/java/com/navercorp/pinpoint/thrift/util/SerializationUtils.java index 4522525282f0..7b67bf72e60c 100644 --- a/thrift/src/main/java/com/navercorp/pinpoint/thrift/util/SerializationUtils.java +++ b/thrift/src/main/java/com/navercorp/pinpoint/thrift/util/SerializationUtils.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.thrift.util; +import com.navercorp.pinpoint.io.request.Message; import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.slf4j.Logger; @@ -70,20 +71,20 @@ public static byte[] serialize(TBase object, HeaderTBaseSerializer serializer, b return defaultValue; } - public static TBase deserialize(byte[] objectData, DeserializerFactory factory) throws TException { + public static Message> deserialize(byte[] objectData, DeserializerFactory factory) throws TException { assertNotNull(factory, "DeserializerFactory may note be null."); return deserialize(objectData, factory.createDeserializer()); } - public static TBase deserialize(byte[] objectData, HeaderTBaseDeserializer deserializer) throws TException { + public static Message> deserialize(byte[] objectData, HeaderTBaseDeserializer deserializer) throws TException { assertNotNull(objectData, "TBase may note be null."); assertNotNull(deserializer, "Deserializer may note be null."); return deserializer.deserialize(objectData); } - public static TBase deserialize(byte[] objectData, DeserializerFactory factory, TBase defaultValue) { + public static Message> deserialize(byte[] objectData, DeserializerFactory factory, Message> defaultValue) { try { return deserialize(objectData, factory); } catch (Exception e) { @@ -95,7 +96,7 @@ public static TBase deserialize(byte[] objectData, DeserializerFactory> deserialize(byte[] objectData, HeaderTBaseDeserializer deserializer, Message> defaultValue) { try { return deserialize(objectData, deserializer); } catch (Exception e) { @@ -113,4 +114,5 @@ private static void assertNotNull(Object object, String message) { throw new NullPointerException(message); } } + } diff --git a/thrift/src/main/thrift/Flink.thrift b/thrift/src/main/thrift/Flink.thrift new file mode 100644 index 000000000000..45d6ec973cc1 --- /dev/null +++ b/thrift/src/main/thrift/Flink.thrift @@ -0,0 +1,143 @@ +namespace java com.navercorp.pinpoint.thrift.dto.flink + +enum TFJvmGcType { + UNKNOWN, + SERIAL, + PARALLEL, + CMS, + G1 +} + +struct TFServiceInfo { + 1: optional string serviceName + 2: optional list serviceLibs +} + +struct TFServerMetaData { + 1: optional string serverInfo + 2: optional list vmArgs + 10: optional list serviceInfos +} + +struct TFJvmInfo { + 1: i16 version = 0 + 2: optional string vmVersion + 3: optional TFJvmGcType gcType = TFJvmGcType.UNKNOWN +} + +struct TFAgentInfo { + 1: string hostname + 2: string ip + 3: string ports + 4: string agentId + 5: string applicationName + 6: i16 serviceType + 7: i32 pid + 8: string agentVersion; + 9: string vmVersion; + + 10: i64 startTimestamp + + 11: optional i64 endTimestamp + 12: optional i32 endStatus + + 20: optional TFServerMetaData serverMetaData + + 30: optional TFJvmInfo jvmInfo + + 40: optional bool container = false +} + +struct TFJvmGc { + 1: TFJvmGcType type = TFJvmGcType.UNKNOWN + 2: i64 jvmMemoryHeapUsed + 3: i64 jvmMemoryHeapMax + 4: i64 jvmMemoryNonHeapUsed + 5: i64 jvmMemoryNonHeapMax + 6: i64 jvmGcOldCount + 7: i64 jvmGcOldTime + 8: optional TFJvmGcDetailed jvmGcDetailed +} + +struct TFDirectBuffer { + 1: optional i64 directCount + 2: optional i64 directMemoryUsed + 3: optional i64 mappedCount + 4: optional i64 mappedMemoryUsed +} + +struct TFJvmGcDetailed { + 1: optional i64 jvmGcNewCount + 2: optional i64 jvmGcNewTime + 3: optional double jvmPoolCodeCacheUsed + 4: optional double jvmPoolNewGenUsed + 5: optional double jvmPoolOldGenUsed + 6: optional double jvmPoolSurvivorSpaceUsed + 7: optional double jvmPoolPermGenUsed + 8: optional double jvmPoolMetaspaceUsed +} + +struct TFCpuLoad { + 1: optional double jvmCpuLoad + 2: optional double systemCpuLoad +} + +struct TFTransaction { + 2: optional i64 sampledNewCount + 3: optional i64 sampledContinuationCount + 4: optional i64 unsampledNewCount + 5: optional i64 unsampledContinuationCount +} + +struct TFActiveTraceHistogram { + 1: i16 version = 0 + 2: optional i32 histogramSchemaType + 3: optional list activeTraceCount +} + +struct TFActiveTrace { + 1: optional TFActiveTraceHistogram histogram +} + +struct TFResponseTime { + 1: optional i64 avg = 0 +} + +struct TFAgentStat { + 1: optional string agentId + 2: optional i64 startTimestamp + 3: optional i64 timestamp + 4: optional i64 collectInterval + 10: optional TFJvmGc gc + 20: optional TFCpuLoad cpuLoad + 30: optional TFTransaction transaction + 40: optional TFActiveTrace activeTrace + 50: optional TFDataSourceList dataSourceList + 60: optional TFResponseTime responseTime + 80: optional TFFileDescriptor fileDescriptor + 90: optional TFDirectBuffer directBuffer + 200: optional string metadata +} + +struct TFAgentStatBatch { + 1: string agentId + 2: i64 startTimestamp + 10: list agentStats +} + +struct TFDataSource { + 1: i32 id + 2: optional i16 serviceTypeCode + 3: optional string databaseName + 4: optional string url + 5: optional i32 activeConnectionSize = 0 + 6: optional i32 maxConnectionSize +} + +struct TFDataSourceList { + 1: list dataSourceList +} + +struct TFFileDescriptor { + 1: i64 openFileDescriptorCount +} diff --git a/thrift/src/main/thrift/Pinpoint.thrift b/thrift/src/main/thrift/Pinpoint.thrift index 7efe7d60317e..8b96f718cfa3 100644 --- a/thrift/src/main/thrift/Pinpoint.thrift +++ b/thrift/src/main/thrift/Pinpoint.thrift @@ -46,6 +46,8 @@ struct TAgentInfo { 20: optional TServerMetaData serverMetaData 30: optional TJvmInfo jvmInfo + + 40: optional bool container = false } struct TJvmGc { @@ -59,6 +61,13 @@ struct TJvmGc { 8: optional TJvmGcDetailed jvmGcDetailed } +struct TDirectBuffer { + 1: optional i64 directCount + 2: optional i64 directMemoryUsed + 3: optional i64 mappedCount + 4: optional i64 mappedMemoryUsed +} + struct TJvmGcDetailed { 1: optional i64 jvmGcNewCount 2: optional i64 jvmGcNewTime @@ -114,6 +123,8 @@ struct TAgentStat { 50: optional TDataSourceList dataSourceList 60: optional TResponseTime responseTime 70: optional TDeadlock deadlock + 80: optional TFileDescriptor fileDescriptor + 90: optional TDirectBuffer directBuffer 200: optional string metadata } @@ -135,3 +146,7 @@ struct TDataSource { struct TDataSourceList { 1: list dataSourceList } + +struct TFileDescriptor { + 1: i64 openFileDescriptorCount +} diff --git a/thrift/src/main/thrift/Trace.thrift b/thrift/src/main/thrift/Trace.thrift index e35c650deaa7..284881fb4bdd 100644 --- a/thrift/src/main/thrift/Trace.thrift +++ b/thrift/src/main/thrift/Trace.thrift @@ -31,6 +31,11 @@ struct TIntBooleanIntBooleanValue { 4: bool boolValue2; } +struct TStringStringValue { + 1: string stringValue1; + 2: optional string stringValue2; +} + union TAnnotationValue { 1: string stringValue 2: bool boolValue; @@ -44,6 +49,7 @@ union TAnnotationValue { 10: TIntStringStringValue intStringStringValue; 11: TLongIntIntByteByteStringValue longIntIntByteByteStringValue; 12: TIntBooleanIntBooleanValue intBooleanIntBooleanValue; + 13: TStringStringValue stringStringValue; } struct TAnnotation { @@ -63,7 +69,7 @@ struct TSpanEvent { 10: optional i32 endElapsed = 0 - 11: optional string rpc + 11: optional string rpc ( deprecated ) 12: i16 serviceType 13: optional string endPoint diff --git a/thrift/src/main/thrift/flink.thrift b/thrift/src/main/thrift/flink.thrift deleted file mode 100644 index 24c45131bcf2..000000000000 --- a/thrift/src/main/thrift/flink.thrift +++ /dev/null @@ -1,128 +0,0 @@ -namespace java com.navercorp.pinpoint.thrift.dto.flink - -enum TFJvmGcType { - UNKNOWN, - SERIAL, - PARALLEL, - CMS, - G1 -} - -struct TFServiceInfo { - 1: optional string serviceName - 2: optional list serviceLibs -} - -struct TFServerMetaData { - 1: optional string serverInfo - 2: optional list vmArgs - 10: optional list serviceInfos -} - -struct TFJvmInfo { - 1: i16 version = 0 - 2: optional string vmVersion - 3: optional TFJvmGcType gcType = TFJvmGcType.UNKNOWN -} - -struct TFAgentInfo { - 1: string hostname - 2: string ip - 3: string ports - 4: string agentId - 5: string applicationName - 6: i16 serviceType - 7: i32 pid - 8: string agentVersion; - 9: string vmVersion; - - 10: i64 startTimestamp - - 11: optional i64 endTimestamp - 12: optional i32 endStatus - - 20: optional TFServerMetaData serverMetaData - - 30: optional TFJvmInfo jvmInfo -} - -struct TFJvmGc { - 1: TFJvmGcType type = TFJvmGcType.UNKNOWN - 2: i64 jvmMemoryHeapUsed - 3: i64 jvmMemoryHeapMax - 4: i64 jvmMemoryNonHeapUsed - 5: i64 jvmMemoryNonHeapMax - 6: i64 jvmGcOldCount - 7: i64 jvmGcOldTime - 8: optional TFJvmGcDetailed jvmGcDetailed -} - -struct TFJvmGcDetailed { - 1: optional i64 jvmGcNewCount - 2: optional i64 jvmGcNewTime - 3: optional double jvmPoolCodeCacheUsed - 4: optional double jvmPoolNewGenUsed - 5: optional double jvmPoolOldGenUsed - 6: optional double jvmPoolSurvivorSpaceUsed - 7: optional double jvmPoolPermGenUsed - 8: optional double jvmPoolMetaspaceUsed -} - -struct TFCpuLoad { - 1: optional double jvmCpuLoad - 2: optional double systemCpuLoad -} - -struct TFTransaction { - 2: optional i64 sampledNewCount - 3: optional i64 sampledContinuationCount - 4: optional i64 unsampledNewCount - 5: optional i64 unsampledContinuationCount -} - -struct TFActiveTraceHistogram { - 1: i16 version = 0 - 2: optional i32 histogramSchemaType - 3: optional list activeTraceCount -} - -struct TFActiveTrace { - 1: optional TFActiveTraceHistogram histogram -} - -struct TFResponseTime { - 1: optional i64 avg = 0 -} - -struct TFAgentStat { - 1: optional string agentId - 2: optional i64 startTimestamp - 3: optional i64 timestamp - 4: optional i64 collectInterval - 10: optional TFJvmGc gc - 20: optional TFCpuLoad cpuLoad - 30: optional TFTransaction transaction - 40: optional TFActiveTrace activeTrace - 50: optional TFDataSourceList dataSourceList - 60: optional TFResponseTime responseTime - 200: optional string metadata -} - -struct TFAgentStatBatch { - 1: string agentId - 2: i64 startTimestamp - 10: list agentStats -} - -struct TFDataSource { - 1: i32 id - 2: optional i16 serviceTypeCode - 3: optional string databaseName - 4: optional string url - 5: optional i32 activeConnectionSize = 0 - 6: optional i32 maxConnectionSize -} - -struct TFDataSourceList { - 1: list dataSourceList -} diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/ByteSizeTest.java b/thrift/src/test/java/com/navercorp/pinpoint/common/util/ByteSizeTest.java similarity index 95% rename from commons/src/test/java/com/navercorp/pinpoint/common/util/ByteSizeTest.java rename to thrift/src/test/java/com/navercorp/pinpoint/common/util/ByteSizeTest.java index 47902d000b30..4d0ea87a1cc5 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/util/ByteSizeTest.java +++ b/thrift/src/test/java/com/navercorp/pinpoint/common/util/ByteSizeTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/thrift/src/test/java/com/navercorp/pinpoint/common/util/BytesUtilsTest.java b/thrift/src/test/java/com/navercorp/pinpoint/common/util/BytesUtilsTest.java new file mode 100644 index 000000000000..6c4076dee7a4 --- /dev/null +++ b/thrift/src/test/java/com/navercorp/pinpoint/common/util/BytesUtilsTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.common.util; + +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TCompactProtocol; +import org.apache.thrift.transport.TMemoryBuffer; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Woonduk Kang(emeroad) + */ +public class BytesUtilsTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Test + public void compactProtocolVint() throws TException { + TMemoryBuffer tMemoryBuffer = writeVInt32(BytesUtils.zigzagToInt(64)); + logger.trace("length:{}", tMemoryBuffer.length()); + + TMemoryBuffer tMemoryBuffer2 = writeVInt32(64); + logger.trace("length:{}", tMemoryBuffer2.length()); + + } + + private TMemoryBuffer writeVInt32(int i) throws TException { + TMemoryBuffer tMemoryBuffer = new TMemoryBuffer(10); + TCompactProtocol tCompactProtocol = new TCompactProtocol(tMemoryBuffer); + tCompactProtocol.writeI32(i); + return tMemoryBuffer; + } +} diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/AnnotationTranscoderTest.java b/thrift/src/test/java/com/navercorp/pinpoint/io/util/AnnotationTranscoderTest.java similarity index 95% rename from commons/src/test/java/com/navercorp/pinpoint/common/util/AnnotationTranscoderTest.java rename to thrift/src/test/java/com/navercorp/pinpoint/io/util/AnnotationTranscoderTest.java index 76bf9c3eb5e1..c07b3ea98725 100644 --- a/commons/src/test/java/com/navercorp/pinpoint/common/util/AnnotationTranscoderTest.java +++ b/thrift/src/test/java/com/navercorp/pinpoint/io/util/AnnotationTranscoderTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,9 +14,12 @@ * limitations under the License. */ -package com.navercorp.pinpoint.common.util; +package com.navercorp.pinpoint.io.util; +import com.navercorp.pinpoint.common.util.IntBooleanIntBooleanValue; +import com.navercorp.pinpoint.common.util.IntStringValue; +import com.navercorp.pinpoint.common.util.LongIntIntByteByteStringValue; import com.navercorp.pinpoint.thrift.dto.TIntBooleanIntBooleanValue; import com.navercorp.pinpoint.thrift.dto.TIntStringValue; diff --git a/thrift/src/test/java/com/navercorp/pinpoint/io/util/TypeLocatorBuilderTest.java b/thrift/src/test/java/com/navercorp/pinpoint/io/util/TypeLocatorBuilderTest.java new file mode 100644 index 000000000000..532a27f263a7 --- /dev/null +++ b/thrift/src/test/java/com/navercorp/pinpoint/io/util/TypeLocatorBuilderTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.io.util; + +import com.navercorp.pinpoint.thrift.dto.TSpan; +import com.navercorp.pinpoint.thrift.dto.TSpanEvent; +import org.apache.thrift.TBase; +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Woonduk Kang(emeroad) + */ +public class TypeLocatorBuilderTest { + + @Test + public void addBodyFactory() { + TypeLocatorBuilder> typeLocatorBuilder = new TypeLocatorBuilder>(); + + typeLocatorBuilder.addBodyFactory((short) 1, new BodyFactory>() { + @Override + public TBase getObject() { + return new TSpan(); + } + }); + + typeLocatorBuilder.addBodyFactory((short) 3, new BodyFactory>() { + @Override + public TBase getObject() { + return new TSpanEvent(); + } + }); + + TypeLocator> build = typeLocatorBuilder.build(); + Assert.assertNotNull(build.bodyLookup((short) 1)); + Assert.assertNull(build.bodyLookup((short) 5)); + + Assert.assertEquals(build.headerLookup((short) 1).getType(), 1); + Assert.assertEquals(build.headerLookup((short) 3).getType(), 3); + } + + + @Test(expected = IllegalStateException.class) + public void addBodyFactory_duplicated_type_code() { + TypeLocatorBuilder> typeLocatorBuilder = new TypeLocatorBuilder>(); + + typeLocatorBuilder.addBodyFactory((short) 1, new BodyFactory>() { + @Override + public TBase getObject() { + return new TSpan(); + } + }); + + typeLocatorBuilder.addBodyFactory((short) 1, new BodyFactory>() { + @Override + public TBase getObject() { + return new TSpanEvent(); + } + }); + + } + + @Test(expected = IllegalStateException.class) + public void addBodyFactory_duplicated_body_class() { + TypeLocatorBuilder> typeLocatorBuilder = new TypeLocatorBuilder>(); + + typeLocatorBuilder.addBodyFactory((short) 1, new BodyFactory>() { + @Override + public TBase getObject() { + return new TSpan(); + } + }); + + typeLocatorBuilder.addBodyFactory((short) 3, new BodyFactory>() { + @Override + public TBase getObject() { + return new TSpan(); + } + }); + + } +} \ No newline at end of file diff --git a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializerTest.java b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializerTest.java index d8d80c918f39..f034e84ef023 100644 --- a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializerTest.java +++ b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderBufferedTBaseSerializerTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,20 +20,18 @@ import java.util.concurrent.atomic.AtomicInteger; +import com.navercorp.pinpoint.io.util.TypeLocator; +import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; import org.junit.Test; import com.navercorp.pinpoint.thrift.dto.TSpanChunk; -import com.navercorp.pinpoint.thrift.io.ChunkHeaderBufferedTBaseSerializer; -import com.navercorp.pinpoint.thrift.io.ChunkHeaderBufferedTBaseSerializerFlushHandler; -import com.navercorp.pinpoint.thrift.io.DefaultTBaseLocator; -import com.navercorp.pinpoint.thrift.io.TBaseLocator; -import com.navercorp.pinpoint.thrift.io.UnsafeByteArrayOutputStream; + public class ChunkHeaderBufferedTBaseSerializerTest { - private static final TBaseLocator DEFAULT_TBASE_LOCATOR = new DefaultTBaseLocator(); + private static final TypeLocator> DEFAULT_TBASE_LOCATOR = DefaultTBaseLocator.getTypeLocator(); private static final TProtocolFactory DEFAULT_PROTOCOL_FACTORY = new TCompactProtocol.Factory(); private AtomicInteger flushCounter = new AtomicInteger(0); diff --git a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializerTest.java b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializerTest.java index 4885833f124a..563901986b3d 100644 --- a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializerTest.java +++ b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/ChunkHeaderTBaseDeserializerTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,20 +20,17 @@ import java.util.List; +import com.navercorp.pinpoint.io.request.Message; +import com.navercorp.pinpoint.io.util.TypeLocator; import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; import org.junit.Test; import com.navercorp.pinpoint.thrift.dto.TSpanChunk; -import com.navercorp.pinpoint.thrift.io.ChunkHeaderBufferedTBaseSerializer; -import com.navercorp.pinpoint.thrift.io.ChunkHeaderTBaseDeserializer; -import com.navercorp.pinpoint.thrift.io.DefaultTBaseLocator; -import com.navercorp.pinpoint.thrift.io.TBaseLocator; -import com.navercorp.pinpoint.thrift.io.UnsafeByteArrayOutputStream; public class ChunkHeaderTBaseDeserializerTest { - private static final TBaseLocator DEFAULT_TBASE_LOCATOR = new DefaultTBaseLocator(); + private static final TypeLocator> DEFAULT_TBASE_LOCATOR = DefaultTBaseLocator.getTypeLocator(); private static final TProtocolFactory DEFAULT_PROTOCOL_FACTORY = new TCompactProtocol.Factory(); @Test @@ -45,9 +42,9 @@ public void deserialize() throws Exception { TSpanChunk chunk = new TSpanMockBuilder().buildChunk(3, 10); serializer.add(chunk); - List> list = deserializer.deserialize(serializer.getTransport().getBuffer(), 0, serializer.getTransport().getBufferPosition()); + List>> list = deserializer.deserialize(serializer.getTransport().getBuffer(), 0, serializer.getTransport().getBufferPosition()); assertEquals(1, list.size()); - TSpanChunk result = (TSpanChunk) list.get(0); + TSpanChunk result = (TSpanChunk) list.get(0).getData(); assertEquals(3, result.getSpanEventList().size()); } } \ No newline at end of file diff --git a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/DefaultTBaseLocatorTest.java b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/DefaultTBaseLocatorTest.java new file mode 100644 index 000000000000..901fa404cd22 --- /dev/null +++ b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/DefaultTBaseLocatorTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.thrift.io; + +import com.navercorp.pinpoint.io.util.TypeLocator; +import org.apache.thrift.TBase; +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Woonduk Kang(emeroad) + */ +public class DefaultTBaseLocatorTest { + + @Test + public void getTypeLocator() { + TypeLocator> typeLocator = DefaultTBaseLocator.getTypeLocator(); + Assert.assertNotNull(typeLocator.bodyLookup(DefaultTBaseLocator.SPAN)); + } +} \ No newline at end of file diff --git a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerTest.java b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerTest.java index e212f70cb7d0..0433f16150c9 100644 --- a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerTest.java +++ b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderTBaseSerializerTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +16,11 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.thrift.dto.TAgentInfo; -import com.navercorp.pinpoint.thrift.io.Header; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializerFactory; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; -import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializerFactory; + +import org.apache.thrift.TBase; import org.apache.thrift.TException; import org.junit.Assert; import org.junit.Test; @@ -56,10 +54,6 @@ public void testSerialize2() throws Exception { private void test(HeaderTBaseSerializer serializer, HeaderTBaseDeserializer deserializer) throws TException { - Header header = new Header(); - // 10 is JVMInfoThriftDTO type - header.setType((short) 10); - TAgentInfo tAgentInfo = new TAgentInfo(); tAgentInfo.setAgentId("agentId"); tAgentInfo.setHostname("host"); @@ -68,7 +62,8 @@ private void test(HeaderTBaseSerializer serializer, HeaderTBaseDeserializer dese byte[] serialize = serializer.serialize(tAgentInfo); dump(serialize); - TAgentInfo deserialize = (TAgentInfo) deserializer.deserialize(serialize); + Message> message = deserializer.deserialize(serialize); + TAgentInfo deserialize = (TAgentInfo) message.getData(); logger.debug("deserializer:{}", deserialize.getClass()); Assert.assertEquals(deserialize, tAgentInfo); diff --git a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderTest.java b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderTest.java index 93481d6b9947..2da66cd6ced4 100644 --- a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderTest.java +++ b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderTest.java @@ -16,11 +16,13 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.navercorp.pinpoint.thrift.io.Header; + /** * @author emeroad @@ -31,7 +33,7 @@ public class HeaderTest { @Test public void testGetSignature() throws Exception { - Header header = new Header(); + Header header = new HeaderV1((short) 1); byte signature = header.getSignature(); short type = header.getType(); byte version = header.getVersion(); diff --git a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderUtilsTest.java b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderUtilsTest.java index 7a490b3e25d6..f74a4ab8b089 100644 --- a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderUtilsTest.java +++ b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/HeaderUtilsTest.java @@ -16,6 +16,9 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.header.InvalidHeaderException; +import com.navercorp.pinpoint.io.header.v1.HeaderV1; import org.apache.thrift.TException; import org.junit.Assert; import org.junit.Test; @@ -31,15 +34,19 @@ public class HeaderUtilsTest { @Test public void validateSignature() throws TException { - Header header = new Header(); + Header header = new HeaderV1((short) 1); Assert.assertTrue(HeaderUtils.validateSignature(header.getSignature()) == HeaderUtils.OK); + logger.debug(header.toString()); + } - Header error = new Header((byte) 0x11, (byte) 0x20, (short) 1); + @Test(expected = InvalidHeaderException.class) + public void validateSignature_error() throws TException { + Header error = new HeaderV1((byte) 0x11, (byte) 0x20, (short) 1); Assert.assertTrue(HeaderUtils.validateSignature(error.getSignature()) != HeaderUtils.OK); - logger.debug(header.toString()); + logger.debug(error.toString()); } } diff --git a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/TBaseStreamTest.java b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/TBaseStreamTest.java index 365b9d86b52d..222427b918c5 100644 --- a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/TBaseStreamTest.java +++ b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/TBaseStreamTest.java @@ -52,7 +52,7 @@ public void clear() throws Exception { assertTrue(stream.size() > 0); stream.clear(); - assertTrue(stream.size() == 0); + assertTrue(stream.isEmpty()); } @Test diff --git a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/TCommandRegistryTest.java b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/TCommandRegistryTest.java index 85d6890f4923..f53ca3d0c8d7 100644 --- a/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/TCommandRegistryTest.java +++ b/thrift/src/test/java/com/navercorp/pinpoint/thrift/io/TCommandRegistryTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,8 @@ package com.navercorp.pinpoint.thrift.io; +import com.navercorp.pinpoint.io.header.Header; +import com.navercorp.pinpoint.io.util.TypeLocator; import com.navercorp.pinpoint.thrift.dto.TResult; import com.navercorp.pinpoint.thrift.dto.command.TCommandThreadDump; import com.navercorp.pinpoint.thrift.dto.command.TCommandTransferResponse; @@ -31,7 +33,7 @@ public class TCommandRegistryTest { @Test public void registryTest1() { - TCommandRegistry registry = new TCommandRegistry(TCommandTypeVersion.UNKNOWN); + TypeLocator> registry = TCommandRegistry.build(TCommandTypeVersion.UNKNOWN); Assert.assertFalse(registry.isSupport(TCommandType.RESULT.getCode())); Assert.assertFalse(registry.isSupport(TCommandType.THREAD_DUMP.getCode())); @@ -40,23 +42,21 @@ public void registryTest1() { Assert.assertFalse(registry.isSupport(TCommandThreadDump.class)); } - @Test(expected = TException.class) public void registryTest2() throws TException { - TCommandRegistry registry = new TCommandRegistry(TCommandTypeVersion.UNKNOWN); + TypeLocator> registry = TCommandRegistry.build(TCommandTypeVersion.UNKNOWN); - registry.headerLookup(new TResult()); + Assert.assertNull(registry.headerLookup(new TResult())); } - @Test(expected = TException.class) public void registryTest3() throws TException { - TCommandRegistry registry = new TCommandRegistry(TCommandTypeVersion.UNKNOWN); + TypeLocator> registry = TCommandRegistry.build(TCommandTypeVersion.UNKNOWN); - registry.tBaseLookup(TCommandType.RESULT.getCode()); + Assert.assertNull(registry.bodyLookup(TCommandType.RESULT.getCode())); } @Test public void registryTest4() { - TCommandRegistry registry = new TCommandRegistry(TCommandTypeVersion.V_1_0_2_SNAPSHOT); + TypeLocator> registry = TCommandRegistry.build(TCommandTypeVersion.V_1_0_2_SNAPSHOT); Assert.assertTrue(registry.isSupport(TCommandType.RESULT.getCode())); Assert.assertTrue(registry.isSupport(TCommandType.THREAD_DUMP.getCode())); @@ -67,7 +67,7 @@ public void registryTest4() { @Test public void registryTest5() throws TException { - TCommandRegistry registry = new TCommandRegistry(TCommandTypeVersion.V_1_0_2_SNAPSHOT); + TypeLocator> registry = TCommandRegistry.build(TCommandTypeVersion.V_1_0_2_SNAPSHOT); Header header = registry.headerLookup(new TResult()); Assert.assertNotNull(header); @@ -75,18 +75,18 @@ public void registryTest5() throws TException { @Test public void registryTest6() throws TException { - TCommandRegistry registry = new TCommandRegistry(TCommandTypeVersion.V_1_0_2_SNAPSHOT); + TypeLocator> registry = TCommandRegistry.build(TCommandTypeVersion.V_1_0_2_SNAPSHOT); - TBase tBase = registry.tBaseLookup(TCommandType.RESULT.getCode()); + TBase tBase = registry.bodyLookup(TCommandType.RESULT.getCode()); Assert.assertEquals(tBase.getClass(), TResult.class); - tBase = registry.tBaseLookup(TCommandType.THREAD_DUMP.getCode()); + tBase = registry.bodyLookup(TCommandType.THREAD_DUMP.getCode()); Assert.assertEquals(tBase.getClass(), TCommandThreadDump.class); } @Test public void isSupportTest() throws TException { - TCommandRegistry registry = new TCommandRegistry(TCommandTypeVersion.V_1_0_2_SNAPSHOT); + TypeLocator> registry = TCommandRegistry.build(TCommandTypeVersion.V_1_0_2_SNAPSHOT); boolean isSupport = registry.isSupport(TResult.class); Assert.assertTrue(isSupport); @@ -95,4 +95,18 @@ public void isSupportTest() throws TException { Assert.assertFalse(isSupport); } +// @Test + public void isSupportTest_Inheritance() throws TException { + TypeLocator> registry = TCommandRegistry.build(TCommandTypeVersion.V_1_0_2_SNAPSHOT); + + boolean isSupport = registry.isSupport(TResultEx.class); + Assert.assertTrue(isSupport); + + isSupport = registry.isSupport(TCommandTransferResponse.class); + Assert.assertFalse(isSupport); + } + + class TResultEx extends TResult { + } + } diff --git a/tools/clover.license b/tools/clover.license deleted file mode 100644 index 569fa6175b4c..000000000000 --- a/tools/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF 4.0.0 + com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-tools @@ -14,9 +15,59 @@ com.navercorp.pinpoint - pinpoint-profiler - provided + pinpoint-bootstrap-core + ${project.version} + + + com.navercorp.pinpoint + pinpoint-thrift + ${project.version} - + + org.apache.thrift + libthrift + 0.11.0 + + + + org.slf4j + slf4j-api + 1.7.21 + + + + org.slf4j + slf4j-log4j12 + 1.7.21 + + + log4j + log4j + 1.2.17 + + + + + + + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + false + + + + diff --git a/tools/src/main/script/networktest.sh b/tools/src/main/script/networktest.sh index 11d40d167ac1..7c04cee4cd85 100644 --- a/tools/src/main/script/networktest.sh +++ b/tools/src/main/script/networktest.sh @@ -3,6 +3,7 @@ WORKING_DIR=$(dirname "$0") cd -P "$WORKING_DIR"/.. > /dev/null -CL_PATH=$(find . -name '*.jar' | tr "\n" :) +CL_PATH=$(find ./tools -name '*.jar' | tr "\n" :) echo "CLASSPATH=$CL_PATH" -java -classpath $CL_PATH com.navercorp.pinpoint.tools.NetworkAvailabilityChecker pinpoint.config + +java -cp $CL_PATH com.navercorp.pinpoint.tools.NetworkAvailabilityChecker ./pinpoint.config diff --git a/web/clover.license b/web/clover.license deleted file mode 100644 index 883220ef15dd..000000000000 --- a/web/clover.license +++ /dev/null @@ -1,5 +0,0 @@ -RMRqrdbgbKFhbaVnDxHUdDQvrOQXxIBklnvcmahheubVC -mh2KM35CLkwUHS4DH7QVhxy52J5hnWbyEm6Cyd3KkF + 4.0.0 com.navercorp.pinpoint pinpoint - 1.7.2-SNAPSHOT + 1.8.1-SNAPSHOT pinpoint-web @@ -16,7 +32,6 @@ ${env.JAVA_8_HOME} yyyyMMddHHmmss java18 - 2.8.10 build_release_without_lint @@ -41,11 +56,6 @@ com.navercorp.pinpoint pinpoint-thrift - - com.navercorp.pinpoint - pinpoint-bootstrap - runtime - com.navercorp.pinpoint pinpoint-plugins @@ -83,8 +93,8 @@ - org.apache.tomcat - servlet-api + javax.servlet + javax.servlet-api provided @@ -153,7 +163,7 @@ spring-messaging ${spring.version} - + org.springframework.security spring-security-web @@ -246,26 +256,10 @@ runtime - - - org.apache.httpcomponents - httpclient - - - commons-logging - commons-logging - - - - org.apache.httpcomponents - httpcore - - - commons-logging - commons-logging - - + commons-codec + commons-codec + 1.11 @@ -316,9 +310,10 @@ - javax.servlet - javax.servlet-api - 3.0.1 + com.navercorp.pinpoint + pinpoint-rpc + ${project.version} + test-jar test @@ -349,50 +344,12 @@ target/main/webapp + + v2/node_modules/ + - - - - com.spotify - docker-maven-plugin - ${docker.maven.plugin.version} - - false - naver/${project.artifactId}:${project.version} - tomcat:8-jre8 - - ["/usr/local/bin/start-web.sh"] - - - 8080 - - - - /assets/ - ${project.build.directory} - ${project.artifactId}-${project.version}.war - - - /assets/ - ${project.build.directory}/deploy/WEB-INF/classes/ - - pinpoint-web.properties - hbase.properties - - - - /usr/local/bin/ - ${project.basedir}/ - start-web.sh - - - - chmod a+x /usr/local/bin/start-web.sh - rm -rf /usr/local/tomcat/webapps/* - unzip /assets/${project.artifactId}-${project.version}.war -d /usr/local/tomcat/webapps/ROOT - rm -rf /assets/${project.artifactId}-${project.version}.war - + v2/node_modules/ @@ -402,20 +359,24 @@ prepare-grunt + generate-resources run - generate-resources - + - + + + - - + + @@ -424,9 +385,8 @@ com.github.eirslett frontend-maven-plugin - 1.0 + 1.5 - ${basedir}/target ${basedir}/target/main/webapp ${basedir}/target/main/webapp target @@ -434,30 +394,36 @@ install node and npm + prepare-package install-node-and-npm v5.11.1 3.9.6 + ${basedir}/target npm install + prepare-package npm install + ${basedir}/target grunt build + prepare-package grunt ${grunt.build.command} + ${basedir}/target @@ -500,5 +466,57 @@ + + + v2 + + + + com.github.eirslett + frontend-maven-plugin + 1.5 + + target + + + + install node and npm v2 + prepare-package + + install-node-and-npm + + + v10.6.0 + 6.1.0 + ${basedir}/target/main/webapp/v2 + + + + npm install v2 + prepare-package + + npm + + + install + ${basedir}/target/main/webapp/v2 + + + + npm run build v2 + prepare-package + + npm + + + run build + ${basedir}/target/main/webapp/v2 + + + + + + + diff --git a/web/src/Gruntfile.js b/web/src/Gruntfile.js index ea0414ca28db..b7e4c14a8706 100644 --- a/web/src/Gruntfile.js +++ b/web/src/Gruntfile.js @@ -19,6 +19,8 @@ module.exports = function (grunt) { 'PAGE': ROOT + '/pages', 'COMMON': ROOT + '/common', 'FEATURE': ROOT + '/features', + 'STAT_HTML': ROOT + '/stat.html', + 'DANGER_HTML': ROOT + '/_danger.html', 'INDEX_HTML': ROOT + '/index.html', 'SERVER_MAP': ROOT + '/components/server-map2', 'TIME_SLIDER': ROOT + '/components/time-slider', diff --git a/web/src/grunt/concat.js b/web/src/grunt/concat.js index 8ba0d2bbde20..115e11051741 100644 --- a/web/src/grunt/concat.js +++ b/web/src/grunt/concat.js @@ -158,6 +158,8 @@ module.exports = function( grunt, options ) { '/common/services/tps-chart-dao.service.js', '/common/services/active-thread-chart-dao.service.js', '/common/services/response-time-chart-dao.service.js', + '/common/services/open-file-descriptor-chart-dao.service.js', + '/common/services/direct-buffer-chart-dao.service.js', '/common/services/agent-histogram-dao.service.js', '/common/services/filtered-map-util.service.js', '/common/services/filter.config.js', diff --git a/web/src/grunt/regex-replace.js b/web/src/grunt/regex-replace.js index 6bda5a179c85..dad70ceb70ce 100644 --- a/web/src/grunt/regex-replace.js +++ b/web/src/grunt/regex-replace.js @@ -43,7 +43,7 @@ module.exports = function( grunt, options ) { }] }, html: { - src: [ options.RESOURCE_PATH.INDEX_HTML ], + src: [ options.RESOURCE_PATH.INDEX_HTML, options.RESOURCE_PATH.DANGER_HTML, options.RESOURCE_PATH.STAT_HTML ], actions: [{ name: 'build.time', search: /\$\{buildTime\}/gm, diff --git a/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmPartitioner.java b/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmPartitioner.java index cac183321e69..7fa5779667be 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmPartitioner.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmPartitioner.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Map; +import com.navercorp.pinpoint.web.batch.DefaultDivider; +import com.navercorp.pinpoint.web.batch.Divider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.partition.support.Partitioner; @@ -28,48 +30,24 @@ import com.navercorp.pinpoint.web.dao.ApplicationIndexDao; import com.navercorp.pinpoint.web.vo.Application; +import org.springframework.beans.factory.annotation.Qualifier; /** * @author minwoo.jung */ public class AlarmPartitioner implements Partitioner { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public static final int APP_COUNT = 5; - public static final String PARTITION_NUMBER = "partition_number"; - @Autowired - private ApplicationIndexDao applicationIndexDao; + private static final String PARTITION_NAME_PREFIX = "alarm_partition_number_"; + private static final String BATCH_NAME = "alarm_batch"; - public AlarmPartitioner() { - } - protected AlarmPartitioner(ApplicationIndexDao applicationIndexDao) { - this.applicationIndexDao = applicationIndexDao; - } + @Autowired(required = false) + @Qualifier("divider") + private Divider divider = new DefaultDivider(); @Override public Map partition(int gridSize) { - int partitionCount = calculateGroupCount(); - Map mapContext = new HashMap<>(); - - for (int i = 1; i <= partitionCount; i++) { - ExecutionContext executionContext = new ExecutionContext(); - executionContext.put(PARTITION_NUMBER, i); - mapContext.put(PARTITION_NUMBER + "_" + i, executionContext); - } - - return mapContext; - } - - public int calculateGroupCount() { - List applicationList = applicationIndexDao.selectAllApplicationNames(); - int partitionCount = applicationList.size() / APP_COUNT; - - if (applicationList.size() % APP_COUNT != 0) { - partitionCount++; - } - - logger.info("application count is {}. partition count is {}", applicationList.size(), partitionCount); - return partitionCount; + return divider.divide(PARTITION_NAME_PREFIX, BATCH_NAME); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmReader.java b/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmReader.java index 6cd21b905fa3..2a985dee4c87 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmReader.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmReader.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedDeque; import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.StepExecution; @@ -50,7 +51,7 @@ public class AlarmReader implements ItemReader, StepExecutionListe @Autowired private AlarmService alarmService; - private final Queue checkers = new LinkedList<>(); + private final Queue checkers = new ConcurrentLinkedDeque<>(); public AlarmReader() { } @@ -68,21 +69,9 @@ public AlarmChecker read() { @Override public void beforeStep(StepExecution stepExecution) { List applicationList = applicationIndexDao.selectAllApplicationNames(); - int appSize = applicationList.size(); - int partitionNumber = (Integer) stepExecution.getExecutionContext().get(AlarmPartitioner.PARTITION_NUMBER); - int from = (partitionNumber - 1) * AlarmPartitioner.APP_COUNT; - int to = partitionNumber * AlarmPartitioner.APP_COUNT; - - if (appSize < from) { - return; - } - if (appSize < to) { - to = appSize; - } - - for(int i = from; i < to; i++) { - addChecker(applicationList.get(i)); + for (Application application : applicationList) { + addChecker(application); } } @@ -94,8 +83,7 @@ private void addChecker(Application application) { for (Rule rule : rules) { CheckerCategory checkerCategory = CheckerCategory.getValue(rule.getCheckerName()); DataCollector collector = collectorMap.get(checkerCategory.getDataCollectorCategory()); - - if(collector == null) { + if (collector == null) { collector = dataCollectorFactory.createDataCollector(checkerCategory, application, timeSlotEndTime); collectorMap.put(collector.getDataCollectorCategory(), collector); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmWriter.java b/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmWriter.java index f995376a96de..a65bb07c7845 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmWriter.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/alarm/AlarmWriter.java @@ -30,26 +30,26 @@ * @author minwoo.jung */ public class AlarmWriter implements ItemWriter { - - @Autowired(required=false) + + @Autowired(required = false) private AlarmMessageSender alarmMessageSender = new EmptyMessageSender(); - + @Autowired private AlarmService alarmService; - + @Override public void write(List checkers) throws Exception { Map beforeCheckerResults = alarmService.selectBeforeCheckerResults(checkers.get(0).getRule().getApplicationId()); - for(AlarmChecker checker : checkers) { + for (AlarmChecker checker : checkers) { CheckerResult beforeCheckerResult = beforeCheckerResults.get(checker.getRule().getCheckerName()); - + if (beforeCheckerResult == null) { - beforeCheckerResult = new CheckerResult(checker.getRule().getApplicationId(), checker.getRule().getCheckerName(), false, 0 , 1); + beforeCheckerResult = new CheckerResult(checker.getRule().getApplicationId(), checker.getRule().getCheckerName(), false, 0, 1); } - + if (checker.isDetected()) { - sendAlarmMessage(beforeCheckerResult, checker); + sendAlarmMessage(beforeCheckerResult, checker); } alarmService.updateBeforeCheckerResult(beforeCheckerResult, checker); @@ -65,20 +65,20 @@ private void sendAlarmMessage(CheckerResult beforeCheckerResult, AlarmChecker ch alarmMessageSender.sendEmail(checker, beforeCheckerResult.getSequenceCount() + 1); } } - + } private boolean isTurnToSendAlarm(CheckerResult beforeCheckerResult) { - if(!beforeCheckerResult.isDetected()) { + if (!beforeCheckerResult.isDetected()) { return true; } - + int sequenceCount = beforeCheckerResult.getSequenceCount() + 1; - + if (sequenceCount == beforeCheckerResult.getTimingCount()) { - return true; + return true; } - + return false; } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/alarm/collector/MapStatisticsCallerDataCollector.java b/web/src/main/java/com/navercorp/pinpoint/web/alarm/collector/MapStatisticsCallerDataCollector.java index 215b66d7409c..3cd84aaca23a 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/alarm/collector/MapStatisticsCallerDataCollector.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/alarm/collector/MapStatisticsCallerDataCollector.java @@ -40,7 +40,7 @@ public class MapStatisticsCallerDataCollector extends DataCollector { private long timeSlotEndTime; private long slotInterval; private Map calleStatMap = new HashMap<>(); - private final AtomicBoolean init =new AtomicBoolean(false); // need to consider a trace condition when checkers start simultaneously. + private final AtomicBoolean init = new AtomicBoolean(false); // need to consider a trace condition when checkers start simultaneously. public MapStatisticsCallerDataCollector(DataCollectorCategory category, Application application, MapStatisticsCallerDao mapStatisticsCallerDao, long timeSlotEndTime, long slotInterval) { super(category); @@ -70,11 +70,13 @@ public void collect() { } public long getCount(String calleName, DataCategory dataCategory) { - LinkCallData linkCallData = calleStatMap.get(calleName); - long count = 0; + final LinkCallData linkCallData = calleStatMap.get(calleName); + if (linkCallData == null) { + return 0; + } - if (linkCallData != null) { - switch (dataCategory) { + long count = 0; + switch (dataCategory) { case SLOW_COUNT: for (TimeHistogram timeHistogram : linkCallData.getTimeHistogram()) { count += timeHistogram.getSlowCount(); @@ -91,23 +93,24 @@ public long getCount(String calleName, DataCategory dataCategory) { count += timeHistogram.getTotalCount(); } break; - default : + default: throw new IllegalArgumentException("Can't count for " + dataCategory.toString()); - } - - return count; } - return 0; + return count; + + } public long getCountRate(String calleName, DataCategory dataCategory) { - LinkCallData linkCallData = calleStatMap.get(calleName); + final LinkCallData linkCallData = calleStatMap.get(calleName); + if (linkCallData == null) { + return 0; + } + long count = 0; long totalCount = 0; - - if (linkCallData != null) { - switch (dataCategory) { + switch (dataCategory) { case SLOW_RATE: for (TimeHistogram timeHistogram : linkCallData.getTimeHistogram()) { count += timeHistogram.getSlowCount(); @@ -121,14 +124,12 @@ public long getCountRate(String calleName, DataCategory dataCategory) { totalCount += timeHistogram.getTotalCount(); } break; - default : + default: throw new IllegalArgumentException("Can't calculate rate for " + dataCategory.toString()); - } - - return calculatePercent(count, totalCount); } - return 0; + return calculatePercent(count, totalCount); + } public enum DataCategory { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/alarm/vo/Rule.java b/web/src/main/java/com/navercorp/pinpoint/web/alarm/vo/Rule.java index 983ad86608dd..b01edfbbfa90 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/alarm/vo/Rule.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/alarm/vo/Rule.java @@ -116,4 +116,20 @@ public String getNotes() { public void setNotes(String notes) { this.notes = notes; } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Rule{"); + sb.append("ruleId='").append(ruleId).append('\''); + sb.append(", applicationId='").append(applicationId).append('\''); + sb.append(", serviceType='").append(serviceType).append('\''); + sb.append(", checkerName='").append(checkerName).append('\''); + sb.append(", threshold=").append(threshold); + sb.append(", userGroupId='").append(userGroupId).append('\''); + sb.append(", smsSend=").append(smsSend); + sb.append(", emailSend=").append(emailSend); + sb.append(", notes='").append(notes).append('\''); + sb.append('}'); + return sb.toString(); + } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/DefaultNodeHistogramAppender.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/DefaultNodeHistogramAppender.java new file mode 100644 index 000000000000..feab7c82eaed --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/DefaultNodeHistogramAppender.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.applicationmap.appender.histogram; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.web.applicationmap.histogram.NodeHistogram; +import com.navercorp.pinpoint.web.applicationmap.link.LinkList; +import com.navercorp.pinpoint.web.applicationmap.nodes.Node; +import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; +import com.navercorp.pinpoint.web.vo.Application; +import com.navercorp.pinpoint.web.vo.Range; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Supplier; + +/** + * @author HyunGil Jeong + */ +public class DefaultNodeHistogramAppender implements NodeHistogramAppender { + + private final NodeHistogramFactory nodeHistogramFactory; + + private final Executor executor; + + public DefaultNodeHistogramAppender(NodeHistogramFactory nodeHistogramFactory, Executor executor) { + this.nodeHistogramFactory = Objects.requireNonNull(nodeHistogramFactory, "nodeHistogramFactory must not be null"); + this.executor = Objects.requireNonNull(executor, "executor must not be null"); + } + + @Override + public void appendNodeHistogram(Range range, NodeList nodeList, LinkList linkList) { + if (nodeList == null) { + return; + } + final Collection nodes = nodeList.getNodeList(); + if (CollectionUtils.isEmpty(nodes)) { + return; + } + CompletableFuture[] futures = getNodeHistogramFutures(range, nodes, linkList); + CompletableFuture.allOf(futures).join(); + } + + private CompletableFuture[] getNodeHistogramFutures(Range range, Collection nodes, LinkList linkList) { + List> nodeHistogramFutures = new ArrayList<>(); + for (Node node : nodes) { + CompletableFuture nodeHistogramFuture = getNodeHistogramFuture(range, node, linkList); + nodeHistogramFutures.add(nodeHistogramFuture); + } + return nodeHistogramFutures.toArray(new CompletableFuture[0]); + } + + private CompletableFuture getNodeHistogramFuture(Range range, Node node, LinkList linkList) { + CompletableFuture nodeHistogramFuture; + final Application application = node.getApplication(); + final ServiceType serviceType = application.getServiceType(); + + if (serviceType.isWas()) { + // for WAS nodes, set their own response time histogram + final Application wasNode = node.getApplication(); + nodeHistogramFuture = CompletableFuture.supplyAsync(new Supplier() { + @Override + public NodeHistogram get() { + return nodeHistogramFactory.createWasNodeHistogram(wasNode, range); + } + }, executor); + } else if (serviceType.isTerminal() || serviceType.isUnknown()) { + nodeHistogramFuture = CompletableFuture.completedFuture(nodeHistogramFactory.createTerminalNodeHistogram(application, range, linkList)); + } else if (serviceType.isQueue()) { + // Virtual queue node - queues with agent installed will be handled above as a WAS node + nodeHistogramFuture = CompletableFuture.completedFuture(nodeHistogramFactory.createQueueNodeHistogram(application, range, linkList)); + } else if (serviceType.isUser()) { + nodeHistogramFuture = CompletableFuture.completedFuture(nodeHistogramFactory.createUserNodeHistogram(application, range, linkList)); + } else { + nodeHistogramFuture = CompletableFuture.completedFuture(nodeHistogramFactory.createEmptyNodeHistogram(application, range)); + } + return nodeHistogramFuture.thenAccept(node::setNodeHistogram); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderFactory.java index 32ed79ad9294..f619d66a3a84 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderFactory.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderFactory.java @@ -16,17 +16,12 @@ package com.navercorp.pinpoint.web.applicationmap.appender.histogram; -import com.navercorp.pinpoint.common.util.PinpointThreadFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; -import javax.annotation.PreDestroy; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Objects; +import java.util.concurrent.Executor; /** * @author HyunGil Jeong @@ -34,40 +29,14 @@ @Component public class NodeHistogramAppenderFactory { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final String mode; - private final ExecutorService executorService; + private final Executor executor; @Autowired - public NodeHistogramAppenderFactory( - @Value("#{pinpointWebProps['web.servermap.appender.mode'] ?: 'serial'}") String mode, - @Value("#{pinpointWebProps['web.servermap.appender.parallel.maxthreads'] ?: 16}") int maxThreads) { - logger.info("NodeHistogramAppender mode : {}", mode); - this.mode = mode; - if (this.mode.equalsIgnoreCase("parallel")) { - executorService = Executors.newFixedThreadPool(maxThreads, new PinpointThreadFactory("Pinpoint-node-histogram-appender", true)); - } else { - executorService = null; - } + public NodeHistogramAppenderFactory(@Qualifier("nodeHistogramAppendExecutor") Executor executor) { + this.executor = Objects.requireNonNull(executor, "executor must not be null"); } public NodeHistogramAppender create(NodeHistogramFactory nodeHistogramFactory) { - if (mode.equalsIgnoreCase("parallel")) { - return new ParallelNodeHistogramAppender(nodeHistogramFactory, executorService); - } - return new SerialNodeHistogramAppender(nodeHistogramFactory); - } - - @PreDestroy - public void preDestroy() { - if (executorService != null) { - executorService.shutdown(); - try { - executorService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } + return new DefaultNodeHistogramAppender(nodeHistogramFactory, executor); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/ParallelNodeHistogramAppender.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/ParallelNodeHistogramAppender.java deleted file mode 100644 index b86941a113f2..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/ParallelNodeHistogramAppender.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.histogram; - -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.web.applicationmap.link.LinkList; -import com.navercorp.pinpoint.web.applicationmap.nodes.Node; -import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; -import com.navercorp.pinpoint.web.applicationmap.histogram.NodeHistogram; -import com.navercorp.pinpoint.web.vo.Application; -import com.navercorp.pinpoint.web.vo.Range; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.function.Supplier; - -/** - * @author HyunGil Jeong - */ -public class ParallelNodeHistogramAppender implements NodeHistogramAppender { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final NodeHistogramFactory nodeHistogramFactory; - - private final ExecutorService executorService; - - public ParallelNodeHistogramAppender(NodeHistogramFactory nodeHistogramFactory, ExecutorService executorService) { - if (nodeHistogramFactory == null) { - throw new NullPointerException("nodeHistogramFactory must not be null"); - } - if (executorService == null) { - throw new NullPointerException("executorService must not be null"); - } - this.nodeHistogramFactory = nodeHistogramFactory; - this.executorService = executorService; - } - - @Override - public void appendNodeHistogram(Range range, NodeList nodeList, LinkList linkList) { - if (nodeList == null) { - return; - } - final Collection nodes = nodeList.getNodeList(); - if (CollectionUtils.isEmpty(nodes)) { - return; - } - CompletableFuture[] futures = getNodeHistogramFutures(range, nodes, linkList); - try { - CompletableFuture.allOf(futures).join(); - } catch (Exception e) { - logger.error("Error appending node histograms", e); - } - } - - private CompletableFuture[] getNodeHistogramFutures(Range range, Collection nodes, LinkList linkList) { - List> nodeHistogramFutures = new ArrayList<>(); - for (Node node : nodes) { - CompletableFuture nodeHistogramFuture = getNodeHistogramFuture(range, node, linkList); - nodeHistogramFutures.add(nodeHistogramFuture); - } - return nodeHistogramFutures.toArray(new CompletableFuture[nodeHistogramFutures.size()]); - } - - private CompletableFuture getNodeHistogramFuture(Range range, Node node, LinkList linkList) { - CompletableFuture nodeHistogramFuture; - final Application application = node.getApplication(); - final ServiceType serviceType = application.getServiceType(); - if (serviceType.isWas()) { - // for WAS nodes, set their own response time histogram - final Application wasNode = node.getApplication(); - nodeHistogramFuture = CompletableFuture.supplyAsync(new Supplier() { - @Override - public NodeHistogram get() { - return nodeHistogramFactory.createWasNodeHistogram(wasNode, range); - } - }, executorService); - } else if (serviceType.isTerminal() || serviceType.isUnknown()) { - nodeHistogramFuture = CompletableFuture.completedFuture(nodeHistogramFactory.createTerminalNodeHistogram(application, range, linkList)); - } else if (serviceType.isQueue()) { - // Virtual queue node - queues with agent installed will be handled above as a WAS node - nodeHistogramFuture = CompletableFuture.completedFuture(nodeHistogramFactory.createQueueNodeHistogram(application, range, linkList)); - } else if (serviceType.isUser()) { - nodeHistogramFuture = CompletableFuture.completedFuture(nodeHistogramFactory.createUserNodeHistogram(application, range, linkList)); - } else { - nodeHistogramFuture = CompletableFuture.completedFuture(nodeHistogramFactory.createEmptyNodeHistogram(application, range)); - } - return nodeHistogramFuture.thenAccept(node::setNodeHistogram); - } -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/SerialNodeHistogramAppender.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/SerialNodeHistogramAppender.java deleted file mode 100644 index 3d00e2c48d00..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/SerialNodeHistogramAppender.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.histogram; - -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.web.applicationmap.link.LinkList; -import com.navercorp.pinpoint.web.applicationmap.nodes.Node; -import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; -import com.navercorp.pinpoint.web.applicationmap.histogram.NodeHistogram; -import com.navercorp.pinpoint.web.vo.Application; -import com.navercorp.pinpoint.web.vo.Range; - -import java.util.Collection; - -/** - * @author emeroad - * @author minwoo.jung - * @author HyunGil Jeong - */ -public class SerialNodeHistogramAppender implements NodeHistogramAppender { - - private final NodeHistogramFactory nodeHistogramFactory; - - public SerialNodeHistogramAppender(NodeHistogramFactory nodeHistogramFactory) { - if (nodeHistogramFactory == null) { - throw new NullPointerException("nodeHistogramFactory must not be null"); - } - this.nodeHistogramFactory = nodeHistogramFactory; - } - - @Override - public void appendNodeHistogram(Range range, NodeList nodeList, LinkList linkList) { - final Collection nodes = nodeList.getNodeList(); - for (Node node : nodes) { - node.setNodeHistogram(createNodeHistogram(range, node, linkList)); - } - } - - private NodeHistogram createNodeHistogram(Range range, Node node, LinkList linkList) { - final Application application = node.getApplication(); - final ServiceType serviceType = application.getServiceType(); - if (serviceType.isWas()) { - // for WAS nodes, set their own response time histogram - return nodeHistogramFactory.createWasNodeHistogram(application, range); - } else if (serviceType.isTerminal() || serviceType.isUnknown()) { - return nodeHistogramFactory.createTerminalNodeHistogram(application, range, linkList); - } else if (serviceType.isQueue()) { - // Virtual queue node - queues with agent installed will be handled above as a WAS node - return nodeHistogramFactory.createQueueNodeHistogram(application, range, linkList); - } else if (serviceType.isUser()) { - return nodeHistogramFactory.createUserNodeHistogram(application, range, linkList); - } else { - return nodeHistogramFactory.createEmptyNodeHistogram(application, range); - } - } -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/DefaultServerInfoAppender.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/DefaultServerInfoAppender.java new file mode 100644 index 000000000000..9f75940c503d --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/DefaultServerInfoAppender.java @@ -0,0 +1,102 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.applicationmap.appender.server; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.web.applicationmap.nodes.Node; +import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; +import com.navercorp.pinpoint.web.applicationmap.nodes.ServerInstanceList; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; +import com.navercorp.pinpoint.web.vo.Range; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Supplier; + +/** + * @author HyunGil Jeong + */ +public class DefaultServerInfoAppender implements ServerInfoAppender { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final ServerInstanceListFactory serverInstanceListFactory; + + private final Executor executor; + + public DefaultServerInfoAppender(ServerInstanceListFactory serverInstanceListFactory, Executor executor) { + this.serverInstanceListFactory = Objects.requireNonNull(serverInstanceListFactory, "serverInstanceListFactory must not be null"); + this.executor = Objects.requireNonNull(executor, "executor must not be null"); + } + + @Override + public void appendServerInfo(Range range, NodeList source, LinkDataDuplexMap linkDataDuplexMap) { + if (source == null) { + return; + } + Collection nodes = source.getNodeList(); + if (CollectionUtils.isEmpty(nodes)) { + return; + } + CompletableFuture[] futures = getServerInstanceListFutures(range, nodes, linkDataDuplexMap); + CompletableFuture.allOf(futures).join(); + } + + private CompletableFuture[] getServerInstanceListFutures(Range range, Collection nodes, LinkDataDuplexMap linkDataDuplexMap) { + List> serverInstanceListFutures = new ArrayList<>(); + for (Node node : nodes) { + if (node.getServiceType().isUnknown()) { + // we do not know the server info for unknown nodes + continue; + } + CompletableFuture serverInstanceListFuture = getServerInstanceListFuture(range, node, linkDataDuplexMap); + serverInstanceListFutures.add(serverInstanceListFuture); + } + return serverInstanceListFutures.toArray(new CompletableFuture[0]); + } + + private CompletableFuture getServerInstanceListFuture(Range range, Node node, LinkDataDuplexMap linkDataDuplexMap) { + CompletableFuture serverInstanceListFuture; + ServiceType nodeServiceType = node.getServiceType(); + if (nodeServiceType.isWas()) { + final long to = range.getTo(); + serverInstanceListFuture = CompletableFuture.supplyAsync(new Supplier() { + @Override + public ServerInstanceList get() { + return serverInstanceListFactory.createWasNodeInstanceList(node, to); + } + }, executor); + } else if (nodeServiceType.isTerminal()) { + // extract information about the terminal node + serverInstanceListFuture = CompletableFuture.completedFuture(serverInstanceListFactory.createTerminalNodeInstanceList(node, linkDataDuplexMap)); + } else if (nodeServiceType.isQueue()) { + serverInstanceListFuture = CompletableFuture.completedFuture(serverInstanceListFactory.createQueueNodeInstanceList(node, linkDataDuplexMap)); + } else if (nodeServiceType.isUser()) { + serverInstanceListFuture = CompletableFuture.completedFuture(serverInstanceListFactory.createUserNodeInstanceList()); + } else { + serverInstanceListFuture = CompletableFuture.completedFuture(serverInstanceListFactory.createEmptyNodeInstanceList()); + } + return serverInstanceListFuture.thenAccept(node::setServerInstanceList); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ParallelServerInfoAppender.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ParallelServerInfoAppender.java deleted file mode 100644 index 240a48d4d02f..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ParallelServerInfoAppender.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.server; - -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.web.applicationmap.nodes.Node; -import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; -import com.navercorp.pinpoint.web.applicationmap.nodes.ServerInstanceList; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; -import com.navercorp.pinpoint.web.vo.Range; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.function.Supplier; - -/** - * @author HyunGil Jeong - */ -public class ParallelServerInfoAppender implements ServerInfoAppender { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final ServerInstanceListFactory serverInstanceListFactory; - - private final ExecutorService executorService; - - public ParallelServerInfoAppender(ServerInstanceListFactory serverInstanceListFactory, ExecutorService executorService) { - if (serverInstanceListFactory == null) { - throw new NullPointerException("serverInstanceListFactory must not be null"); - } - if (executorService == null) { - throw new NullPointerException("executorService must not be null"); - } - this.serverInstanceListFactory = serverInstanceListFactory; - this.executorService = executorService; - } - - @Override - public void appendServerInfo(Range range, NodeList source, LinkDataDuplexMap linkDataDuplexMap) { - if (source == null) { - return; - } - Collection nodes = source.getNodeList(); - if (CollectionUtils.isEmpty(nodes)) { - return; - } - CompletableFuture[] futures = getServerInstanceListFutures(range, nodes, linkDataDuplexMap); - try { - CompletableFuture.allOf(futures).join(); - } catch (Exception e) { - logger.error("Error appending node histograms", e); - } - } - - private CompletableFuture[] getServerInstanceListFutures(Range range, Collection nodes, LinkDataDuplexMap linkDataDuplexMap) { - List> serverInstanceListFutures = new ArrayList<>(); - for (Node node : nodes) { - if (node.getServiceType().isUnknown()) { - // we do not know the server info for unknown nodes - continue; - } - CompletableFuture serverInstanceListFuture = getServerInstanceListFuture(range, node, linkDataDuplexMap); - serverInstanceListFutures.add(serverInstanceListFuture); - } - return serverInstanceListFutures.toArray(new CompletableFuture[serverInstanceListFutures.size()]); - } - - private CompletableFuture getServerInstanceListFuture(Range range, Node node, LinkDataDuplexMap linkDataDuplexMap) { - CompletableFuture serverInstanceListFuture; - ServiceType nodeServiceType = node.getServiceType(); - if (nodeServiceType.isWas()) { - final long to = range.getTo(); - serverInstanceListFuture = CompletableFuture.supplyAsync(new Supplier() { - @Override - public ServerInstanceList get() { - return serverInstanceListFactory.createWasNodeInstanceList(node, to); - } - }, executorService); - } else if (nodeServiceType.isTerminal()) { - // extract information about the terminal node - serverInstanceListFuture = CompletableFuture.completedFuture(serverInstanceListFactory.createTerminalNodeInstanceList(node, linkDataDuplexMap)); - } else if (nodeServiceType.isQueue()) { - serverInstanceListFuture = CompletableFuture.completedFuture(serverInstanceListFactory.createQueueNodeInstanceList(node, linkDataDuplexMap)); - } else if (nodeServiceType.isUser()) { - serverInstanceListFuture = CompletableFuture.completedFuture(serverInstanceListFactory.createUserNodeInstanceList()); - } else { - serverInstanceListFuture = CompletableFuture.completedFuture(serverInstanceListFactory.createEmptyNodeInstanceList()); - } - return serverInstanceListFuture.thenAccept(node::setServerInstanceList); - } -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/SerialServerInfoAppender.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/SerialServerInfoAppender.java deleted file mode 100644 index 537d825964fe..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/SerialServerInfoAppender.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.server; - -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.web.applicationmap.nodes.Node; -import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; -import com.navercorp.pinpoint.web.applicationmap.nodes.ServerInstanceList; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; -import com.navercorp.pinpoint.web.vo.Range; - -/** - * @author emeroad - * @author minwoo.jung - * @author HyunGil Jeong - */ -public class SerialServerInfoAppender implements ServerInfoAppender { - - private final ServerInstanceListFactory serverInstanceListFactory; - - public SerialServerInfoAppender(ServerInstanceListFactory serverInstanceListFactory) { - if (serverInstanceListFactory == null) { - throw new NullPointerException("serverInstanceListFactory must not be null"); - } - this.serverInstanceListFactory = serverInstanceListFactory; - } - - @Override - public void appendServerInfo(Range range, NodeList source, LinkDataDuplexMap linkDataDuplexMap) { - if (source == null) { - return; - } - for (Node node : source.getNodeList()) { - ServiceType nodeServiceType = node.getServiceType(); - if (nodeServiceType.isUnknown()) { - continue; - } - ServerInstanceList serverInstanceList; - if (nodeServiceType.isWas()) { - serverInstanceList = serverInstanceListFactory.createWasNodeInstanceList(node, range.getTo()); - } else if (nodeServiceType.isTerminal()) { - serverInstanceList = serverInstanceListFactory.createTerminalNodeInstanceList(node, linkDataDuplexMap); - } else if (nodeServiceType.isQueue()) { - serverInstanceList = serverInstanceListFactory.createQueueNodeInstanceList(node, linkDataDuplexMap); - } else if (nodeServiceType.isUser()) { - serverInstanceList = serverInstanceListFactory.createUserNodeInstanceList(); - } else { - serverInstanceList = serverInstanceListFactory.createEmptyNodeInstanceList(); - } - node.setServerInstanceList(serverInstanceList); - } - } -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderFactory.java index 91c405498f20..aadbc0f7423e 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderFactory.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderFactory.java @@ -16,17 +16,12 @@ package com.navercorp.pinpoint.web.applicationmap.appender.server; -import com.navercorp.pinpoint.common.util.PinpointThreadFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; -import javax.annotation.PreDestroy; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Objects; +import java.util.concurrent.Executor; /** * @author HyunGil Jeong @@ -34,40 +29,14 @@ @Component public class ServerInfoAppenderFactory { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final String mode; - private final ExecutorService executorService; + private final Executor executor; @Autowired - public ServerInfoAppenderFactory( - @Value("#{pinpointWebProps['web.servermap.appender.mode'] ?: 'serial'}") String mode, - @Value("#{pinpointWebProps['web.servermap.appender.parallel.maxthreads'] ?: 16}") int maxThreads) { - logger.info("ServerInfoAppender mode : {}", mode); - this.mode = mode; - if (this.mode.equalsIgnoreCase("parallel")) { - executorService = Executors.newFixedThreadPool(maxThreads, new PinpointThreadFactory("Pinpoint-node-histogram-appender", true)); - } else { - executorService = null; - } + public ServerInfoAppenderFactory(@Qualifier("serverInfoAppendExecutor") Executor executor) { + this.executor = Objects.requireNonNull(executor, "executor must not be null"); } public ServerInfoAppender create(ServerInstanceListFactory serverInstanceListFactory) { - if (mode.equalsIgnoreCase("parallel")) { - return new ParallelServerInfoAppender(serverInstanceListFactory, executorService); - } - return new SerialServerInfoAppender(serverInstanceListFactory); - } - - @PreDestroy - public void preDestroy() { - if (executorService != null) { - executorService.shutdown(); - try { - executorService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } + return new DefaultServerInfoAppender(serverInstanceListFactory, executor); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/AgentTimeHistogram.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/AgentTimeHistogram.java index 03d3b54e6f59..fe91faa2c75c 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/AgentTimeHistogram.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/AgentTimeHistogram.java @@ -86,7 +86,7 @@ public List createViewModel() { AgentResponseTimeViewModel model = createAgentResponseTimeViewModel(agentId, timeList); result.add(model); } - Collections.sort(result, new Comparator() { + result.sort(new Comparator() { @Override public int compare(AgentResponseTimeViewModel o1, AgentResponseTimeViewModel o2) { return o1.getAgentName().compareTo(o2.getAgentName()); @@ -97,7 +97,7 @@ public int compare(AgentResponseTimeViewModel o1, AgentResponseTimeViewModel o2) private List sortTimeHistogram(Collection timeMap) { List timeList = new ArrayList<>(timeMap); - Collections.sort(timeList, TimeHistogram.TIME_STAMP_ASC_COMPARATOR); + timeList.sort(TimeHistogram.TIME_STAMP_ASC_COMPARATOR); return timeList; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogramBuilder.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogramBuilder.java index c41c053048b3..319e51ea0ae1 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogramBuilder.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogramBuilder.java @@ -120,17 +120,13 @@ private List interpolation(Collection histogramLis for (TimeHistogram timeHistogram : histogramList) { long time = window.refineTimestamp(timeHistogram.getTimeStamp()); - TimeHistogram windowHistogram = resultMap.get(time); - if (windowHistogram == null) { - windowHistogram = new TimeHistogram(application.getServiceType(), time); - resultMap.put(time, windowHistogram); - } + TimeHistogram windowHistogram = resultMap.computeIfAbsent(time, t -> new TimeHistogram(application.getServiceType(), t)); windowHistogram.add(timeHistogram); } List resultList = new ArrayList<>(resultMap.values()); - Collections.sort(resultList, TimeHistogram.TIME_STAMP_ASC_COMPARATOR); + resultList.sort(TimeHistogram.TIME_STAMP_ASC_COMPARATOR); return resultList; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/nodes/ServerInstanceList.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/nodes/ServerInstanceList.java index 976b8994e595..0d6b41066d0e 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/nodes/ServerInstanceList.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/nodes/ServerInstanceList.java @@ -71,11 +71,7 @@ private void addServerInstance(List nodeList, ServerInstance ser } private List getServerInstanceList(String hostName) { - List find = serverInstanceList.get(hostName); - if (find == null) { - find = new ArrayList<>(); - serverInstanceList.put(hostName, find); - } + List find = serverInstanceList.computeIfAbsent(hostName, k -> new ArrayList<>()); return find; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/rawdata/AgentHistogramList.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/rawdata/AgentHistogramList.java index a7c3b045eec8..ff46ae69bd3b 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/rawdata/AgentHistogramList.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/rawdata/AgentHistogramList.java @@ -93,11 +93,7 @@ private AgentHistogram getAgentHistogram(Application agentId) { throw new NullPointerException("agentId must not be null"); } - AgentHistogram agentHistogram = agentHistogramMap.get(agentId); - if (agentHistogram == null) { - agentHistogram = new AgentHistogram(agentId); - agentHistogramMap.put(agentId, agentHistogram); - } + AgentHistogram agentHistogram = agentHistogramMap.computeIfAbsent(agentId, k -> new AgentHistogram(agentId)); return agentHistogram; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/rawdata/LinkDataMap.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/rawdata/LinkDataMap.java index 5aae2a781f79..1527fa04068c 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/rawdata/LinkDataMap.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/rawdata/LinkDataMap.java @@ -70,11 +70,7 @@ public void addLinkData(LinkData copyLinkData) { private LinkData getLinkData(Application fromApplication, Application toApplication) { final LinkKey key = new LinkKey(fromApplication, toApplication); - LinkData findLink = linkDataMap.get(key); - if (findLink == null) { - findLink = new LinkData(fromApplication, toApplication, timeWindow); - linkDataMap.put(key, findLink); - } + LinkData findLink = linkDataMap.computeIfAbsent(key, k -> new LinkData(fromApplication, toApplication, timeWindow)); return findLink; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/BatchConfiguration.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/BatchConfiguration.java index 78e83bed7d89..4615644db2f5 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/batch/BatchConfiguration.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/BatchConfiguration.java @@ -1,21 +1,5 @@ -package com.navercorp.pinpoint.web.batch; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Properties; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ConfigurationCondition; -import org.springframework.context.annotation.ImportResource; /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import org.springframework.core.io.Resource; +package com.navercorp.pinpoint.web.batch; + +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ConfigurationCondition; +import org.springframework.context.annotation.ImportResource; + import org.springframework.core.type.AnnotatedTypeMetadata; /** @@ -40,51 +39,34 @@ @Conditional(BatchConfiguration.Condition.class) @ImportResource("classpath:/batch/applicationContext-batch-schedule.xml") public class BatchConfiguration implements InitializingBean { - private static final Logger logger = LoggerFactory.getLogger(BatchConfiguration.class); - private Properties properties; - private List flinkServerList; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("#{batchProps['batch.enable'] ?: false}") + private boolean enableBatch; + + @Value("#{T(com.navercorp.pinpoint.common.util.StringUtils).tokenizeToStringList((batchProps['batch.flink.server'] ?: ''), ',')}") + private List flinkServerList = Collections.emptyList(); + + @Value("#{batchProps['batch.server.ip'] ?: null}") private String batchServerIp; - public void setProperties(Properties properties) { - this.properties = properties; - } @Override public void afterPropertiesSet() throws Exception { - readPropertyValues(this.properties); + logger.info("BatchConfiguration:{}", this.toString()); } - private void readPropertyValues(Properties properties) { - logger.info("pinpoint-batch.properties read."); - - batchServerIp = readString(properties, "batch.server.ip", null); - String[] flinkServers = StringUtils.split(readString(properties, "batch.flink.server", null), ","); - if (flinkServers == null) { - this.flinkServerList = Collections.emptyList(); - } else { - this.flinkServerList = new ArrayList<>(flinkServers.length); - for (String flinkServer : flinkServers) { - if (!StringUtils.isEmpty(flinkServer)) { - this.flinkServerList.add(StringUtils.trim(flinkServer)); - } - } - } - } - - private String readString(Properties properties, String propertyName, String defaultValue) { - final String result = properties.getProperty(propertyName, defaultValue); - if (logger.isInfoEnabled()) { - logger.info("{}={}", propertyName, result); - } - return result ; - } public String getBatchServerIp() { return batchServerIp; } static class Condition implements ConfigurationCondition { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + public Condition() { + } @Override public ConfigurationPhase getConfigurationPhase() { @@ -92,25 +74,23 @@ public ConfigurationPhase getConfigurationPhase() { } @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { - Properties properties=new Properties(); - Resource resource = context.getResourceLoader().getResource("classpath:/batch.properties"); - try { - properties.load(resource.getInputStream()); - final String enable = properties.getProperty("batch.enable"); - if(enable == null) { - return false; - } - - return Boolean.valueOf(enable.trim()); - } catch (Exception e) { - logger.error("Exception occurred while batch configuration" , e); - } - - return false; + Properties batchProps = context.getBeanFactory().getBean("batchProps", Properties.class); + final String enable = batchProps.getProperty("batch.enable", "false").trim(); + logger.info("batch.enable:{}", enable); + return Boolean.valueOf(enable); } } public List getFlinkServerList() { return flinkServerList; } + + @Override + public String toString() { + return "BatchConfiguration{" + + "enableBatch=" + enableBatch + + ", flinkServerList=" + flinkServerList + + ", batchServerIp='" + batchServerIp + '\'' + + '}'; + } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/DefaultDivider.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/DefaultDivider.java new file mode 100644 index 000000000000..674905456272 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/DefaultDivider.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.batch; + +import org.springframework.batch.item.ExecutionContext; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author minwoo.jung + */ +public class DefaultDivider implements Divider { + @Override + public Map divide(String partitionNamePrefix, String batchName) { + Map mapContext = new HashMap<>(); + ExecutionContext emptyExecutionContext = new ExecutionContext(); + mapContext.put(partitionNamePrefix + 1, emptyExecutionContext); + return mapContext; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/Divider.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/Divider.java new file mode 100644 index 000000000000..80600733120c --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/Divider.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.batch; + +import org.springframework.batch.item.ExecutionContext; + +import java.util.Map; + +/** + * @author minwoo.jung + */ +public interface Divider { + Map divide(String partitionNamePrefix, String batchName); +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/EmptyJobFailMessageSender.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/EmptyJobFailMessageSender.java index 34e7bd92fa2e..3409e79d628c 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/batch/EmptyJobFailMessageSender.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/EmptyJobFailMessageSender.java @@ -18,16 +18,16 @@ import org.springframework.batch.core.JobExecution; /** - * @author minwoo.jung + * @author minwoo.jung */ public class EmptyJobFailMessageSender implements JobFailMessageSender { - @Override - public void sendSMS(JobExecution jobExecution) { - } + @Override + public void sendSMS(JobExecution jobExecution) { + } - @Override - public void sendEmail(JobExecution jobExecution) { - } + @Override + public void sendEmail(JobExecution jobExecution) { + } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/JobFailListener.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/JobFailListener.java index 1826a77c3508..488e3ef3a887 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/batch/JobFailListener.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/JobFailListener.java @@ -23,13 +23,12 @@ /** * @author minwoo.jung - * */ public class JobFailListener implements JobExecutionListener { - @Autowired(required=false) - JobFailMessageSender jobFailMessageSender = new EmptyJobFailMessageSender(); - + @Autowired(required = false) + private JobFailMessageSender jobFailMessageSender = new EmptyJobFailMessageSender(); + public JobFailListener() { } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/JobFailMessageSender.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/JobFailMessageSender.java index 6a5e023e7844..82e04b18cd40 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/batch/JobFailMessageSender.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/JobFailMessageSender.java @@ -21,6 +21,7 @@ * @author minwoo.jung */ public interface JobFailMessageSender { - void sendSMS(JobExecution jobExecution); - void sendEmail(JobExecution jobExecution); + void sendSMS(JobExecution jobExecution); + + void sendEmail(JobExecution jobExecution); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/JobLaunchSupport.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/JobLaunchSupport.java index 68632dcb29f6..0b153d2713a0 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/batch/JobLaunchSupport.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/JobLaunchSupport.java @@ -16,14 +16,8 @@ package com.navercorp.pinpoint.web.batch; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.Enumeration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.navercorp.pinpoint.web.util.BatchUtils; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; @@ -39,8 +33,6 @@ */ public class JobLaunchSupport implements InitializingBean { - private final Logger logger = LoggerFactory.getLogger(getClass()); - @Autowired private BatchConfiguration batchConfiguration; @Autowired @@ -49,7 +41,7 @@ public class JobLaunchSupport implements InitializingBean { private JobLauncher launcher; public JobExecution run(String jobName, JobParameters params) { - if(!decisionBatchServer()) { + if(!BatchUtils.decisionBatchServer(batchConfiguration.getBatchServerIp())) { return null; } try { @@ -60,34 +52,6 @@ public JobExecution run(String jobName, JobParameters params) { } } - private boolean decisionBatchServer() { - Enumeration interfaces; - - try { - interfaces = NetworkInterface.getNetworkInterfaces(); - } catch (SocketException e) { - logger.error("not found network interface", e); - return false; - } - - while (interfaces.hasMoreElements()) { - NetworkInterface network = interfaces.nextElement(); - Enumeration inets = network.getInetAddresses(); - - while (inets.hasMoreElements()) { - InetAddress next = inets.nextElement(); - - if (next instanceof Inet4Address) { - if (next.getHostAddress().equals(batchConfiguration.getBatchServerIp())) { - return true; - } - } - } - } - - return false; - } - @Override public void afterPropertiesSet() throws Exception { Assert.notNull(locator, "jobLocator name must be provided"); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/flink/HealthCheckTasklet.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/flink/HealthCheckTasklet.java index 957fd029eefb..57505641876c 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/batch/flink/HealthCheckTasklet.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/flink/HealthCheckTasklet.java @@ -47,9 +47,6 @@ public class HealthCheckTasklet implements Tasklet { @Autowired private BatchConfiguration batchConfiguration; - @Autowired(required=false) - private AlarmMessageSender alarmMessageSender = new EmptyMessageSender(); - public HealthCheckTasklet() { this.jobNameList = new ArrayList<>(1); jobNameList.add("Aggregation Stat Data"); @@ -59,7 +56,7 @@ public HealthCheckTasklet() { public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { List urlList = generatedFlinkManagerServerApi(); - if (urlList.size() == 0) { + if (urlList.isEmpty()) { return RepeatStatus.FINISHED; } @@ -118,7 +115,7 @@ private List generatedFlinkManagerServerApi() { List urlList = new ArrayList<>(flinkServerList.size()); for (String flinkServerIp : flinkServerList) { - urlList.add(String.format("http://%s:8081/joboverview", flinkServerIp)); + urlList.add(String.format(URL_FORMAT, flinkServerIp)); } return urlList; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/flink/HealthCheckTaskletV2.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/flink/HealthCheckTaskletV2.java new file mode 100644 index 000000000000..d999b6407296 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/flink/HealthCheckTaskletV2.java @@ -0,0 +1,137 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.batch.flink; + +import com.navercorp.pinpoint.web.batch.BatchConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author minwoo.jung + */ +public class HealthCheckTaskletV2 implements Tasklet { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final static String URL_FORMAT = "http://%s:8081/jobs/overview"; + private final static String NAME = "name"; + private final static String STATE = "state"; + private final static String RUNNING = "RUNNING"; + private final List jobNameList; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private BatchConfiguration batchConfiguration; + + public HealthCheckTaskletV2() { + this.jobNameList = new ArrayList<>(1); + jobNameList.add("Aggregation Stat Data"); + } + + @Override + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { + List urlList = generatedFlinkManagerServerApi(); + + if (urlList.isEmpty()) { + return RepeatStatus.FINISHED; + } + + Map jobExecuteStatus = createjobExecuteStatus(); + + for(String url : urlList) { + try { + ResponseEntity responseEntity = this.restTemplate.exchange(url, HttpMethod.GET, null, Map.class); + + if (responseEntity.getStatusCode() != HttpStatus.OK) { + continue; + } + + checkJobExecuteStatus(responseEntity, jobExecuteStatus); + } catch (Exception e) { + logger.error("fail call api to flink server.", e); + } + } + + List notExecuteJobList = new ArrayList<>(3); + for (Map.Entry entry : jobExecuteStatus.entrySet()) { + if (entry.getValue().equals(Boolean.FALSE)) { + notExecuteJobList.add(entry.getKey()); + } + } + + if (notExecuteJobList.size() > 0) { + String exceptionMessage = String.format("job fail : %s", notExecuteJobList); + throw new Exception(exceptionMessage); + } + + return RepeatStatus.FINISHED; + } + + private void checkJobExecuteStatus(ResponseEntity responseEntity, Map jobExecuteStatus) { + Map responseData = responseEntity.getBody(); + List jobs = (List)responseData.get("jobs"); + + if (jobs != null) { + for (Object job : jobs) { + Map jobInfo = (Map)job; + final String jobName = (String) jobInfo.get(NAME); + if (jobExecuteStatus.containsKey(jobName)) { + if (RUNNING.equals(jobInfo.get(STATE))) { + jobExecuteStatus.put(jobName, true); + } + } + } + } + } + + + private List generatedFlinkManagerServerApi() { + List flinkServerList = batchConfiguration.getFlinkServerList(); + List urlList = new ArrayList<>(flinkServerList.size()); + + for (String flinkServerIp : flinkServerList) { + urlList.add(String.format(URL_FORMAT, flinkServerIp)); + } + + return urlList; + } + + public Map createjobExecuteStatus() { + Map jobExecuteStatus = new HashMap<>(); + + for (String jobName : jobNameList) { + jobExecuteStatus.put(jobName, false); + } + + return jobExecuteStatus; + } + +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountPartitioner.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountPartitioner.java new file mode 100644 index 000000000000..80b79327caf1 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountPartitioner.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.batch.job; + +import com.navercorp.pinpoint.web.batch.DefaultDivider; +import com.navercorp.pinpoint.web.batch.Divider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.partition.support.Partitioner; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +import java.util.Map; + +/** + * @author minwoo.jung + */ +public class AgentCountPartitioner implements Partitioner { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private static final String PARTITION_NAME_PREFIX = "agent_count_partition_number_"; + private static final String BATCH_NAME = "agent_count_batch"; + + @Autowired(required = false) + @Qualifier("divider") + private Divider divider = new DefaultDivider(); + + @Override + public Map partition(int gridSize) { + return divider.divide(PARTITION_NAME_PREFIX, BATCH_NAME); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountProcessor.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountProcessor.java index 22e7a567752d..771358fcf030 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountProcessor.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountProcessor.java @@ -18,35 +18,33 @@ import com.navercorp.pinpoint.common.util.DateUtils; import com.navercorp.pinpoint.web.vo.AgentCountStatistics; -import com.navercorp.pinpoint.web.vo.AgentInfo; import com.navercorp.pinpoint.web.vo.ApplicationAgentList; +import com.navercorp.pinpoint.web.vo.ApplicationAgentsList; import org.springframework.batch.item.ItemProcessor; import java.util.List; -import java.util.Map; /** * @author Taejin Koo */ -public class AgentCountProcessor implements ItemProcessor { +public class AgentCountProcessor implements ItemProcessor { @Override - public AgentCountStatistics process(ApplicationAgentList item) throws Exception { + public AgentCountStatistics process(ApplicationAgentsList item) throws Exception { if (item == null) { return null; } - int agentCount = getAgentCount(item.getApplicationAgentList()); + int agentCount = getAgentCount(item.getApplicationAgentLists()); AgentCountStatistics agentCountStatistics = new AgentCountStatistics(agentCount, DateUtils.timestampToMidNight(System.currentTimeMillis())); return agentCountStatistics; } - private int getAgentCount(Map> applicationAgentListMap) { + private int getAgentCount(List applicationAgentLists) { int agentCount = 0; - for (Map.Entry> eachApplicationAgentList : applicationAgentListMap.entrySet()) { - agentCount += eachApplicationAgentList.getValue().size(); + for (ApplicationAgentList applicationAgentList : applicationAgentLists) { + agentCount += applicationAgentList.getAgentInfos().size(); } - return agentCount; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountReader.java b/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountReader.java index 84ee3c14e2a2..63ec81fe8bfe 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountReader.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/batch/job/AgentCountReader.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.web.batch.job; import com.navercorp.pinpoint.web.service.AgentInfoService; -import com.navercorp.pinpoint.web.vo.ApplicationAgentList; +import com.navercorp.pinpoint.web.vo.ApplicationAgentsList; import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.StepExecutionListener; @@ -33,21 +33,22 @@ /** * @author Taejin Koo */ -public class AgentCountReader implements ItemReader, StepExecutionListener { +public class AgentCountReader implements ItemReader, StepExecutionListener { @Autowired private AgentInfoService agentInfoService; - private final Queue queue = new LinkedList<>(); + private final Queue queue = new LinkedList<>(); @Override public void beforeStep(StepExecution stepExecution) { - ApplicationAgentList applicationAgentList = agentInfoService.getApplicationAgentList(ApplicationAgentList.Key.APPLICATION_NAME); + long timestamp = System.currentTimeMillis(); + ApplicationAgentsList applicationAgentList = agentInfoService.getAllApplicationAgentsList(ApplicationAgentsList.Filter.NONE, timestamp); queue.add(applicationAgentList); } @Override - public ApplicationAgentList read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { + public ApplicationAgentsList read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { return queue.poll(); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/CallTreeIterator.java b/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/CallTreeIterator.java index d65e0ad9cea7..d53428a7959b 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/CallTreeIterator.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/CallTreeIterator.java @@ -260,7 +260,7 @@ public int size() { } public boolean isEmpty() { - return size() == 0; + return nodes.isEmpty(); } public String toString() { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanAligner.java b/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanAligner.java index 335690f94a66..d6313f96c57d 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanAligner.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanAligner.java @@ -18,6 +18,7 @@ import com.navercorp.pinpoint.common.server.bo.SpanBo; import com.navercorp.pinpoint.common.server.bo.SpanEventBo; +import com.navercorp.pinpoint.common.util.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -235,7 +236,7 @@ private void fill() { } // find missing grand parent. final List targetLinkList = LinkList.filterSpan(this.linkList, node.span); - if (targetLinkList != null && !targetLinkList.isEmpty()) { + if (CollectionUtils.hasLength(targetLinkList)) { final Link matchedLink = LinkList.matchSpan(targetLinkList, node.span); if (matchedLink != null) { if (isDebug) { @@ -395,7 +396,7 @@ private CallTree selectInNodeList(final Node node, final List topNodeList) return unknownCallTree; } - private class Node { + private static class Node { private SpanBo span; private SpanCallTree spanCallTree; private boolean linked = false; @@ -457,8 +458,8 @@ public boolean filter(Node node) { } private static List filter(List nodeList, NodeFilter filter) { - if (nodeList == null && nodeList.isEmpty()) { - return Collections.EMPTY_LIST; + if (CollectionUtils.isEmpty(nodeList)) { + return Collections.emptyList(); } final List result = new ArrayList<>(); @@ -475,7 +476,7 @@ private interface NodeFilter { boolean filter(final Node node); } - private class Link { + private static class Link { private long parentSpanId; private long spanId; private long nextSpanId; @@ -506,8 +507,8 @@ public String toString() { private static class LinkList { private static List filterSpan(final List linkList, final SpanBo span) { - if (linkList == null || linkList.isEmpty()) { - return Collections.EMPTY_LIST; + if (CollectionUtils.isEmpty(linkList)) { + return Collections.emptyList(); } final List result = new ArrayList<>(); @@ -524,7 +525,7 @@ private static List filterSpan(final List linkList, final SpanBo spa } private static Link matchSpan(final List linkList, final SpanBo span) { - if (linkList == null || linkList.isEmpty()) { + if (CollectionUtils.isEmpty(linkList)) { return null; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanAsyncEventMap.java b/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanAsyncEventMap.java index 9017cbb867f7..0fa42927a6c7 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanAsyncEventMap.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanAsyncEventMap.java @@ -12,8 +12,8 @@ public class SpanAsyncEventMap { - final Map>> map = new HashMap<>(); - int size = 0; + private final Map>> map = new HashMap<>(); + private int size = 0; public boolean add(final SpanEventBo spanEvent) { if (!spanEvent.isAsync()) { @@ -21,11 +21,7 @@ public boolean add(final SpanEventBo spanEvent) { } final int id = spanEvent.getAsyncId(); - Map> subMap = map.get(id); - if (subMap == null) { - subMap = new HashMap<>(); - map.put(id, subMap); - } + Map> subMap = map.computeIfAbsent(id, k -> new HashMap<>()); final short sequence = spanEvent.getAsyncSequence(); List list = subMap.get(sequence); @@ -44,7 +40,7 @@ public boolean add(final SpanEventBo spanEvent) { public void sort() { for (Map> subMap : map.values()) { for (List list : subMap.values()) { - Collections.sort(list, new Comparator() { + list.sort(new Comparator() { public int compare(SpanEventBo source, SpanEventBo target) { return source.getSequence() - target.getSequence(); } @@ -55,11 +51,10 @@ public int compare(SpanEventBo source, SpanEventBo target) { public Collection> get(final int asyncId) { final Map> subMap = map.get(asyncId); - if (subMap != null) { - return subMap.values(); + if (subMap == null) { + return Collections.emptyList(); } - - return Collections.emptyList(); + return subMap.values(); } public int size() { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanCallTree.java b/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanCallTree.java index 4219d0219a4a..cbf6c57e3b61 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanCallTree.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/calltree/span/SpanCallTree.java @@ -282,7 +282,7 @@ void sortChildSibling(final CallTreeNode parent) { } // order by abs. - Collections.sort(spans, new Comparator() { + spans.sort(new Comparator() { @Override public int compare(CallTreeNode source, CallTreeNode target) { return (int) (source.getValue().getStartTime() - target.getValue().getStartTime()); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/CollectorClusterInfoRepository.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/CollectorClusterInfoRepository.java index 126b4059933e..eadfd2a213e8 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/CollectorClusterInfoRepository.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/cluster/CollectorClusterInfoRepository.java @@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -53,6 +54,10 @@ public void put(String id, byte[] bytes) { } private Set newProfilerInfo(byte[] bytes) { + if (bytes == null) { + return Collections.emptySet(); + } + final String strData = new String(bytes, charset); final List profilerInfoList = Arrays.asList(StringUtils.tokenizeToStringArray(strData, PROFILER_SEPARATOR)); return new HashSet<>(profilerInfoList); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/DefaultPinpointRouteResponse.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/DefaultPinpointRouteResponse.java index 66586d6a9d2a..c05c771c9943 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/DefaultPinpointRouteResponse.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/cluster/DefaultPinpointRouteResponse.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.web.cluster; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.thrift.dto.command.TCommandTransferResponse; import com.navercorp.pinpoint.thrift.dto.command.TRouteResult; import com.navercorp.pinpoint.thrift.io.DeserializerFactory; @@ -47,7 +48,7 @@ public void parse(DeserializerFactory commandDeserializ return; } - TBase object = deserialize(commandDeserializerFactory, payload, null); + TBase object = deserialize(commandDeserializerFactory, payload, null); if (object == null) { routeResult = TRouteResult.NOT_SUPPORTED_RESPONSE; @@ -109,8 +110,12 @@ private void assertParsed() { } } - private TBase deserialize(DeserializerFactory commandDeserializerFactory, byte[] objectData, TBase defaultValue) { - return SerializationUtils.deserialize(objectData, commandDeserializerFactory, defaultValue); + private TBase deserialize(DeserializerFactory commandDeserializerFactory, byte[] objectData, Message> defaultValue) { + final Message> message = SerializationUtils.deserialize(objectData, commandDeserializerFactory, defaultValue); + if (message == null) { + return null; + } + return message.getData(); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterAcceptor.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterAcceptor.java index a1697dcddf35..4ce23261e604 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterAcceptor.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterAcceptor.java @@ -17,16 +17,11 @@ package com.navercorp.pinpoint.web.cluster.connection; import com.navercorp.pinpoint.rpc.PinpointSocket; -import com.navercorp.pinpoint.rpc.UnsupportOperationMessageListener; import com.navercorp.pinpoint.rpc.cluster.ClusterOption; import com.navercorp.pinpoint.rpc.cluster.Role; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; -import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; -import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; import com.navercorp.pinpoint.rpc.server.ChannelFilter; -import com.navercorp.pinpoint.rpc.server.PinpointServer; import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor; -import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.rpc.server.ServerOption; import com.navercorp.pinpoint.rpc.util.ClassUtils; import com.navercorp.pinpoint.web.util.WebUtils; import org.slf4j.Logger; @@ -34,7 +29,6 @@ import java.net.InetSocketAddress; import java.util.List; -import java.util.Map; /** * @author Taejin Koo @@ -53,14 +47,18 @@ public ClusterAcceptor(String host, int port) { this.bindPort = port; ClusterOption clusterOption = new ClusterOption(true, WebUtils.getServerIdentifier(), Role.CALLER); - this.serverAcceptor = new PinpointServerAcceptor(clusterOption, ChannelFilter.BYPASS); + + ServerOption.Builder serverOptionBuilder = new ServerOption.Builder(); + serverOptionBuilder.setClusterOption(clusterOption); + + this.serverAcceptor = new PinpointServerAcceptor(serverOptionBuilder.build(), ChannelFilter.BYPASS); } @Override public void start() { logger.info("{} initialization started.", ClassUtils.simpleClassName(this)); - this.serverAcceptor.setMessageListener(new WebClusterAcceptorListener()); + this.serverAcceptor.setMessageListenerFactory(new ClusterAcceptorMessageListenerFactory()); this.serverAcceptor.bind(new InetSocketAddress(bindHost, bindPort)); logger.info("{} initialization completed.", ClassUtils.simpleClassName(this)); @@ -90,19 +88,4 @@ public List getClusterSocketList() { return serverAcceptor.getWritableSocketList(); } - private class WebClusterAcceptorListener extends UnsupportOperationMessageListener implements ServerMessageListener { - - @Override - public HandshakeResponseCode handleHandshake(Map properties) { - logger.warn("do handShake {}", properties); - return HandshakeResponseType.Success.DUPLEX_COMMUNICATION; - } - - @Override - public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { - logger.debug("ping received packet:{}, remote:{}", pingPacket, pinpointServer); - } - - } - } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterAcceptorMessageListenerFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterAcceptorMessageListenerFactory.java new file mode 100644 index 000000000000..805474026528 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterAcceptorMessageListenerFactory.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.cluster.connection; + +import com.navercorp.pinpoint.rpc.UnsupportOperationMessageListener; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseCode; +import com.navercorp.pinpoint.rpc.packet.HandshakeResponseType; +import com.navercorp.pinpoint.rpc.packet.PingPayloadPacket; +import com.navercorp.pinpoint.rpc.server.PinpointServer; +import com.navercorp.pinpoint.rpc.server.ServerMessageListener; +import com.navercorp.pinpoint.rpc.server.ServerMessageListenerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + * @author Taejin Koo + */ +class ClusterAcceptorMessageListenerFactory implements ServerMessageListenerFactory { + + @Override + public ServerMessageListener create() { + return new ClusterAcceptorMessageListener(); + } + + + private static class ClusterAcceptorMessageListener extends UnsupportOperationMessageListener implements ServerMessageListener { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public HandshakeResponseCode handleHandshake(Map properties) { + logger.warn("do handShake {}", properties); + return HandshakeResponseType.Success.DUPLEX_COMMUNICATION; + } + + @Override + public void handlePing(PingPayloadPacket pingPacket, PinpointServer pinpointServer) { + logger.debug("ping received packet:{}, remote:{}", pingPacket, pinpointServer); + } + + } + +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterConnector.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterConnector.java index 1772f2e1ae29..fde1047ee8f9 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterConnector.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/cluster/connection/ClusterConnector.java @@ -54,7 +54,8 @@ public ClusterConnector(String connectString) { public void start() { logger.info("start() started."); - clientFactory.setTimeoutMillis(1000 * 5); + clientFactory.setWriteTimeoutMillis(1000 * 3); + clientFactory.setRequestTimeoutMillis(1000 * 5); clientFactory.setMessageListener(UnsupportOperationMessageListener.getInstance()); clientFactory.addStateChangeEventListener(LoggingStateChangeEventListener.INSTANCE); clientFactory.setProperties(Collections.emptyMap()); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClient.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClient.java deleted file mode 100644 index 60f20a76b55e..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClient.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.cluster.zookeeper; - - -import com.navercorp.pinpoint.common.server.util.concurrent.CommonStateContext; -import com.navercorp.pinpoint.rpc.util.TimerFactory; -import com.navercorp.pinpoint.web.cluster.zookeeper.exception.AuthException; -import com.navercorp.pinpoint.web.cluster.zookeeper.exception.BadOperationException; -import com.navercorp.pinpoint.web.cluster.zookeeper.exception.ConnectionException; -import com.navercorp.pinpoint.web.cluster.zookeeper.exception.NoNodeException; -import com.navercorp.pinpoint.web.cluster.zookeeper.exception.PinpointZookeeperException; -import com.navercorp.pinpoint.web.cluster.zookeeper.exception.TimeoutException; -import com.navercorp.pinpoint.web.cluster.zookeeper.exception.UnknownException; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException; -import org.apache.zookeeper.KeeperException.Code; -import org.apache.zookeeper.ZooDefs.Ids; -import org.apache.zookeeper.ZooKeeper; -import org.apache.zookeeper.data.Stat; -import org.jboss.netty.util.HashedWheelTimer; -import org.jboss.netty.util.Timeout; -import org.jboss.netty.util.TimerTask; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * - * Conditional thread safe
- * If multiple threads invokes connect, reconnect, or close concurrently; then it is possible for the object's zookeeper field to be out of sync. - * - * @author koo.taejin - */ -public class ZookeeperClient { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public static final long DEFAULT_RECONNECT_DELAY_WHEN_SESSION_EXPIRED = 30000; - - private final CommonStateContext stateContext; - - private final HashedWheelTimer timer; - - private final String hostPort; - private final int sessionTimeout; - private final ZookeeperEventWatcher zookeeperEventWatcher; - private final long reconnectDelayWhenSessionExpired; - - // ZK client is thread-safe - private volatile ZooKeeper zookeeper; - - // hmm this structure should contain all necessary information - public ZookeeperClient(String hostPort, int sessionTimeout, ZookeeperEventWatcher manager) { - this(hostPort, sessionTimeout, manager, DEFAULT_RECONNECT_DELAY_WHEN_SESSION_EXPIRED); - } - - public ZookeeperClient(String hostPort, int sessionTimeout, ZookeeperEventWatcher zookeeperEventWatcher, long reconnectDelayWhenSessionExpired) { - this.hostPort = hostPort; - this.sessionTimeout = sessionTimeout; - this.zookeeperEventWatcher = zookeeperEventWatcher; - this.reconnectDelayWhenSessionExpired = reconnectDelayWhenSessionExpired; - - - this.timer = TimerFactory.createHashedWheelTimer(this.getClass().getSimpleName(), 100, TimeUnit.MILLISECONDS, 512); - - this.stateContext = new CommonStateContext(); - } - - public void connect() throws IOException { - if (stateContext.changeStateInitializing()) { - this.zookeeper = new ZooKeeper(hostPort, sessionTimeout, zookeeperEventWatcher); // server - stateContext.changeStateStarted(); - } else { - logger.warn("connect() failed. error : Illegal State. State may be {}.", stateContext.getCurrentState()); - } - } - - public void reconnectWhenSessionExpired() { - if (!stateContext.isStarted()) { - logger.warn("ZookeeperClient.reconnectWhenSessionExpired() failed. Error: Already closed."); - return; - } - - ZooKeeper zookeeper = this.zookeeper; - if (zookeeper.getState().isConnected()) { - logger.warn("ZookeeperClient.reconnectWhenSessionExpired() failed. Error: session(0x{}) is connected.", Long.toHexString(zookeeper.getSessionId())); - return; - } - - logger.warn("Execute ZookeeperClient.reconnectWhenSessionExpired()(Expired session:0x{}).", Long.toHexString(zookeeper.getSessionId())); - - try { - zookeeper.close(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - ZooKeeper newZookeeper = createNewZookeeper(); - if (newZookeeper == null) { - logger.warn("Failed to create new Zookeeper instance. It will be retry AFTER {}ms.", reconnectDelayWhenSessionExpired); - - timer.newTimeout(new TimerTask() { - @Override - public void run(Timeout timeout) throws Exception { - if (timeout.isCancelled()) { - return; - } - - reconnectWhenSessionExpired(); - } - }, reconnectDelayWhenSessionExpired, TimeUnit.MILLISECONDS); - } else { - this.zookeeper = newZookeeper; - } - - } - - private ZooKeeper createNewZookeeper() { - try { - return new ZooKeeper(hostPort, sessionTimeout, zookeeperEventWatcher); - } catch (IOException ignore) { - // ignore - } - return null; - } - - /** - * do not create node in path suffix - * - * @throws PinpointZookeeperException - * @throws InterruptedException - */ - public void createPath(String path) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - int pos = 1; - do { - pos = path.indexOf('/', pos + 1); - - if (pos != -1) { - try { - String subPath = path.substring(0, pos); - if (zookeeper.exists(subPath, false) != null) { - continue; - } - - zookeeper.create(subPath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); - } catch (KeeperException exception) { - if (exception.code() != Code.NODEEXISTS) { - handleException(exception); - } - } - } else { - pos = path.length(); - } - } while (pos < path.length()); - } - - // we need deep node inspection for verification purpose (node content) - public String createNode(String zNodePath, byte[] data, CreateMode createMode) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - if (zookeeper.exists(zNodePath, false) != null) { - return zNodePath; - } - - String pathName = zookeeper.create(zNodePath, data, Ids.OPEN_ACL_UNSAFE, createMode); - return pathName; - } catch (KeeperException exception) { - if (exception.code() != Code.NODEEXISTS) { - handleException(exception); - } - } - return zNodePath; - } - - public List getChildren(String path, boolean watch) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - return zookeeper.getChildren(path, watch); - } catch (KeeperException exception) { - if (exception.code() != Code.NONODE) { - handleException(exception); - } - } - - return Collections.emptyList(); - } - - public byte[] getData(String path) throws PinpointZookeeperException, InterruptedException { - return getData(path, false); - } - - public byte[] getData(String path, boolean watch) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - return zookeeper.getData(path, watch, null); - } catch (KeeperException exception) { - handleException(exception); - } - - throw new UnknownException("UnknownException."); - } - - - public void delete(String path) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - zookeeper.delete(path, -1); - } catch (KeeperException exception) { - if (exception.code() != Code.NONODE) { - handleException(exception); - } - } - } - - public boolean exists(String path) throws PinpointZookeeperException, InterruptedException { - checkState(); - - ZooKeeper zookeeper = this.zookeeper; - try { - Stat stat = zookeeper.exists(path, false); - if (stat == null) { - return false; - } - } catch (KeeperException exception) { - if (exception.code() != Code.NODEEXISTS) { - handleException(exception); - } - } - return true; - } - - private void checkState() throws PinpointZookeeperException { - if (!zookeeperEventWatcher.isConnected() || !stateContext.isStarted()) { - throw new ConnectionException("Instance must be connected."); - } - } - - private void handleException(KeeperException keeperException) throws PinpointZookeeperException { - switch (keeperException.code()) { - case CONNECTIONLOSS: - case SESSIONEXPIRED: - throw new ConnectionException(keeperException.getMessage(), keeperException); - case AUTHFAILED: - case INVALIDACL: - case NOAUTH: - throw new AuthException(keeperException.getMessage(), keeperException); - case BADARGUMENTS: - case BADVERSION: - case NOCHILDRENFOREPHEMERALS: - case NOTEMPTY: - case NODEEXISTS: - throw new BadOperationException(keeperException.getMessage(), keeperException); - case NONODE: - throw new NoNodeException(keeperException.getMessage(), keeperException); - case OPERATIONTIMEOUT: - throw new TimeoutException(keeperException.getMessage(), keeperException); - default: - throw new UnknownException(keeperException.getMessage(), keeperException); - } - } - - public void close() { - if (stateContext.changeStateDestroying()) { - if (timer != null) { - timer.stop(); - } - - if (zookeeper != null) { - try { - zookeeper.close(); - } catch (InterruptedException ignore) { - logger.debug(ignore.getMessage(), ignore); - } - } - stateContext.changeStateStopped(); - } else { - logger.warn("close failed. error : Illegal State. State may be {}.", stateContext.getCurrentState()); - } - } - -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterDataManager.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterDataManager.java index d95e2adf9cda..01b9a7572375 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterDataManager.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterDataManager.java @@ -16,13 +16,19 @@ package com.navercorp.pinpoint.web.cluster.zookeeper; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.CuratorZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperClient; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperConstants; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperEventWatcher; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.NoNodeException; +import com.navercorp.pinpoint.common.util.MapUtils; import com.navercorp.pinpoint.rpc.util.ClassUtils; import com.navercorp.pinpoint.rpc.util.TimerFactory; import com.navercorp.pinpoint.web.cluster.ClusterDataManager; import com.navercorp.pinpoint.web.cluster.CollectorClusterInfoRepository; -import com.navercorp.pinpoint.web.cluster.zookeeper.exception.NoNodeException; import com.navercorp.pinpoint.web.config.WebConfig; import com.navercorp.pinpoint.web.vo.AgentInfo; +import org.apache.curator.utils.ZKPaths; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.Watcher.Event.KeeperState; @@ -33,11 +39,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; /** @@ -45,9 +49,6 @@ */ public class ZookeeperClusterDataManager implements ClusterDataManager, ZookeeperEventWatcher { - private static final String PINPOINT_CLUSTER_PATH = "/pinpoint-cluster"; - private static final String PINPOINT_WEB_CLUSTER_PATH = PINPOINT_CLUSTER_PATH + "/web"; - private static final String PINPOINT_COLLECTOR_CLUSTER_PATH = PINPOINT_CLUSTER_PATH + "/collector"; private static final long SYNC_INTERVAL_TIME_MILLIS = 15 * 1000; private final Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -56,7 +57,6 @@ public class ZookeeperClusterDataManager implements ClusterDataManager, Zookeepe private final int sessionTimeout; private final int retryInterval; - private final AtomicBoolean connected = new AtomicBoolean(false); private ZookeeperClient client; private final ZookeeperClusterDataManagerHelper clusterDataManagerHelper = new ZookeeperClusterDataManagerHelper(); @@ -79,7 +79,7 @@ public ZookeeperClusterDataManager(String connectAddress, int sessionTimeout, in @Override public void start() throws Exception { this.timer = createTimer(); - this.client = new ZookeeperClient(connectAddress, sessionTimeout, this, ZookeeperClient.DEFAULT_RECONNECT_DELAY_WHEN_SESSION_EXPIRED); + this.client = new CuratorZookeeperClient(connectAddress, sessionTimeout, this); this.client.connect(); } @@ -98,7 +98,7 @@ public void stop() { // not too much overhead, just logging @Override public boolean registerWebCluster(String zNodeName, byte[] contents) { - String zNodePath = clusterDataManagerHelper.bindingPathAndZNode(PINPOINT_WEB_CLUSTER_PATH, zNodeName); + String zNodePath = ZKPaths.makePath(ZookeeperConstants.PINPOINT_WEB_CLUSTER_PATH, zNodeName); logger.info("registerWebCluster() started. create UniqPath={}.", zNodePath); @@ -120,12 +120,12 @@ public boolean registerWebCluster(String zNodeName, byte[] contents) { return true; } - + @SuppressWarnings("deprecation") @Override public void process(WatchedEvent event) { logger.info("Handle Zookeeper Event({}) started.", event); - + KeeperState state = event.getState(); EventType eventType = event.getType(); String path = event.getPath(); @@ -133,15 +133,8 @@ public void process(WatchedEvent event) { // when this happens, ephemeral node disappears // reconnects automatically, and process gets notified for all events boolean result = false; - if (ZookeeperUtils.isDisconnectedEvent(event)) { - result = handleDisconnected(); - if (state == KeeperState.Expired) { - client.reconnectWhenSessionExpired(); - } - } else if (state == KeeperState.SyncConnected || state == KeeperState.NoSyncConnected) { - if (eventType == EventType.None) { - result = handleConnected(); - } else if (eventType == EventType.NodeChildrenChanged) { + if (state == KeeperState.SyncConnected || state == KeeperState.NoSyncConnected) { + if (eventType == EventType.NodeChildrenChanged) { result = handleNodeChildrenChanged(path); } else if (eventType == EventType.NodeDeleted) { result = handleNodeDeleted(path); @@ -157,39 +150,31 @@ public void process(WatchedEvent event) { } } - private boolean handleDisconnected() { - connected.compareAndSet(true, false); - collectorClusterInfo.clear(); - return true; - } - - private boolean handleConnected() { - boolean result = true; - - // is it ok to keep this since previous condition was possibly RUN - boolean changed = connected.compareAndSet(false, true); - if (changed) { - PushWebClusterJob job = this.job.get(); - if (job != null) { - if (!clusterDataManagerHelper.pushZnode(client, job)) { - timer.newTimeout(job, job.getRetryInterval(), TimeUnit.MILLISECONDS); - result = false; - } + @Override + public boolean handleConnected() { + PushWebClusterJob job = this.job.get(); + if (job != null) { + if (!clusterDataManagerHelper.pushZnode(client, job)) { + timer.newTimeout(job, job.getRetryInterval(), TimeUnit.MILLISECONDS); + return false; } + } - if (!syncPullCollectorCluster()) { - timer.newTimeout(new PullCollectorClusterJob(), SYNC_INTERVAL_TIME_MILLIS, TimeUnit.MILLISECONDS); - result = false; - } - } else { - result = false; + if (!syncPullCollectorCluster()) { + timer.newTimeout(new PullCollectorClusterJob(), SYNC_INTERVAL_TIME_MILLIS, TimeUnit.MILLISECONDS); + return false; } + return true; + } - return result; + @Override + public boolean handleDisconnected() { + collectorClusterInfo.clear(); + return true; } private boolean handleNodeChildrenChanged(String path) { - if (PINPOINT_COLLECTOR_CLUSTER_PATH.equals(path)) { + if (ZookeeperConstants.PINPOINT_COLLECTOR_CLUSTER_PATH.equals(path)) { if (syncPullCollectorCluster()) { return true; } @@ -201,7 +186,7 @@ private boolean handleNodeChildrenChanged(String path) { private boolean handleNodeDeleted(String path) { if (path != null) { - String id = clusterDataManagerHelper.extractCollectorClusterId(path, PINPOINT_COLLECTOR_CLUSTER_PATH); + String id = clusterDataManagerHelper.extractCollectorClusterId(path, ZookeeperConstants.PINPOINT_COLLECTOR_CLUSTER_PATH); if (id != null) { collectorClusterInfo.remove(id); return true; @@ -212,7 +197,7 @@ private boolean handleNodeDeleted(String path) { private boolean handleNodeDataChanged(String path) { if (path != null) { - String id = clusterDataManagerHelper.extractCollectorClusterId(path, PINPOINT_COLLECTOR_CLUSTER_PATH); + String id = clusterDataManagerHelper.extractCollectorClusterId(path, ZookeeperConstants.PINPOINT_COLLECTOR_CLUSTER_PATH); if (id != null) { if (pushCollectorClusterData(id)) { return true; @@ -240,16 +225,15 @@ private Timer createTimer() { return timer; } - @Override public boolean isConnected() { - return connected.get(); + return client.isConnected(); } private boolean syncPullCollectorCluster() { logger.info("syncPullCollectorCluster() started."); synchronized (this) { - Map map = clusterDataManagerHelper.syncPullCollectorCluster(client, PINPOINT_COLLECTOR_CLUSTER_PATH); - if (Collections.EMPTY_MAP == map) { + Map map = clusterDataManagerHelper.syncPullCollectorCluster(client, ZookeeperConstants.PINPOINT_COLLECTOR_CLUSTER_PATH); + if (MapUtils.isEmpty(map)) { return false; } @@ -265,7 +249,7 @@ private boolean syncPullCollectorCluster() { private boolean pushCollectorClusterData(String id) { logger.info("pushCollectorClusterData() started."); - String path = clusterDataManagerHelper.bindingPathAndZNode(PINPOINT_COLLECTOR_CLUSTER_PATH, id); + String path = ZKPaths.makePath(ZookeeperConstants.PINPOINT_COLLECTOR_CLUSTER_PATH, id); synchronized (this) { try { byte[] data = client.getData(path, true); @@ -273,7 +257,7 @@ private boolean pushCollectorClusterData(String id) { collectorClusterInfo.put(id, data); logger.info("pushCollectorClusterData() completed."); return true; - } catch(NoNodeException e) { + } catch (NoNodeException e) { logger.warn("No node path({}).", path); collectorClusterInfo.remove(id); } catch (Exception e) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterDataManagerHelper.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterDataManagerHelper.java index 681b9219b4fb..f798ee464705 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterDataManagerHelper.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterDataManagerHelper.java @@ -16,7 +16,10 @@ package com.navercorp.pinpoint.web.cluster.zookeeper; -import org.apache.zookeeper.CreateMode; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.ZookeeperClient; +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.common.util.MapUtils; +import org.apache.curator.utils.ZKPaths; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,27 +33,25 @@ */ public class ZookeeperClusterDataManagerHelper { - private static final String PATH_SEPARATOR = "/"; - private final Logger logger = LoggerFactory.getLogger(this.getClass()); public ZookeeperClusterDataManagerHelper() { } - Map getCollectorData(ZookeeperClient client, String path) { + Map getCollectorData(ZookeeperClient client, String parentPath) { try { - List collectorList = client.getChildren(path, true); - if (collectorList == Collections.EMPTY_LIST) { + List collectorList = client.getChildNodeList(parentPath, true); + if (CollectionUtils.isEmpty(collectorList)) { return Collections.emptyMap(); } Map map = new HashMap<>(); for (String collector : collectorList) { - String node = bindingPathAndZNode(path, collector); + String fullPath = ZKPaths.makePath(parentPath, collector); - byte[] data = client.getData(node, true); - map.put(node, data); + byte[] data = client.getData(fullPath, true); + map.put(fullPath, data); } return map; @@ -61,18 +62,6 @@ Map getCollectorData(ZookeeperClient client, String path) { return Collections.emptyMap(); } - public String bindingPathAndZNode(String path, String zNodeName) { - StringBuilder fullPath = new StringBuilder(); - - fullPath.append(path); - if (!path.endsWith(PATH_SEPARATOR)) { - fullPath.append(PATH_SEPARATOR); - } - fullPath.append(zNodeName); - - return fullPath.toString(); - } - String extractCollectorClusterId(String path, String collectorClusterPath) { int index = path.indexOf(collectorClusterPath); @@ -90,17 +79,14 @@ public boolean pushZnode(ZookeeperClient client, PushZnodeJob job) { if (job == null) { return false; } - + String zNodePath = job.getZNodePath(); byte[] contents = job.getContents(); try { - if (!client.exists(zNodePath)) { - client.createPath(zNodePath); - } + client.createPath(zNodePath); - // ip:port zNode naming scheme - String nodeName = client.createNode(zNodePath, contents, CreateMode.EPHEMERAL); + String nodeName = client.createOrSetNode(zNodePath, contents); logger.info("Register Zookeeper node UniqPath = {}.", zNodePath); return true; } catch (Exception e) { @@ -111,7 +97,7 @@ public boolean pushZnode(ZookeeperClient client, PushZnodeJob job) { Map syncPullCollectorCluster(ZookeeperClient client, String path) { Map map = getCollectorData(client, path); - if (map == Collections.EMPTY_MAP) { + if (MapUtils.isEmpty(map)) { return Collections.emptyMap(); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperEventWatcher.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperEventWatcher.java deleted file mode 100644 index 3bfc18660c20..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperEventWatcher.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.navercorp.pinpoint.web.cluster.zookeeper; - -import org.apache.zookeeper.Watcher; - -/** - * @author minwoo.jung - */ -public interface ZookeeperEventWatcher extends Watcher { - boolean isConnected(); -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperUtils.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperUtils.java deleted file mode 100644 index e8e0a70d045e..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.cluster.zookeeper; - -import org.apache.zookeeper.WatchedEvent; -import org.apache.zookeeper.Watcher.Event.EventType; -import org.apache.zookeeper.Watcher.Event.KeeperState; - -/** - * @author Taejin Koo - */ -public final class ZookeeperUtils { - - // would be a good idea to move to commons-hbase (if implemented) in the future - private ZookeeperUtils() { - } - - public static boolean isConnectedEvent(WatchedEvent event) { - KeeperState state = event.getState(); - EventType eventType = event.getType(); - - return isConnectedEvent(state, eventType); - } - - @SuppressWarnings("deprecation") - public static boolean isConnectedEvent(KeeperState state, EventType eventType) { - if ((state == KeeperState.SyncConnected || state == KeeperState.NoSyncConnected) && eventType == EventType.None) { - return true; - } else { - return false; - } - } - - - public static boolean isDisconnectedEvent(WatchedEvent event) { - KeeperState state = event.getState(); - EventType eventType = event.getType(); - - return isDisconnectedEvent(state, eventType); - } - - public static boolean isDisconnectedEvent(KeeperState state, EventType eventType) { - if ((state == KeeperState.Disconnected || state == KeeperState.Expired) && eventType == eventType.None) { - return true; - } else { - return false; - } - } - -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/AuthException.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/AuthException.java deleted file mode 100644 index e76c5af81f2a..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/AuthException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class AuthException extends PinpointZookeeperException { - - public AuthException() { - } - - public AuthException(String message) { - super(message); - } - - public AuthException(String message, Throwable cause) { - super(message, cause); - } - - public AuthException(Throwable cause) { - super(cause); - } - -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/BadOperationException.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/BadOperationException.java deleted file mode 100644 index cda08a0cf6c8..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/BadOperationException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class BadOperationException extends PinpointZookeeperException { - - public BadOperationException() { - } - - public BadOperationException(String message) { - super(message); - } - - public BadOperationException(String message, Throwable cause) { - super(message, cause); - } - - public BadOperationException(Throwable cause) { - super(cause); - } - -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/ConnectionException.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/ConnectionException.java deleted file mode 100644 index cbae894b4f44..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/ConnectionException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class ConnectionException extends PinpointZookeeperException { - - public ConnectionException() { - } - - public ConnectionException(String message) { - super(message); - } - - public ConnectionException(String message, Throwable cause) { - super(message, cause); - } - - public ConnectionException(Throwable cause) { - super(cause); - } - -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/NoNodeException.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/NoNodeException.java deleted file mode 100644 index 37d17d9c7aa4..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/NoNodeException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.cluster.zookeeper.exception; - -public class NoNodeException extends PinpointZookeeperException { - - public NoNodeException() { - } - - public NoNodeException(String message) { - super(message); - } - - public NoNodeException(String message, Throwable cause) { - super(message, cause); - } - - public NoNodeException(Throwable cause) { - super(cause); - } - -} \ No newline at end of file diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/PinpointZookeeperException.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/PinpointZookeeperException.java deleted file mode 100644 index 674736a64028..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/PinpointZookeeperException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class PinpointZookeeperException extends Exception { - - public PinpointZookeeperException() { - } - - public PinpointZookeeperException(String message) { - super(message); - } - - public PinpointZookeeperException(String message, Throwable cause) { - super(message, cause); - } - - public PinpointZookeeperException(Throwable cause) { - super(cause); - } - -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/TimeoutException.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/TimeoutException.java deleted file mode 100644 index c4b6fef9a0af..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/TimeoutException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class TimeoutException extends PinpointZookeeperException { - - public TimeoutException() { - } - - public TimeoutException(String message) { - super(message); - } - - public TimeoutException(String message, Throwable cause) { - super(message, cause); - } - - public TimeoutException(Throwable cause) { - super(cause); - } - -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/UnknownException.java b/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/UnknownException.java deleted file mode 100644 index ca69f63b235f..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/cluster/zookeeper/exception/UnknownException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.cluster.zookeeper.exception; - -/** - * @author koo.taejin - */ -public class UnknownException extends PinpointZookeeperException { - - public UnknownException() { - } - - public UnknownException(String message) { - super(message); - } - - public UnknownException(String message, Throwable cause) { - super(message, cause); - } - - public UnknownException(Throwable cause) { - super(cause); - } - -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/config/ConfigProperties.java b/web/src/main/java/com/navercorp/pinpoint/web/config/ConfigProperties.java index 92af34f85214..10fadb418139 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/config/ConfigProperties.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/config/ConfigProperties.java @@ -45,13 +45,16 @@ public class ConfigProperties { @Value("#{pinpointWebProps['config.openSource'] ?: true}") private boolean openSource; - + @Value("#{pinpointWebProps['security.guide.url']}") private String securityGuideUrl; @Value("#{pinpointWebProps['config.show.applicationStat'] ?: false}") private boolean showApplicationStat; + @Value("#{pinpointWebProps['config.show.stackTraceOnError'] ?: true}") + private boolean showStackTraceOnError; + @Value("#{pinpointWebProps['websocket.allowedOrigins']}") private String webSocketAllowedOrigins; @@ -91,6 +94,10 @@ public boolean isShowApplicationStat() { return this.showApplicationStat; } + public boolean isShowStackTraceOnError() { + return showStackTraceOnError; + } + public String getWebSocketAllowedOrigins() { return webSocketAllowedOrigins; } @@ -107,6 +114,7 @@ public String toString() { sb.append(", openSource=").append(openSource); sb.append(", securityGuideUrl='").append(securityGuideUrl).append('\''); sb.append(", showApplicationStat=").append(showApplicationStat); + sb.append(", showStackTraceOnError=").append(showStackTraceOnError); sb.append(", webSocketAllowedOrigins=").append(webSocketAllowedOrigins); sb.append('}'); return sb.toString(); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/config/WebSocketConfig.java b/web/src/main/java/com/navercorp/pinpoint/web/config/WebSocketConfig.java index 0f9ad8bee538..5d41a7f156c8 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/config/WebSocketConfig.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/config/WebSocketConfig.java @@ -17,19 +17,21 @@ package com.navercorp.pinpoint.web.config; -import com.navercorp.pinpoint.web.websocket.PinpointWebSocketHandler; -import com.navercorp.pinpoint.web.websocket.PinpointWebSocketHandlerManager; -import com.navercorp.pinpoint.web.websocket.WebSocketSessionContextPrepareHandshakeInterceptor; +import com.navercorp.pinpoint.web.websocket.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; +import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistration; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; +import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; +import java.util.Objects; + /** * @author Taejin Koo */ @@ -48,16 +50,27 @@ public class WebSocketConfig implements WebSocketConfigurer { @Autowired private ConfigProperties configProperties; + @Autowired(required = false) + private WebSocketHandlerDecoratorFactory webSocketHandlerDecoratorFactory = new DefaultWebSocketHandlerDecoratorFactory(); + + @Autowired(required = false) + private CustomHandshakeInterceptor customHandshakeInterceptor = null; + @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { final String[] allowedOriginArray = getAllowedOriginArray(configProperties.getWebSocketAllowedOrigins()); for (PinpointWebSocketHandler handler : handlerRepository.getWebSocketHandlerRepository()) { String path = handler.getRequestMapping() + WEBSOCKET_SUFFIX; - final WebSocketHandlerRegistration webSocketHandlerRegistration = registry.addHandler(handler, path); + + WebSocketHandler webSocketHandler = webSocketHandlerDecoratorFactory.decorate(handler); + final WebSocketHandlerRegistration webSocketHandlerRegistration = registry.addHandler(webSocketHandler, path); webSocketHandlerRegistration.addInterceptors(new HttpSessionHandshakeInterceptor()); webSocketHandlerRegistration.addInterceptors(new WebSocketSessionContextPrepareHandshakeInterceptor()); + if (Objects.nonNull(customHandshakeInterceptor)) { + webSocketHandlerRegistration.addInterceptors(customHandshakeInterceptor); + } webSocketHandlerRegistration.setAllowedOrigins(allowedOriginArray); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentInfoController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentInfoController.java index 49ac968dace6..56ae264db941 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentInfoController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentInfoController.java @@ -17,6 +17,7 @@ package com.navercorp.pinpoint.web.controller; import com.navercorp.pinpoint.common.PinpointConstants; +import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; import com.navercorp.pinpoint.common.util.IdValidateUtils; import com.navercorp.pinpoint.web.service.AgentEventService; import com.navercorp.pinpoint.web.service.AgentInfoService; @@ -25,7 +26,7 @@ import com.navercorp.pinpoint.web.vo.AgentInfo; import com.navercorp.pinpoint.web.vo.AgentInstallationInfo; import com.navercorp.pinpoint.web.vo.AgentStatus; -import com.navercorp.pinpoint.web.vo.ApplicationAgentList; +import com.navercorp.pinpoint.web.vo.ApplicationAgentsList; import com.navercorp.pinpoint.web.vo.CodeResult; import com.navercorp.pinpoint.web.vo.Range; import com.navercorp.pinpoint.web.vo.timeline.inspector.InspectorTimeline; @@ -56,50 +57,71 @@ public class AgentInfoController { @RequestMapping(value = "/getAgentList", method = RequestMethod.GET, params = {"!application"}) @ResponseBody - public ApplicationAgentList getAgentList() { - return this.agentInfoService.getApplicationAgentList(ApplicationAgentList.Key.APPLICATION_NAME); + public ApplicationAgentsList getAgentList() { + long timestamp = System.currentTimeMillis(); + return getAgentList(timestamp); } @RequestMapping(value = "/getAgentList", method = RequestMethod.GET, params = {"!application", "from", "to"}) @ResponseBody - public ApplicationAgentList getAgentList( + public ApplicationAgentsList getAgentList( @RequestParam("from") long from, @RequestParam("to") long to) { - return this.agentInfoService.getApplicationAgentList(ApplicationAgentList.Key.APPLICATION_NAME, to); + long timestamp = to; + return this.agentInfoService.getAllApplicationAgentsList(ApplicationAgentsList.Filter.NONE, timestamp); } @PreAuthorize("hasPermission(#applicationName, 'application', 'inspector')") @RequestMapping(value = "/getAgentList", method = RequestMethod.GET, params = {"!application", "timestamp"}) @ResponseBody - public ApplicationAgentList getAgentList( + public ApplicationAgentsList getAgentList( @RequestParam("timestamp") long timestamp) { - return this.agentInfoService.getApplicationAgentList(ApplicationAgentList.Key.APPLICATION_NAME, timestamp); + return this.agentInfoService.getAllApplicationAgentsList(ApplicationAgentsList.Filter.NONE, timestamp); } @RequestMapping(value = "/getAgentList", method = RequestMethod.GET, params = {"application"}) @ResponseBody - public ApplicationAgentList getAgentList( - @RequestParam("application") String applicationName) { - return this.agentInfoService.getApplicationAgentList(ApplicationAgentList.Key.HOST_NAME, applicationName); + public ApplicationAgentsList getAgentList(@RequestParam("application") String applicationName) { + long timestamp = System.currentTimeMillis(); + return getAgentList(applicationName, timestamp); } @PreAuthorize("hasPermission(#applicationName, 'application', 'inspector')") @RequestMapping(value = "/getAgentList", method = RequestMethod.GET, params = {"application", "from", "to"}) @ResponseBody - public ApplicationAgentList getAgentList( + public ApplicationAgentsList getAgentList( @RequestParam("application") String applicationName, @RequestParam("from") long from, @RequestParam("to") long to) { - return this.agentInfoService.getApplicationAgentList(ApplicationAgentList.Key.HOST_NAME, applicationName, to); + ApplicationAgentsList.Filter containerFilter = agentInfo -> { + if (agentInfo.isContainer()) { + AgentStatus agentStatus = agentInfo.getStatus(); + if (agentStatus == null || agentStatus.getEventTimestamp() < from) { + return ApplicationAgentsList.Filter.REJECT; + } + } + return ApplicationAgentsList.Filter.ACCEPT; + }; + long timestamp = to; + return this.agentInfoService.getApplicationAgentsList(ApplicationAgentsList.GroupBy.HOST_NAME, containerFilter, applicationName, timestamp); } @PreAuthorize("hasPermission(#applicationName, 'application', 'inspector')") @RequestMapping(value = "/getAgentList", method = RequestMethod.GET, params = {"application", "timestamp"}) @ResponseBody - public ApplicationAgentList getAgentList( + public ApplicationAgentsList getAgentList( @RequestParam("application") String applicationName, @RequestParam("timestamp") long timestamp) { - return this.agentInfoService.getApplicationAgentList(ApplicationAgentList.Key.HOST_NAME, applicationName, timestamp); + ApplicationAgentsList.Filter runningContainerFilter = agentInfo -> { + if (agentInfo.isContainer()) { + AgentStatus agentStatus = agentInfo.getStatus(); + if (agentStatus == null || agentStatus.getState() != AgentLifeCycleState.RUNNING) { + return ApplicationAgentsList.Filter.REJECT; + } + } + return ApplicationAgentsList.Filter.ACCEPT; + }; + return this.agentInfoService.getApplicationAgentsList(ApplicationAgentsList.GroupBy.HOST_NAME, runningContainerFilter, applicationName, timestamp); } @RequestMapping(value = "/getAgentInfo", method = RequestMethod.GET) diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentStatController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentStatController.java index 0f002b9a5540..12d6b0ac4992 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentStatController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentStatController.java @@ -16,11 +16,15 @@ package com.navercorp.pinpoint.web.controller; + + import com.navercorp.pinpoint.common.server.bo.stat.ActiveTraceBo; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatDataPoint; import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; import com.navercorp.pinpoint.common.server.bo.stat.DataSourceListBo; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcDetailedBo; import com.navercorp.pinpoint.common.server.bo.stat.ResponseTimeBo; @@ -35,6 +39,10 @@ import com.navercorp.pinpoint.web.service.stat.DataSourceService; import com.navercorp.pinpoint.web.service.stat.DeadlockChartService; import com.navercorp.pinpoint.web.service.stat.DeadlockService; +import com.navercorp.pinpoint.web.service.stat.DirectBufferChartService; +import com.navercorp.pinpoint.web.service.stat.DirectBufferService; +import com.navercorp.pinpoint.web.service.stat.FileDescriptorChartService; +import com.navercorp.pinpoint.web.service.stat.FileDescriptorService; import com.navercorp.pinpoint.web.service.stat.JvmGcChartService; import com.navercorp.pinpoint.web.service.stat.JvmGcDetailedChartService; import com.navercorp.pinpoint.web.service.stat.JvmGcDetailedService; @@ -214,11 +222,28 @@ public ResponseTimeController(ResponseTimeService responseTimeService, ResponseT @Controller @RequestMapping("/getAgentStat/deadlock") - public static class DeadlockController extends AgentStatController { + public static class DeadlockController extends AgentStatController { @Autowired public DeadlockController(DeadlockService deadlockService, DeadlockChartService deadlockChartService) { super(deadlockService, deadlockChartService); } } + @Controller + @RequestMapping("/getAgentStat/fileDescriptor") + public static class FileDescriptorController extends AgentStatController { + @Autowired + public FileDescriptorController(FileDescriptorService fileDescriptorService, FileDescriptorChartService fileDescriptorChartService) { + super(fileDescriptorService, fileDescriptorChartService); + } + } + + @Controller + @RequestMapping("/getAgentStat/directBuffer") + public static class DirectBufferController extends AgentStatController { + @Autowired + public DirectBufferController(DirectBufferService directBufferService, DirectBufferChartService directBufferChartService) { + super(directBufferService, directBufferChartService); + } + } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentStatisticsController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentStatisticsController.java index b08052498e5e..bbee39b4ddc0 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentStatisticsController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/AgentStatisticsController.java @@ -27,7 +27,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; @@ -92,7 +91,7 @@ public List selectAgentCount(@RequestParam("from") long fr Range range = new Range(DateUtils.timestampToMidNight(from), DateUtils.timestampToMidNight(to), true); List agentCountStatisticsList = agentStatisticsService.selectAgentCount(range); - Collections.sort(agentCountStatisticsList, new Comparator() { + agentCountStatisticsList.sort(new Comparator() { @Override public int compare(AgentCountStatistics o1, AgentCountStatistics o2) { if (o1.getTimestamp() > o2.getTimestamp()) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/ApplicationStatController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/ApplicationStatController.java index b8387d84bd28..89ac69eded0e 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/ApplicationStatController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/ApplicationStatController.java @@ -15,8 +15,15 @@ */ package com.navercorp.pinpoint.web.controller; -import com.navercorp.pinpoint.web.service.stat.*; +import com.navercorp.pinpoint.web.service.stat.ApplicationActiveTraceService; +import com.navercorp.pinpoint.web.service.stat.ApplicationCpuLoadService; +import com.navercorp.pinpoint.web.service.stat.ApplicationDataSourceService; +import com.navercorp.pinpoint.web.service.stat.ApplicationDirectBufferService; +import com.navercorp.pinpoint.web.service.stat.ApplicationMemoryService; +import com.navercorp.pinpoint.web.service.stat.ApplicationResponseTimeService; import com.navercorp.pinpoint.web.service.stat.ApplicationStatChartService; +import com.navercorp.pinpoint.web.service.stat.ApplicationTransactionService; +import com.navercorp.pinpoint.web.service.stat.ApplicationFileDescriptorService; import com.navercorp.pinpoint.web.util.TimeWindow; import com.navercorp.pinpoint.web.util.TimeWindowSlotCentricSampler; import com.navercorp.pinpoint.web.vo.Range; @@ -127,5 +134,23 @@ public List getAgentStatChart(@RequestParam("applicationId") String a } } } + + @Controller + @RequestMapping("/getApplicationStat/fileDescriptor/chart") + public static class ApplicationFileDescriptorController extends ApplicationStatController { + @Autowired + public ApplicationFileDescriptorController(ApplicationFileDescriptorService applicationFileDescriptorService) { + super(applicationFileDescriptorService); + } + } + + @Controller + @RequestMapping("/getApplicationStat/directBuffer/chart") + public static class ApplicationDirectBufferController extends ApplicationStatController { + @Autowired + public ApplicationDirectBufferController(ApplicationDirectBufferService applicationDirectBufferService) { + super(applicationDirectBufferService); + } + } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java index 9137a8c30425..532c72cd2f6f 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/BusinessTransactionController.java @@ -1,11 +1,11 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,14 +16,22 @@ package com.navercorp.pinpoint.web.controller; -import java.util.List; - import com.navercorp.pinpoint.common.util.DefaultSqlParser; import com.navercorp.pinpoint.common.util.OutputParameterParser; import com.navercorp.pinpoint.common.util.SqlParser; import com.navercorp.pinpoint.common.util.TransactionId; import com.navercorp.pinpoint.common.util.TransactionIdUtils; +import com.navercorp.pinpoint.web.applicationmap.ApplicationMap; +import com.navercorp.pinpoint.web.calltree.span.CallTreeIterator; +import com.navercorp.pinpoint.web.service.FilteredMapService; +import com.navercorp.pinpoint.web.service.SpanResult; +import com.navercorp.pinpoint.web.service.SpanService; +import com.navercorp.pinpoint.web.service.TransactionInfoService; +import com.navercorp.pinpoint.web.util.DefaultMongoJsonParser; +import com.navercorp.pinpoint.web.util.MongoJsonParser; +import com.navercorp.pinpoint.web.util.OutputParameterMongoJsonParser; import com.navercorp.pinpoint.web.view.TransactionInfoViewModel; +import com.navercorp.pinpoint.web.vo.callstacks.RecordSet; import org.apache.commons.lang3.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,13 +43,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import com.navercorp.pinpoint.web.applicationmap.ApplicationMap; -import com.navercorp.pinpoint.web.calltree.span.CallTreeIterator; -import com.navercorp.pinpoint.web.service.FilteredMapService; -import com.navercorp.pinpoint.web.service.SpanResult; -import com.navercorp.pinpoint.web.service.SpanService; -import com.navercorp.pinpoint.web.service.TransactionInfoService; -import com.navercorp.pinpoint.web.vo.callstacks.RecordSet; +import java.util.List; /** * @author emeroad @@ -76,6 +78,9 @@ public class BusinessTransactionController { private SqlParser sqlParser = new DefaultSqlParser(); private OutputParameterParser parameterParser = new OutputParameterParser(); + private MongoJsonParser mongoJsonParser = new DefaultMongoJsonParser(); + private OutputParameterMongoJsonParser parameterJsonParser = new OutputParameterMongoJsonParser(); + /** * info lookup for a selected transaction * @@ -106,24 +111,34 @@ public TransactionInfoViewModel transactionInfo(@RequestParam("traceId") String return result; } - @RequestMapping(value = "/sqlBind", method = RequestMethod.POST) + @RequestMapping(value = "/bind", method = RequestMethod.POST) @ResponseBody - public String sqlBind(@RequestParam("sql") String sql, - @RequestParam("bind") String bind) { + public String metaDataBind(@RequestParam("type") String type, + @RequestParam("metaData") String metaData, + @RequestParam("bind") String bind) { if (logger.isDebugEnabled()) { - logger.debug("GET /sqlBind params {sql={}, bind={}}", sql, bind); + logger.debug("POST /bind params {metaData={}, bind={}}", metaData, bind); } - if (sql == null) { + if (metaData == null) { return ""; } - final List bindValues = parameterParser.parseOutputParameter(bind); - final String combineSql = sqlParser.combineBindValues(sql, bindValues); - if(logger.isDebugEnabled()) { - logger.debug("Combine SQL. sql={}", combineSql); + List bindValues; + String combinedResult = ""; + + if (type.equals("sql")) { + bindValues = parameterParser.parseOutputParameter(bind); + combinedResult = sqlParser.combineBindValues(metaData, bindValues); + } else if (type.equals("mongoJson")) { + bindValues = parameterJsonParser.parseOutputParameter(bind); + combinedResult = mongoJsonParser.combineBindValues(metaData, bindValues); + } + + if (logger.isDebugEnabled()) { + logger.debug("Combined result={}", combinedResult); } - return StringEscapeUtils.escapeHtml4(combineSql); + return StringEscapeUtils.escapeHtml4(combinedResult); } } \ No newline at end of file diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/CommandController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/CommandController.java index 20a2b58a1dc9..fb150ee1b7a0 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/CommandController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/CommandController.java @@ -52,6 +52,7 @@ public class CommandController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired + @Qualifier("commandHeaderTBaseSerializerFactory") private SerializerFactory commandSerializerFactory; @Autowired diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/ConfigController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/ConfigController.java index fec44e0dbeb0..b25ba225f03d 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/ConfigController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/ConfigController.java @@ -59,6 +59,7 @@ public Map getProperties(@RequestHeader(value=SSO_USER, required result.put("showActiveThreadDump", webProperties.isShowActiveThreadDump()); result.put("enableServerMapRealTime", webProperties.isEnableServerMapRealTime()); result.put("showApplicationStat", webProperties.isShowApplicationStat()); + result.put("showStackTraceOnError", webProperties.isShowStackTraceOnError()); result.put("openSource", webProperties.isOpenSource()); result.put("version", Version.VERSION); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/ControllerExceptionHandler.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/ControllerExceptionHandler.java index 2ff14fcb7f1a..bef8e0f8bea0 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/ControllerExceptionHandler.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/ControllerExceptionHandler.java @@ -26,8 +26,10 @@ import javax.servlet.http.HttpServletRequest; +import com.navercorp.pinpoint.web.config.ConfigProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.AccessDeniedException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -45,6 +47,8 @@ public class ControllerExceptionHandler { private final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Autowired + private ConfigProperties webProperties; @ExceptionHandler(value = Exception.class) public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception exception) throws Exception { @@ -66,7 +70,9 @@ private Map createExceptionResource(HttpServletRequest request, Map exceptionMap = new HashMap<>(); exceptionMap.put("message", getExceptionMessage(throwable)); - exceptionMap.put("stacktrace", getExceptionStackTrace(throwable)); + if (webProperties.isShowStackTraceOnError()) { + exceptionMap.put("stacktrace", getExceptionStackTrace(throwable)); + } exceptionMap.put("request", createRequestResource(request)); return exceptionMap; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java index e90a79c52755..eb3aa9ee2845 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/ScatterChartController.java @@ -44,7 +44,6 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -209,7 +208,7 @@ private ModelAndView selectFilterScatterData(String applicationName, Range range boolean requestComplete = transactionIdList.size() < limit; - Collections.sort(transactionIdList, TransactionIdComparator.INSTANCE); + transactionIdList.sort(TransactionIdComparator.INSTANCE); Filter filter = filterBuilder.build(filterText); ModelAndView mv; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/UserGroupController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/UserGroupController.java index b9c75d7df772..cb9f614bee64 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/UserGroupController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/UserGroupController.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; +import com.navercorp.pinpoint.web.vo.exception.PinpointUserGroupException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -32,8 +33,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import com.navercorp.pinpoint.web.config.ConfigProperties; -import com.navercorp.pinpoint.web.service.AlarmService; import com.navercorp.pinpoint.web.service.UserGroupService; import com.navercorp.pinpoint.web.vo.UserGroup; import com.navercorp.pinpoint.web.vo.UserGroupMember; @@ -54,80 +53,46 @@ public class UserGroupController { @Autowired UserGroupService userGroupService; - - @Autowired - AlarmService alarmService; - - @Autowired - private ConfigProperties webProperties; - + @RequestMapping(method = RequestMethod.POST) @ResponseBody public Map createUserGroup(@RequestBody UserGroup userGroup, @RequestHeader(value=SSO_USER, required=false) String userId) { if (StringUtils.isEmpty(userGroup.getId())) { - Map result = new HashMap<>(); - result.put("errorCode", "500"); - result.put("errorMessage", "There is not id of userGroup in params to create user group"); - return result; + return createErrorMessage("500", "There is not id of userGroup in params to create user group"); } - - String userGroupNumber = userGroupService.createUserGroup(userGroup); - if (webProperties.isOpenSource() == false) { - if (initUserGroup(userGroup, userId) == false) { - Map result = new HashMap<>(); - result.put("errorCode", "500"); - result.put("errorMessage", "There is not userId or fail to create userGroup."); - return result; - } - } - Map result = new HashMap<>(); - result.put("number", userGroupNumber); - return result; - } - - private boolean initUserGroup(UserGroup userGroup, String userId) { - if (StringUtils.isEmpty(userId)) { - userGroupService.deleteUserGroup(userGroup); - return false; + try { + String userGroupNumber = userGroupService.createUserGroup(userGroup, userId); + Map result = new HashMap<>(); + result.put("number", userGroupNumber); + return result; + } catch (PinpointUserGroupException e) { + logger.error(e.getMessage(), e); + return createErrorMessage("500", e.getMessage()); } - - userGroupService.insertMember(new UserGroupMember(userGroup.getId(), userId)); - return true; } @RequestMapping(method = RequestMethod.DELETE) @ResponseBody public Map deleteUserGroup(@RequestBody UserGroup userGroup, @RequestHeader(value=SSO_USER, required=false) String userId) { if (StringUtils.isEmpty(userGroup.getId())) { + return createErrorMessage("500", "there is id of userGroup in params to delete user group"); + } + + try { + userGroupService.deleteUserGroup(userGroup, userId); Map result = new HashMap<>(); - result.put("errorCode", "500"); - result.put("errorMessage", "there is id of userGroup in params to delete user group"); + result.put("result", "SUCCESS"); return result; + } catch (PinpointUserGroupException e) { + logger.error(e.getMessage(), e); + return createErrorMessage("500", e.getMessage()); } - if (webProperties.isOpenSource() == false) { - if (checkValid(userId, userGroup.getId()) == false) { - Map result = new HashMap<>(); - result.put("errorCode", "500"); - result.put("errorMessage", "There is not userId or you don't have authoriy for user group."); - return result; - } - } - userGroupService.deleteUserGroup(userGroup); - userGroupService.deleteMemberByUserGroupId(userGroup.getId()); - alarmService.deleteRuleByUserGroupId(userGroup.getId()); - - - - Map result = new HashMap<>(); - result.put("result", "SUCCESS"); - return result; } @RequestMapping(method = RequestMethod.GET) @ResponseBody public List getUserGroup(@RequestParam(value=USER_ID, required=false) String userId, @RequestParam(value=USER_GROUP_ID, required=false) String userGroupId) { - if (!StringUtils.isEmpty(userId)) { return userGroupService.selectUserGroupByUserId(userId); } else if (!StringUtils.isEmpty(userGroupId)) { @@ -135,69 +100,41 @@ public List getUserGroup(@RequestParam(value=USER_ID, required=false) } return userGroupService.selectUserGroup(); } - + @RequestMapping(value = "/member", method = RequestMethod.POST) @ResponseBody public Map insertUserGroupMember(@RequestBody UserGroupMemberParam userGroupMember, @RequestHeader(value=SSO_USER, required=false) String userId) { if (StringUtils.isEmpty(userGroupMember.getMemberId()) || StringUtils.isEmpty(userGroupMember.getUserGroupId())) { - Map result = new HashMap<>(); - result.put("errorCode", "500"); - result.put("errorMessage", "there is not userGroupId or memberId in params to insert user group member"); - return result; - } - - if (webProperties.isOpenSource() == false) { - boolean isValid = checkValid(userId, userGroupMember.getUserGroupId()); - if (isValid == false) { - Map result = new HashMap<>(); - result.put("errorCode", "500"); - result.put("errorMessage", "there is not userId or you don't have authority for user group."); - return result; - } + return createErrorMessage("500", "there is not userGroupId or memberId in params to insert user group member"); } - - userGroupService.insertMember(userGroupMember); - Map result = new HashMap<>(); - result.put("result", "SUCCESS"); - return result; - } - - private boolean checkValid(String userId, String userGroupId) { - if (StringUtils.isEmpty(userId)) { - return false; - } - if (userGroupService.containMemberForUserGroup(userId, userGroupId) == false) { - return false; + try { + userGroupService.insertMemberWithCheckAuthority(userGroupMember, userId); + Map result = new HashMap<>(); + result.put("result", "SUCCESS"); + return result; + } catch (PinpointUserGroupException e) { + logger.error(e.getMessage(), e); + return createErrorMessage("500", e.getMessage()); } - - return true; } @RequestMapping(value = "/member", method = RequestMethod.DELETE) @ResponseBody public Map deleteUserGroupMember(@RequestBody UserGroupMemberParam userGroupMember, @RequestHeader(value=SSO_USER, required=false) String userId) { if (StringUtils.isEmpty(userGroupMember.getUserGroupId()) || StringUtils.isEmpty(userGroupMember.getMemberId())) { + return createErrorMessage("500", "there is not userGroupId or memberId in params to delete user group member"); + } + + try { + userGroupService.deleteMemberWithCheckAuthority(userGroupMember, userId); Map result = new HashMap<>(); - result.put("errorCode", "500"); - result.put("errorMessage", "there is not userGroupId or memberId in params to delete user group member"); + result.put("result", "SUCCESS"); return result; + } catch (PinpointUserGroupException e) { + logger.error(e.getMessage(), e); + return createErrorMessage("500", e.getMessage()); } - if (webProperties.isOpenSource() == false) { - boolean isValid = checkValid(userId, userGroupMember.getUserGroupId()); - if (isValid == false) { - Map result = new HashMap<>(); - result.put("errorCode", "500"); - result.put("errorMessage", "there is not userId or you don't have authority for user group."); - return result; - } - } - - userGroupService.deleteMember(userGroupMember); - - Map result = new HashMap<>(); - result.put("result", "SUCCESS"); - return result; } @RequestMapping(value = "/member", method = RequestMethod.GET) @@ -210,9 +147,13 @@ public List getUserGroupMember(@RequestParam(USER_GROUP_ID) Str @ResponseBody public Map handleException(Exception e) { logger.error("Exception occurred while trying to CRUD userGroup information", e); + return createErrorMessage("500", "Exception occurred while trying to CRUD userGroup information"); + } + + private Map createErrorMessage(String code, String errorMessage) { Map result = new HashMap<>(); - result.put("errorCode", "500"); - result.put("errorMessage", "Exception occurred while trying to CRUD userGroup information"); + result.put("errorCode", code); + result.put("errorMessage", errorMessage); return result; } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/ApplicationDirectBufferDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/ApplicationDirectBufferDao.java new file mode 100644 index 000000000000..96f5849fd19c --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/ApplicationDirectBufferDao.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.dao; + +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinDirectBufferBo; + +import java.util.List; + +/** + * @author Roy Kim + */ +public interface ApplicationDirectBufferDao { + List getApplicationStatList(String applicationId, TimeWindow timeWindow); +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/ApplicationFileDescriptorDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/ApplicationFileDescriptorDao.java new file mode 100644 index 000000000000..be745633ebee --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/ApplicationFileDescriptorDao.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.dao; + +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinFileDescriptorBo; + +import java.util.List; + +/** + * @author Roy Kim + */ +public interface ApplicationFileDescriptorDao { + List getApplicationStatList(String applicationId, TimeWindow timeWindow); +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentEventDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentEventDao.java index e808224df058..400641324851 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentEventDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentEventDao.java @@ -19,6 +19,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.hbase.RowMapper; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; import com.navercorp.pinpoint.common.server.util.AgentEventType; import com.navercorp.pinpoint.common.server.util.RowKeyUtils; @@ -28,6 +29,7 @@ import com.navercorp.pinpoint.web.mapper.AgentEventResultsExtractor; import com.navercorp.pinpoint.web.vo.Range; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.filter.BinaryComparator; import org.apache.hadoop.hbase.filter.CompareFilter; @@ -56,6 +58,9 @@ public class HbaseAgentEventDao implements AgentEventDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("agentEventMapper") private RowMapper> agentEventMapper; @@ -88,7 +93,9 @@ public List getAgentEvents(String agentId, Range range, Set agentEvents = this.hbaseOperations2.find(HBaseTables.AGENT_EVENT, scan, agentEventResultsExtractor); + + TableName agentEventTableName = tableNameProvider.getTableName(HBaseTables.AGENT_EVENT_STR); + List agentEvents = this.hbaseOperations2.find(agentEventTableName, scan, agentEventResultsExtractor); logger.debug("agentEvents found. {}", agentEvents); return agentEvents; } @@ -107,7 +114,9 @@ public AgentEventBo getAgentEvent(String agentId, long eventTimestamp, AgentEven final byte[] rowKey = createRowKey(agentId, eventTimestamp); byte[] qualifier = Bytes.toBytes(eventType.getCode()); - List events = this.hbaseOperations2.get(HBaseTables.AGENT_EVENT, rowKey, + + TableName agentEventTableName = tableNameProvider.getTableName(HBaseTables.AGENT_EVENT_STR); + List events = this.hbaseOperations2.get(agentEventTableName, rowKey, HBaseTables.AGENT_EVENT_CF_EVENTS, qualifier, this.agentEventMapper); if (CollectionUtils.isEmpty(events)) { return null; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentInfoDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentInfoDao.java index 00e9fe19931e..b4bf2973c98c 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentInfoDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentInfoDao.java @@ -18,6 +18,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.util.RowKeyUtils; import com.navercorp.pinpoint.common.util.TimeUtils; import com.navercorp.pinpoint.web.dao.AgentInfoDao; @@ -25,6 +26,7 @@ import com.navercorp.pinpoint.web.mapper.AgentInfoResultsExtractor; import com.navercorp.pinpoint.web.vo.AgentInfo; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.*; import org.apache.hadoop.hbase.util.Bytes; import org.springframework.beans.factory.annotation.Autowired; @@ -46,6 +48,9 @@ public class HbaseAgentInfoDao implements AgentInfoDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentInfoResultsExtractor agentInfoResultsExtractor; @@ -60,7 +65,9 @@ public AgentInfo getInitialAgentInfo(final String agentId) { throw new NullPointerException("agentId must not be null"); } Scan scan = createScanForInitialAgentInfo(agentId); - return this.hbaseOperations2.find(HBaseTables.AGENTINFO, scan, agentInfoResultsExtractor); + + TableName agentInfoTableName = tableNameProvider.getTableName(HBaseTables.AGENTINFO_STR); + return this.hbaseOperations2.find(agentInfoTableName, scan, agentInfoResultsExtractor); } @Override @@ -72,7 +79,9 @@ public List getInitialAgentInfos(List agentIds) { for (String agentId : agentIds) { scans.add(createScanForInitialAgentInfo(agentId)); } - return this.hbaseOperations2.find(HBaseTables.AGENTINFO, scans, agentInfoResultsExtractor); + + TableName agentInfoTableName = tableNameProvider.getTableName(HBaseTables.AGENTINFO_STR); + return this.hbaseOperations2.find(agentInfoTableName, scans, agentInfoResultsExtractor); } private Scan createScanForInitialAgentInfo(String agentId) { @@ -101,7 +110,8 @@ public AgentInfo getAgentInfo(final String agentId, final long timestamp) { Scan scan = createScan(agentId, timestamp); - return this.hbaseOperations2.find(HBaseTables.AGENTINFO, scan, agentInfoResultsExtractor); + TableName agentInfoTableName = tableNameProvider.getTableName(HBaseTables.AGENTINFO_STR); + return this.hbaseOperations2.find(agentInfoTableName, scan, agentInfoResultsExtractor); } @Override @@ -115,7 +125,8 @@ public List getAgentInfos(List agentIds, long timestamp) { scans.add(createScan(agentId, timestamp)); } - return this.hbaseOperations2.findParallel(HBaseTables.AGENTINFO, scans, agentInfoResultsExtractor); + TableName agentInfoTableName = tableNameProvider.getTableName(HBaseTables.AGENTINFO_STR); + return this.hbaseOperations2.findParallel(agentInfoTableName, scans, agentInfoResultsExtractor); } private Scan createScan(String agentId, long currentTime) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentLifeCycleDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentLifeCycleDao.java index a5a13367847f..78cc216a1d85 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentLifeCycleDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentLifeCycleDao.java @@ -20,10 +20,12 @@ import java.util.Collection; import java.util.List; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; import com.navercorp.pinpoint.web.vo.AgentInfo; import com.navercorp.pinpoint.web.vo.AgentStatus; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; @@ -53,6 +55,9 @@ public class HbaseAgentLifeCycleDao implements AgentLifeCycleDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("agentLifeCycleMapper") private RowMapper agentLifeCycleMapper; @@ -64,7 +69,8 @@ public AgentStatus getAgentStatus(String agentId, long timestamp) { Scan scan = createScan(agentId, 0, timestamp); - AgentLifeCycleBo agentLifeCycleBo = this.hbaseOperations2.find(HBaseTables.AGENT_LIFECYCLE, scan, new MostRecentAgentLifeCycleResultsExtractor(this.agentLifeCycleMapper, timestamp)); + TableName agentLifeCycleTableName = tableNameProvider.getTableName(HBaseTables.AGENT_LIFECYCLE_STR); + AgentLifeCycleBo agentLifeCycleBo = this.hbaseOperations2.find(agentLifeCycleTableName, scan, new MostRecentAgentLifeCycleResultsExtractor(this.agentLifeCycleMapper, timestamp)); return createAgentStatus(agentId, agentLifeCycleBo); } @@ -80,7 +86,8 @@ public void populateAgentStatus(AgentInfo agentInfo, long timestamp) { final long fromTimestamp = toTimestamp - 1; Scan scan = createScan(agentId, fromTimestamp, toTimestamp); - AgentLifeCycleBo agentLifeCycleBo = this.hbaseOperations2.find(HBaseTables.AGENT_LIFECYCLE, scan, new MostRecentAgentLifeCycleResultsExtractor(this.agentLifeCycleMapper, timestamp)); + TableName agentLifeCycleTableName = tableNameProvider.getTableName(HBaseTables.AGENT_LIFECYCLE_STR); + AgentLifeCycleBo agentLifeCycleBo = this.hbaseOperations2.find(agentLifeCycleTableName, scan, new MostRecentAgentLifeCycleResultsExtractor(this.agentLifeCycleMapper, timestamp)); AgentStatus agentStatus = createAgentStatus(agentId, agentLifeCycleBo); agentInfo.setStatus(agentStatus); } @@ -100,7 +107,9 @@ public void populateAgentStatuses(Collection agentInfos, long timesta scans.add(createScan(agentId, fromTimestamp, toTimestamp)); } } - List agentLifeCycles = this.hbaseOperations2.findParallel(HBaseTables.AGENT_LIFECYCLE, scans, new MostRecentAgentLifeCycleResultsExtractor(this.agentLifeCycleMapper, timestamp)); + + TableName agentLifeCycleTableName = tableNameProvider.getTableName(HBaseTables.AGENT_LIFECYCLE_STR); + List agentLifeCycles = this.hbaseOperations2.findParallel(agentLifeCycleTableName, scans, new MostRecentAgentLifeCycleResultsExtractor(this.agentLifeCycleMapper, timestamp)); int idx = 0; for (AgentInfo agentInfo : agentInfos) { if (agentInfo != null) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApiMetaDataDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApiMetaDataDao.java index ae96e3289f66..a39dea240c15 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApiMetaDataDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApiMetaDataDao.java @@ -18,8 +18,10 @@ import java.util.List; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Get; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -43,6 +45,9 @@ public class HbaseApiMetaDataDao implements ApiMetaDataDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("apiMetaDataMapper") private RowMapper> apiMetaDataMapper; @@ -62,7 +67,9 @@ public List getApiMetaData(String agentId, long time, int apiId) byte[] sqlId = getDistributedKey(apiMetaDataBo.toRowKey()); Get get = new Get(sqlId); get.addFamily(HBaseTables.API_METADATA_CF_API); - return hbaseOperations2.get(HBaseTables.API_METADATA, get, apiMetaDataMapper); + + TableName apiMetaDataTableName = tableNameProvider.getTableName(HBaseTables.API_METADATA_STR); + return hbaseOperations2.get(apiMetaDataTableName, get, apiMetaDataMapper); } private byte[] getDistributedKey(byte[] rowKey) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationDirectBufferDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationDirectBufferDao.java new file mode 100644 index 000000000000..e251f1c54248 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationDirectBufferDao.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.dao.hbase; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.join.DirectBufferDecoder; +import com.navercorp.pinpoint.common.server.bo.stat.join.StatType; +import com.navercorp.pinpoint.web.dao.ApplicationDirectBufferDao; +import com.navercorp.pinpoint.web.mapper.stat.ApplicationStatMapper; +import com.navercorp.pinpoint.web.mapper.stat.SampledApplicationStatResultExtractor; +import com.navercorp.pinpoint.web.mapper.stat.sampling.sampler.JoinDirectBufferSampler; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.Range; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinDirectBufferBo; +import com.navercorp.pinpoint.web.vo.stat.AggregationStatData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Roy Kim + */ +@Repository +public class HbaseApplicationDirectBufferDao implements ApplicationDirectBufferDao { + + @Autowired + private DirectBufferDecoder directBufferDecoder; + + @Autowired + private JoinDirectBufferSampler directBufferSampler; + + @Autowired + private HbaseApplicationStatDaoOperations operations; + + @Override + public List getApplicationStatList(String applicationId, TimeWindow timeWindow) { + long scanFrom = timeWindow.getWindowRange().getFrom(); + long scanTo = timeWindow.getWindowRange().getTo() + timeWindow.getWindowSlotSize(); + Range range = new Range(scanFrom, scanTo); + ApplicationStatMapper mapper = operations.createRowMapper(directBufferDecoder, range); + SampledApplicationStatResultExtractor resultExtractor = new SampledApplicationStatResultExtractor(timeWindow, mapper, directBufferSampler); + List aggregationStatDataList = operations.getSampledStatList(StatType.APP_DIRECT_BUFFER, resultExtractor, applicationId, range); + return cast(aggregationStatDataList); + } + + private List cast(List aggregationStatDataList) { + List aggreJoinDirectBufferBoList = new ArrayList<>(aggregationStatDataList.size()); + + for (AggregationStatData aggregationStatData : aggregationStatDataList) { + aggreJoinDirectBufferBoList.add((AggreJoinDirectBufferBo) aggregationStatData); + } + + return aggreJoinDirectBufferBoList; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationFileDescriptorDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationFileDescriptorDao.java new file mode 100644 index 000000000000..1bc8e9fc3543 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationFileDescriptorDao.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.dao.hbase; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.join.FileDescriptorDecoder; +import com.navercorp.pinpoint.common.server.bo.stat.join.StatType; +import com.navercorp.pinpoint.web.dao.ApplicationFileDescriptorDao; +import com.navercorp.pinpoint.web.mapper.stat.ApplicationStatMapper; +import com.navercorp.pinpoint.web.mapper.stat.SampledApplicationStatResultExtractor; +import com.navercorp.pinpoint.web.mapper.stat.sampling.sampler.JoinFileDescriptorSampler; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.Range; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinFileDescriptorBo; +import com.navercorp.pinpoint.web.vo.stat.AggregationStatData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Roy Kim + */ +@Repository +public class HbaseApplicationFileDescriptorDao implements ApplicationFileDescriptorDao { + + @Autowired + private FileDescriptorDecoder fileDescriptorDecoder; + + @Autowired + private JoinFileDescriptorSampler fileDescriptorSampler; + + @Autowired + private HbaseApplicationStatDaoOperations operations; + + @Override + public List getApplicationStatList(String applicationId, TimeWindow timeWindow) { + long scanFrom = timeWindow.getWindowRange().getFrom(); + long scanTo = timeWindow.getWindowRange().getTo() + timeWindow.getWindowSlotSize(); + Range range = new Range(scanFrom, scanTo); + ApplicationStatMapper mapper = operations.createRowMapper(fileDescriptorDecoder, range); + SampledApplicationStatResultExtractor resultExtractor = new SampledApplicationStatResultExtractor(timeWindow, mapper, fileDescriptorSampler); + List aggregationStatDataList = operations.getSampledStatList(StatType.APP_FILE_DESCRIPTOR, resultExtractor, applicationId, range); + return cast(aggregationStatDataList); + } + + private List cast(List aggregationStatDataList) { + List aggreJoinFileDescriptorBoList = new ArrayList<>(aggregationStatDataList.size()); + + for (AggregationStatData aggregationStatData : aggregationStatDataList) { + aggreJoinFileDescriptorBoList.add((AggreJoinFileDescriptorBo) aggregationStatData); + } + + return aggreJoinFileDescriptorBoList; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationIndexDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationIndexDao.java index 9cab5e30ae2f..9cb10183b35b 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationIndexDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationIndexDao.java @@ -20,9 +20,11 @@ import java.util.List; import java.util.Map; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.Scan; @@ -47,6 +49,9 @@ public class HbaseApplicationIndexDao implements ApplicationIndexDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("applicationNameMapper") private RowMapper> applicationNameMapper; @@ -59,7 +64,9 @@ public class HbaseApplicationIndexDao implements ApplicationIndexDao { public List selectAllApplicationNames() { Scan scan = new Scan(); scan.setCaching(30); - List> results = hbaseOperations2.find(HBaseTables.APPLICATION_INDEX, scan, applicationNameMapper); + + TableName applicationIndexTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_INDEX_STR); + List> results = hbaseOperations2.find(applicationIndexTableName, scan, applicationNameMapper); List applications = new ArrayList<>(); for (List result : results) { applications.addAll(result); @@ -77,14 +84,17 @@ public List selectAgentIds(String applicationName) { Get get = new Get(rowKey); get.addFamily(HBaseTables.APPLICATION_INDEX_CF_AGENTS); - return hbaseOperations2.get(HBaseTables.APPLICATION_INDEX, get, agentIdMapper); + TableName applicationIndexTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_INDEX_STR); + return hbaseOperations2.get(applicationIndexTableName, get, agentIdMapper); } @Override public void deleteApplicationName(String applicationName) { byte[] rowKey = Bytes.toBytes(applicationName); Delete delete = new Delete(rowKey); - hbaseOperations2.delete(HBaseTables.APPLICATION_INDEX, delete); + + TableName applicationIndexTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_INDEX_STR); + hbaseOperations2.delete(applicationIndexTableName, delete); } @Override @@ -112,7 +122,9 @@ public void deleteAgentIds(Map> applicationAgentIdMap) { deletes.add(delete); } } - hbaseOperations2.delete(HBaseTables.APPLICATION_INDEX, deletes); + + TableName applicationIndexTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_INDEX_STR); + hbaseOperations2.delete(applicationIndexTableName, deletes); } @Override @@ -127,6 +139,8 @@ public void deleteAgentId(String applicationName, String agentId) { Delete delete = new Delete(rowKey); byte[] qualifier = Bytes.toBytes(agentId); delete.addColumns(HBaseTables.APPLICATION_INDEX_CF_AGENTS, qualifier); - hbaseOperations2.delete(HBaseTables.APPLICATION_INDEX, delete); + + TableName applicationIndexTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_INDEX_STR); + hbaseOperations2.delete(applicationIndexTableName, delete); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationMemoryDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationMemoryDao.java index 8307b5f0c917..80b432208267 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationMemoryDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationMemoryDao.java @@ -18,7 +18,6 @@ import com.navercorp.pinpoint.common.server.bo.codec.stat.join.MemoryDecoder; import com.navercorp.pinpoint.common.server.bo.stat.join.StatType; import com.navercorp.pinpoint.web.dao.ApplicationMemoryDao; -import com.navercorp.pinpoint.web.dao.hbase.HbaseApplicationStatDaoOperations; import com.navercorp.pinpoint.web.mapper.stat.ApplicationStatMapper; import com.navercorp.pinpoint.web.mapper.stat.SampledApplicationStatResultExtractor; import com.navercorp.pinpoint.web.mapper.stat.sampling.sampler.JoinMemorySampler; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationResponseTimeDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationResponseTimeDao.java index 35c42201d721..6bfeaf62220e 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationResponseTimeDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationResponseTimeDao.java @@ -18,7 +18,6 @@ import com.navercorp.pinpoint.common.server.bo.codec.stat.join.ResponseTimeDecoder; import com.navercorp.pinpoint.common.server.bo.stat.join.StatType; import com.navercorp.pinpoint.web.dao.ApplicationResponseTimeDao; -import com.navercorp.pinpoint.web.dao.hbase.HbaseApplicationStatDaoOperations; import com.navercorp.pinpoint.web.mapper.stat.ApplicationStatMapper; import com.navercorp.pinpoint.web.mapper.stat.SampledApplicationStatResultExtractor; import com.navercorp.pinpoint.web.mapper.stat.sampling.sampler.JoinResponseTimeSampler; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationStatDaoOperations.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationStatDaoOperations.java index 702d738bb38d..262ec1117d45 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationStatDaoOperations.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationStatDaoOperations.java @@ -18,6 +18,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.codec.stat.ApplicationStatDecoder; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatUtils; import com.navercorp.pinpoint.common.server.bo.serializer.stat.ApplicationStatHbaseOperationFactory; @@ -28,6 +29,7 @@ import com.navercorp.pinpoint.web.mapper.stat.SampledApplicationStatResultExtractor; import com.navercorp.pinpoint.web.vo.Range; import com.navercorp.pinpoint.web.vo.stat.AggregationStatData; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Scan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,6 +52,9 @@ public class HbaseApplicationStatDaoOperations { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private ApplicationStatHbaseOperationFactory operationFactory; @@ -64,7 +69,9 @@ List getSampledStatList(StatType statType, SampledApplicati throw new NullPointerException("resultExtractor must not be null"); } Scan scan = this.createScan(statType, applicationId, range); - return hbaseOperations2.findParallel(HBaseTables.APPLICATION_STAT_AGGRE, scan, this.operationFactory.getRowKeyDistributor(), resultExtractor, APPLICATION_STAT_NUM_PARTITIONS); + + TableName applicationStatAggreTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_STAT_AGGRE_STR); + return hbaseOperations2.findParallel(applicationStatAggreTableName, scan, this.operationFactory.getRowKeyDistributor(), resultExtractor, APPLICATION_STAT_NUM_PARTITIONS); } ApplicationStatMapper createRowMapper(ApplicationStatDecoder decoder, Range range) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationTraceIndexDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationTraceIndexDao.java index 7b7f4d09aa86..2bdc90f85a5d 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationTraceIndexDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseApplicationTraceIndexDao.java @@ -23,6 +23,7 @@ import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.hbase.LimitEventHandler; import com.navercorp.pinpoint.common.hbase.RowMapper; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.util.BytesUtils; import com.navercorp.pinpoint.common.util.DateUtils; import com.navercorp.pinpoint.common.server.util.SpanUtils; @@ -42,6 +43,7 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellUtil; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.filter.BinaryPrefixComparator; @@ -74,6 +76,9 @@ public class HbaseApplicationTraceIndexDao implements ApplicationTraceIndexDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("transactionIdMapper") private RowMapper> traceIndexMapper; @@ -108,7 +113,9 @@ public LimitedScanResult> scanTraceIndex(final String applic final LimitedScanResult> limitedScanResult = new LimitedScanResult<>(); LastRowAccessor lastRowAccessor = new LastRowAccessor(); - List> traceIndexList = hbaseOperations2.findParallel(HBaseTables.APPLICATION_TRACE_INDEX, + + TableName applicationTraceIndexTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_TRACE_INDEX_STR); + List> traceIndexList = hbaseOperations2.findParallel(applicationTraceIndexTableName, scan, traceIdRowKeyDistributor, limit, traceIndexMapper, lastRowAccessor, APPLICATION_TRACE_INDEX_NUM_PARTITIONS); List transactionIdSum = new ArrayList<>(128); @@ -149,7 +156,9 @@ public LimitedScanResult> scanTraceIndex(final String applic final LimitedScanResult> limitedScanResult = new LimitedScanResult<>(); LastRowAccessor lastRowAccessor = new LastRowAccessor(); - List> traceIndexList = hbaseOperations2.findParallel(HBaseTables.APPLICATION_TRACE_INDEX, + + TableName applicationTraceIndexTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_TRACE_INDEX_STR); + List> traceIndexList = hbaseOperations2.findParallel(applicationTraceIndexTableName, scan, traceIdRowKeyDistributor, limit, traceIndexMapper, lastRowAccessor, APPLICATION_TRACE_INDEX_NUM_PARTITIONS); List transactionIdSum = new ArrayList<>(128); @@ -223,8 +232,8 @@ private Scan createScan(String applicationName, Range range, boolean scanBackwar scan.setCaching(this.scanCacheSize); byte[] bApplicationName = Bytes.toBytes(applicationName); - byte[] traceIndexStartKey = SpanUtils.getTraceIndexRowKey(bApplicationName, range.getFrom()); - byte[] traceIndexEndKey = SpanUtils.getTraceIndexRowKey(bApplicationName, range.getTo()); + byte[] traceIndexStartKey = SpanUtils.getApplicationTraceIndexRowKey(bApplicationName, range.getFrom()); + byte[] traceIndexEndKey = SpanUtils.getApplicationTraceIndexRowKey(bApplicationName, range.getTo()); if (scanBackward) { // start key is replaced by end key because key has been reversed @@ -269,7 +278,8 @@ public List scanTraceScatter(String applicationName, SelectedScatterArea ar ResponseTimeRange responseTimeRange = area.getResponseTimeRange(); TraceIndexScatterMapper2 mapper = new TraceIndexScatterMapper2(responseTimeRange.getFrom(), responseTimeRange.getTo()); - List> dotListList = hbaseOperations2.findParallel(HBaseTables.APPLICATION_TRACE_INDEX, scan, traceIdRowKeyDistributor, limit, mapper, APPLICATION_TRACE_INDEX_NUM_PARTITIONS); + TableName applicationTraceIndexTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_TRACE_INDEX_STR); + List> dotListList = hbaseOperations2.findParallel(applicationTraceIndexTableName, scan, traceIdRowKeyDistributor, limit, mapper, APPLICATION_TRACE_INDEX_NUM_PARTITIONS); List result = new ArrayList<>(); for(List dotList : dotListList) { @@ -294,7 +304,9 @@ public ScatterData scanTraceScatterData(String applicationName, Range range, int Scan scan = createScan(applicationName, range, scanBackward); TraceIndexScatterMapper3 mapper = new TraceIndexScatterMapper3(range.getFrom(), range.getTo(), xGroupUnit, yGroupUnit); - List dotGroupList = hbaseOperations2.findParallel(HBaseTables.APPLICATION_TRACE_INDEX, scan, traceIdRowKeyDistributor, limit, mapper, APPLICATION_TRACE_INDEX_NUM_PARTITIONS); + + TableName applicationTraceIndexTableName = tableNameProvider.getTableName(HBaseTables.APPLICATION_TRACE_INDEX_STR); + List dotGroupList = hbaseOperations2.findParallel(applicationTraceIndexTableName, scan, traceIdRowKeyDistributor, limit, mapper, APPLICATION_TRACE_INDEX_NUM_PARTITIONS); if (CollectionUtils.isEmpty(dotGroupList)) { return new ScatterData(range.getFrom(), range.getTo(), xGroupUnit, yGroupUnit); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseHostApplicationMapDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseHostApplicationMapDao.java index 0cbce95ec47e..4e633ed264dd 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseHostApplicationMapDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseHostApplicationMapDao.java @@ -26,6 +26,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.hbase.RowMapper; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.util.TimeSlot; import com.navercorp.pinpoint.common.util.TimeUtils; import com.navercorp.pinpoint.web.dao.HostApplicationMapDao; @@ -35,6 +36,7 @@ import com.sematext.hbase.wd.AbstractRowKeyDistributor; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Scan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,6 +61,9 @@ public class HbaseHostApplicationMapDao implements HostApplicationMapDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("hostApplicationMapperVer2") private RowMapper> hostApplicationMapperVer2; @@ -77,7 +82,9 @@ public Set findAcceptApplicationName(Application fromApplicat throw new NullPointerException("fromApplication must not be null"); } final Scan scan = createScan(fromApplication, range); - final List> result = hbaseOperations2.findParallel(HBaseTables.HOST_APPLICATION_MAP_VER2, scan, acceptApplicationRowKeyDistributor, hostApplicationMapperVer2, HOST_APPLICATION_MAP_VER2_NUM_PARTITIONS); + + TableName hostApplicationMapTableName = tableNameProvider.getTableName(HBaseTables.HOST_APPLICATION_MAP_VER2_STR); + final List> result = hbaseOperations2.findParallel(hostApplicationMapTableName, scan, acceptApplicationRowKeyDistributor, hostApplicationMapperVer2, HOST_APPLICATION_MAP_VER2_NUM_PARTITIONS); if (CollectionUtils.isNotEmpty(result)) { final Set resultSet = new HashSet<>(); for (List resultList : result) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapResponseTimeDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapResponseTimeDao.java index 57e682cb4a93..95c95cc7f3a1 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapResponseTimeDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapResponseTimeDao.java @@ -19,6 +19,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.hbase.RowMapper; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.util.ApplicationMapStatisticsUtils; import com.navercorp.pinpoint.web.dao.MapResponseDao; import com.navercorp.pinpoint.web.vo.Application; @@ -27,6 +28,7 @@ import com.navercorp.pinpoint.web.vo.ResponseTime; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Scan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,6 +59,9 @@ public class HbaseMapResponseTimeDao implements MapResponseDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private RangeFactory rangeFactory; @@ -76,7 +81,8 @@ public List selectResponseTime(Application application, Range rang Scan scan = createScan(application, range, HBaseTables.MAP_STATISTICS_SELF_VER2_CF_COUNTER); - List responseTimeList = hbaseOperations2.findParallel(HBaseTables.MAP_STATISTICS_SELF_VER2, scan, rowKeyDistributorByHashPrefix, responseTimeMapper, MAP_STATISTICS_SELF_VER2_NUM_PARTITIONS); + TableName mapStatisticsSelfTableName = tableNameProvider.getTableName(HBaseTables.MAP_STATISTICS_SELF_VER2_STR); + List responseTimeList = hbaseOperations2.findParallel(mapStatisticsSelfTableName, scan, rowKeyDistributorByHashPrefix, responseTimeMapper, MAP_STATISTICS_SELF_VER2_NUM_PARTITIONS); if (logger.isDebugEnabled()) { logger.debug("Self data {}", responseTimeList); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapStatisticsCalleeDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapStatisticsCalleeDao.java index 53db8debfdeb..78f8aa6b056e 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapStatisticsCalleeDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapStatisticsCalleeDao.java @@ -20,6 +20,7 @@ import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.hbase.ResultsExtractor; import com.navercorp.pinpoint.common.hbase.RowMapper; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.util.ApplicationMapStatisticsUtils; import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataMap; import com.navercorp.pinpoint.web.dao.MapStatisticsCalleeDao; @@ -31,6 +32,7 @@ import com.navercorp.pinpoint.web.vo.RangeFactory; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Scan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,6 +40,8 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Repository; +import java.util.Objects; + /** * @author netspider * @author emeroad @@ -46,24 +50,33 @@ public class HbaseMapStatisticsCalleeDao implements MapStatisticsCalleeDao { private static final int MAP_STATISTICS_CALLER_VER2_NUM_PARTITIONS = 32; + private static final int SCAN_CACHE_SIZE = 40; private Logger logger = LoggerFactory.getLogger(this.getClass()); - private int scanCacheSize = 40; - @Autowired - private HbaseOperations2 hbaseOperations2; + private final HbaseOperations2 hbaseTemplate; - @Autowired - @Qualifier("mapStatisticsCalleeMapper") - private RowMapper mapStatisticsCalleeMapper; + private final TableNameProvider tableNameProvider; - @Autowired - private RangeFactory rangeFactory; + private final RowMapper mapStatisticsCalleeMapper; - @Autowired - @Qualifier("statisticsCalleeRowKeyDistributor") - private RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix; + private final RangeFactory rangeFactory; + private final RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix; + + @Autowired + public HbaseMapStatisticsCalleeDao( + HbaseOperations2 hbaseTemplate, + TableNameProvider tableNameProvider, + @Qualifier("mapStatisticsCalleeMapper") RowMapper mapStatisticsCalleeMapper, + RangeFactory rangeFactory, + @Qualifier("statisticsCalleeRowKeyDistributor") RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix) { + this.hbaseTemplate = Objects.requireNonNull(hbaseTemplate, "hbaseTemplate must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); + this.mapStatisticsCalleeMapper = Objects.requireNonNull(mapStatisticsCalleeMapper, "mapStatisticsCalleeMapper must not be null"); + this.rangeFactory = Objects.requireNonNull(rangeFactory, "rangeFactory must not be null"); + this.rowKeyDistributorByHashPrefix = Objects.requireNonNull(rowKeyDistributorByHashPrefix, "rowKeyDistributorByHashPrefix must not be null"); + } @Override public LinkDataMap selectCallee(Application calleeApplication, Range range) { @@ -78,7 +91,9 @@ public LinkDataMap selectCallee(Application calleeApplication, Range range) { // find distributed key - ver2. final Scan scan = createScan(calleeApplication, range, HBaseTables.MAP_STATISTICS_CALLER_VER2_CF_COUNTER); ResultsExtractor resultExtractor = new RowMapReduceResultExtractor<>(mapStatisticsCalleeMapper, new MapStatisticsTimeWindowReducer(timeWindow)); - LinkDataMap linkDataMap = hbaseOperations2.findParallel(HBaseTables.MAP_STATISTICS_CALLER_VER2, scan, rowKeyDistributorByHashPrefix, resultExtractor, MAP_STATISTICS_CALLER_VER2_NUM_PARTITIONS); + + TableName mapStatisticsCallerTableName = tableNameProvider.getTableName(HBaseTables.MAP_STATISTICS_CALLER_VER2_STR); + LinkDataMap linkDataMap = hbaseTemplate.findParallel(mapStatisticsCallerTableName, scan, rowKeyDistributorByHashPrefix, resultExtractor, MAP_STATISTICS_CALLER_VER2_NUM_PARTITIONS); logger.debug("Callee data. {}, {}", linkDataMap, range); if (linkDataMap != null && linkDataMap.size() > 0) { return linkDataMap; @@ -100,7 +115,7 @@ private Scan createScan(Application application, Range range, byte[] family) { byte[] endKey = ApplicationMapStatisticsUtils.makeRowKey(application.getName(), application.getServiceTypeCode(), range.getFrom()); Scan scan = new Scan(); - scan.setCaching(this.scanCacheSize); + scan.setCaching(SCAN_CACHE_SIZE); scan.setStartRow(startKey); scan.setStopRow(endKey); scan.addFamily(family); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapStatisticsCallerDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapStatisticsCallerDao.java index 3373d212e188..2b9ea29e749d 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapStatisticsCallerDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseMapStatisticsCallerDao.java @@ -20,6 +20,7 @@ import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.hbase.ResultsExtractor; import com.navercorp.pinpoint.common.hbase.RowMapper; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.util.ApplicationMapStatisticsUtils; import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataMap; import com.navercorp.pinpoint.web.dao.MapStatisticsCallerDao; @@ -31,6 +32,7 @@ import com.navercorp.pinpoint.web.vo.RangeFactory; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Scan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,32 +40,44 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Repository; +import java.util.Objects; + /** * @author netspider * @author emeroad + * @author HyunGil Jeong */ @Repository public class HbaseMapStatisticsCallerDao implements MapStatisticsCallerDao { private static final int MAP_STATISTICS_CALLEE_VER2_NUM_PARTITIONS = 32; + private static final int SCAN_CACHE_SIZE = 40; private final Logger logger = LoggerFactory.getLogger(this.getClass()); - private int scanCacheSize = 40; - @Autowired - private HbaseOperations2 hbaseOperations2; + private final HbaseOperations2 hbaseTemplate; - @Autowired - @Qualifier("mapStatisticsCallerMapper") - private RowMapper mapStatisticsCallerMapper; + private final TableNameProvider tableNameProvider; - @Autowired - private RangeFactory rangeFactory; + private final RowMapper mapStatisticsCallerMapper; - @Autowired - @Qualifier("statisticsCallerRowKeyDistributor") - private RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix; + private final RangeFactory rangeFactory; + private final RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix; + + @Autowired + public HbaseMapStatisticsCallerDao( + HbaseOperations2 hbaseTemplate, + TableNameProvider tableNameProvider, + @Qualifier("mapStatisticsCallerMapper") RowMapper mapStatisticsCallerMapper, + RangeFactory rangeFactory, + @Qualifier("statisticsCallerRowKeyDistributor") RowKeyDistributorByHashPrefix rowKeyDistributorByHashPrefix) { + this.hbaseTemplate = Objects.requireNonNull(hbaseTemplate, "hbaseTemplate must not be null"); + this.tableNameProvider = Objects.requireNonNull(tableNameProvider, "tableNameProvider must not be null"); + this.mapStatisticsCallerMapper = Objects.requireNonNull(mapStatisticsCallerMapper, "mapStatisticsCallerMapper must not be null"); + this.rangeFactory = Objects.requireNonNull(rangeFactory, "rangeFactory must not be null"); + this.rowKeyDistributorByHashPrefix = Objects.requireNonNull(rowKeyDistributorByHashPrefix, "rowKeyDistributorByHashPrefix must not be null"); + } @Override public LinkDataMap selectCaller(Application callerApplication, Range range) { @@ -78,7 +92,9 @@ public LinkDataMap selectCaller(Application callerApplication, Range range) { // find distributed key. final Scan scan = createScan(callerApplication, range, HBaseTables.MAP_STATISTICS_CALLEE_VER2_CF_COUNTER); ResultsExtractor resultExtractor = new RowMapReduceResultExtractor<>(mapStatisticsCallerMapper, new MapStatisticsTimeWindowReducer(timeWindow)); - LinkDataMap linkDataMap = hbaseOperations2.findParallel(HBaseTables.MAP_STATISTICS_CALLEE_VER2, scan, rowKeyDistributorByHashPrefix, resultExtractor, MAP_STATISTICS_CALLEE_VER2_NUM_PARTITIONS); + + TableName mapStatisticsCalleeTableName = tableNameProvider.getTableName(HBaseTables.MAP_STATISTICS_CALLEE_VER2_STR); + LinkDataMap linkDataMap = this.hbaseTemplate.findParallel(mapStatisticsCalleeTableName, scan, rowKeyDistributorByHashPrefix, resultExtractor, MAP_STATISTICS_CALLEE_VER2_NUM_PARTITIONS); logger.debug("Caller data. {}, {}", linkDataMap, range); if (linkDataMap != null && linkDataMap.size() > 0) { return linkDataMap; @@ -100,7 +116,7 @@ private Scan createScan(Application application, Range range, byte[]... familyAr byte[] endKey = ApplicationMapStatisticsUtils.makeRowKey(application.getName(), application.getServiceTypeCode(), range.getFrom()); Scan scan = new Scan(); - scan.setCaching(this.scanCacheSize); + scan.setCaching(SCAN_CACHE_SIZE); scan.setStartRow(startKey); scan.setStopRow(endKey); for(byte[] family : familyArgs) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseSqlMetaDataDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseSqlMetaDataDao.java index d5ff76933943..dc63a88ea27a 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseSqlMetaDataDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseSqlMetaDataDao.java @@ -18,8 +18,10 @@ import java.util.List; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Get; import org.springframework.beans.factory.annotation.Autowired; @@ -39,6 +41,9 @@ public class HbaseSqlMetaDataDao implements SqlMetaDataDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + // @Autowired // @Qualifier("sqlMetaDataMapper") private RowMapper> sqlMetaDataMapper; @@ -59,7 +64,8 @@ public List getSqlMetaData(String agentId, long time, int sqlId) Get get = new Get(rowKey); get.addFamily(HBaseTables.SQL_METADATA_VER2_CF_SQL); - return hbaseOperations2.get(HBaseTables.SQL_METADATA_VER2, get, sqlMetaDataMapper); + TableName sqlMetaDataTableName = tableNameProvider.getTableName(HBaseTables.SQL_METADATA_VER2_STR); + return hbaseOperations2.get(sqlMetaDataTableName, get, sqlMetaDataMapper); } private byte[] getDistributedKey(byte[] rowKey) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseStringMetaDataDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseStringMetaDataDao.java index a394339cb16c..88f7b5c86005 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseStringMetaDataDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseStringMetaDataDao.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.web.dao.hbase; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.StringMetaDataBo; import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; @@ -23,6 +24,7 @@ import com.navercorp.pinpoint.web.dao.StringMetaDataDao; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Get; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -39,6 +41,9 @@ public class HbaseStringMetaDataDao implements StringMetaDataDao { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("stringMetaDataMapper") private RowMapper> stringMetaDataMapper; @@ -59,7 +64,8 @@ public List getStringMetaData(String agentId, long time, int s Get get = new Get(rowKey); get.addFamily(HBaseTables.STRING_METADATA_CF_STR); - return hbaseOperations2.get(HBaseTables.STRING_METADATA, get, stringMetaDataMapper); + TableName stringMetaDataTableName = tableNameProvider.getTableName(HBaseTables.STRING_METADATA_STR); + return hbaseOperations2.get(stringMetaDataTableName, get, stringMetaDataMapper); } private byte[] getDistributedKey(byte[] rowKey) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseTraceDaoV2.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseTraceDaoV2.java index 9e53f0af5a08..67cabb7fd38a 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseTraceDaoV2.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/HbaseTraceDaoV2.java @@ -4,6 +4,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.hbase.RowMapper; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.SpanBo; import com.navercorp.pinpoint.common.server.bo.serializer.RowKeyEncoder; import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.SpanEncoder; @@ -11,6 +12,7 @@ import com.navercorp.pinpoint.web.dao.TraceDao; import com.navercorp.pinpoint.web.mapper.CellTraceMapper; import org.apache.commons.collections.CollectionUtils; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.filter.BinaryPrefixComparator; import org.apache.hadoop.hbase.filter.CompareFilter; @@ -38,6 +40,9 @@ public class HbaseTraceDaoV2 implements TraceDao { @Autowired private HbaseOperations2 template2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired @Qualifier("traceRowKeyEncoderV2") private RowKeyEncoder rowKeyEncoder; @@ -72,7 +77,8 @@ public List selectSpan(TransactionId transactionId) { } byte[] transactionIdRowKey = rowKeyEncoder.encodeRowKey(transactionId); - return template2.get(HBaseTables.TRACE_V2, transactionIdRowKey, HBaseTables.TRACE_V2_CF_SPAN, spanMapperV2); + TableName traceTableName = tableNameProvider.getTableName(HBaseTables.TRACE_V2_STR); + return template2.get(traceTableName, transactionIdRowKey, HBaseTables.TRACE_V2_CF_SPAN, spanMapperV2); } @@ -137,7 +143,9 @@ private List> select0(List transactionIdList, byte[] final Get get = createGet(transactionId, columnFamily, filter); multiGet.add(get); } - return template2.get(HBaseTables.TRACE_V2, multiGet, spanMapperV2); + + TableName traceTableName = tableNameProvider.getTableName(HBaseTables.TRACE_V2_STR); + return template2.get(traceTableName, multiGet, spanMapperV2); } private Get createGet(TransactionId transactionId, byte[] columnFamily, Filter filter) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/AgentStatDaoFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/AgentStatDaoFactory.java index a3e8b11347c7..9762fbc8a1d8 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/AgentStatDaoFactory.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/AgentStatDaoFactory.java @@ -16,11 +16,14 @@ package com.navercorp.pinpoint.web.dao.hbase.stat; + import com.navercorp.pinpoint.common.server.bo.stat.ActiveTraceBo; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatDataPoint; import com.navercorp.pinpoint.common.server.bo.stat.CpuLoadBo; import com.navercorp.pinpoint.common.server.bo.stat.DataSourceListBo; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcBo; import com.navercorp.pinpoint.common.server.bo.stat.JvmGcDetailedBo; import com.navercorp.pinpoint.common.server.bo.stat.ResponseTimeBo; @@ -30,6 +33,8 @@ import com.navercorp.pinpoint.web.dao.stat.CpuLoadDao; import com.navercorp.pinpoint.web.dao.stat.DataSourceDao; import com.navercorp.pinpoint.web.dao.stat.DeadlockDao; +import com.navercorp.pinpoint.web.dao.stat.DirectBufferDao; +import com.navercorp.pinpoint.web.dao.stat.FileDescriptorDao; import com.navercorp.pinpoint.web.dao.stat.JvmGcDao; import com.navercorp.pinpoint.web.dao.stat.JvmGcDetailedDao; import com.navercorp.pinpoint.web.dao.stat.ResponseTimeDao; @@ -219,7 +224,7 @@ public boolean isSingleton() { } @Repository("deadlockDaoFactory") - public static class DeadlockDaoFactory extends AgentStatDaoFactory implements FactoryBean { + public static class DeadlockDaoFactory extends AgentStatDaoFactory implements FactoryBean { @Autowired public void setV2(@Qualifier("deadlockDaoV2") DeadlockDao v2) { @@ -242,4 +247,51 @@ public boolean isSingleton() { } } + @Repository("fileDescriptorDaoFactory") + public static class FileDescriptorDaoFactory extends AgentStatDaoFactory implements FactoryBean { + + @Autowired + public void setV2(@Qualifier("fileDescriptorDaoV2") FileDescriptorDao v2) { + this.v2 = v2; + } + + @Override + public FileDescriptorDao getObject() throws Exception { + return super.getDao(); + } + + @Override + public Class getObjectType() { + return FileDescriptorDao.class; + } + + @Override + public boolean isSingleton() { + return true; + } + } + + @Repository("directBufferDaoFactory") + public static class DirectBufferDaoFactory extends AgentStatDaoFactory implements FactoryBean { + + @Autowired + public void setV2(@Qualifier("directBufferDaoV2") DirectBufferDao v2) { + this.v2 = v2; + } + + @Override + public DirectBufferDao getObject() throws Exception { + return super.getDao(); + } + + @Override + public Class getObjectType() { + return DirectBufferDao.class; + } + + @Override + public boolean isSingleton() { + return true; + } + } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/SampledAgentStatDaoFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/SampledAgentStatDaoFactory.java index d402b28ca8ee..98a782670116 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/SampledAgentStatDaoFactory.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/SampledAgentStatDaoFactory.java @@ -17,10 +17,13 @@ package com.navercorp.pinpoint.web.dao.hbase.stat; import com.navercorp.pinpoint.web.dao.SampledAgentStatDao; + import com.navercorp.pinpoint.web.dao.stat.SampledActiveTraceDao; import com.navercorp.pinpoint.web.dao.stat.SampledCpuLoadDao; import com.navercorp.pinpoint.web.dao.stat.SampledDataSourceDao; import com.navercorp.pinpoint.web.dao.stat.SampledDeadlockDao; +import com.navercorp.pinpoint.web.dao.stat.SampledDirectBufferDao; +import com.navercorp.pinpoint.web.dao.stat.SampledFileDescriptorDao; import com.navercorp.pinpoint.web.dao.stat.SampledJvmGcDao; import com.navercorp.pinpoint.web.dao.stat.SampledJvmGcDetailedDao; import com.navercorp.pinpoint.web.dao.stat.SampledResponseTimeDao; @@ -30,6 +33,8 @@ import com.navercorp.pinpoint.web.vo.stat.SampledCpuLoad; import com.navercorp.pinpoint.web.vo.stat.SampledDataSourceList; import com.navercorp.pinpoint.web.vo.stat.SampledDeadlock; +import com.navercorp.pinpoint.web.vo.stat.SampledDirectBuffer; +import com.navercorp.pinpoint.web.vo.stat.SampledFileDescriptor; import com.navercorp.pinpoint.web.vo.stat.SampledJvmGc; import com.navercorp.pinpoint.web.vo.stat.SampledJvmGcDetailed; import com.navercorp.pinpoint.web.vo.stat.SampledResponseTime; @@ -242,4 +247,51 @@ public boolean isSingleton() { } } + @Repository("sampledFileDescriptorDaoFactory") + public static class SampledFileDescriptorDaoFactory extends SampledAgentStatDaoFactory implements FactoryBean { + + @Autowired + public void setV2(@Qualifier("sampledFileDescriptorDaoV2") SampledFileDescriptorDao v2) { + this.v2 = v2; + } + + @Override + public SampledFileDescriptorDao getObject() throws Exception { + return super.getDao(); + } + + @Override + public Class getObjectType() { + return SampledFileDescriptorDao.class; + } + + @Override + public boolean isSingleton() { + return true; + } + } + + @Repository("sampledDirectBufferDaoFactory") + public static class SampledDirectBufferDaoFactory extends SampledAgentStatDaoFactory implements FactoryBean { + + @Autowired + public void setV2(@Qualifier("sampledDirectBufferDaoV2") SampledDirectBufferDao v2) { + this.v2 = v2; + } + + @Override + public SampledDirectBufferDao getObject() throws Exception { + return super.getDao(); + } + + @Override + public Class getObjectType() { + return SampledDirectBufferDao.class; + } + + @Override + public boolean isSingleton() { + return true; + } + } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseAgentStatDaoOperationsV2.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseAgentStatDaoOperationsV2.java index 146be05d1a06..9f135a70835f 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseAgentStatDaoOperationsV2.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseAgentStatDaoOperationsV2.java @@ -19,6 +19,7 @@ import com.navercorp.pinpoint.common.hbase.HBaseTables; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.hbase.ResultsExtractor; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.codec.stat.AgentStatDecoder; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatHbaseOperationFactory; import com.navercorp.pinpoint.common.server.bo.serializer.stat.AgentStatUtils; @@ -29,6 +30,7 @@ import com.navercorp.pinpoint.web.mapper.stat.AgentStatMapperV2; import com.navercorp.pinpoint.web.vo.Range; import com.navercorp.pinpoint.web.vo.stat.SampledAgentStatDataPoint; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Scan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,6 +54,9 @@ public class HbaseAgentStatDaoOperationsV2 { @Autowired private HbaseOperations2 hbaseOperations2; + @Autowired + private TableNameProvider tableNameProvider; + @Autowired private AgentStatHbaseOperationFactory operationFactory; @@ -65,7 +70,8 @@ List getAgentStatList(AgentStatType agentStatT Scan scan = this.createScan(agentStatType, agentId, range); - List> intermediate = hbaseOperations2.findParallel(HBaseTables.AGENT_STAT_VER2, scan, this.operationFactory.getRowKeyDistributor(), mapper, AGENT_STAT_VER2_NUM_PARTITIONS); + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List> intermediate = hbaseOperations2.findParallel(agentStatTableName, scan, this.operationFactory.getRowKeyDistributor(), mapper, AGENT_STAT_VER2_NUM_PARTITIONS); int expectedSize = (int) (range.getRange() / HBaseTables.AGENT_STAT_TIMESPAN_MS); List merged = new ArrayList<>(expectedSize); for (List each : intermediate) { @@ -89,7 +95,8 @@ boolean agentStatExists(AgentStatType agentStatTy int resultLimit = 20; Scan scan = this.createScan(agentStatType, agentId, range, resultLimit); - List> result = hbaseOperations2.findParallel(HBaseTables.AGENT_STAT_VER2, scan, this.operationFactory.getRowKeyDistributor(), resultLimit, mapper, AGENT_STAT_VER2_NUM_PARTITIONS); + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + List> result = hbaseOperations2.findParallel(agentStatTableName, scan, this.operationFactory.getRowKeyDistributor(), resultLimit, mapper, AGENT_STAT_VER2_NUM_PARTITIONS); if (result.isEmpty()) { return false; } else { @@ -108,7 +115,9 @@ List getSampledAgentStatList(AgentStatT throw new NullPointerException("resultExtractor must not be null"); } Scan scan = this.createScan(agentStatType, agentId, range); - return hbaseOperations2.findParallel(HBaseTables.AGENT_STAT_VER2, scan, this.operationFactory.getRowKeyDistributor(), resultExtractor, AGENT_STAT_VER2_NUM_PARTITIONS); + + TableName agentStatTableName = tableNameProvider.getTableName(HBaseTables.AGENT_STAT_VER2_STR); + return hbaseOperations2.findParallel(agentStatTableName, scan, this.operationFactory.getRowKeyDistributor(), resultExtractor, AGENT_STAT_VER2_NUM_PARTITIONS); } AgentStatMapperV2 createRowMapper(AgentStatDecoder decoder, Range range) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseDeadlockDaoV2.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseDeadlockDaoV2.java index fedbff66c9b1..8483f608a985 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseDeadlockDaoV2.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseDeadlockDaoV2.java @@ -18,7 +18,7 @@ import com.navercorp.pinpoint.common.server.bo.codec.stat.DeadlockDecoder; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import com.navercorp.pinpoint.web.dao.stat.DeadlockDao; import com.navercorp.pinpoint.web.mapper.stat.AgentStatMapperV2; import com.navercorp.pinpoint.web.vo.Range; @@ -40,14 +40,14 @@ public class HbaseDeadlockDaoV2 implements DeadlockDao { private HbaseAgentStatDaoOperationsV2 operations; @Override - public List getAgentStatList(String agentId, Range range) { - AgentStatMapperV2 mapper = operations.createRowMapper(deadlockDecoder, range); + public List getAgentStatList(String agentId, Range range) { + AgentStatMapperV2 mapper = operations.createRowMapper(deadlockDecoder, range); return operations.getAgentStatList(AgentStatType.DEADLOCK, mapper, agentId, range); } @Override public boolean agentStatExists(String agentId, Range range) { - AgentStatMapperV2 mapper = operations.createRowMapper(deadlockDecoder, range); + AgentStatMapperV2 mapper = operations.createRowMapper(deadlockDecoder, range); return operations.agentStatExists(AgentStatType.DEADLOCK, mapper, agentId, range); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseDirectBufferDaoV2.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseDirectBufferDaoV2.java new file mode 100644 index 000000000000..d723450bd877 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseDirectBufferDaoV2.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.dao.hbase.stat.v2; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.DirectBufferDecoder; +import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.web.dao.stat.DirectBufferDao; +import com.navercorp.pinpoint.web.mapper.stat.AgentStatMapperV2; +import com.navercorp.pinpoint.web.vo.Range; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Repository("directBufferDaoV2") +public class HbaseDirectBufferDaoV2 implements DirectBufferDao { + + @Autowired + private DirectBufferDecoder directBufferDecoder; + + @Autowired + private HbaseAgentStatDaoOperationsV2 operations; + + @Override + public List getAgentStatList(String agentId, Range range) { + AgentStatMapperV2 mapper = operations.createRowMapper(directBufferDecoder, range); + return operations.getAgentStatList(AgentStatType.DIRECT_BUFFER, mapper, agentId, range); + } + + @Override + public boolean agentStatExists(String agentId, Range range) { + AgentStatMapperV2 mapper = operations.createRowMapper(directBufferDecoder, range); + return operations.agentStatExists(AgentStatType.DIRECT_BUFFER, mapper, agentId, range); + } + +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseFileDescriptorDaoV2.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseFileDescriptorDaoV2.java new file mode 100644 index 000000000000..ec77078a7fd5 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseFileDescriptorDaoV2.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.dao.hbase.stat.v2; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.FileDescriptorDecoder; +import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import com.navercorp.pinpoint.web.dao.stat.FileDescriptorDao; +import com.navercorp.pinpoint.web.mapper.stat.AgentStatMapperV2; +import com.navercorp.pinpoint.web.vo.Range; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Repository("fileDescriptorDaoV2") +public class HbaseFileDescriptorDaoV2 implements FileDescriptorDao { + + @Autowired + private FileDescriptorDecoder fileDescriptorDecoder; + + @Autowired + private HbaseAgentStatDaoOperationsV2 operations; + + @Override + public List getAgentStatList(String agentId, Range range) { + AgentStatMapperV2 mapper = operations.createRowMapper(fileDescriptorDecoder, range); + return operations.getAgentStatList(AgentStatType.FILE_DESCRIPTOR, mapper, agentId, range); + } + + @Override + public boolean agentStatExists(String agentId, Range range) { + AgentStatMapperV2 mapper = operations.createRowMapper(fileDescriptorDecoder, range); + return operations.agentStatExists(AgentStatType.FILE_DESCRIPTOR, mapper, agentId, range); + } + +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledDeadlockDaoV2.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledDeadlockDaoV2.java index aa86a095cbc2..f0ef2dfd8fd4 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledDeadlockDaoV2.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledDeadlockDaoV2.java @@ -18,7 +18,7 @@ import com.navercorp.pinpoint.common.server.bo.codec.stat.DeadlockDecoder; import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import com.navercorp.pinpoint.web.dao.stat.SampledDeadlockDao; import com.navercorp.pinpoint.web.mapper.stat.AgentStatMapperV2; import com.navercorp.pinpoint.web.mapper.stat.SampledAgentStatResultExtractor; @@ -51,9 +51,9 @@ public List getSampledAgentStatList(String agentId, TimeWindow long scanFrom = timeWindow.getWindowRange().getFrom(); long scanTo = timeWindow.getWindowRange().getTo() + timeWindow.getWindowSlotSize(); Range range = new Range(scanFrom, scanTo); - AgentStatMapperV2 mapper = operations.createRowMapper(deadlockDecoder, range); + AgentStatMapperV2 mapper = operations.createRowMapper(deadlockDecoder, range); - SampledAgentStatResultExtractor resultExtractor = new SampledAgentStatResultExtractor<>(timeWindow, mapper, deadlockSampler); + SampledAgentStatResultExtractor resultExtractor = new SampledAgentStatResultExtractor<>(timeWindow, mapper, deadlockSampler); return operations.getSampledAgentStatList(AgentStatType.DEADLOCK, resultExtractor, agentId, range); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledDirectBufferDaoV2.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledDirectBufferDaoV2.java new file mode 100644 index 000000000000..c6050419b231 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledDirectBufferDaoV2.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.dao.hbase.stat.v2; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.DirectBufferDecoder; +import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.web.dao.stat.SampledDirectBufferDao; +import com.navercorp.pinpoint.web.mapper.stat.AgentStatMapperV2; +import com.navercorp.pinpoint.web.mapper.stat.SampledAgentStatResultExtractor; +import com.navercorp.pinpoint.web.mapper.stat.sampling.sampler.DirectBufferSampler; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.Range; +import com.navercorp.pinpoint.web.vo.stat.SampledDirectBuffer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Repository("sampledDirectBufferDaoV2") +public class HbaseSampledDirectBufferDaoV2 implements SampledDirectBufferDao { + + @Autowired + private DirectBufferDecoder directBufferDecoder; + + @Autowired + private DirectBufferSampler directBufferSampler; + + @Autowired + private HbaseAgentStatDaoOperationsV2 operations; + + @Override + public List getSampledAgentStatList(String agentId, TimeWindow timeWindow) { + long scanFrom = timeWindow.getWindowRange().getFrom(); + long scanTo = timeWindow.getWindowRange().getTo() + timeWindow.getWindowSlotSize(); + Range range = new Range(scanFrom, scanTo); + AgentStatMapperV2 mapper = operations.createRowMapper(directBufferDecoder, range); + SampledAgentStatResultExtractor resultExtractor = new SampledAgentStatResultExtractor<>(timeWindow, mapper, directBufferSampler); + return operations.getSampledAgentStatList(AgentStatType.DIRECT_BUFFER, resultExtractor, agentId, range); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledFileDescriptorDaoV2.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledFileDescriptorDaoV2.java new file mode 100644 index 000000000000..5ee501788625 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/hbase/stat/v2/HbaseSampledFileDescriptorDaoV2.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.dao.hbase.stat.v2; + +import com.navercorp.pinpoint.common.server.bo.codec.stat.FileDescriptorDecoder; +import com.navercorp.pinpoint.common.server.bo.stat.AgentStatType; +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import com.navercorp.pinpoint.web.dao.stat.SampledFileDescriptorDao; +import com.navercorp.pinpoint.web.mapper.stat.AgentStatMapperV2; +import com.navercorp.pinpoint.web.mapper.stat.SampledAgentStatResultExtractor; +import com.navercorp.pinpoint.web.mapper.stat.sampling.sampler.FileDescriptorSampler; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.Range; +import com.navercorp.pinpoint.web.vo.stat.SampledFileDescriptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Repository("sampledFileDescriptorDaoV2") +public class HbaseSampledFileDescriptorDaoV2 implements SampledFileDescriptorDao { + + @Autowired + private FileDescriptorDecoder fileDescriptorDecoder; + + @Autowired + private FileDescriptorSampler fileDescriptorSampler; + + @Autowired + private HbaseAgentStatDaoOperationsV2 operations; + + @Override + public List getSampledAgentStatList(String agentId, TimeWindow timeWindow) { + long scanFrom = timeWindow.getWindowRange().getFrom(); + long scanTo = timeWindow.getWindowRange().getTo() + timeWindow.getWindowSlotSize(); + Range range = new Range(scanFrom, scanTo); + AgentStatMapperV2 mapper = operations.createRowMapper(fileDescriptorDecoder, range); + SampledAgentStatResultExtractor resultExtractor = new SampledAgentStatResultExtractor<>(timeWindow, mapper, fileDescriptorSampler); + return operations.getSampledAgentStatList(AgentStatType.FILE_DESCRIPTOR, resultExtractor, agentId, range); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/memory/MemoryAlarmDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/memory/MemoryAlarmDao.java index 252722a04f68..1be4863c8b89 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/memory/MemoryAlarmDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/memory/MemoryAlarmDao.java @@ -85,7 +85,7 @@ public List selectRuleByApplicationId(String applicationId) { for (Entry entry : alarmRule.entrySet()) { if (entry.getValue().getApplicationId().equals(applicationId)) { - alarmRule.remove(entry.getKey()); + ruleList.add(entry.getValue()); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/rest/GithubAgentDownloadInfoDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/rest/GithubAgentDownloadInfoDao.java index a5a962fa26cf..766e41cc58ac 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/rest/GithubAgentDownloadInfoDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/rest/GithubAgentDownloadInfoDao.java @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.web.dao.rest; -import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.navercorp.pinpoint.common.util.CollectionUtils; import com.navercorp.pinpoint.common.util.IdValidateUtils; @@ -48,11 +48,11 @@ public List getDownloadInfoList() { List result = new ArrayList<>(); try { RestTemplate restTemplate = new RestTemplate(); - String responseBody = restTemplate.getForObject(GITHUB_API_URL, String.class); - JavaType agentDownloadInfoListType = objectMapper.getTypeFactory().constructCollectionType(List.class, GithubAgentDownloadInfo.class); - List agentDownloadInfoList = objectMapper.readValue(responseBody, agentDownloadInfoListType); + TypeReference> typeReference = new TypeReference>() {}; + List agentDownloadInfoList = objectMapper.readValue(responseBody, typeReference); + if (CollectionUtils.isEmpty(agentDownloadInfoList)) { return result; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/DeadlockDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/DeadlockDao.java index e591ac670338..1fe949e5f33a 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/DeadlockDao.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/DeadlockDao.java @@ -16,10 +16,10 @@ package com.navercorp.pinpoint.web.dao.stat; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; /** * @author Taejin Koo */ -public interface DeadlockDao extends AgentStatDao { +public interface DeadlockDao extends AgentStatDao { } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/DirectBufferDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/DirectBufferDao.java new file mode 100644 index 000000000000..cc4f8d101028 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/DirectBufferDao.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.dao.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; + +/** + * @author Roy Kim + */ +public interface DirectBufferDao extends AgentStatDao { +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/FileDescriptorDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/FileDescriptorDao.java new file mode 100644 index 000000000000..1b3870d0a2f6 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/FileDescriptorDao.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.dao.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; + +/** + * @author Roy Kim + */ +public interface FileDescriptorDao extends AgentStatDao { +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/SampledDirectBufferDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/SampledDirectBufferDao.java new file mode 100644 index 000000000000..54cbf3c23408 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/SampledDirectBufferDao.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.dao.stat; + +import com.navercorp.pinpoint.web.dao.SampledAgentStatDao; +import com.navercorp.pinpoint.web.vo.stat.SampledDirectBuffer; + +/** + * @author Roy Kim + */ +public interface SampledDirectBufferDao extends SampledAgentStatDao { +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/SampledFileDescriptorDao.java b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/SampledFileDescriptorDao.java new file mode 100644 index 000000000000..6ba6accc7bda --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/dao/stat/SampledFileDescriptorDao.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.dao.stat; + +import com.navercorp.pinpoint.web.dao.SampledAgentStatDao; +import com.navercorp.pinpoint.web.vo.stat.SampledFileDescriptor; + +/** + * @author Roy Kim + */ +public interface SampledFileDescriptorDao extends SampledAgentStatDao { +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/AgentEventMapper.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/AgentEventMapper.java index 9b8a003e0abc..757d242306e5 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/AgentEventMapper.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/AgentEventMapper.java @@ -33,6 +33,7 @@ /** * @author HyunGil Jeong + * @author jaehong.kim - Add case for version 1 */ @Component public class AgentEventMapper implements RowMapper> { @@ -57,6 +58,7 @@ public List mapRow(Result result, int rowNum) throws Exception { final int version = buffer.readInt(); switch (version) { case 0 : + case 1 : final String agentId = buffer.readPrefixedString(); final long startTimestamp = buffer.readLong(); final long eventTimestamp = buffer.readLong(); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/AgentInfoMapper.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/AgentInfoMapper.java index faf7cbd63cd8..bbd9cfa02208 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/AgentInfoMapper.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/AgentInfoMapper.java @@ -78,6 +78,10 @@ private AgentInfoBo.Builder createBuilderFromValue(byte[] serializedAgentInfo) { if (buffer.hasRemaining()) { builder.setVmVersion(buffer.readPrefixedString()); } + // FIXME - 2018.06 v1.8.0 added container (check for compatibility) + if (buffer.hasRemaining()) { + builder.isContainer(buffer.readBoolean()); + } return builder; } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/MapStatisticsCalleeMapper.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/MapStatisticsCalleeMapper.java index 2e8b6dddde8b..70781ebcfe0f 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/MapStatisticsCalleeMapper.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/MapStatisticsCalleeMapper.java @@ -27,6 +27,7 @@ import com.navercorp.pinpoint.web.service.ApplicationFactory; import com.navercorp.pinpoint.web.vo.Application; import com.sematext.hbase.wd.RowKeyDistributorByHashPrefix; +import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.client.Result; @@ -96,6 +97,12 @@ public LinkDataMap mapRow(Result result, int rowNum) throws Exception { short histogramSlot = ApplicationMapStatisticsUtils.getHistogramSlotFromColumnName(qualifier); String callerHost = ApplicationMapStatisticsUtils.getHost(qualifier); + // There may be no callerHost for virtual queue nodes from user-defined entry points. + // Terminal nodes, such as httpclient will not have callerHost set as well, but since they're terminal + // nodes, they would not have reached here in the first place. + if (calleeApplication.getServiceType().isQueue()) { + callerHost = StringUtils.defaultString(callerHost); + } boolean isError = histogramSlot == (short) -1; if (logger.isDebugEnabled()) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/SpanMapperV2.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/SpanMapperV2.java index d268e66463f2..90b0e2cb7130 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/SpanMapperV2.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/SpanMapperV2.java @@ -154,7 +154,7 @@ private List buildSpanBoList(ListMultimap spanMap, Lis private void sortSpanEvent(List spanBoList) { for (SpanBo spanBo : spanBoList) { List spanEventBoList = spanBo.getSpanEventBoList(); - Collections.sort(spanEventBoList, SpanEventComparator.INSTANCE); + spanEventBoList.sort(SpanEventComparator.INSTANCE); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/AgentStatMapperV2.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/AgentStatMapperV2.java index cb71cb430d02..118c83968006 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/AgentStatMapperV2.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/AgentStatMapperV2.java @@ -90,7 +90,7 @@ public List mapRow(Result result, int rowNum) throws Exception { } } // Reverse sort as timestamp is stored in a reversed order. - Collections.sort(dataPoints, REVERSE_TIMESTAMP_COMPARATOR); + dataPoints.sort(REVERSE_TIMESTAMP_COMPARATOR); return dataPoints; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/ApplicationStatMapper.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/ApplicationStatMapper.java index de98ae560bb6..1bcb78d4a970 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/ApplicationStatMapper.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/ApplicationStatMapper.java @@ -90,7 +90,7 @@ public List mapRow(Result result, int rowNum) throws Exception { } } // Reverse sort as timestamp is stored in a reversed order. - Collections.sort(dataPoints, REVERSE_TIMESTAMP_COMPARATOR); + dataPoints.sort(REVERSE_TIMESTAMP_COMPARATOR); return dataPoints; } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/SampledDataSourceResultExtractor.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/SampledDataSourceResultExtractor.java index 2d559b1ad6d3..1eadc5365802 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/SampledDataSourceResultExtractor.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/SampledDataSourceResultExtractor.java @@ -80,11 +80,7 @@ private Map> divideByDataSourceId(ResultScanner resu DataSourceBo first = ListUtils.getFirst(dataPoint.getList(), null); int id = first.getId(); - List dataSourceBoList = dataSourceBoListMap.get(id); - if (dataSourceBoList == null) { - dataSourceBoList = new ArrayList<>(); - dataSourceBoListMap.put(id, dataSourceBoList); - } + List dataSourceBoList = dataSourceBoListMap.computeIfAbsent(id, k -> new ArrayList<>()); dataSourceBoList.addAll(dataPoint.getList()); } @@ -93,7 +89,7 @@ private Map> divideByDataSourceId(ResultScanner resu } private SampledDataSourceList getSampleData(List dataSourceBoList) { - Collections.sort(dataSourceBoList, new Comparator() { + dataSourceBoList.sort(new Comparator() { @Override public int compare(DataSourceBo o1, DataSourceBo o2) { return Long.compare(o2.getTimestamp(), o1.getTimestamp()); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/EagerSamplingHandler.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/EagerSamplingHandler.java index 01318c272ad1..39489a728a32 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/EagerSamplingHandler.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/EagerSamplingHandler.java @@ -59,11 +59,7 @@ public void addDataPoint(T dataPoint) { samplingContext.addDataPoint(dataPoint); } else if (timeslotTimestampToSample > timeslotTimestamp){ S sampledPoint = samplingContext.sampleDataPoints(dataPoint); - SortedMap sampledPoints = sampledPointProjection.get(timeslotTimestampToSample); - if (sampledPoints == null) { - sampledPoints = new TreeMap<>(); - sampledPointProjection.put(timeslotTimestampToSample, sampledPoints); - } + SortedMap sampledPoints = sampledPointProjection.computeIfAbsent(timeslotTimestampToSample, k -> new TreeMap<>()); sampledPoints.put(startTimestamp, sampledPoint); samplingContext = new SamplingPartitionContext(timeslotTimestamp, dataPoint); samplingContexts.put(startTimestamp, samplingContext); @@ -82,11 +78,7 @@ public List getSampledDataPoints() { SamplingPartitionContext samplingPartitionContext = e.getValue(); long timeslotTimestamp = samplingPartitionContext.getTimeslotTimestamp(); S sampledDataPoint = samplingPartitionContext.sampleDataPoints(); - SortedMap reduceCandidates = sampledPointProjection.get(timeslotTimestamp); - if (reduceCandidates == null) { - reduceCandidates = new TreeMap<>(); - sampledPointProjection.put(timeslotTimestamp, reduceCandidates); - } + SortedMap reduceCandidates = sampledPointProjection.computeIfAbsent(timeslotTimestamp, k -> new TreeMap<>()); reduceCandidates.put(startTimestamp, sampledDataPoint); } // reduce projection diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/DeadlockSampler.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/DeadlockSampler.java index 8a8d873d1c99..67535364973b 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/DeadlockSampler.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/DeadlockSampler.java @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.web.mapper.stat.sampling.sampler; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import com.navercorp.pinpoint.web.vo.stat.SampledDeadlock; import com.navercorp.pinpoint.web.vo.stat.chart.DownSampler; import com.navercorp.pinpoint.web.vo.stat.chart.DownSamplers; @@ -30,13 +30,13 @@ * @author Taejin Koo */ @Component -public class DeadlockSampler implements AgentStatSampler { +public class DeadlockSampler implements AgentStatSampler { private static final DownSampler INTEGER_DOWN_SAMPLER = DownSamplers.getIntegerDownSampler(SampledDeadlock.UNCOLLECTED_COUNT); @Override - public SampledDeadlock sampleDataPoints(int index, long timestamp, List deadlockBoList, DeadlockBo previousDataPoint) { - List deadlockedThreadCountList = filter(deadlockBoList); + public SampledDeadlock sampleDataPoints(int index, long timestamp, List deadlockThreadCountBoList, DeadlockThreadCountBo previousDataPoint) { + List deadlockedThreadCountList = filter(deadlockThreadCountBoList); AgentStatPoint point = createPoint(timestamp, deadlockedThreadCountList); SampledDeadlock sampledDeadlock = new SampledDeadlock(point); @@ -44,11 +44,11 @@ public SampledDeadlock sampleDataPoints(int index, long timestamp, List filter(List deadlockBoList) { - List deadlockedThreadCountList = new ArrayList<>(deadlockBoList.size()); + public List filter(List deadlockThreadCountBoList) { + List deadlockedThreadCountList = new ArrayList<>(deadlockThreadCountBoList.size()); - for (DeadlockBo deadlockBo : deadlockBoList) { - deadlockedThreadCountList.add(deadlockBo.getDeadlockedThreadCount()); + for (DeadlockThreadCountBo deadlockThreadCountBo : deadlockThreadCountBoList) { + deadlockedThreadCountList.add(deadlockThreadCountBo.getDeadlockedThreadCount()); } return deadlockedThreadCountList; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/DirectBufferSampler.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/DirectBufferSampler.java new file mode 100644 index 000000000000..3199d0ef8e4b --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/DirectBufferSampler.java @@ -0,0 +1,79 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.mapper.stat.sampling.sampler; + +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.web.vo.stat.SampledDirectBuffer; +import com.navercorp.pinpoint.web.vo.stat.chart.DownSampler; +import com.navercorp.pinpoint.web.vo.stat.chart.DownSamplers; +import com.navercorp.pinpoint.web.vo.stat.chart.agent.AgentStatPoint; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.ToLongFunction; + +/** + * @author Roy Kim + */ +@Component +public class DirectBufferSampler implements AgentStatSampler { + + private static final DownSampler LONG_DOWN_SAMPLER = DownSamplers.getLongDownSampler(SampledDirectBuffer.UNCOLLECTED_VALUE); + + + @Override + public SampledDirectBuffer sampleDataPoints(int timeWindowIndex, long timestamp, List dataPoints, DirectBufferBo previousDataPoint) { + final AgentStatPoint directCount = newAgentStatPoint(timestamp, dataPoints, DirectBufferBo::getDirectCount); + final AgentStatPoint directMemoryUsed = newAgentStatPoint(timestamp, dataPoints, DirectBufferBo::getDirectMemoryUsed); + final AgentStatPoint mappedCount = newAgentStatPoint(timestamp, dataPoints, DirectBufferBo::getMappedCount); + final AgentStatPoint mappedMemoryUsed = newAgentStatPoint(timestamp, dataPoints, DirectBufferBo::getMappedMemoryUsed); + + SampledDirectBuffer sampledDirectBuffer = new SampledDirectBuffer(directCount, directMemoryUsed, mappedCount, mappedMemoryUsed); + return sampledDirectBuffer; + } + + private AgentStatPoint newAgentStatPoint(long timestamp, List dataPoints, ToLongFunction filter) { + List directBuffers = filter(dataPoints, filter); + return createPoint(timestamp, directBuffers); + } + + private List filter(List dataPoints, ToLongFunction filter) { + final List result = new ArrayList<>(dataPoints.size()); + for (DirectBufferBo directBufferBo : dataPoints) { + final long apply = filter.applyAsLong(directBufferBo); + if (apply != DirectBufferBo.UNCOLLECTED_VALUE) { + result.add(apply); + } + } + return result; + } + + private AgentStatPoint createPoint(long timestamp, List values) { + if (values.isEmpty()) { + return SampledDirectBuffer.UNCOLLECTED_POINT_CREATOR.createUnCollectedPoint(timestamp); + } + + return new AgentStatPoint<>( + timestamp, + LONG_DOWN_SAMPLER.sampleMin(values), + LONG_DOWN_SAMPLER.sampleMax(values), + LONG_DOWN_SAMPLER.sampleAvg(values), + LONG_DOWN_SAMPLER.sampleSum(values)); + + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/FileDescriptorSampler.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/FileDescriptorSampler.java new file mode 100644 index 000000000000..f007738cc712 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/FileDescriptorSampler.java @@ -0,0 +1,76 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.mapper.stat.sampling.sampler; + +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import com.navercorp.pinpoint.web.vo.stat.SampledFileDescriptor; +import com.navercorp.pinpoint.web.vo.stat.chart.DownSampler; +import com.navercorp.pinpoint.web.vo.stat.chart.DownSamplers; +import com.navercorp.pinpoint.web.vo.stat.chart.agent.AgentStatPoint; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.ToLongFunction; + +/** + * @author Roy Kim + */ +@Component +public class FileDescriptorSampler implements AgentStatSampler { + + private static final DownSampler LONG_DOWN_SAMPLER = DownSamplers.getLongDownSampler(SampledFileDescriptor.UNCOLLECTED_VALUE); + + + @Override + public SampledFileDescriptor sampleDataPoints(int timeWindowIndex, long timestamp, List dataPoints, FileDescriptorBo previousDataPoint) { + final AgentStatPoint openFileDescriptorCount = newAgentStatPoint(timestamp, dataPoints, FileDescriptorBo::getOpenFileDescriptorCount); + + SampledFileDescriptor sampledFileDescriptor = new SampledFileDescriptor(openFileDescriptorCount); + return sampledFileDescriptor; + } + + private AgentStatPoint newAgentStatPoint(long timestamp, List dataPoints, ToLongFunction filter) { + List fileDescriptors = filter(dataPoints, filter); + return createPoint(timestamp, fileDescriptors); + } + + private List filter(List dataPoints, ToLongFunction filter) { + final List result = new ArrayList<>(dataPoints.size()); + for (FileDescriptorBo fileDescriptorBo : dataPoints) { + final long apply = filter.applyAsLong(fileDescriptorBo); + if (apply != FileDescriptorBo.UNCOLLECTED_VALUE) { + result.add(apply); + } + } + return result; + } + + private AgentStatPoint createPoint(long timestamp, List values) { + if (values.isEmpty()) { + return SampledFileDescriptor.UNCOLLECTED_POINT_CREATOR.createUnCollectedPoint(timestamp); + } + + return new AgentStatPoint<>( + timestamp, + LONG_DOWN_SAMPLER.sampleMin(values), + LONG_DOWN_SAMPLER.sampleMax(values), + LONG_DOWN_SAMPLER.sampleAvg(values), + LONG_DOWN_SAMPLER.sampleSum(values)); + + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDirectBufferSampler.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDirectBufferSampler.java new file mode 100644 index 000000000000..fb720c2386a9 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDirectBufferSampler.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.mapper.stat.sampling.sampler; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinDirectBufferBo; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinDirectBufferBo; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Component +public class JoinDirectBufferSampler implements ApplicationStatSampler { + + @Override + public AggreJoinDirectBufferBo sampleDataPoints(int timeWindowIndex, long timestamp, List joinDirectBufferBoList, JoinDirectBufferBo previousDataPoint) { + if (CollectionUtils.isEmpty(joinDirectBufferBoList)) { + return AggreJoinDirectBufferBo.createUncollectedObject(timestamp); + } + + JoinDirectBufferBo joinDirectBufferBo = JoinDirectBufferBo.joinDirectBufferBoList(joinDirectBufferBoList, timestamp); + + String id = joinDirectBufferBo.getId(); + long avgDirectCount = joinDirectBufferBo.getAvgDirectCount(); + long minDirectCount = joinDirectBufferBo.getMinDirectCount(); + String minDirectCountAgentId = joinDirectBufferBo.getMinDirectCountAgentId(); + long maxDirectCount = joinDirectBufferBo.getMaxDirectCount(); + String maxDirectCountAgentId = joinDirectBufferBo.getMaxDirectCountAgentId(); + + long avgDirectMemoryUsed = joinDirectBufferBo.getAvgDirectMemoryUsed(); + long minDirectMemoryUsed = joinDirectBufferBo.getMinDirectMemoryUsed(); + String minDirectMemoryUsedAgentId = joinDirectBufferBo.getMinDirectMemoryUsedAgentId(); + long maxDirectMemoryUsed = joinDirectBufferBo.getMaxDirectMemoryUsed(); + String maxDirectMemoryUsedAgentId = joinDirectBufferBo.getMaxDirectMemoryUsedAgentId(); + + long avgMappedCount = joinDirectBufferBo.getAvgMappedCount(); + long minMappedCount = joinDirectBufferBo.getMinMappedCount(); + String minMappedCountAgentId = joinDirectBufferBo.getMinMappedCountAgentId(); + long maxMappedCount = joinDirectBufferBo.getMaxMappedCount(); + String maxMappedCountAgentId = joinDirectBufferBo.getMaxMappedCountAgentId(); + + long avgMappedMemoryUsed = joinDirectBufferBo.getAvgMappedMemoryUsed(); + long minMappedMemoryUsed = joinDirectBufferBo.getMinMappedMemoryUsed(); + String minMappedMemoryUsedAgentId = joinDirectBufferBo.getMinMappedMemoryUsedAgentId(); + long maxMappedMemoryUsed = joinDirectBufferBo.getMaxMappedMemoryUsed(); + String maxMappedMemoryUsedAgentId = joinDirectBufferBo.getMaxMappedMemoryUsedAgentId(); + + AggreJoinDirectBufferBo aggreJoinDirectBufferBo = new AggreJoinDirectBufferBo(id, avgDirectCount, maxDirectCount , maxDirectCountAgentId, minDirectCount, minDirectCountAgentId + , avgDirectMemoryUsed, maxDirectMemoryUsed , maxDirectMemoryUsedAgentId, minDirectMemoryUsed, minDirectMemoryUsedAgentId + , avgMappedCount, maxMappedCount , maxMappedCountAgentId, minMappedCount, minMappedCountAgentId + , avgMappedMemoryUsed, maxMappedMemoryUsed , maxMappedMemoryUsedAgentId, minMappedMemoryUsed, minMappedMemoryUsedAgentId, timestamp); + return aggreJoinDirectBufferBo; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinFileDescriptorSampler.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinFileDescriptorSampler.java new file mode 100644 index 000000000000..45d20d301838 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinFileDescriptorSampler.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.mapper.stat.sampling.sampler; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinFileDescriptorBo; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinFileDescriptorBo; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Component +public class JoinFileDescriptorSampler implements ApplicationStatSampler { + + @Override + public AggreJoinFileDescriptorBo sampleDataPoints(int timeWindowIndex, long timestamp, List joinFileDescriptorBoList, JoinFileDescriptorBo previousDataPoint) { + if (CollectionUtils.isEmpty(joinFileDescriptorBoList)) { + return AggreJoinFileDescriptorBo.createUncollectedObject(timestamp); + } + + JoinFileDescriptorBo joinFileDescriptorBo = JoinFileDescriptorBo.joinFileDescriptorBoList(joinFileDescriptorBoList, timestamp); + + String id = joinFileDescriptorBo.getId(); + long openFileDescriptorCount = joinFileDescriptorBo.getAvgOpenFDCount(); + long minOpenFileDescriptor = joinFileDescriptorBo.getMinOpenFDCount(); + String minOpenFileDescriptorAgentId = joinFileDescriptorBo.getMinOpenFDCountAgentId(); + long maxOpenFileDescriptor = joinFileDescriptorBo.getMaxOpenFDCount(); + String maxOpenFileDescriptorAgentId = joinFileDescriptorBo.getMaxOpenFDCountAgentId(); + + AggreJoinFileDescriptorBo aggreJoinFileDescriptorBo = new AggreJoinFileDescriptorBo(id, openFileDescriptorCount, maxOpenFileDescriptor , maxOpenFileDescriptorAgentId, minOpenFileDescriptor, minOpenFileDescriptorAgentId, timestamp); + return aggreJoinFileDescriptorBo; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/join/EagerSamplingHandler.java b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/join/EagerSamplingHandler.java index 0c45420d55fa..a4b42251f21a 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/join/EagerSamplingHandler.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/join/EagerSamplingHandler.java @@ -53,11 +53,7 @@ public void addDataPoint(JoinStatBo dataPoint) { samplingContext.addDataPoint(dataPoint); } else if (timeslotTimestampToSample > timeslotTimestamp) { AggregationStatData sampledPoint = samplingContext.sampleDataPoints(dataPoint); - SortedMap sampledPoints = sampledPointProjection.get(timeslotTimestampToSample); - if (sampledPoints == null) { - sampledPoints = new TreeMap<>(); - sampledPointProjection.put(timeslotTimestampToSample, sampledPoints); - } + SortedMap sampledPoints = sampledPointProjection.computeIfAbsent(timeslotTimestampToSample, k -> new TreeMap<>()); sampledPoints.put(id, sampledPoint); samplingContext = new SamplingPartitionContext(timeslotTimestamp, dataPoint); samplingContexts.put(id, samplingContext); @@ -76,11 +72,7 @@ public List getSampledDataPoints() { SamplingPartitionContext samplingPartitionContext = e.getValue(); long timeslotTimestamp = samplingPartitionContext.getTimeslotTimestamp(); AggregationStatData sampledDataPoint = samplingPartitionContext.sampleDataPoints(); - SortedMap reduceCandidates = sampledPointProjection.get(timeslotTimestamp); - if (reduceCandidates == null) { - reduceCandidates = new TreeMap<>(); - sampledPointProjection.put(timeslotTimestamp, reduceCandidates); - } + SortedMap reduceCandidates = sampledPointProjection.computeIfAbsent(timeslotTimestamp, k -> new TreeMap<>()); reduceCandidates.put(id, sampledDataPoint); } // reduce projection diff --git a/web/src/main/java/com/navercorp/pinpoint/web/scatter/ScatterData.java b/web/src/main/java/com/navercorp/pinpoint/web/scatter/ScatterData.java index 8b519515d521..0761fd034cb2 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/scatter/ScatterData.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/scatter/ScatterData.java @@ -89,11 +89,7 @@ public void addDot(Dot dot) { } private void addDot(Coordinates coordinates, Dot dot) { - DotGroups dotGroups = scatterData.get(coordinates.getX()); - if (dotGroups == null) { - dotGroups = new DotGroups(coordinates.getX()); - scatterData.put(coordinates.getX(), dotGroups); - } + DotGroups dotGroups = scatterData.computeIfAbsent(coordinates.getX(), k -> new DotGroups(coordinates.getX())); dotGroups.addDot(coordinates, dot); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentEventServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentEventServiceImpl.java index fcd6f6ffdff0..5351969f416d 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentEventServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentEventServiceImpl.java @@ -18,6 +18,7 @@ import com.navercorp.pinpoint.common.server.bo.event.AgentEventBo; import com.navercorp.pinpoint.common.server.util.AgentEventMessageDeserializer; +import com.navercorp.pinpoint.common.server.util.AgentEventMessageDeserializerV1; import com.navercorp.pinpoint.common.server.util.AgentEventType; import com.navercorp.pinpoint.common.server.util.AgentEventTypeCategory; import com.navercorp.pinpoint.common.util.ArrayUtils; @@ -41,6 +42,7 @@ /** * @author HyunGil Jeong + * @author jaehong.kim - Add agentEventMessageDeserializerV1 */ @Service public class AgentEventServiceImpl implements AgentEventService { @@ -53,6 +55,9 @@ public class AgentEventServiceImpl implements AgentEventService { @Autowired private AgentEventMessageDeserializer agentEventMessageDeserializer; + @Autowired + private AgentEventMessageDeserializerV1 agentEventMessageDeserializerV1; + @Override public List getAgentEvents(String agentId, Range range, int... excludeEventTypeCodes) { if (agentId == null) { @@ -67,7 +72,7 @@ public List getAgentEvents(String agentId, Range range, int... exclu } List agentEventBos = this.agentEventDao.getAgentEvents(agentId, range, excludeEventTypes); List agentEvents = createAgentEvents(agentEventBos); - Collections.sort(agentEvents, AgentEvent.EVENT_TIMESTAMP_ASC_COMPARATOR); + agentEvents.sort(AgentEvent.EVENT_TIMESTAMP_ASC_COMPARATOR); return agentEvents; } @@ -142,7 +147,13 @@ private DurationalAgentEvent createDurationalAgentEvent(AgentEventBo agentEventB private Object deserializeEventMessage(AgentEventBo agentEventBo) { try { - return this.agentEventMessageDeserializer.deserialize(agentEventBo.getEventType(), agentEventBo.getEventBody()); + if (agentEventBo.getVersion() == 0) { + return this.agentEventMessageDeserializer.deserialize(agentEventBo.getEventType(), agentEventBo.getEventBody()); + } else if (agentEventBo.getVersion() == AgentEventBo.CURRENT_VERSION) { + return this.agentEventMessageDeserializerV1.deserialize(agentEventBo.getEventType(), agentEventBo.getEventBody()); + } else { + throw new UnsupportedEncodingException("invalid version " + agentEventBo.getVersion()); + } } catch (UnsupportedEncodingException e) { logger.warn("error deserializing event message", e); return null; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentInfoService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentInfoService.java index 8c3ee82e9184..78c42b4542fb 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentInfoService.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentInfoService.java @@ -20,7 +20,7 @@ import com.navercorp.pinpoint.web.vo.AgentInfo; import com.navercorp.pinpoint.web.vo.AgentStatus; import com.navercorp.pinpoint.web.vo.ApplicationAgentHostList; -import com.navercorp.pinpoint.web.vo.ApplicationAgentList; +import com.navercorp.pinpoint.web.vo.ApplicationAgentsList; import com.navercorp.pinpoint.web.vo.Range; import com.navercorp.pinpoint.web.vo.timeline.inspector.InspectorTimeline; @@ -33,13 +33,9 @@ */ public interface AgentInfoService { - ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key); + ApplicationAgentsList getAllApplicationAgentsList(ApplicationAgentsList.Filter filter, long timestamp); - ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key, String applicationName); - - ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key, long timestamp); - - ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key, String applicationName, long timestamp); + ApplicationAgentsList getApplicationAgentsList(ApplicationAgentsList.GroupBy key, ApplicationAgentsList.Filter filter, String applicationName, long timestamp); ApplicationAgentHostList getApplicationAgentHostList(int offset, int limit); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentInfoServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentInfoServiceImpl.java index 9d519c054026..e8dae1c1c31a 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentInfoServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentInfoServiceImpl.java @@ -33,7 +33,7 @@ import com.navercorp.pinpoint.web.vo.AgentStatus; import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.ApplicationAgentHostList; -import com.navercorp.pinpoint.web.vo.ApplicationAgentList; +import com.navercorp.pinpoint.web.vo.ApplicationAgentsList; import com.navercorp.pinpoint.web.vo.Range; import com.navercorp.pinpoint.web.vo.timeline.inspector.AgentEventTimeline; import com.navercorp.pinpoint.web.vo.timeline.inspector.AgentEventTimelineBuilder; @@ -56,8 +56,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; /** * @author netspider @@ -87,70 +85,35 @@ public class AgentInfoServiceImpl implements AgentInfoService { private AgentDownloadInfoDao agentDownloadInfoDao; @Override - public ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key) { - return this.getApplicationAgentList(key, System.currentTimeMillis()); - } - - @Override - public ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key, long timestamp) { - ApplicationAgentList applicationAgentList = new ApplicationAgentList(); + public ApplicationAgentsList getAllApplicationAgentsList(ApplicationAgentsList.Filter filter, long timestamp) { + ApplicationAgentsList.GroupBy groupBy = ApplicationAgentsList.GroupBy.APPLICATION_NAME; + ApplicationAgentsList applicationAgentList = new ApplicationAgentsList(groupBy, filter); List applications = applicationIndexDao.selectAllApplicationNames(); for (Application application : applications) { - applicationAgentList.merge(this.getApplicationAgentList(key, application.getName(), timestamp)); + applicationAgentList.merge(getApplicationAgentsList(groupBy, filter, application.getName(), timestamp)); } return applicationAgentList; } @Override - public ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key key, String applicationName) { - return this.getApplicationAgentList(key, applicationName, System.currentTimeMillis()); - } - - @Override - public ApplicationAgentList getApplicationAgentList(ApplicationAgentList.Key applicationAgentListKey, String applicationName, long timestamp) { + public ApplicationAgentsList getApplicationAgentsList(ApplicationAgentsList.GroupBy groupBy, ApplicationAgentsList.Filter filter, String applicationName, long timestamp) { if (applicationName == null) { throw new NullPointerException("applicationName must not be null"); } - if (applicationAgentListKey == null) { - throw new NullPointerException("applicationAgentListKey must not be null"); - } - final List agentIdList = this.applicationIndexDao.selectAgentIds(applicationName); - if (logger.isDebugEnabled()) { - logger.debug("agentIdList={}", agentIdList); - } - - if (CollectionUtils.isEmpty(agentIdList)) { - logger.debug("agentIdList is empty. applicationName={}", applicationName); - return new ApplicationAgentList(new TreeMap>()); + if (groupBy == null) { + throw new NullPointerException("groupBy must not be null"); } - - // key = hostname - // value= list fo agentinfo - SortedMap> result = new TreeMap<>(); - - List agentInfos = this.agentInfoDao.getAgentInfos(agentIdList, timestamp); - this.agentLifeCycleDao.populateAgentStatuses(agentInfos, timestamp); - for (AgentInfo agentInfo : agentInfos) { - if (agentInfo != null) { - String hostname = applicationAgentListKey.getKey(agentInfo); - - if (result.containsKey(hostname)) { - result.get(hostname).add(agentInfo); - } else { - List list = new ArrayList<>(); - list.add(agentInfo); - result.put(hostname, list); - } - } + ApplicationAgentsList applicationAgentsList = new ApplicationAgentsList(groupBy, filter); + Set agentInfos = getAgentsByApplicationName(applicationName, timestamp); + if (agentInfos.isEmpty()) { + logger.warn("agent list is empty for application:{}", applicationName); + return applicationAgentsList; } - - for (List agentInfoList : result.values()) { - Collections.sort(agentInfoList, AgentInfo.AGENT_NAME_ASC_COMPARATOR); + applicationAgentsList.addAll(agentInfos); + if (logger.isDebugEnabled()) { + logger.debug("getApplicationAgentsList={}", applicationAgentsList); } - - logger.info("getApplicationAgentList={}", result); - - return new ApplicationAgentList(result); + return applicationAgentsList; } @Override @@ -187,7 +150,7 @@ private List getApplicationNameList(List applications) { } } - Collections.sort(applicationNameList, Ordering.usingToString()); + applicationNameList.sort(Ordering.usingToString()); return applicationNameList; } @@ -307,7 +270,7 @@ public AgentDownloadInfo getLatestStableAgentDownloadInfo() { return null; } - Collections.sort(downloadInfoList, new Comparator() { + downloadInfoList.sort(new Comparator() { @Override public int compare(AgentDownloadInfo o1, AgentDownloadInfo o2) { return o2.getVersion().compareTo(o1.getVersion()); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentService.java index a811d97e126d..5e2249d073d8 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentService.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentService.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.web.service; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.rpc.stream.ClientStreamChannel; import com.navercorp.pinpoint.rpc.stream.ClientStreamChannelContext; import com.navercorp.pinpoint.rpc.stream.ClientStreamChannelMessageListener; @@ -67,6 +68,6 @@ public interface AgentService { byte[] serializeRequest(TBase tBase, byte[] defaultValue); TBase deserializeResponse(byte[] objectData) throws TException; - TBase deserializeResponse(byte[] objectData, TBase defaultValue); + TBase deserializeResponse(byte[] objectData, Message> defaultValue); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentServiceImpl.java index f9f2fa92177e..a074b835f706 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/AgentServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/AgentServiceImpl.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.web.service; +import com.navercorp.pinpoint.io.request.Message; import com.navercorp.pinpoint.rpc.Future; import com.navercorp.pinpoint.rpc.PinpointSocket; import com.navercorp.pinpoint.rpc.ResponseMessage; @@ -29,6 +30,7 @@ import com.navercorp.pinpoint.thrift.dto.command.TCommandTransfer; import com.navercorp.pinpoint.thrift.dto.command.TRouteResult; import com.navercorp.pinpoint.thrift.io.DeserializerFactory; +import com.navercorp.pinpoint.thrift.io.HeaderTBaseDeserializer; import com.navercorp.pinpoint.thrift.io.HeaderTBaseSerializer; import com.navercorp.pinpoint.thrift.io.SerializerFactory; import com.navercorp.pinpoint.thrift.util.SerializationUtils; @@ -72,11 +74,12 @@ public class AgentServiceImpl implements AgentService { private ClusterManager clusterManager; @Autowired + @Qualifier("commandHeaderTBaseSerializerFactory") private SerializerFactory commandSerializerFactory; @Autowired @Qualifier("commandHeaderTBaseDeserializerFactory") - private DeserializerFactory commandDeserializerFactory; + private DeserializerFactory commandDeserializerFactory; @Value("#{pinpointWebProps['web.activethread.activeAgent.duration.days'] ?: 7}") private void setTimeDiffMs(int durationDays) { @@ -351,12 +354,20 @@ public byte[] serializeRequest(TBase tBase, byte[] defaultValue) { @Override public TBase deserializeResponse(byte[] objectData) throws TException { - return SerializationUtils.deserialize(objectData, commandDeserializerFactory); + Message> message = SerializationUtils.deserialize(objectData, commandDeserializerFactory); + if (message == null) { + return null; + } + return message.getData(); } @Override - public TBase deserializeResponse(byte[] objectData, TBase defaultValue) { - return SerializationUtils.deserialize(objectData, commandDeserializerFactory, defaultValue); + public TBase deserializeResponse(byte[] objectData, Message> defaultValue) { + Message> message = SerializationUtils.deserialize(objectData, commandDeserializerFactory, defaultValue); + if (message == null) { + return null; + } + return message.getData(); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/AlarmServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/AlarmServiceImpl.java index 4fedf3c37e67..2e87122d1e4a 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/AlarmServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/AlarmServiceImpl.java @@ -27,11 +27,13 @@ import com.navercorp.pinpoint.web.alarm.vo.Rule; import com.navercorp.pinpoint.web.dao.AlarmDao; import com.navercorp.pinpoint.web.vo.UserGroup; +import org.springframework.transaction.annotation.Transactional; /** * @author minwoo.jung */ @Service +@Transactional(rollbackFor = {Exception.class}) public class AlarmServiceImpl implements AlarmService { @Autowired @@ -49,11 +51,13 @@ public void deleteRule(Rule rule) { } @Override + @Transactional(readOnly = true) public List selectRuleByUserGroupId(String userGroupId) { return alarmDao.selectRuleByUserGroupId(userGroupId); } @Override + @Transactional(readOnly = true) public List selectRuleByApplicationId(String applicationId) { return alarmDao.selectRuleByApplicationId(applicationId); } @@ -64,6 +68,7 @@ public void updateRule(Rule rule) { } @Override + @Transactional(readOnly = true) public Map selectBeforeCheckerResults(String applicationId) { Map checkerResults = new HashMap<>(); List CheckerResultList = alarmDao.selectBeforeCheckerResultList(applicationId); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/DotExtractor.java b/web/src/main/java/com/navercorp/pinpoint/web/service/DotExtractor.java index 301f4b21e9c0..cefd454e034b 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/DotExtractor.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/DotExtractor.java @@ -66,11 +66,7 @@ public void addDot(SpanBo span) { } private List getDotList(Application spanApplication) { - List dotList = this.dotMap.get(spanApplication); - if (dotList == null) { - dotList = new ArrayList<>(); - this.dotMap.put(spanApplication, dotList); - } + List dotList = this.dotMap.computeIfAbsent(spanApplication, k -> new ArrayList<>()); return dotList; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/SpanServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/SpanServiceImpl.java index 6c8bb1c4f23c..c0b2f3e40a87 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/SpanServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/SpanServiceImpl.java @@ -16,9 +16,6 @@ package com.navercorp.pinpoint.web.service; -import java.util.ArrayList; -import java.util.List; - import com.navercorp.pinpoint.common.server.bo.AnnotationBo; import com.navercorp.pinpoint.common.server.bo.ApiMetaDataBo; import com.navercorp.pinpoint.common.server.bo.MethodTypeEnum; @@ -32,7 +29,9 @@ import com.navercorp.pinpoint.common.util.IntStringStringValue; import com.navercorp.pinpoint.common.util.OutputParameterParser; import com.navercorp.pinpoint.common.util.SqlParser; +import com.navercorp.pinpoint.common.util.StringStringValue; import com.navercorp.pinpoint.common.util.TransactionId; +import com.navercorp.pinpoint.plugin.mongo.MongoConstants; import com.navercorp.pinpoint.web.calltree.span.CallTree; import com.navercorp.pinpoint.web.calltree.span.CallTreeIterator; import com.navercorp.pinpoint.web.calltree.span.SpanAlign; @@ -43,7 +42,6 @@ import com.navercorp.pinpoint.web.dao.TraceDao; import com.navercorp.pinpoint.web.security.MetaDataFilter; import com.navercorp.pinpoint.web.security.MetaDataFilter.MetaData; - import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -51,6 +49,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import java.util.ArrayList; +import java.util.List; + /** * @author emeroad * @author jaehong.kim @@ -65,10 +66,10 @@ public class SpanServiceImpl implements SpanService { @Qualifier("hbaseTraceDaoFactory") private TraceDao traceDao; -// @Autowired + // @Autowired private SqlMetaDataDao sqlMetaDataDao; - - @Autowired(required=false) + + @Autowired(required = false) private MetaDataFilter metaDataFilter; @Autowired @@ -98,9 +99,10 @@ public SpanResult selectSpan(TransactionId transactionId, long selectedSpanHint) final SpanResult result = order(spans, selectedSpanHint); final CallTreeIterator callTreeIterator = result.getCallTree(); final List values = callTreeIterator.values(); - + transitionDynamicApiId(values); transitionSqlId(values); + transitionMongoJson(values); transitionCachedString(values); transitionException(values); // TODO need to at least show the row data when root span is not found. @@ -108,7 +110,6 @@ public SpanResult selectSpan(TransactionId transactionId, long selectedSpanHint) } - private void transitionAnnotation(List spans, AnnotationReplacementCallback annotationReplacementCallback) { for (SpanAlign spanAlign : spans) { List annotationBoList = spanAlign.getAnnotationBoList(); @@ -205,6 +206,55 @@ public void replacement(SpanAlign spanAlign, List annotationBoList }); } + private void transitionMongoJson(final List spans) { + this.transitionAnnotation(spans, new AnnotationReplacementCallback() { + @Override + public void replacement(SpanAlign spanAlign, List annotationBoList) { + AnnotationBo collectionInfo = findAnnotation(annotationBoList, MongoConstants.MONGO_COLLECTION_INFO.getCode()); + AnnotationBo collectionOption = findAnnotation(annotationBoList, MongoConstants.MONGO_COLLECTION_OPTION.getCode()); + + if (collectionInfo != null) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(spanAlign.getDestinationId()) + .append(".") + .append((String) collectionInfo.getValue()); + + if (collectionOption != null) { + stringBuilder.append(" with ") + .append(((String) collectionOption.getValue()).toUpperCase()); + } + collectionInfo.setValue(stringBuilder); + } + + AnnotationBo jsonAnnotation = findAnnotation(annotationBoList, MongoConstants.MONGO_JSON_DATA.getCode()); + if (jsonAnnotation == null) { + return; + } + + final StringStringValue jsonValue = (StringStringValue) jsonAnnotation.getValue(); + + final String json = jsonValue.getStringValue1(); + final String jsonbindValue = jsonValue.getStringValue2(); + + if (StringUtils.isEmpty(json)) { + logger.debug("No values in Json:{}", json); + } else { + AnnotationBo jsonMeta = new AnnotationBo(); + jsonMeta.setKey(MongoConstants.MONGO_JSON.getCode()); + jsonMeta.setValue(json); + annotationBoList.add(jsonMeta); + } + + if (StringUtils.isNotEmpty(jsonbindValue)) { + AnnotationBo bindValueAnnotation = new AnnotationBo(); + bindValueAnnotation.setKey(MongoConstants.MONGO_JSON_BINDVALUE.getCode()); + bindValueAnnotation.setValue(jsonbindValue); + annotationBoList.add(bindValueAnnotation); + } + } + }); + } + private AnnotationBo findAnnotation(List annotationBoList, int key) { for (AnnotationBo annotationBo : annotationBoList) { if (key == annotationBo.getKey()) { @@ -392,7 +442,7 @@ private String getApiInfo(ApiMetaDataBo apiMetaDataBo) { return apiMetaDataBo.getApiInfo(); } } - + private String getApiTagInfo(ApiMetaDataBo apiMetaDataBo) { return apiMetaDataBo.getApiInfo(); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java index ce80fc26e35f..08b129c8d9eb 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/TransactionInfoServiceImpl.java @@ -31,7 +31,6 @@ import com.navercorp.pinpoint.web.calltree.span.CallTreeIterator; import com.navercorp.pinpoint.web.calltree.span.CallTreeNode; import com.navercorp.pinpoint.web.calltree.span.SpanAlign; -import com.navercorp.pinpoint.web.dao.StringMetaDataDao; import com.navercorp.pinpoint.web.dao.TraceDao; import com.navercorp.pinpoint.web.filter.Filter; import com.navercorp.pinpoint.web.security.MetaDataFilter; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/UserGroupService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/UserGroupService.java index 8f3e77b67280..d6cbd3c717fb 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/UserGroupService.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/UserGroupService.java @@ -19,12 +19,14 @@ import com.navercorp.pinpoint.web.vo.UserGroup; import com.navercorp.pinpoint.web.vo.UserGroupMember; +import com.navercorp.pinpoint.web.vo.UserGroupMemberParam; +import com.navercorp.pinpoint.web.vo.exception.PinpointUserGroupException; /** * @author minwoo.jung */ public interface UserGroupService { - String createUserGroup(UserGroup userGroup); + String createUserGroup(UserGroup userGroup, String userId) throws PinpointUserGroupException; List selectUserGroup(); @@ -33,11 +35,13 @@ public interface UserGroupService { List selectUserGroupByUserGroupId(String userGroupId); void updateUserGroup(UserGroup userGroup); - - void deleteUserGroup(UserGroup userGroup); + + void deleteUserGroup(UserGroup userGroup, String userId) throws PinpointUserGroupException; void insertMember(UserGroupMember userGroupMember); + void deleteMemberWithCheckAuthority(UserGroupMember userGroupMember, String userId) throws PinpointUserGroupException; + void deleteMember(UserGroupMember userGroupMember); List selectMember(String userGroupId); @@ -54,4 +58,5 @@ public interface UserGroupService { boolean containMemberForUserGroup(String userId, String userGroupId); + void insertMemberWithCheckAuthority(UserGroupMemberParam userGroupMember, String userId) throws PinpointUserGroupException; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/UserGroupServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/UserGroupServiceImpl.java index c5430ad26a45..b2eb94d90c3f 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/UserGroupServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/UserGroupServiceImpl.java @@ -17,20 +17,26 @@ import java.util.List; +import com.navercorp.pinpoint.web.config.ConfigProperties; import com.navercorp.pinpoint.web.util.DefaultUserInfoDecoder; import com.navercorp.pinpoint.web.util.UserInfoDecoder; import com.navercorp.pinpoint.web.vo.User; +import com.navercorp.pinpoint.web.vo.UserGroupMemberParam; +import com.navercorp.pinpoint.web.vo.exception.PinpointUserGroupException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.navercorp.pinpoint.web.dao.UserGroupDao; import com.navercorp.pinpoint.web.vo.UserGroup; import com.navercorp.pinpoint.web.vo.UserGroupMember; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; /** * @author minwoo.jung */ @Service +@Transactional(rollbackFor = {Exception.class}) public class UserGroupServiceImpl implements UserGroupService { @Autowired @@ -38,23 +44,44 @@ public class UserGroupServiceImpl implements UserGroupService { @Autowired(required = false) UserInfoDecoder userInfoDecoder = DefaultUserInfoDecoder.EMPTY_USER_INFO_DECODER; + + @Autowired + AlarmService alarmService; + + @Autowired + private ConfigProperties webProperties; + + @Override - public String createUserGroup(UserGroup userGroup) { - return userGroupDao.createUserGroup(userGroup); + public String createUserGroup(UserGroup userGroup, String userId) throws PinpointUserGroupException { + String userGroupNumber = userGroupDao.createUserGroup(userGroup); + + if (webProperties.isOpenSource() == false) { + if (StringUtils.isEmpty(userId)) { + throw new PinpointUserGroupException("There is not userId or fail to create userGroup."); + } + + insertMember(new UserGroupMember(userGroup.getId(), userId)); + } + + return userGroupNumber; } @Override + @Transactional(readOnly = true) public List selectUserGroup() { return userGroupDao.selectUserGroup(); } @Override + @Transactional(readOnly = true) public List selectUserGroupByUserId(String userId) { return userGroupDao.selectUserGroupByUserId(userId); } @Override + @Transactional(readOnly = true) public List selectUserGroupByUserGroupId(String userGroupId) { return userGroupDao.selectUserGroupByUserGroupId(userGroupId); } @@ -65,8 +92,27 @@ public void updateUserGroup(UserGroup userGroup) { } @Override - public void deleteUserGroup(UserGroup userGroup) { + public void deleteUserGroup(UserGroup userGroup, String userId) throws PinpointUserGroupException { + if (webProperties.isOpenSource() == false) { + if (checkValid(userId, userGroup.getId()) == false) { + throw new PinpointUserGroupException("There is not userId or you don't have authoriy for user group."); + } + } + userGroupDao.deleteUserGroup(userGroup); + deleteMemberByUserGroupId(userGroup.getId()); + alarmService.deleteRuleByUserGroupId(userGroup.getId()); + } + + private boolean checkValid(String userId, String userGroupId) { + if (StringUtils.isEmpty(userId)) { + return false; + } + if (containMemberForUserGroup(userId, userGroupId) == false) { + return false; + } + + return true; } @Override @@ -74,12 +120,38 @@ public void insertMember(UserGroupMember userGroupMember) { userGroupDao.insertMember(userGroupMember); } + @Override + public void insertMemberWithCheckAuthority(UserGroupMemberParam userGroupMember, String userId) throws PinpointUserGroupException { + if (webProperties.isOpenSource() == false) { + boolean isValid = checkValid(userId, userGroupMember.getUserGroupId()); + if (isValid == false) { + throw new PinpointUserGroupException("there is not userId or you don't have authority for user group."); + } + } + + insertMember(userGroupMember); + } + + + @Override + public void deleteMemberWithCheckAuthority(UserGroupMember userGroupMember, String userId) throws PinpointUserGroupException { + if (webProperties.isOpenSource() == false) { + boolean isValid = checkValid(userId, userGroupMember.getUserGroupId()); + if (isValid == false) { + throw new PinpointUserGroupException("there is not userId or you don't have authority for user group."); + } + } + + userGroupDao.deleteMember(userGroupMember); + } + @Override public void deleteMember(UserGroupMember userGroupMember) { - userGroupDao.deleteMember(userGroupMember); + userGroupDao.deleteMember(userGroupMember); } @Override + @Transactional(readOnly = true) public List selectMember(String userGroupId) { return userGroupDao.selectMember(userGroupId); } @@ -90,6 +162,7 @@ public void updateMember(UserGroupMember userGroupMember) { } @Override + @Transactional(readOnly = true) public List selectPhoneNumberOfMember(String userGroupId) { final List phoneNumberList = userGroupDao.selectPhoneNumberOfMember(userGroupId); List decodedPhoneNumberList = phoneNumberList; @@ -102,6 +175,7 @@ public List selectPhoneNumberOfMember(String userGroupId) { } @Override + @Transactional(readOnly = true) public List selectEmailOfMember(String userGroupId) { return userGroupDao.selectEmailOfMember(userGroupId); } @@ -117,6 +191,7 @@ public void updateUserGroupIdOfMember(UserGroup userGroup) { } @Override + @Transactional(readOnly = true) public boolean containMemberForUserGroup(String userId, String userGroupId) { List memberList = userGroupDao.selectMember(userGroupId); for (UserGroupMember member : memberList) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/UserService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/UserService.java index 11f254c09991..ec8d786639e1 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/UserService.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/UserService.java @@ -28,6 +28,8 @@ public interface UserService { void insertUser(User user); + void insertUserList(List users); + void deleteUser(User user); void updateUser(User user); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/UserServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/UserServiceImpl.java index 4413302ac4e7..7afaed0396cb 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/UserServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/UserServiceImpl.java @@ -22,11 +22,13 @@ import com.navercorp.pinpoint.web.dao.UserDao; import com.navercorp.pinpoint.web.vo.User; +import org.springframework.transaction.annotation.Transactional; /** * @author minwoo.jung */ @Service +@Transactional(rollbackFor = {Exception.class}) public class UserServiceImpl implements UserService { @Autowired @@ -49,21 +51,25 @@ public void updateUser(User user) { } @Override + @Transactional(readOnly = true) public List selectUser() { return userDao.selectUser(); } @Override + @Transactional(readOnly = true) public User selectUserByUserId(String userId) { return userDao.selectUserByUserId(userId); } @Override + @Transactional(readOnly = true) public List selectUserByUserName(String userName) { return userDao.selectUserByUserName(userName); } @Override + @Transactional(readOnly = true) public List selectUserByDepartment(String department) { return userDao.selectUserByDepartment(department); } @@ -73,4 +79,9 @@ public void dropAndCreateUserTable() { userDao.dropAndCreateUserTable(); } + @Override + public void insertUserList(List users) { + userDao.insertUserList(users); + } + } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/map/ApplicationsMapCreatorFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/service/map/ApplicationsMapCreatorFactory.java index 900a35285e00..36944b097a0e 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/map/ApplicationsMapCreatorFactory.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/map/ApplicationsMapCreatorFactory.java @@ -16,17 +16,12 @@ package com.navercorp.pinpoint.web.service.map; -import com.navercorp.pinpoint.common.util.PinpointThreadFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; -import javax.annotation.PreDestroy; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.Objects; +import java.util.concurrent.Executor; /** * @author HyunGil Jeong @@ -34,41 +29,14 @@ @Component public class ApplicationsMapCreatorFactory { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final String mode; - - private final ExecutorService executorService; + private final Executor executor; @Autowired - public ApplicationsMapCreatorFactory( - @Value("#{pinpointWebProps['web.servermap.creator.mode'] ?: 'serial'}") String mode, - @Value("#{pinpointWebProps['web.servermap.creator.parallel.maxthreads'] ?: '16'}") int threadCount) { - logger.info("ApplicationsMapCreatorFactory mode : {}", mode); - this.mode = mode; - if (this.mode.equalsIgnoreCase("parallel")) { - this.executorService = Executors.newFixedThreadPool(threadCount, new PinpointThreadFactory("Pinpoint-parallel-link-selector", true)); - } else { - this.executorService = null; - } + public ApplicationsMapCreatorFactory(@Qualifier("applicationsMapCreateExecutor") Executor executor) { + this.executor = Objects.requireNonNull(executor, "executor must not be null"); } public ApplicationsMapCreator create(ApplicationMapCreator applicationMapCreator) { - if (mode.equalsIgnoreCase("parallel")) { - return new ParallelApplicationsMapCreator(applicationMapCreator, executorService); - } - return new SerialApplicationsMapCreator(applicationMapCreator); - } - - @PreDestroy - public void preDestroy() { - if (executorService != null) { - executorService.shutdown(); - try { - executorService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } + return new DefaultApplicationsMapCreator(applicationMapCreator, executor); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/map/DefaultApplicationsMapCreator.java b/web/src/main/java/com/navercorp/pinpoint/web/service/map/DefaultApplicationsMapCreator.java new file mode 100644 index 000000000000..e675b5bdee17 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/map/DefaultApplicationsMapCreator.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.service.map; + +import com.google.common.collect.Sets; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; +import com.navercorp.pinpoint.web.vo.Application; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Supplier; + +/** + * @author HyunGil Jeong + */ +public class DefaultApplicationsMapCreator implements ApplicationsMapCreator { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final ApplicationMapCreator applicationMapCreator; + + private final Executor executor; + + public DefaultApplicationsMapCreator(ApplicationMapCreator applicationMapCreator, Executor executor) { + this.applicationMapCreator = Objects.requireNonNull(applicationMapCreator, "applicationMapCreator must not be null"); + this.executor = Objects.requireNonNull(executor, "executor must not be null"); + } + + @Override + public LinkDataDuplexMap createLinkDataDuplexMap(List applications, LinkSelectContext linkSelectContext) { + if (CollectionUtils.isEmpty(applications)) { + return new LinkDataDuplexMap(); + } + + if (applications.size() > 1) { + return createParallel(applications, linkSelectContext); + } + return createSerial(applications, linkSelectContext); + } + + private LinkDataDuplexMap createSerial(List applications, LinkSelectContext linkSelectContext) { + final LinkDataDuplexMap resultMap = new LinkDataDuplexMap(); + for (Application application : applications) { + LinkDataDuplexMap searchResult = applicationMapCreator.createMap(application, linkSelectContext); + resultMap.addLinkDataDuplexMap(searchResult); + } + logger.debug("depth search. callerDepth : {}, calleeDepth : {}", linkSelectContext.getCallerDepth(), linkSelectContext.getCalleeDepth()); + return resultMap; + } + + private LinkDataDuplexMap createParallel(List applications, LinkSelectContext linkSelectContext) { + final Set searchResults = Sets.newConcurrentHashSet(); + CompletableFuture[] futures = getLinkDataMapFutures(searchResults, applications, linkSelectContext); + CompletableFuture.allOf(futures).join(); + LinkDataDuplexMap resultMap = new LinkDataDuplexMap(); + for (LinkDataDuplexMap searchResult : searchResults) { + resultMap.addLinkDataDuplexMap(searchResult); + } + logger.debug("depth search. callerDepth : {}, calleeDepth : {}", linkSelectContext.getCallerDepth(), linkSelectContext.getCalleeDepth()); + return resultMap; + } + + private CompletableFuture[] getLinkDataMapFutures(Set searchResults, List targetApplicationList, LinkSelectContext linkSelectContext) { + List> linkDataDuplexMapFutures = new ArrayList<>(); + for (Application targetApplication : targetApplicationList) { + CompletableFuture linkDataDuplexMapFuture = CompletableFuture.supplyAsync(new Supplier() { + @Override + public LinkDataDuplexMap get() { + return applicationMapCreator.createMap(targetApplication, linkSelectContext); + } + }, executor); + CompletableFuture searchResultsFuture = linkDataDuplexMapFuture.thenAccept(searchResults::add); + linkDataDuplexMapFutures.add(searchResultsFuture); + } + return linkDataDuplexMapFutures.toArray(new CompletableFuture[0]); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/map/ParallelApplicationsMapCreator.java b/web/src/main/java/com/navercorp/pinpoint/web/service/map/ParallelApplicationsMapCreator.java deleted file mode 100644 index 19b743d1dda0..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/map/ParallelApplicationsMapCreator.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.service.map; - -import com.google.common.collect.Sets; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; -import com.navercorp.pinpoint.web.vo.Application; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.function.Supplier; - -/** - * @author HyunGil Jeong - */ -public class ParallelApplicationsMapCreator implements ApplicationsMapCreator { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final ApplicationMapCreator applicationMapCreator; - - private final ExecutorService executorService; - - public ParallelApplicationsMapCreator(ApplicationMapCreator applicationMapCreator, ExecutorService executorService) { - if (applicationMapCreator == null) { - throw new NullPointerException("applicationMapCreator must not be null"); - } - if (executorService == null) { - throw new NullPointerException("executorService must not be null"); - } - this.applicationMapCreator = applicationMapCreator; - this.executorService = executorService; - } - - @Override - public LinkDataDuplexMap createLinkDataDuplexMap(List applications, LinkSelectContext linkSelectContext) { - final Set searchResults = Sets.newConcurrentHashSet(); - CompletableFuture[] futures = getLinkDataMapFutures(searchResults, applications, linkSelectContext); - try { - CompletableFuture.allOf(futures).join(); - } catch (Exception e) { - logger.error("Error selecting link", e); - return new LinkDataDuplexMap(); - } - LinkDataDuplexMap resultMap = new LinkDataDuplexMap(); - for (LinkDataDuplexMap searchResult : searchResults) { - resultMap.addLinkDataDuplexMap(searchResult); - } - return resultMap; - } - - private CompletableFuture[] getLinkDataMapFutures(Set searchResults, List targetApplicationList, LinkSelectContext linkSelectContext) { - List> linkDataDuplexMapFutures = new ArrayList<>(); - for (Application targetApplication : targetApplicationList) { - CompletableFuture linkDataDuplexMapFuture = CompletableFuture.supplyAsync(new Supplier() { - @Override - public LinkDataDuplexMap get() { - return applicationMapCreator.createMap(targetApplication, linkSelectContext); - } - }, executorService); - CompletableFuture searchResultsFuture = linkDataDuplexMapFuture.thenAccept(searchResults::add); - linkDataDuplexMapFutures.add(searchResultsFuture); - } - return linkDataDuplexMapFutures.toArray(new CompletableFuture[linkDataDuplexMapFutures.size()]); - } -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/map/SerialApplicationsMapCreator.java b/web/src/main/java/com/navercorp/pinpoint/web/service/map/SerialApplicationsMapCreator.java deleted file mode 100644 index 0ef04d6e97d5..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/map/SerialApplicationsMapCreator.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.service.map; - -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; -import com.navercorp.pinpoint.web.vo.Application; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; - -/** - * @author HyunGil Jeong - */ -public class SerialApplicationsMapCreator implements ApplicationsMapCreator { - - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final ApplicationMapCreator applicationMapCreator; - - public SerialApplicationsMapCreator(ApplicationMapCreator applicationMapCreator) { - if (applicationMapCreator == null) { - throw new NullPointerException("applicationMapCreator must not be null"); - } - this.applicationMapCreator = applicationMapCreator; - } - - @Override - public LinkDataDuplexMap createLinkDataDuplexMap(List applications, LinkSelectContext linkSelectContext) { - final LinkDataDuplexMap resultMap = new LinkDataDuplexMap(); - for (Application application : applications) { - LinkDataDuplexMap searchResult = applicationMapCreator.createMap(application, linkSelectContext); - resultMap.addLinkDataDuplexMap(searchResult); - } - logger.debug("depth search end. callerDepth : {}, calleeDepth : {}", linkSelectContext.getCallerDepth(), linkSelectContext.getCalleeDepth()); - return resultMap; - } -} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/map/processor/WasOnlyProcessor.java b/web/src/main/java/com/navercorp/pinpoint/web/service/map/processor/WasOnlyProcessor.java index d470973e1d05..a2ed4dc7e4e5 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/map/processor/WasOnlyProcessor.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/map/processor/WasOnlyProcessor.java @@ -18,7 +18,6 @@ import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkData; import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataMap; -import com.navercorp.pinpoint.web.service.map.processor.LinkDataMapProcessor; import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.Range; import org.slf4j.Logger; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/AgentWarningStatServiceImpl.java b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/AgentWarningStatServiceImpl.java index 6b9f28e354c0..b942a47bd9aa 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/AgentWarningStatServiceImpl.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/AgentWarningStatServiceImpl.java @@ -17,7 +17,7 @@ package com.navercorp.pinpoint.web.service.stat; import com.navercorp.pinpoint.common.server.bo.stat.AgentWarningStatDataPoint; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import com.navercorp.pinpoint.common.util.CollectionUtils; import com.navercorp.pinpoint.rpc.util.ListUtils; import com.navercorp.pinpoint.web.dao.stat.DeadlockDao; @@ -74,9 +74,9 @@ public Map> selectSeparatedByStartTimesta private List select0(String agentId, Range range) { List agentWarningStatDataPointList = new ArrayList<>(); - List deadlockBoList = deadlockDao.getAgentStatList(agentId, range); - for (DeadlockBo deadlockBo : deadlockBoList) { - agentWarningStatDataPointList.add(deadlockBo); + List deadlockThreadCountBoList = deadlockDao.getAgentStatList(agentId, range); + for (DeadlockThreadCountBo deadlockThreadCountBo : deadlockThreadCountBoList) { + agentWarningStatDataPointList.add(deadlockThreadCountBo); } return agentWarningStatDataPointList; @@ -88,11 +88,7 @@ private Map> parseByStartTimestamp(List partition = partitions.get(startTimestamp); - if (partition == null) { - partition = new ArrayList<>(); - partitions.put(startTimestamp, partition); - } + List partition = partitions.computeIfAbsent(startTimestamp, k -> new ArrayList<>()); partition.add(agentWarningStatDataPoint); } } @@ -100,7 +96,7 @@ private Map> parseByStartTimestamp(List createTimelineSegment(List agentWarningStatDataPointList) { - Collections.sort(agentWarningStatDataPointList, new Comparator() { + agentWarningStatDataPointList.sort(new Comparator() { @Override public int compare(AgentWarningStatDataPoint o1, AgentWarningStatDataPoint o2) { int eventTimestampComparison = Long.compare(o1.getTimestamp(), o2.getTimestamp()); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationDataSourceService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationDataSourceService.java index 786473b48210..0d08e20b0b57 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationDataSourceService.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationDataSourceService.java @@ -53,7 +53,7 @@ public List selectApplicationChart(String applicationId, TimeWindow t List result = new ArrayList<>(); List aggreJoinDataSourceListBoList = this.applicationDataSourceDao.getApplicationStatList(applicationId, timeWindow); - if (aggreJoinDataSourceListBoList.size() == 0) { + if (aggreJoinDataSourceListBoList.isEmpty()) { result.add(new ApplicationDataSourceChart(timeWindow, "", "", Collections.emptyList())); return result; } @@ -77,19 +77,14 @@ protected Map> classifyByDataSourceUr for (AggreJoinDataSourceListBo aggreJoinDataSourceListBo : aggreJoinDataSourceListBoList) { for (AggreJoinDataSourceBo aggreJoinDataSourceBo : aggreJoinDataSourceListBo.getAggreJoinDataSourceBoList()) { DataSourceKey dataSourceKey = new DataSourceKey(aggreJoinDataSourceBo.getUrl(), aggreJoinDataSourceBo.getServiceTypeCode()); - List aggreJoinDataSourceBoList = aggreJoinDataSourceBoMap.get(dataSourceKey); - - if (aggreJoinDataSourceBoList == null) { - aggreJoinDataSourceBoList = new ArrayList<>(); - aggreJoinDataSourceBoMap.put(dataSourceKey, aggreJoinDataSourceBoList); - } + List aggreJoinDataSourceBoList = aggreJoinDataSourceBoMap.computeIfAbsent(dataSourceKey, k -> new ArrayList<>()); aggreJoinDataSourceBoList.add(aggreJoinDataSourceBo); } } - for(List aggreJoinDataSourceBoList : aggreJoinDataSourceBoMap.values()) { - Collections.sort(aggreJoinDataSourceBoList, comparator); + for (List aggreJoinDataSourceBoList : aggreJoinDataSourceBoMap.values()) { + aggreJoinDataSourceBoList.sort(comparator); } return aggreJoinDataSourceBoMap; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationDirectBufferService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationDirectBufferService.java new file mode 100644 index 000000000000..600e7102c7c1 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationDirectBufferService.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.service.stat; + +import com.navercorp.pinpoint.web.dao.ApplicationDirectBufferDao; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinDirectBufferBo; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChart; +import com.navercorp.pinpoint.web.vo.stat.chart.application.ApplicationDirectBufferChart; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Service +public class ApplicationDirectBufferService implements ApplicationStatChartService { + + @Autowired + private ApplicationDirectBufferDao applicationDirectBufferDao; + + + @Override + public StatChart selectApplicationChart(String applicationId, TimeWindow timeWindow) { + if (applicationId == null) { + throw new NullPointerException("applicationId must not be null"); + } + if (timeWindow == null) { + throw new NullPointerException("timeWindow must not be null"); + } + List aggreJoinDirectBufferBoList = this.applicationDirectBufferDao.getApplicationStatList(applicationId, timeWindow); + return new ApplicationDirectBufferChart(timeWindow, aggreJoinDirectBufferBoList); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationFileDescriptorService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationFileDescriptorService.java new file mode 100644 index 000000000000..c36011689632 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/ApplicationFileDescriptorService.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.service.stat; + +import com.navercorp.pinpoint.web.dao.ApplicationFileDescriptorDao; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinFileDescriptorBo; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChart; +import com.navercorp.pinpoint.web.vo.stat.chart.application.ApplicationFileDescriptorChart; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Service +public class ApplicationFileDescriptorService implements ApplicationStatChartService { + + @Autowired + private ApplicationFileDescriptorDao applicationFileDescriptorDao; + + + @Override + public StatChart selectApplicationChart(String applicationId, TimeWindow timeWindow) { + if (applicationId == null) { + throw new NullPointerException("applicationId must not be null"); + } + if (timeWindow == null) { + throw new NullPointerException("timeWindow must not be null"); + } + List aggreJoinFileDescriptorBoList = this.applicationFileDescriptorDao.getApplicationStatList(applicationId, timeWindow); + return new ApplicationFileDescriptorChart(timeWindow, aggreJoinFileDescriptorBoList); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DeadlockService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DeadlockService.java index bba9402aa891..b9dd13109766 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DeadlockService.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DeadlockService.java @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.web.service.stat; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import com.navercorp.pinpoint.web.dao.stat.DeadlockDao; import com.navercorp.pinpoint.web.vo.Range; import org.springframework.beans.factory.annotation.Autowired; @@ -29,7 +29,7 @@ * @author Taejin Koo */ @Service -public class DeadlockService implements AgentStatService { +public class DeadlockService implements AgentStatService { private final DeadlockDao deadlockDao; @@ -39,7 +39,7 @@ public DeadlockService(@Qualifier("deadlockDaoFactory") DeadlockDao deadlockDao) } @Override - public List selectAgentStatList(String agentId, Range range) { + public List selectAgentStatList(String agentId, Range range) { if (agentId == null) { throw new NullPointerException("agentId must not be null"); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DirectBufferChartService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DirectBufferChartService.java new file mode 100644 index 000000000000..cd71baac6591 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DirectBufferChartService.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.service.stat; + +import com.navercorp.pinpoint.web.dao.stat.SampledDirectBufferDao; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.stat.SampledDirectBuffer; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChart; +import com.navercorp.pinpoint.web.vo.stat.chart.agent.DirectBufferChart; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Roy Kim + */ +@Service +public class DirectBufferChartService implements AgentStatChartService { + + private final SampledDirectBufferDao sampledDirectBufferDao; + + @Autowired + public DirectBufferChartService(@Qualifier("sampledDirectBufferDaoFactory") SampledDirectBufferDao sampledDirectBufferDao) { + this.sampledDirectBufferDao = sampledDirectBufferDao; + } + + @Override + public StatChart selectAgentChart(String agentId, TimeWindow timeWindow) { + if (agentId == null) { + throw new NullPointerException("agentId must not be null"); + } + if (timeWindow == null) { + throw new NullPointerException("timeWindow must not be null"); + } + List sampledDirectBuffers = this.sampledDirectBufferDao.getSampledAgentStatList(agentId, timeWindow); + return new DirectBufferChart(timeWindow, sampledDirectBuffers); + } + + @Override + public List selectAgentChartList(String agentId, TimeWindow timeWindow) { + StatChart agentStatChart = selectAgentChart(agentId, timeWindow); + + List result = new ArrayList<>(1); + result.add(agentStatChart); + + return result; + } + +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DirectBufferService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DirectBufferService.java new file mode 100644 index 000000000000..92700d3f7076 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/DirectBufferService.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.service.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.DirectBufferBo; +import com.navercorp.pinpoint.web.dao.stat.DirectBufferDao; +import com.navercorp.pinpoint.web.vo.Range; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Service +public class DirectBufferService implements AgentStatService { + + private final DirectBufferDao directBufferDao; + + @Autowired + public DirectBufferService(@Qualifier("directBufferDaoFactory") DirectBufferDao directBufferDao) { + this.directBufferDao = directBufferDao; + } + + @Override + public List selectAgentStatList(String agentId, Range range) { + if (agentId == null) { + throw new NullPointerException("agentId must not be null"); + } + if (range == null) { + throw new NullPointerException("range must not be null"); + } + return this.directBufferDao.getAgentStatList(agentId, range); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/FileDescriptorChartService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/FileDescriptorChartService.java new file mode 100644 index 000000000000..f6c2ec633192 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/FileDescriptorChartService.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.service.stat; + +import com.navercorp.pinpoint.web.dao.stat.SampledFileDescriptorDao; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.stat.SampledFileDescriptor; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChart; +import com.navercorp.pinpoint.web.vo.stat.chart.agent.FileDescriptorChart; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Roy Kim + */ +@Service +public class FileDescriptorChartService implements AgentStatChartService { + + private final SampledFileDescriptorDao sampledFileDescriptorDao; + + @Autowired + public FileDescriptorChartService(@Qualifier("sampledFileDescriptorDaoFactory") SampledFileDescriptorDao sampledFileDescriptorDao) { + this.sampledFileDescriptorDao = sampledFileDescriptorDao; + } + + @Override + public StatChart selectAgentChart(String agentId, TimeWindow timeWindow) { + if (agentId == null) { + throw new NullPointerException("agentId must not be null"); + } + if (timeWindow == null) { + throw new NullPointerException("timeWindow must not be null"); + } + List sampledFileDescriptors = this.sampledFileDescriptorDao.getSampledAgentStatList(agentId, timeWindow); + return new FileDescriptorChart(timeWindow, sampledFileDescriptors); + } + + @Override + public List selectAgentChartList(String agentId, TimeWindow timeWindow) { + StatChart agentStatChart = selectAgentChart(agentId, timeWindow); + + List result = new ArrayList<>(1); + result.add(agentStatChart); + + return result; + } + +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/service/stat/FileDescriptorService.java b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/FileDescriptorService.java new file mode 100644 index 000000000000..e7dbd409367f --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/service/stat/FileDescriptorService.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.service.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.FileDescriptorBo; +import com.navercorp.pinpoint.web.dao.stat.FileDescriptorDao; +import com.navercorp.pinpoint.web.vo.Range; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author Roy Kim + */ +@Service +public class FileDescriptorService implements AgentStatService { + + private final FileDescriptorDao fileDescriptorDao; + + @Autowired + public FileDescriptorService(@Qualifier("fileDescriptorDaoFactory") FileDescriptorDao fileDescriptorDao) { + this.fileDescriptorDao = fileDescriptorDao; + } + + @Override + public List selectAgentStatList(String agentId, Range range) { + if (agentId == null) { + throw new NullPointerException("agentId must not be null"); + } + if (range == null) { + throw new NullPointerException("range must not be null"); + } + return this.fileDescriptorDao.getAgentStatList(agentId, range); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/servlet/RewriteForV2Filter.java b/web/src/main/java/com/navercorp/pinpoint/web/servlet/RewriteForV2Filter.java new file mode 100644 index 000000000000..10c8fb1fc1b0 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/servlet/RewriteForV2Filter.java @@ -0,0 +1,101 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.servlet; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.IOException; + +/** + * @author Taejin Koo + */ +public class RewriteForV2Filter implements Filter { + + private static final Log logger = LogFactory.getLog(RewriteForV2Filter.class); + + private static final char PATH_DELIMITER = '/'; + + private final String[] rewriteTargetArray = { + "/v2/admin", + "/v2/error", + "/v2/filteredMap", + "/v2/inspector", + "/v2/main", + "/v2/realtime", + "/v2/scatterFullScreenMode", + "/v2/threadDump", + "/v2/transactionDetail", + "/v2/transactionList", + "/v2/transactionView" + }; + + private final boolean enable; + + public RewriteForV2Filter(boolean enable) { + this.enable = enable; + } + + public void init(FilterConfig filterConfig) { + logger.info("init"); + } + + public void destroy() { + + } + + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + if (enable) { + HttpServletRequest req = (HttpServletRequest) request; + String requestURI = req.getRequestURI(); + + if (isRedirectTarget(requestURI)) { + HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper((HttpServletRequest) request); + RequestDispatcher dispatcher = wrapper.getRequestDispatcher("/v2/index.html"); + + dispatcher.forward(request, response); + } else { + chain.doFilter(request, response); + } + } else { + chain.doFilter(request, response); + } + + } + + private boolean isRedirectTarget(String uri) { + for (String rewriteTarget : rewriteTargetArray) { + if (uri.equals(rewriteTarget)) { + return true; + } + if (uri.startsWith(rewriteTarget + PATH_DELIMITER)) { + return true; + } + } + return false; + } + +} \ No newline at end of file diff --git a/web/src/main/java/com/navercorp/pinpoint/web/task/ChainedTaskDecorator.java b/web/src/main/java/com/navercorp/pinpoint/web/task/ChainedTaskDecorator.java new file mode 100644 index 000000000000..efa83315e6a3 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/task/ChainedTaskDecorator.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.task; + +import org.springframework.core.task.TaskDecorator; + +import java.util.List; +import java.util.Objects; + +/** + * @author HyunGil Jeong + */ +public class ChainedTaskDecorator implements TaskDecorator { + + private final List taskDecorators; + + public ChainedTaskDecorator(List taskDecorators) { + this.taskDecorators = Objects.requireNonNull(taskDecorators, "taskDecorators must not be null"); + } + + @Override + public Runnable decorate(Runnable runnable) { + Runnable decoratedRunnable = runnable; + for (TaskDecorator taskDecorator : taskDecorators) { + decoratedRunnable = taskDecorator.decorate(decoratedRunnable); + } + return decoratedRunnable; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/task/RequestContextPropagatingTaskDecorator.java b/web/src/main/java/com/navercorp/pinpoint/web/task/RequestContextPropagatingTaskDecorator.java new file mode 100644 index 000000000000..17b70f09e381 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/task/RequestContextPropagatingTaskDecorator.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.task; + +import org.springframework.core.task.TaskDecorator; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +import java.util.Objects; + +/** + * @author HyunGil Jeong + */ +public class RequestContextPropagatingTaskDecorator implements TaskDecorator { + + @Override + public Runnable decorate(Runnable runnable) { + return new RequestContextPropagatingRunnable(runnable); + } + + private static class RequestContextPropagatingRunnable implements Runnable { + + private final Runnable delegate; + private final RequestAttributes requestAttributes; + + private RequestContextPropagatingRunnable(Runnable delegate) { + this.delegate = Objects.requireNonNull(delegate, "delegate must not be null"); + this.requestAttributes = RequestContextHolder.getRequestAttributes(); + } + + @Override + public void run() { + RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes(); + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + delegate.run(); + } finally { + RequestContextHolder.setRequestAttributes(previousRequestAttributes); + } + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/task/SecurityContextPropagatingTaskDecorator.java b/web/src/main/java/com/navercorp/pinpoint/web/task/SecurityContextPropagatingTaskDecorator.java new file mode 100644 index 000000000000..83d55bcb8b58 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/task/SecurityContextPropagatingTaskDecorator.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.task; + +import org.springframework.core.task.TaskDecorator; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.Objects; + +/** + * @author HyunGil Jeong + */ +public class SecurityContextPropagatingTaskDecorator implements TaskDecorator { + + @Override + public Runnable decorate(Runnable runnable) { + return new SecurityContextPropagatingRunnable(runnable); + } + + private static class SecurityContextPropagatingRunnable implements Runnable { + + private final Runnable delegate; + private final SecurityContext securityContext; + + private SecurityContextPropagatingRunnable(Runnable delegate) { + this.delegate = Objects.requireNonNull(delegate, "delegate must not be null"); + this.securityContext = SecurityContextHolder.getContext(); + } + + @Override + public void run() { + SecurityContext previousSecurityContext = SecurityContextHolder.getContext(); + SecurityContextHolder.setContext(securityContext); + try { + delegate.run(); + } finally { + SecurityContextHolder.setContext(previousSecurityContext); + } + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/task/TimerTaskDecorator.java b/web/src/main/java/com/navercorp/pinpoint/web/task/TimerTaskDecorator.java new file mode 100644 index 000000000000..dc4180767d44 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/task/TimerTaskDecorator.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.task; + +import java.util.TimerTask; + +/** + * @author HyunGil Jeong + */ +public interface TimerTaskDecorator { + + TimerTask decorate(TimerTask timerTask); +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/task/TimerTaskDecoratorFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/task/TimerTaskDecoratorFactory.java new file mode 100644 index 000000000000..9394dcacd138 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/task/TimerTaskDecoratorFactory.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.task; + +/** + * @author HyunGil Jeong + */ +public interface TimerTaskDecoratorFactory { + + TimerTaskDecorator createTimerTaskDecorator(); +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/util/AnnotationKeyMatcherRegistry.java b/web/src/main/java/com/navercorp/pinpoint/web/util/AnnotationKeyMatcherRegistry.java index 37ab7cf9ff4b..701934379b13 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/util/AnnotationKeyMatcherRegistry.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/util/AnnotationKeyMatcherRegistry.java @@ -22,7 +22,6 @@ import com.navercorp.pinpoint.common.util.apache.IntHashMapUtils; import java.util.HashMap; -import java.util.Map; /** * @author emeroad diff --git a/web/src/main/java/com/navercorp/pinpoint/web/util/BatchUtils.java b/web/src/main/java/com/navercorp/pinpoint/web/util/BatchUtils.java new file mode 100644 index 000000000000..137bf03166b8 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/util/BatchUtils.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Collections; +import java.util.Enumeration; + +/** + * @author minwoo.jung + */ +public class BatchUtils { + + private final static Logger logger = LoggerFactory.getLogger(BatchUtils.class); + + public static boolean decisionBatchServer(String ip) { + Enumeration interfaces; + + try { + interfaces = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException e) { + logger.error("not found network interface", e); + return false; + } + + if (interfaces == null) { + return false; + } + + while (interfaces.hasMoreElements()) { + NetworkInterface network = interfaces.nextElement(); + Enumeration inets = network.getInetAddresses(); + + while (inets.hasMoreElements()) { + InetAddress next = inets.nextElement(); + + if (next instanceof Inet4Address) { + if (next.getHostAddress().equals(ip)) { + return true; + } + } + } + } + + return false; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/util/DefaultMongoJsonParser.java b/web/src/main/java/com/navercorp/pinpoint/web/util/DefaultMongoJsonParser.java new file mode 100644 index 000000000000..e21423c6e1f5 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/util/DefaultMongoJsonParser.java @@ -0,0 +1,125 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.util; + +import com.navercorp.pinpoint.common.util.CollectionUtils; +import com.navercorp.pinpoint.common.util.StringUtils; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Stack; + +/** + * @author Roy Kim + */ +public class DefaultMongoJsonParser implements MongoJsonParser { + + private static final int NEXT_TOKEN_NOT_EXIST = -1; + + public DefaultMongoJsonParser() { + } + + private int lookAhead(String json, int index, int gap) { + index += gap; + if (index < json.length()) { + return json.charAt(index); + } else { + return NEXT_TOKEN_NOT_EXIST; + } + } + + private int lookFoward(String json, int index, int gap) { + index -= gap; + if (index < json.length() && 0 <= index) { + return json.charAt(index); + } else { + return NEXT_TOKEN_NOT_EXIST; + } + } + + public String combineBindValues(String json, List bindValues) { + if (StringUtils.isEmpty(json)) { + return json; + } + if (CollectionUtils.isEmpty(bindValues)) { + return json; + } + + int additionalSize = 0; + final Queue bindValueQueue = new LinkedList(); + for (String value : bindValues) { + bindValueQueue.add(value); + additionalSize += value.length(); + additionalSize -= 3; + } + final int length = json.length(); + final StringBuilder result = new StringBuilder(length + additionalSize); + + Stack stack = new Stack(); + + boolean statusKey = true; + boolean inString = false; + + for (int i = 0; i < length; i++) { + final char ch = json.charAt(i); + + if (statusKey && ch == '\"' && lookFoward(json, i, 1) != '\\') { + inString = !inString; + } + + if (!inString) { + if (statusKey && ch == ':') { + statusKey = false; + } else if (ch == '{') { + statusKey = true; + stack.push(ch); + } else if (ch == '}' && !stack.empty()) { + stack.pop(); + if (!stack.empty() && stack.peek() != '[') { + statusKey = true; + } + } else if (ch == '[') { + stack.push(ch); + } else if (ch == ']' && !stack.empty()) { + stack.pop(); + if (!stack.empty() && stack.peek() != '[') { + statusKey = true; + } + } + } + + if (!statusKey) { + if (ch == '\"' && lookAhead(json, i, 1) == '?' && lookAhead(json, i, 2) == '\"') { + if (!bindValueQueue.isEmpty()) { + result.append(bindValueQueue.poll()); + i += 2; + if (!stack.empty() && stack.peek() != '[') { + statusKey = true; + } + } + } else { + result.append(ch); + } + } else { + result.append(ch); + } + + } + return result.toString(); + } +} \ No newline at end of file diff --git a/web/src/main/java/com/navercorp/pinpoint/web/util/MongoJsonParser.java b/web/src/main/java/com/navercorp/pinpoint/web/util/MongoJsonParser.java new file mode 100644 index 000000000000..c84f303812ab --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/util/MongoJsonParser.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.util; + +import java.util.List; + +/** + * @author Roy Kim + */ +public interface MongoJsonParser { + + String combineBindValues(String sql, List bindValues); +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/util/OutputParameterMongoJsonParser.java b/web/src/main/java/com/navercorp/pinpoint/web/util/OutputParameterMongoJsonParser.java new file mode 100644 index 000000000000..97ab935b16e9 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/util/OutputParameterMongoJsonParser.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.util; + +import com.navercorp.pinpoint.common.util.StringUtils; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Roy Kim + */ +public class OutputParameterMongoJsonParser { + + public static final char SEPARATOR = ','; + + public List parseOutputParameter(String outputParams) { + // may also need to know about the parsing result + if (StringUtils.isEmpty(outputParams)) { + return Collections.emptyList(); + } + + final List result = new LinkedList(); + StringBuilder params = new StringBuilder(); + int len = outputParams.length(); + + for (int index = 0; index < len; index++) { + final char ch = outputParams.charAt(index); + + if (ch == SEPARATOR) { + result.add(params.toString()); + params = new StringBuilder(); + } else if (ch == '\"') { + params.append(ch); + + for (index = index + 1; index < len; index++) { + char stateCh = outputParams.charAt(index); + + if (stateCh == '\"') { + if (lookAhead1(outputParams, index) == '\"') { + params.append(stateCh); + index++; + continue; + } else { + params.append(stateCh); + break; + } + } else { + params.append(stateCh); + } + } + } else { + params.append(ch); + } + } + + result.add(params.toString()); + + return result; + } + + private int lookAhead1(String sql, int index) { + index++; + if (index < sql.length()) { + return sql.charAt(index); + } else { + return -1; + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/util/ThreadDumpUtils.java b/web/src/main/java/com/navercorp/pinpoint/web/util/ThreadDumpUtils.java index 73f7f2ee83a8..5ce8e939c984 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/util/ThreadDumpUtils.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/util/ThreadDumpUtils.java @@ -16,6 +16,9 @@ package com.navercorp.pinpoint.web.util; +import com.navercorp.pinpoint.common.server.bo.event.MonitorInfoBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadDumpBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadState; import com.navercorp.pinpoint.common.util.CollectionUtils; import com.navercorp.pinpoint.thrift.dto.command.TMonitorInfo; import com.navercorp.pinpoint.thrift.dto.command.TThreadDump; @@ -26,6 +29,7 @@ /** * @author Taejin Koo + * @author jaehong.kim - Add createDumpMessage() for ThreadDumpBo */ public final class ThreadDumpUtils { @@ -118,4 +122,90 @@ private static TThreadState getThreadState(TThreadState threadState) { } } -} + public static String createDumpMessage(ThreadDumpBo threadDump) { + ThreadState threadState = getThreadState(threadDump.getThreadState()); + + // set threadName + StringBuilder message = new StringBuilder("\"" + threadDump.getThreadName() + "\""); + + // set threadId + String hexStringThreadId = Long.toHexString(threadDump.getThreadId()); + message.append(" Id=0x" + hexStringThreadId); + + // set threadState + message.append(" " + threadState.name()); + + if (!StringUtils.isBlank(threadDump.getLockName())) { + message.append(" on ").append(threadDump.getLockName()); + } + + if (!StringUtils.isBlank(threadDump.getLockOwnerName())) { + message.append(" owned by \"").append(threadDump.getLockOwnerName()).append("\" Id=").append(threadDump.getLockOwnerId()); + } + + if (threadDump.isSuspended()) { + message.append(" (suspended)"); + } + if (threadDump.isInNative()) { + message.append(" (in native)"); + } + message.append(LINE_SEPARATOR); + + // set StackTrace + final int stackTraceSize = threadDump.getStackTraceList().size(); + for (int i = 0; i < stackTraceSize; i++) { + final String stackTrace = threadDump.getStackTraceList().get(i); + message.append(TAB_SEPARATOR + "at ").append(stackTrace); + message.append(LINE_SEPARATOR); + + if (i == 0 && !StringUtils.isBlank(threadDump.getLockName())) { + switch (threadState) { + case BLOCKED: + message.append(TAB_SEPARATOR + "- blocked on ").append(threadDump.getLockName()); + message.append(LINE_SEPARATOR); + break; + case WAITING: + message.append(TAB_SEPARATOR + "- waiting on ").append(threadDump.getLockName()); + message.append(LINE_SEPARATOR); + break; + case TIMED_WAITING: + message.append(TAB_SEPARATOR + "- waiting on ").append(threadDump.getLockName()); + message.append(LINE_SEPARATOR); + break; + default: + } + } + + if (CollectionUtils.hasLength(threadDump.getLockedMonitorInfoList())) { + for (MonitorInfoBo lockedMonitor : threadDump.getLockedMonitorInfoList()) { + if (lockedMonitor.getStackDepth() == i) { + message.append(TAB_SEPARATOR + "- locked ").append(lockedMonitor.getStackFrame()); + message.append(LINE_SEPARATOR); + } + } + } + } + + // set Locks + List lockedSynchronizerList = threadDump.getLockedSynchronizerList(); + if (CollectionUtils.hasLength(lockedSynchronizerList)) { + message.append(LINE_SEPARATOR + TAB_SEPARATOR + "Number of locked synchronizers = ").append(lockedSynchronizerList.size()); + message.append(LINE_SEPARATOR); + for (String lockedSynchronizer : lockedSynchronizerList) { + message.append(TAB_SEPARATOR + "- ").append(lockedSynchronizer); + message.append(LINE_SEPARATOR); + } + } + + message.append(LINE_SEPARATOR); + return message.toString(); + } + + private static ThreadState getThreadState(ThreadState threadState) { + if (threadState == null) { + return ThreadState.UNKNOWN; + } else { + return threadState; + } + } +} \ No newline at end of file diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/AgentEventSerializer.java b/web/src/main/java/com/navercorp/pinpoint/web/view/AgentEventSerializer.java index ab0768d6bcaa..31b7dae2cbe1 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/view/AgentEventSerializer.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/AgentEventSerializer.java @@ -19,6 +19,8 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; +import com.navercorp.pinpoint.common.server.bo.event.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.event.ThreadDumpBo; import com.navercorp.pinpoint.thrift.dto.TDeadlock; import com.navercorp.pinpoint.thrift.dto.command.TThreadDump; import com.navercorp.pinpoint.web.util.ThreadDumpUtils; @@ -29,6 +31,7 @@ /** * @author Taejin Koo + * @author jaehong.kim - Add DeadlockBo logic */ public class AgentEventSerializer extends JsonSerializer { @@ -62,6 +65,13 @@ public void serialize(AgentEvent agentEvent, JsonGenerator jgen, SerializerProvi message.append(ThreadDumpUtils.createDumpMessage(threadDump)); } + jgen.writeObjectField("eventMessage", message.toString()); + } else if (eventMessage instanceof DeadlockBo) { + final StringBuilder message = new StringBuilder(); + final List threadDumpBoList = ((DeadlockBo) eventMessage).getThreadDumpBoList(); + for (ThreadDumpBo threadDump : threadDumpBoList) { + message.append(ThreadDumpUtils.createDumpMessage(threadDump)); + } jgen.writeObjectField("eventMessage", message.toString()); } else { jgen.writeObjectField("eventMessage", eventMessage); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/ApplicationAgentListSerializer.java b/web/src/main/java/com/navercorp/pinpoint/web/view/ApplicationAgentListSerializer.java deleted file mode 100644 index 337a789a86a4..000000000000 --- a/web/src/main/java/com/navercorp/pinpoint/web/view/ApplicationAgentListSerializer.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.view; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.navercorp.pinpoint.web.vo.AgentInfo; -import com.navercorp.pinpoint.web.vo.ApplicationAgentList; - -/** - * @author minwoo.jung - * @author HyunGil Jeong - */ -public class ApplicationAgentListSerializer extends JsonSerializer { - - @Override - public void serialize(ApplicationAgentList applicationAgentList, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { - jgen.writeStartObject(); - Map> map = applicationAgentList.getApplicationAgentList(); - - for (Map.Entry> entry : map.entrySet()) { - jgen.writeFieldName(entry.getKey()); - writeAgentList(jgen, entry.getValue()); - } - - jgen.writeEndObject(); - } - - private void writeAgentList(JsonGenerator jgen, List agentList) throws IOException { - jgen.writeStartArray(); - for (AgentInfo agentInfo : agentList) { - jgen.writeObject(agentInfo); - } - jgen.writeEndArray(); - } -} \ No newline at end of file diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/ApplicationAgentsListSerializer.java b/web/src/main/java/com/navercorp/pinpoint/web/view/ApplicationAgentsListSerializer.java new file mode 100644 index 000000000000..ff347053bf61 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/ApplicationAgentsListSerializer.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.view; + +import java.io.IOException; +import java.util.List; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.navercorp.pinpoint.web.vo.AgentInfo; +import com.navercorp.pinpoint.web.vo.ApplicationAgentList; +import com.navercorp.pinpoint.web.vo.ApplicationAgentsList; + +/** + * @author minwoo.jung + * @author HyunGil Jeong + */ +public class ApplicationAgentsListSerializer extends JsonSerializer { + + @Override + public void serialize(ApplicationAgentsList applicationAgentsList, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { + jgen.writeStartObject(); + List applicationAgentLists = applicationAgentsList.getApplicationAgentLists(); + for (ApplicationAgentList applicationAgentList : applicationAgentLists) { + jgen.writeFieldName(applicationAgentList.getGroupName()); + writeAgentList(jgen, applicationAgentList.getAgentInfos()); + } + jgen.writeEndObject(); + } + + private void writeAgentList(JsonGenerator jgen, List agentList) throws IOException { + jgen.writeStartArray(); + for (AgentInfo agentInfo : agentList) { + jgen.writeObject(agentInfo); + } + jgen.writeEndArray(); + } +} \ No newline at end of file diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/DirectBufferPointSerializer.java b/web/src/main/java/com/navercorp/pinpoint/web/view/DirectBufferPointSerializer.java new file mode 100644 index 000000000000..f2575249f0cb --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/DirectBufferPointSerializer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.view; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.navercorp.pinpoint.web.vo.stat.chart.application.DirectBufferPoint; + +import java.io.IOException; + +/** + * @author Roy Kim + */ +public class DirectBufferPointSerializer extends JsonSerializer { + + @Override + public void serialize(DirectBufferPoint directBufferPoint, JsonGenerator jgen, SerializerProvider serializers) throws IOException, JsonProcessingException { + jgen.writeStartArray(); + jgen.writeNumber(directBufferPoint.getYValForMin()); + jgen.writeString(directBufferPoint.getAgentIdForMin()); + jgen.writeNumber(directBufferPoint.getYValForMax()); + jgen.writeString(directBufferPoint.getAgentIdForMax()); + jgen.writeNumber(directBufferPoint.getYValForAvg()); + jgen.writeEndArray(); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/FileDescriptorPointSerializer.java b/web/src/main/java/com/navercorp/pinpoint/web/view/FileDescriptorPointSerializer.java new file mode 100644 index 000000000000..b41d61133742 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/FileDescriptorPointSerializer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.view; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.navercorp.pinpoint.web.vo.stat.chart.application.FileDescriptorPoint; + +import java.io.IOException; + +/** + * @author Roy Kim + */ +public class FileDescriptorPointSerializer extends JsonSerializer { + + @Override + public void serialize(FileDescriptorPoint fileDescriptorPoint, JsonGenerator jgen, SerializerProvider serializers) throws IOException, JsonProcessingException { + jgen.writeStartArray(); + jgen.writeNumber(fileDescriptorPoint.getYValForMin()); + jgen.writeString(fileDescriptorPoint.getAgentIdForMin()); + jgen.writeNumber(fileDescriptorPoint.getYValForMax()); + jgen.writeString(fileDescriptorPoint.getAgentIdForMax()); + jgen.writeNumber(fileDescriptorPoint.getYValForAvg()); + jgen.writeEndArray(); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentActiveThreadCountList.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentActiveThreadCountList.java index 2b1f689cf583..86f918a2bca2 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentActiveThreadCountList.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentActiveThreadCountList.java @@ -47,7 +47,7 @@ public void add(AgentActiveThreadCount agentActiveThreadStatus) { public List getAgentActiveThreadRepository() { // sort agentId - Collections.sort(agentActiveThreadRepository, new Comparator() { + agentActiveThreadRepository.sort(new Comparator() { @Override public int compare(AgentActiveThreadCount o1, AgentActiveThreadCount o2) { final String agentId1 = StringUtils.defaultString(o1.getAgentId(), ""); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentActiveThreadDumpList.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentActiveThreadDumpList.java index 353c086f2f3e..b301844a613d 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentActiveThreadDumpList.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentActiveThreadDumpList.java @@ -51,8 +51,8 @@ public List getAgentActiveThreadDumpRepository() { } public List getSortOldestAgentActiveThreadDumpRepository() { - ArrayList copied = new ArrayList<>(agentActiveThreadDumpRepository); - Collections.sort(copied, new Comparator() { + List copied = new ArrayList<>(agentActiveThreadDumpRepository); + copied.sort(new Comparator() { private static final int CHANGE_TO_NEW_ELEMENT = 1; private static final int KEEP_OLD_ELEMENT = -1; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentInfo.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentInfo.java index 24b1a7fede98..da6ca01e6b01 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentInfo.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/AgentInfo.java @@ -52,6 +52,7 @@ public int compare(AgentInfo lhs, AgentInfo rhs) { private ServerMetaDataBo serverMetaData; private JvmInfoBo jvmInfo; private long initialStartTimestamp; + private boolean container; private AgentStatus status; public AgentInfo() { @@ -70,6 +71,7 @@ public AgentInfo(AgentInfoBo agentInfoBo) { this.agentVersion = agentInfoBo.getAgentVersion(); this.serverMetaData = agentInfoBo.getServerMetaData(); this.jvmInfo = agentInfoBo.getJvmInfo(); + this.container = agentInfoBo.isContainer(); } public String getApplicationName() { @@ -176,6 +178,14 @@ public void setInitialStartTimestamp(long initialStartTimestamp) { this.initialStartTimestamp = initialStartTimestamp; } + public boolean isContainer() { + return container; + } + + public void setContainer(boolean container) { + this.container = container; + } + public AgentStatus getStatus() { return status; } @@ -218,6 +228,7 @@ public String toString() { sb.append(", agentVersion='").append(agentVersion).append('\''); sb.append(", jvmInfo=").append(jvmInfo); sb.append(", initialStartTimestamp=").append(initialStartTimestamp); + sb.append(", container=").append(container); sb.append(", status=").append(status); sb.append('}'); return sb.toString(); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentList.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentList.java index 46d4811683b8..72249cefad20 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentList.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentList.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,64 +16,36 @@ package com.navercorp.pinpoint.web.vo; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.navercorp.pinpoint.web.view.ApplicationAgentListSerializer; - import java.util.List; -import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; +import java.util.Objects; /** - * @author minwoo.jung * @author HyunGil Jeong */ -@JsonSerialize(using = ApplicationAgentListSerializer.class) public class ApplicationAgentList { - public enum Key { - APPLICATION_NAME { - @Override - public String getKey(AgentInfo agentInfo) { - return agentInfo.getApplicationName(); - } - }, - HOST_NAME { - @Override - public String getKey(AgentInfo agentInfo) { - return agentInfo.getHostName(); - } - }; + private final String groupName; + private final List agentInfos; - public abstract String getKey(AgentInfo agentInfo); + public ApplicationAgentList(String groupName, List agentInfos) { + this.groupName = Objects.requireNonNull(groupName, "groupName must not be null"); + this.agentInfos = Objects.requireNonNull(agentInfos, "agentInfos must not be null"); } - private final SortedMap> applicationAgentList; - - public ApplicationAgentList() { - this.applicationAgentList = new TreeMap<>(); + public String getGroupName() { + return groupName; } - public ApplicationAgentList(SortedMap> applicationAgentList) { - if (applicationAgentList == null) { - throw new NullPointerException("applicationAgentList must not be null"); - } - this.applicationAgentList = applicationAgentList; + public List getAgentInfos() { + return agentInfos; } - public void merge(ApplicationAgentList applicationAgentList) { - for (Map.Entry> e : applicationAgentList.getApplicationAgentList().entrySet()) { - String key = e.getKey(); - if (this.applicationAgentList.containsKey(key)) { - this.applicationAgentList.get(key).addAll(e.getValue()); - } else { - this.applicationAgentList.put(key, e.getValue()); - } - } + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("{"); + sb.append('\'').append(groupName).append('\''); + sb.append(":").append(agentInfos); + sb.append('}'); + return sb.toString(); } - - public SortedMap> getApplicationAgentList() { - return this.applicationAgentList; - } - } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsList.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsList.java new file mode 100644 index 000000000000..62529b25c1bc --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsList.java @@ -0,0 +1,195 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.vo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.navercorp.pinpoint.common.annotations.VisibleForTesting; +import com.navercorp.pinpoint.web.view.ApplicationAgentsListSerializer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * @author minwoo.jung + * @author HyunGil Jeong + */ +@JsonSerialize(using = ApplicationAgentsListSerializer.class) +public class ApplicationAgentsList { + + public enum GroupBy { + APPLICATION_NAME { + @Override + protected GroupingKey extractKey(AgentInfo agentInfo) { + return new StringGroupingKey(agentInfo.getApplicationName()); + } + }, + HOST_NAME { + @Override + protected GroupingKey extractKey(AgentInfo agentInfo) { + return new HostNameContainerGroupingKey(agentInfo.getHostName(), agentInfo.isContainer()); + } + }; + + protected abstract GroupingKey extractKey(AgentInfo agentInfo); + } + + private interface GroupingKey> extends Comparable { + String value(); + } + + public interface Filter { + + boolean ACCEPT = true; + boolean REJECT = false; + + boolean filter(AgentInfo agentInfo); + + Filter NONE = agentInfo -> ACCEPT; + } + + private final GroupBy groupBy; + private final Filter filter; + private final SortedMap> agentsMap = new TreeMap<>(); + + public ApplicationAgentsList(GroupBy groupBy, Filter filter) { + this.groupBy = Objects.requireNonNull(groupBy, "groupBy must not be null"); + this.filter = Objects.requireNonNull(filter, "filter must not be null"); + } + + public void add(AgentInfo agentInfo) { + if (filter.filter(agentInfo) == Filter.REJECT) { + return; + } + GroupingKey key = groupBy.extractKey(agentInfo); + List agentInfos = agentsMap.computeIfAbsent(key, k -> new ArrayList<>()); + agentInfos.add(agentInfo); + } + + public void addAll(Iterable agentInfos) { + for (AgentInfo agentInfo : agentInfos) { + add(agentInfo); + } + } + + public void merge(ApplicationAgentsList applicationAgentList) { + for (List agentInfos : applicationAgentList.agentsMap.values()) { + addAll(agentInfos); + } + } + + public List getApplicationAgentLists() { + if (agentsMap.isEmpty()) { + return Collections.emptyList(); + } + List applicationAgentLists = new ArrayList<>(agentsMap.size()); + for (Map.Entry> e : agentsMap.entrySet()) { + GroupingKey groupingKey = e.getKey(); + List applicationAgents = new ArrayList<>(e.getValue()); + applicationAgents.sort(AgentInfo.AGENT_NAME_ASC_COMPARATOR); + applicationAgentLists.add(new ApplicationAgentList(groupingKey.value(), applicationAgents)); + } + return applicationAgentLists; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ApplicationAgentsList{"); + sb.append("groupBy=").append(groupBy); + sb.append(", agentsMap=").append(agentsMap); + sb.append('}'); + return sb.toString(); + } + + @VisibleForTesting + static class StringGroupingKey implements GroupingKey { + + private final String keyValue; + + private StringGroupingKey(String keyValue) { + this.keyValue = Objects.requireNonNull(keyValue, "keyValue must not be null"); + } + + @Override + public String value() { + return keyValue; + } + + @Override + public int compareTo(StringGroupingKey o) { + return keyValue.compareTo(o.keyValue); + } + + @Override + public String toString() { + return keyValue; + } + } + + @VisibleForTesting + static class HostNameContainerGroupingKey implements GroupingKey { + + public static final String CONTAINER = "Container"; + + private final StringGroupingKey hostNameGroupingKey; + private final boolean isContainer; + + private HostNameContainerGroupingKey(String hostName, boolean isContainer) { + String keyValue = Objects.requireNonNull(hostName, "hostName must not be null"); + if (isContainer) { + keyValue = CONTAINER; + } + this.hostNameGroupingKey = new StringGroupingKey(keyValue); + this.isContainer = isContainer; + } + + @Override + public String value() { + if (isContainer) { + return CONTAINER; + } + return hostNameGroupingKey.value(); + } + + @Override + public int compareTo(HostNameContainerGroupingKey o) { + if (isContainer && o.isContainer) { + return 0; + } + if (isContainer) { + return 1; + } + if (o.isContainer) { + return -1; + } + return hostNameGroupingKey.compareTo(o.hostNameGroupingKey); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("{"); + sb.append("hostName=").append(hostNameGroupingKey.value()); + sb.append(", isContainer=").append(isContainer); + sb.append('}'); + return sb.toString(); + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/ResponseHistograms.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/ResponseHistograms.java index ae74dde8c2f8..3ff6d8cc6610 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/ResponseHistograms.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/ResponseHistograms.java @@ -41,7 +41,7 @@ private ResponseHistograms(Map> responseTimeMap) } public List getResponseTimeList(Application application) { - List responseTimes = responseTimeMap.get(application); + List responseTimes = responseTimeMap.getOrDefault(application, Collections.emptyList()); return Collections.unmodifiableList(responseTimes); } @@ -83,11 +83,7 @@ public void addLinkHistogram(Application application, String agentId, TimeHistog } private ResponseTime getResponseTime(Application application, Long timestamp) { - Map responseTimeMap = responseTimeApplicationMap.get(timestamp); - if (responseTimeMap == null) { - responseTimeMap = new HashMap<>(); - responseTimeApplicationMap.put(timestamp, responseTimeMap); - } + Map responseTimeMap = responseTimeApplicationMap.computeIfAbsent(timestamp, (Long k) -> new HashMap<>()); ResponseTime responseTime = responseTimeMap.get(application); if (responseTime == null) { responseTime = new ResponseTime(application.getName(), application.getServiceType(), timestamp); @@ -101,12 +97,7 @@ public ResponseHistograms build() { for (Map entry : responseTimeApplicationMap.values()) { for (Map.Entry applicationResponseTimeEntry : entry.entrySet()) { - List responseTimeList = responseTimeMap.get(applicationResponseTimeEntry.getKey()); - if (responseTimeList == null) { - responseTimeList = new ArrayList<>(); - Application key = applicationResponseTimeEntry.getKey(); - responseTimeMap.put(key, responseTimeList); - } + List responseTimeList = responseTimeMap.computeIfAbsent(applicationResponseTimeEntry.getKey(), (Application k) -> new ArrayList<>()); responseTimeList.add(applicationResponseTimeEntry.getValue()); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/ResponseTime.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/ResponseTime.java index 7ddc0c901629..65a6209f07f8 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/ResponseTime.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/ResponseTime.java @@ -71,11 +71,7 @@ private Histogram getHistogram(String agentId) { if (agentId == null) { throw new NullPointerException("agentId must not be null"); } - TimeHistogram histogram = responseHistogramMap.get(agentId); - if (histogram == null) { - histogram = new TimeHistogram(applicationServiceType, timeStamp); - responseHistogramMap.put(agentId, histogram); - } + TimeHistogram histogram = responseHistogramMap.computeIfAbsent(agentId, k -> new TimeHistogram(applicationServiceType, timeStamp)); return histogram; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/User.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/User.java index 95d0f5880b3d..941f2da7b3b3 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/User.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/User.java @@ -80,8 +80,12 @@ public static List removeHyphenForPhoneNumberList(List phoneNumb List editedPhoneNumberList = new ArrayList<>(phoneNumberList.size()); for (String phoneNumber : phoneNumberList) { - if (phoneNumber != null && phoneNumber.contains("-")) { + if (phoneNumber == null) { + continue; + } else if (phoneNumber.contains("-")) { editedPhoneNumberList.add(phoneNumber.replace("-", "")); + } else { + editedPhoneNumberList.add(phoneNumber); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/AnnotationRecordFormatter.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/AnnotationRecordFormatter.java index 444a27ca665e..ccd5ca042a9a 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/AnnotationRecordFormatter.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/AnnotationRecordFormatter.java @@ -22,7 +22,6 @@ import com.navercorp.pinpoint.common.util.IntBooleanIntBooleanValue; import com.navercorp.pinpoint.common.util.LongIntIntByteByteStringValue; import com.navercorp.pinpoint.web.calltree.span.SpanAlign; -import com.navercorp.pinpoint.web.dao.StringMetaDataDao; import java.util.Objects; import java.util.concurrent.TimeUnit; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/ExceptionRecord.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/ExceptionRecord.java index 703fe01e0d0b..b8053edf78de 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/ExceptionRecord.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/ExceptionRecord.java @@ -31,6 +31,7 @@ public ExceptionRecord(final int tab, final int id, final int parentId, final Sp this.title = toSimpleExceptionName(align.getExceptionClass()); this.arguments = buildArgument(align.getExceptionMessage()); this.isAuthorized = true; + this.hasException = align.isSpan() ? false : true; } String toSimpleExceptionName(String exceptionClass) { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/RecordFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/RecordFactory.java index 8326e210181e..839fd505ba83 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/RecordFactory.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/callstacks/RecordFactory.java @@ -17,11 +17,9 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; import com.navercorp.pinpoint.common.server.bo.AnnotationBo; import com.navercorp.pinpoint.common.server.bo.ApiMetaDataBo; -import com.navercorp.pinpoint.common.server.bo.Event; import com.navercorp.pinpoint.common.server.bo.MethodTypeEnum; import com.navercorp.pinpoint.common.server.bo.SpanBo; import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; @@ -34,7 +32,6 @@ import com.navercorp.pinpoint.common.server.util.ApiDescriptionParser; import com.navercorp.pinpoint.web.calltree.span.CallTreeNode; import com.navercorp.pinpoint.web.calltree.span.SpanAlign; -import com.navercorp.pinpoint.web.dao.StringMetaDataDao; import com.navercorp.pinpoint.web.service.AnnotationKeyMatcherService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/exception/PinpointUserGroupException.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/exception/PinpointUserGroupException.java new file mode 100644 index 000000000000..072eda1e9fa4 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/exception/PinpointUserGroupException.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.vo.exception; + +/** + * @author minwoo.jung + */ +public class PinpointUserGroupException extends Exception { + + public PinpointUserGroupException(String message) { + super(message); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/scatter/ScatterScanResult.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/scatter/ScatterScanResult.java index 93487b1ed2f7..d6f130e30428 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/scatter/ScatterScanResult.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/scatter/ScatterScanResult.java @@ -79,12 +79,8 @@ public ScatterIndex getScatterIndex() { @JsonProperty("scatter") public Map> getScatter() { final Map> scatterAgentData = new HashMap<>(); - for(Dot dot : scatter) { - List list = scatterAgentData.get(dot.getAgentId()); - if(list == null) { - list = new ArrayList<>(); - scatterAgentData.put(dot.getAgentId(), list); - } + for (Dot dot : scatter) { + List list = scatterAgentData.computeIfAbsent(dot.getAgentId(), k -> new ArrayList<>()); list.add(dot); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinDataSourceBo.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinDataSourceBo.java index 4de6c42949d1..c1664662ec0f 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinDataSourceBo.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinDataSourceBo.java @@ -17,14 +17,13 @@ import com.navercorp.pinpoint.common.server.bo.stat.join.JoinDataSourceBo; -import java.util.List; /** * @author minwoo.jung */ public class AggreJoinDataSourceBo extends JoinDataSourceBo implements AggregationStatData { - private long timestamp = Long.MIN_VALUE; + private long timestamp; public AggreJoinDataSourceBo(short serviceTypeCode, String url, int avgActiveConnectionSize, int minActiveConnectionSize, String minActiveConnectionAgentId, int maxActiveConnectionSize, String maxActiveConnectionAgentId ,long timestamp) { @@ -36,4 +35,22 @@ public AggreJoinDataSourceBo(short serviceTypeCode, String url, int avgActiveCon public long getTimestamp() { return timestamp; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AggreJoinDataSourceBo)) return false; + if (!super.equals(o)) return false; + + AggreJoinDataSourceBo that = (AggreJoinDataSourceBo) o; + + return timestamp == that.timestamp; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (int) (timestamp ^ (timestamp >>> 32)); + return result; + } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinDirectBufferBo.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinDirectBufferBo.java new file mode 100644 index 000000000000..5034612970a2 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinDirectBufferBo.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.vo.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinDirectBufferBo; + +/** + * @author Roy Kim + */ +public class AggreJoinDirectBufferBo extends JoinDirectBufferBo implements AggregationStatData { + + public AggreJoinDirectBufferBo() { + } + + public AggreJoinDirectBufferBo(String id, long avgDirectCount, long maxDirectCount, String maxDirectCountAgentId, long minDirectCount, String minDirectCountAgentId, long avgDirectMemoryUsed, long maxDirectMemoryUsed, String maxDirectMemoryUsedAgentId, long minDirectMemoryUsed, String minDirectMemoryUsedAgentId, long avgMappedCount, long maxMappedCount, String maxMappedCountAgentId, long minMappedCount, String minMappedCountAgentId, long avgMappedMemoryUsed, long maxMappedMemoryUsed, String maxMappedMemoryUsedAgentId, long minMappedMemoryUsed, String minMappedMemoryUsedAgentId, long timestamp) { + super(id, avgDirectCount, maxDirectCount, maxDirectCountAgentId, minDirectCount, minDirectCountAgentId, avgDirectMemoryUsed, maxDirectMemoryUsed, maxDirectMemoryUsedAgentId, minDirectMemoryUsed, minDirectMemoryUsedAgentId, avgMappedCount, maxMappedCount, maxMappedCountAgentId, minMappedCount, minMappedCountAgentId, avgMappedMemoryUsed, maxMappedMemoryUsed, maxMappedMemoryUsedAgentId, minMappedMemoryUsed, minMappedMemoryUsedAgentId, timestamp); + } + + public static AggreJoinDirectBufferBo createUncollectedObject(long timestamp) { + AggreJoinDirectBufferBo aggreJoinDirectBufferBo = new AggreJoinDirectBufferBo(); + aggreJoinDirectBufferBo.setTimestamp(timestamp); + return aggreJoinDirectBufferBo; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinFileDescriptorBo.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinFileDescriptorBo.java new file mode 100644 index 000000000000..d0c6b945f4d9 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/AggreJoinFileDescriptorBo.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.vo.stat; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinFileDescriptorBo; + +/** + * @author Roy Kim + */ +public class AggreJoinFileDescriptorBo extends JoinFileDescriptorBo implements AggregationStatData { + + public AggreJoinFileDescriptorBo() { + } + + public AggreJoinFileDescriptorBo(String id, long avgOpenFDCount, long maxOpenFDCount, String maxOpenFDCountAgentId, long minOpenFDCount, String minOpenFDCountAgentId, long timestamp) { + super(id, avgOpenFDCount, maxOpenFDCount, maxOpenFDCountAgentId, minOpenFDCount, minOpenFDCountAgentId, timestamp); + } + + public static AggreJoinFileDescriptorBo createUncollectedObject(long timestamp) { + AggreJoinFileDescriptorBo aggreJoinFileDescriptorBo = new AggreJoinFileDescriptorBo(); + aggreJoinFileDescriptorBo.setTimestamp(timestamp); + return aggreJoinFileDescriptorBo; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/SampledDirectBuffer.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/SampledDirectBuffer.java new file mode 100644 index 000000000000..53f427bd4ebb --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/SampledDirectBuffer.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.vo.stat; + +import com.navercorp.pinpoint.web.vo.chart.Point; +import com.navercorp.pinpoint.web.vo.stat.chart.agent.AgentStatPoint; + +import java.util.Objects; + +/** + * @author Roy Kim + */ +public class SampledDirectBuffer implements SampledAgentStatDataPoint { + + public static final Long UNCOLLECTED_VALUE = -1L; + public static final Point.UncollectedPointCreator> UNCOLLECTED_POINT_CREATOR = new Point.UncollectedPointCreator>() { + @Override + public AgentStatPoint createUnCollectedPoint(long xVal) { + return new AgentStatPoint<>(xVal, UNCOLLECTED_VALUE); + } + }; + + private final AgentStatPoint directCount; + private final AgentStatPoint directMemoryUsed; + private final AgentStatPoint mappedCount; + private final AgentStatPoint mappedMemoryUsed; + + public SampledDirectBuffer(AgentStatPoint directCount, AgentStatPoint directMemoryUsed, AgentStatPoint mappedCount, AgentStatPoint mappedMemoryUsed) { + this.directCount = Objects.requireNonNull(directCount, "directCount must not be null"); + this.directMemoryUsed = Objects.requireNonNull(directMemoryUsed, "directMemoryUsed must not be null"); + this.mappedCount = Objects.requireNonNull(mappedCount, "mappedCount must not be null"); + this.mappedMemoryUsed = Objects.requireNonNull(mappedMemoryUsed, "mappedMemoryUsed must not be null"); + } + public AgentStatPoint getDirectCount() { + return directCount; + } + + public AgentStatPoint getDirectMemoryUsed() { + return directMemoryUsed; + } + + public AgentStatPoint getMappedCount() { + return mappedCount; + } + + public AgentStatPoint getMappedMemoryUsed() { + return mappedMemoryUsed; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("SampledDirectBuffer{"); + sb.append("directCount=").append(directCount); + sb.append("directMemoryUsed=").append(directMemoryUsed); + sb.append("mappedCount=").append(mappedCount); + sb.append("mappedMemoryUsed=").append(mappedMemoryUsed); + sb.append('}'); + return sb.toString(); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/SampledFileDescriptor.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/SampledFileDescriptor.java new file mode 100644 index 000000000000..6cd739f2c0de --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/SampledFileDescriptor.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Naver Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.vo.stat; + +import com.navercorp.pinpoint.web.vo.chart.Point; +import com.navercorp.pinpoint.web.vo.stat.chart.agent.AgentStatPoint; + +import java.util.Objects; + +/** + * @author Roy Kim + */ +public class SampledFileDescriptor implements SampledAgentStatDataPoint { + + public static final Long UNCOLLECTED_VALUE = -1L; + public static final Point.UncollectedPointCreator> UNCOLLECTED_POINT_CREATOR = new Point.UncollectedPointCreator>() { + @Override + public AgentStatPoint createUnCollectedPoint(long xVal) { + return new AgentStatPoint<>(xVal, UNCOLLECTED_VALUE); + } + }; + + private final AgentStatPoint openFileDescriptorCount; + + public SampledFileDescriptor(AgentStatPoint openFileDescriptorCount) { + this.openFileDescriptorCount = Objects.requireNonNull(openFileDescriptorCount, "openFileDescriptorCount must not be null"); + } + + public AgentStatPoint getOpenFileDescriptorCount() { + return openFileDescriptorCount; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("SampledFileDescriptor{"); + sb.append("openFileDescriptorCount=").append(openFileDescriptorCount); + sb.append('}'); + return sb.toString(); + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DirectBufferChart.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DirectBufferChart.java new file mode 100644 index 000000000000..e84fbf07d571 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DirectBufferChart.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.vo.stat.chart.agent; + +import com.google.common.collect.ImmutableMap; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.chart.Chart; +import com.navercorp.pinpoint.web.vo.chart.Point; +import com.navercorp.pinpoint.web.vo.chart.TimeSeriesChartBuilder; +import com.navercorp.pinpoint.web.vo.stat.SampledDirectBuffer; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChart; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChartGroup; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * @author Roy Kim + */ +public class DirectBufferChart implements StatChart { + + private final DirectBufferChartGroup DirectBufferChartGroup; + + public DirectBufferChart(TimeWindow timeWindow, List sampledDirectBuffers) { + this.DirectBufferChartGroup = new DirectBufferChartGroup(timeWindow, sampledDirectBuffers); + } + + @Override + public StatChartGroup getCharts() { + return DirectBufferChartGroup; + } + + public static class DirectBufferChartGroup implements StatChartGroup { + + private final TimeWindow timeWindow; + + private Map> DirectBufferCharts; + + public enum DirectBufferChartType implements AgentChartType { + DIRECT_COUNT, + DIRECT_MEMORY_USED, + MAPPED_COUNT, + MAPPED_MEMORY_USED + } + + private DirectBufferChartGroup(TimeWindow timeWindow, List sampledDirectBuffers) { + this.timeWindow = timeWindow; + this.DirectBufferCharts = newChart(sampledDirectBuffers); + } + + private Map> newChart(List sampledDirectBuffers) { + Chart> directCount = newChart(sampledDirectBuffers, SampledDirectBuffer::getDirectCount); + Chart> directMemoryUsed = newChart(sampledDirectBuffers, SampledDirectBuffer::getDirectMemoryUsed); + Chart> mappedCount = newChart(sampledDirectBuffers, SampledDirectBuffer::getMappedCount); + Chart> mappedMemoryUsed = newChart(sampledDirectBuffers, SampledDirectBuffer::getMappedMemoryUsed); + + return ImmutableMap.of(DirectBufferChartType.DIRECT_COUNT, directCount, + DirectBufferChartType.DIRECT_MEMORY_USED, directMemoryUsed, + DirectBufferChartType.MAPPED_COUNT, mappedCount, + DirectBufferChartType.MAPPED_MEMORY_USED, mappedMemoryUsed); + } + + private Chart> newChart(List sampledActiveTraces, Function> function) { + TimeSeriesChartBuilder> builder = new TimeSeriesChartBuilder<>(this.timeWindow, SampledDirectBuffer.UNCOLLECTED_POINT_CREATOR); + return builder.build(sampledActiveTraces, function); + } + + + + @Override + public TimeWindow getTimeWindow() { + return timeWindow; + } + + @Override + public Map> getCharts() { + return DirectBufferCharts; + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/FileDescriptorChart.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/FileDescriptorChart.java new file mode 100644 index 000000000000..ae257e31c698 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/FileDescriptorChart.java @@ -0,0 +1,86 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.vo.stat.chart.agent; + +import com.google.common.collect.ImmutableMap; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.chart.Chart; +import com.navercorp.pinpoint.web.vo.chart.Point; +import com.navercorp.pinpoint.web.vo.chart.TimeSeriesChartBuilder; +import com.navercorp.pinpoint.web.vo.stat.SampledFileDescriptor; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChart; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChartGroup; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * @author Roy Kim + */ +public class FileDescriptorChart implements StatChart { + + private final FileDescriptorChartGroup FileDescriptorChartGroup; + + public FileDescriptorChart(TimeWindow timeWindow, List sampledFileDescriptors) { + this.FileDescriptorChartGroup = new FileDescriptorChartGroup(timeWindow, sampledFileDescriptors); + } + + @Override + public StatChartGroup getCharts() { + return FileDescriptorChartGroup; + } + + public static class FileDescriptorChartGroup implements StatChartGroup { + + private final TimeWindow timeWindow; + + private Map> FileDescriptorCharts; + + public enum FileDescriptorChartType implements AgentChartType { + OPEN_FILE_DESCRIPTOR_COUNT + } + + private FileDescriptorChartGroup(TimeWindow timeWindow, List sampledFileDescriptors) { + this.timeWindow = timeWindow; + this.FileDescriptorCharts = newChart(sampledFileDescriptors); + } + + private Map> newChart(List sampledFileDescriptors) { + Chart> openFileDescriptorChart = newChart(sampledFileDescriptors, SampledFileDescriptor::getOpenFileDescriptorCount); + + return ImmutableMap.of(FileDescriptorChartType.OPEN_FILE_DESCRIPTOR_COUNT, openFileDescriptorChart); + } + + private Chart> newChart(List sampledActiveTraces, Function> function) { + TimeSeriesChartBuilder> builder = new TimeSeriesChartBuilder<>(this.timeWindow, SampledFileDescriptor.UNCOLLECTED_POINT_CREATOR); + return builder.build(sampledActiveTraces, function); + } + + + + @Override + public TimeWindow getTimeWindow() { + return timeWindow; + } + + @Override + public Map> getCharts() { + return FileDescriptorCharts; + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationDirectBufferChart.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationDirectBufferChart.java new file mode 100644 index 000000000000..5d14930731e4 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationDirectBufferChart.java @@ -0,0 +1,109 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.vo.stat.chart.application; + +import com.google.common.collect.ImmutableMap; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.chart.Chart; +import com.navercorp.pinpoint.web.vo.chart.Point; +import com.navercorp.pinpoint.web.vo.chart.TimeSeriesChartBuilder; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinDirectBufferBo; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChart; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChartGroup; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * @author Roy Kim + */ +public class ApplicationDirectBufferChart implements StatChart { + + private final ApplicationDirectBufferChartGroup directBufferChartGroup; + + public ApplicationDirectBufferChart(TimeWindow timeWindow, List aggreJoinDirectBufferBoList) { + this.directBufferChartGroup = new ApplicationDirectBufferChartGroup(timeWindow, aggreJoinDirectBufferBoList); + } + + @Override + public StatChartGroup getCharts() { + return directBufferChartGroup; + } + + public static class ApplicationDirectBufferChartGroup implements StatChartGroup { + + private static final DirectBufferPoint.UncollectedDirectBufferPointCreator UNCOLLECTED_FILE_DESCRIPTOR_POINT = new DirectBufferPoint.UncollectedDirectBufferPointCreator(); + + private final TimeWindow timeWindow; + private final Map> directBufferChartMap; + + public enum DirectBufferChartType implements ApplicationChartType { + DIRECT_COUNT, + DIRECT_MEMORY_USED, + MAPPED_COUNT, + MAPPED_MEMORY_USED + } + + public ApplicationDirectBufferChartGroup(TimeWindow timeWindow, List aggreDirectBufferList) { + this.timeWindow = timeWindow; + this.directBufferChartMap = newChart(aggreDirectBufferList); + } + + private Map> newChart(List aggreDirectBufferList) { + Chart directCountChart = newChart(aggreDirectBufferList, this::newDirectCount); + Chart directMemoryUsedChart = newChart(aggreDirectBufferList, this::newDirectMemoryUsed); + Chart mappedCountChart = newChart(aggreDirectBufferList, this::newMappedCount); + Chart mappedMemoryUsedChart = newChart(aggreDirectBufferList, this::newMappedMemoryUsed); + return ImmutableMap.of(DirectBufferChartType.DIRECT_COUNT, directCountChart + , DirectBufferChartType.DIRECT_MEMORY_USED, directMemoryUsedChart + , DirectBufferChartType.MAPPED_COUNT, mappedCountChart + , DirectBufferChartType.MAPPED_MEMORY_USED, mappedMemoryUsedChart); + } + + private Chart newChart(List directBufferList, Function filter) { + + TimeSeriesChartBuilder builder = new TimeSeriesChartBuilder<>(this.timeWindow, UNCOLLECTED_FILE_DESCRIPTOR_POINT); + return builder.build(directBufferList, filter); + } + + private DirectBufferPoint newDirectCount(AggreJoinDirectBufferBo directBuffer) { + return new DirectBufferPoint(directBuffer.getTimestamp(), directBuffer.getMinDirectCount(), directBuffer.getMinDirectCountAgentId(), directBuffer.getMaxDirectCount(), directBuffer.getMaxDirectCountAgentId(), directBuffer.getAvgDirectCount()); + } + + private DirectBufferPoint newDirectMemoryUsed(AggreJoinDirectBufferBo directBuffer) { + return new DirectBufferPoint(directBuffer.getTimestamp(), directBuffer.getMinDirectMemoryUsed(), directBuffer.getMinDirectMemoryUsedAgentId(), directBuffer.getMaxDirectMemoryUsed(), directBuffer.getMaxDirectMemoryUsedAgentId(), directBuffer.getAvgDirectMemoryUsed()); + } + + private DirectBufferPoint newMappedCount(AggreJoinDirectBufferBo directBuffer) { + return new DirectBufferPoint(directBuffer.getTimestamp(), directBuffer.getMinMappedCount(), directBuffer.getMinMappedCountAgentId(), directBuffer.getMaxMappedCount(), directBuffer.getMaxMappedCountAgentId(), directBuffer.getAvgMappedCount()); + } + + private DirectBufferPoint newMappedMemoryUsed(AggreJoinDirectBufferBo directBuffer) { + return new DirectBufferPoint(directBuffer.getTimestamp(), directBuffer.getMinMappedMemoryUsed(), directBuffer.getMinMappedMemoryUsedAgentId(), directBuffer.getMaxMappedMemoryUsed(), directBuffer.getMaxMappedMemoryUsedAgentId(), directBuffer.getAvgMappedMemoryUsed()); + } + + @Override + public TimeWindow getTimeWindow() { + return timeWindow; + } + + @Override + public Map> getCharts() { + return this.directBufferChartMap; + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationFileDescriptorChart.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationFileDescriptorChart.java new file mode 100644 index 000000000000..77e7e763edcc --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationFileDescriptorChart.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.vo.stat.chart.application; + +import com.google.common.collect.ImmutableMap; +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.chart.Chart; +import com.navercorp.pinpoint.web.vo.chart.Point; +import com.navercorp.pinpoint.web.vo.chart.TimeSeriesChartBuilder; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinFileDescriptorBo; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChart; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChartGroup; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * @author Roy Kim + */ +public class ApplicationFileDescriptorChart implements StatChart { + + private final ApplicationFileDescriptorChartGroup fileDescriptorChartGroup; + + public ApplicationFileDescriptorChart(TimeWindow timeWindow, List aggreJoinFileDescriptorBoList) { + this.fileDescriptorChartGroup = new ApplicationFileDescriptorChartGroup(timeWindow, aggreJoinFileDescriptorBoList); + } + + @Override + public StatChartGroup getCharts() { + return fileDescriptorChartGroup; + } + + public static class ApplicationFileDescriptorChartGroup implements StatChartGroup { + + private static final FileDescriptorPoint.UncollectedFileDescriptorPointCreator UNCOLLECTED_FILE_DESCRIPTOR_POINT = new FileDescriptorPoint.UncollectedFileDescriptorPointCreator(); + + private final TimeWindow timeWindow; + private final Map> fileDescriptorChartMap; + + public enum FileDescriptorChartType implements ApplicationChartType { + OPEN_FILE_DESCRIPTOR_COUNT + } + + public ApplicationFileDescriptorChartGroup(TimeWindow timeWindow, List aggreFileDescriptorList) { + this.timeWindow = timeWindow; + this.fileDescriptorChartMap = newChart(aggreFileDescriptorList); + } + + private Map> newChart(List aggreFileDescriptorList) { + Chart openFileDescriptorCountChart = newChart(aggreFileDescriptorList, this::newOpenFileDescriptorCount); + return ImmutableMap.of(FileDescriptorChartType.OPEN_FILE_DESCRIPTOR_COUNT, openFileDescriptorCountChart); + } + + private Chart newChart(List fileDescriptorList, Function filter) { + + TimeSeriesChartBuilder builder = new TimeSeriesChartBuilder<>(this.timeWindow, UNCOLLECTED_FILE_DESCRIPTOR_POINT); + return builder.build(fileDescriptorList, filter); + } + + private FileDescriptorPoint newOpenFileDescriptorCount(AggreJoinFileDescriptorBo fileDescriptor) { + return new FileDescriptorPoint(fileDescriptor.getTimestamp(), fileDescriptor.getMinOpenFDCount(), fileDescriptor.getMinOpenFDCountAgentId(), fileDescriptor.getMaxOpenFDCount(), fileDescriptor.getMaxOpenFDCountAgentId(), fileDescriptor.getAvgOpenFDCount()); + } + + @Override + public TimeWindow getTimeWindow() { + return timeWindow; + } + + @Override + public Map> getCharts() { + return this.fileDescriptorChartMap; + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/DirectBufferPoint.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/DirectBufferPoint.java new file mode 100644 index 000000000000..91f1d4d236e1 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/DirectBufferPoint.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.vo.stat.chart.application; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinDirectBufferBo; +import com.navercorp.pinpoint.web.view.DirectBufferPointSerializer; +import com.navercorp.pinpoint.web.vo.chart.Point; + +/** + * @author Roy Kim + */ +@JsonSerialize(using = DirectBufferPointSerializer.class) +public class DirectBufferPoint implements Point { + + private final long xVal; + private final long yValForMin; + private final String agentIdForMin; + private final long yValForMax; + private final String agentIdForMax; + private final long yValForAvg; + + public DirectBufferPoint(long xVal, long yValForMin, String agentIdForMin, long yValForMax, String agentIdForMax, long yValForAvg) { + this.xVal = xVal; + this.yValForMin = yValForMin; + this.agentIdForMin = agentIdForMin; + this.yValForMax = yValForMax; + this.agentIdForMax = agentIdForMax; + this.yValForAvg = yValForAvg; + } + + public long getYValForMin() { + return yValForMin; + } + + public String getAgentIdForMin() { + return agentIdForMin; + } + + public long getYValForMax() { + return yValForMax; + } + + public String getAgentIdForMax() { + return agentIdForMax; + } + + public long getYValForAvg() { + return yValForAvg; + } + + @Override + public long getXVal() { + return this.xVal; + } + + public static class UncollectedDirectBufferPointCreator implements UncollectedPointCreator { + @Override + public DirectBufferPoint createUnCollectedPoint(long xVal) { + return new DirectBufferPoint(xVal, JoinDirectBufferBo.UNCOLLECTED_VALUE, JoinDirectBufferBo.UNKNOWN_AGENT, JoinDirectBufferBo.UNCOLLECTED_VALUE, JoinDirectBufferBo.UNKNOWN_AGENT, JoinDirectBufferBo.UNCOLLECTED_VALUE); + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/FileDescriptorPoint.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/FileDescriptorPoint.java new file mode 100644 index 000000000000..cb414159c222 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/stat/chart/application/FileDescriptorPoint.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.vo.stat.chart.application; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinFileDescriptorBo; +import com.navercorp.pinpoint.web.view.FileDescriptorPointSerializer; +import com.navercorp.pinpoint.web.vo.chart.Point; + +/** + * @author Roy Kim + */ +@JsonSerialize(using = FileDescriptorPointSerializer.class) +public class FileDescriptorPoint implements Point { + + private final long xVal; + private final long yValForMin; + private final String agentIdForMin; + private final long yValForMax; + private final String agentIdForMax; + private final long yValForAvg; + + public FileDescriptorPoint(long xVal, long yValForMin, String agentIdForMin, long yValForMax, String agentIdForMax, long yValForAvg) { + this.xVal = xVal; + this.yValForMin = yValForMin; + this.agentIdForMin = agentIdForMin; + this.yValForMax = yValForMax; + this.agentIdForMax = agentIdForMax; + this.yValForAvg = yValForAvg; + } + + public long getYValForMin() { + return yValForMin; + } + + public String getAgentIdForMin() { + return agentIdForMin; + } + + public long getYValForMax() { + return yValForMax; + } + + public String getAgentIdForMax() { + return agentIdForMax; + } + + public long getYValForAvg() { + return yValForAvg; + } + + @Override + public long getXVal() { + return this.xVal; + } + + public static class UncollectedFileDescriptorPointCreator implements UncollectedPointCreator { + @Override + public FileDescriptorPoint createUnCollectedPoint(long xVal) { + return new FileDescriptorPoint(xVal, JoinFileDescriptorBo.UNCOLLECTED_VALUE, JoinFileDescriptorBo.UNKNOWN_AGENT, JoinFileDescriptorBo.UNCOLLECTED_VALUE, JoinFileDescriptorBo.UNKNOWN_AGENT, JoinFileDescriptorBo.UNCOLLECTED_VALUE); + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/vo/timeline/inspector/AgentStatusTimelineBuilder.java b/web/src/main/java/com/navercorp/pinpoint/web/vo/timeline/inspector/AgentStatusTimelineBuilder.java index e767149ccfe1..6468801fc316 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/vo/timeline/inspector/AgentStatusTimelineBuilder.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/vo/timeline/inspector/AgentStatusTimelineBuilder.java @@ -212,18 +212,15 @@ private Map> partitionByStartTimestamp(List a Map> partitions = new HashMap<>(); for (AgentEvent agentEvent : agentEvents) { long startTimestamp = agentEvent.getStartTimestamp(); - List partition = partitions.get(startTimestamp); - if (partition == null) { - partition = new ArrayList<>(); - partitions.put(startTimestamp, partition); - } + List partition = partitions.computeIfAbsent(startTimestamp, k -> new ArrayList<>()); partition.add(agentEvent); } return partitions; } private AgentLifeCycle createAgentLifeCycle(long agentStartTimestamp, List agentEvents) { - Collections.sort(agentEvents, AgentEvent.EVENT_TIMESTAMP_ASC_COMPARATOR); + agentEvents.sort(AgentEvent.EVENT_TIMESTAMP_ASC_COMPARATOR); + AgentEvent first = agentEvents.get(0); AgentEvent last = agentEvents.get(agentEvents.size() - 1); AgentState endState = AgentState.fromAgentEvent(last); @@ -239,7 +236,8 @@ private AgentLifeCycle createAgentLifeCycle(long agentStartTimestamp, List mergeOverlappingLifeCycles(List agentLifeCycles) { - Collections.sort(agentLifeCycles, AgentLifeCycle.START_TIMESTAMP_ASC_COMPARATOR); + agentLifeCycles.sort(AgentLifeCycle.START_TIMESTAMP_ASC_COMPARATOR); + Queue mergedAgentLifeCycles = new PriorityQueue<>(agentLifeCycles.size(), AgentLifeCycle.START_TIMESTAMP_ASC_COMPARATOR); for (AgentLifeCycle agentLifeCycle : agentLifeCycles) { Iterator mergedAgentLifeCyclesIterator = mergedAgentLifeCycles.iterator(); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountHandler.java b/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountHandler.java index 8eca77645915..2433f4144103 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountHandler.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountHandler.java @@ -22,6 +22,8 @@ import com.navercorp.pinpoint.rpc.util.MapUtils; import com.navercorp.pinpoint.web.security.ServerMapDataFilter; import com.navercorp.pinpoint.web.service.AgentService; +import com.navercorp.pinpoint.web.task.TimerTaskDecorator; +import com.navercorp.pinpoint.web.task.TimerTaskDecoratorFactory; import com.navercorp.pinpoint.web.util.SimpleOrderedThreadPool; import com.navercorp.pinpoint.web.websocket.message.PinpointWebSocketMessage; import com.navercorp.pinpoint.web.websocket.message.PinpointWebSocketMessageConverter; @@ -68,21 +70,25 @@ public class ActiveThreadCountHandler extends TextWebSocketHandler implements Pi private final AtomicBoolean onTimerTask = new AtomicBoolean(false); + private SimpleOrderedThreadPool webSocketFlushExecutor; - private java.util.Timer flushTimer; + private Timer flushTimer; private static final long DEFAULT_FLUSH_DELAY = 1000; private final long flushDelay; - private java.util.Timer healthCheckTimer; + private Timer healthCheckTimer; private static final long DEFAULT_HEALTH_CHECk_DELAY = 60 * 1000; private final long healthCheckDelay; - private java.util.Timer reactiveTimer; - + private Timer reactiveTimer; + @Autowired(required=false) ServerMapDataFilter serverMapDataFilter; + @Autowired(required = false) + private TimerTaskDecoratorFactory timerTaskDecoratorFactory = new PinpointWebSocketTimerTaskDecoratorFactory(); + public ActiveThreadCountHandler(AgentService agentService) { this(DEFAULT_REQUEST_MAPPING, agentService); } @@ -113,7 +119,7 @@ public void start() { } private Timer newJavaTimer(String timerName) { - return new java.util.Timer(timerName, true); + return new Timer(timerName, true); } @Override @@ -272,7 +278,8 @@ private void bindingResponseAggregator(WebSocketSession webSocketSession, WebSoc PinpointWebSocketResponseAggregator responseAggregator = aggregatorRepository.get(applicationName); if (responseAggregator == null) { - responseAggregator = new ActiveThreadCountResponseAggregator(applicationName, agentService, reactiveTimer); + TimerTaskDecorator timerTaskDecorator = timerTaskDecoratorFactory.createTimerTaskDecorator(); + responseAggregator = new ActiveThreadCountResponseAggregator(applicationName, agentService, reactiveTimer, timerTaskDecorator); responseAggregator.start(); aggregatorRepository.put(applicationName, responseAggregator); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountResponseAggregator.java b/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountResponseAggregator.java index 766c233504f9..de1e1901bc03 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountResponseAggregator.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountResponseAggregator.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; import com.navercorp.pinpoint.web.service.AgentService; +import com.navercorp.pinpoint.web.task.TimerTaskDecorator; import com.navercorp.pinpoint.web.vo.AgentActiveThreadCount; import com.navercorp.pinpoint.web.vo.AgentActiveThreadCountList; import com.navercorp.pinpoint.web.vo.AgentInfo; @@ -32,6 +33,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Timer; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -55,6 +57,7 @@ public class ActiveThreadCountResponseAggregator implements PinpointWebSocketRes private final String applicationName; private final AgentService agentService; private final Timer timer; + private final TimerTaskDecorator timerTaskDecorator; private final Object workerManagingLock = new Object(); private final List webSocketSessions = new CopyOnWriteArrayList<>(); @@ -70,11 +73,12 @@ public class ActiveThreadCountResponseAggregator implements PinpointWebSocketRes private Map activeThreadCountMap = new HashMap<>(); - public ActiveThreadCountResponseAggregator(String applicationName, AgentService agentService, Timer timer) { - this.applicationName = applicationName; - this.agentService = agentService; + public ActiveThreadCountResponseAggregator(String applicationName, AgentService agentService, Timer timer, TimerTaskDecorator timerTaskDecorator) { + this.applicationName = Objects.requireNonNull(applicationName, "applicationName must not be null"); + this.agentService = Objects.requireNonNull(agentService, "agentService must not be null"); - this.timer = timer; + this.timer = Objects.requireNonNull(timer, "timer must not be null"); + this.timerTaskDecorator = Objects.requireNonNull(timerTaskDecorator, "timerTaskDecorator must not be null"); this.messageConverter = new PinpointWebSocketMessageConverter(); } @@ -82,7 +86,7 @@ public ActiveThreadCountResponseAggregator(String applicationName, AgentService @Override public void start() { synchronized (workerManagingLock) { - workerActiveManager = new WorkerActiveManager(this, agentService, timer); + workerActiveManager = new WorkerActiveManager(this, agentService, timer, timerTaskDecorator); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountWorker.java b/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountWorker.java index 99bcbdbc8d7f..19a260866986 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountWorker.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/websocket/ActiveThreadCountWorker.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -39,6 +39,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Objects; + /** * @author Taejin Koo */ @@ -76,13 +78,12 @@ public ActiveThreadCountWorker(AgentService agentService, AgentInfo agentInfo, P } public ActiveThreadCountWorker(AgentService agentService, String applicationName, String agentId, PinpointWebSocketResponseAggregator webSocketResponseAggregator, WorkerActiveManager workerActiveManager) { - this.agentService = agentService; - - this.applicationName = applicationName; - this.agentId = agentId; + this.agentService = Objects.requireNonNull(agentService, "agentService must not be null"); + this.applicationName = Objects.requireNonNull(applicationName, "applicationName must not be null"); + this.agentId = Objects.requireNonNull(agentId, "agentId must not be null"); - this.responseAggregator = webSocketResponseAggregator; - this.workerActiveManager = workerActiveManager; + this.responseAggregator = Objects.requireNonNull(webSocketResponseAggregator, "responseAggregator must not be null"); + this.workerActiveManager = Objects.requireNonNull(workerActiveManager, "workerActiveManager must not be null"); AgentActiveThreadCountFactory failResponseFactory = new AgentActiveThreadCountFactory(); failResponseFactory.setAgentId(agentId); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/websocket/CustomHandshakeInterceptor.java b/web/src/main/java/com/navercorp/pinpoint/web/websocket/CustomHandshakeInterceptor.java new file mode 100644 index 000000000000..8f725dd6dbbc --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/websocket/CustomHandshakeInterceptor.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.websocket; + +import org.springframework.web.socket.server.HandshakeInterceptor; + +/** + * @author minwoo.jung + */ +public interface CustomHandshakeInterceptor extends HandshakeInterceptor { +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/websocket/DefaultWebSocketHandlerDecoratorFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/websocket/DefaultWebSocketHandlerDecoratorFactory.java new file mode 100644 index 000000000000..494722883250 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/websocket/DefaultWebSocketHandlerDecoratorFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.web.websocket; + +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory; + +/** + * @author minwoo.jung + */ +public class DefaultWebSocketHandlerDecoratorFactory implements WebSocketHandlerDecoratorFactory { + + @Override + public WebSocketHandler decorate(WebSocketHandler handler) { + return handler; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/websocket/PinpointWebSocketTimerTaskDecoratorFactory.java b/web/src/main/java/com/navercorp/pinpoint/web/websocket/PinpointWebSocketTimerTaskDecoratorFactory.java new file mode 100644 index 000000000000..97a13170d317 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/websocket/PinpointWebSocketTimerTaskDecoratorFactory.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.websocket; + +import com.navercorp.pinpoint.web.task.TimerTaskDecorator; +import com.navercorp.pinpoint.web.task.TimerTaskDecoratorFactory; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.TimerTask; + +/** + * @author HyunGil Jeong + */ +public class PinpointWebSocketTimerTaskDecoratorFactory implements TimerTaskDecoratorFactory { + + @Override + public TimerTaskDecorator createTimerTaskDecorator() { + return new SecurityContextPreservingTimerTaskDecorator(); + } + + private static class SecurityContextPreservingTimerTaskDecorator implements TimerTaskDecorator { + + private final SecurityContext securityContext; + + private SecurityContextPreservingTimerTaskDecorator() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + SecurityContext currentSecurityContext = SecurityContextHolder.getContext(); + Authentication authentication = currentSecurityContext.getAuthentication(); + if (authentication != null) { + securityContext.setAuthentication(authentication); + } + this.securityContext = securityContext; + } + + @Override + public TimerTask decorate(TimerTask timerTask) { + return new TimerTask() { + @Override + public void run() { + SecurityContext previousSecurityContext = SecurityContextHolder.getContext(); + try { + SecurityContextHolder.setContext(securityContext); + timerTask.run(); + } finally { + SecurityContextHolder.setContext(previousSecurityContext); + } + } + }; + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/websocket/WorkerActiveManager.java b/web/src/main/java/com/navercorp/pinpoint/web/websocket/WorkerActiveManager.java index 212295d10e49..f84bf24fd321 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/websocket/WorkerActiveManager.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/websocket/WorkerActiveManager.java @@ -18,6 +18,7 @@ import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; import com.navercorp.pinpoint.web.service.AgentService; +import com.navercorp.pinpoint.web.task.TimerTaskDecorator; import com.navercorp.pinpoint.web.vo.AgentInfo; import com.navercorp.pinpoint.web.vo.AgentStatus; import org.slf4j.Logger; @@ -26,6 +27,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.Timer; import java.util.TimerTask; @@ -39,7 +41,7 @@ public class WorkerActiveManager { private static final long DEFAULT_RECONNECT_DELAY = 5000; - private static final long DEFAULT_AGENT_CHECk_DELAY = 10000; + private static final long DEFAULT_AGENT_CHECK_DELAY = 10000; private final Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -49,6 +51,7 @@ public class WorkerActiveManager { private final AgentService agentService; private final Timer timer; + private final TimerTaskDecorator timerTaskDecorator; private final AtomicBoolean isStopped = new AtomicBoolean(); @@ -60,13 +63,14 @@ public class WorkerActiveManager { private final AtomicBoolean onAgentCheckTimerTask = new AtomicBoolean(false); private final List defaultAgentIdList = new CopyOnWriteArrayList<>(); - public WorkerActiveManager(PinpointWebSocketResponseAggregator responseAggregator, AgentService agentService, Timer timer) { - this.responseAggregator = responseAggregator; + public WorkerActiveManager(PinpointWebSocketResponseAggregator responseAggregator, AgentService agentService, Timer timer, TimerTaskDecorator timerTaskDecorator) { + this.responseAggregator = Objects.requireNonNull(responseAggregator, "responseAggregator must not be null"); + this.agentService = Objects.requireNonNull(agentService, "agentService must not be null"); - this.applicationName = responseAggregator.getApplicationName(); - this.agentService = agentService; + this.timer = Objects.requireNonNull(timer, "timer must not be null"); + this.timerTaskDecorator = Objects.requireNonNull(timerTaskDecorator, "timerTaskDecorator must not be null"); - this.timer = timer; + this.applicationName = this.responseAggregator.getApplicationName(); } public void close() { @@ -100,7 +104,8 @@ public void addReactiveWorker(String agentId) { boolean turnOn = onReconnectTimerTask.compareAndSet(false, true); logger.info("addReactiveWorker turnOn:{}", turnOn); if (turnOn) { - timer.schedule(new ReactiveTimerTask(), DEFAULT_RECONNECT_DELAY); + TimerTask reactiveTimerTask = timerTaskDecorator.decorate(new ReactiveTimerTask()); + timer.schedule(reactiveTimerTask, DEFAULT_RECONNECT_DELAY); } } } @@ -110,7 +115,8 @@ public void startAgentCheckJob() { boolean turnOn = onAgentCheckTimerTask.compareAndSet(false, true); if (turnOn) { - timer.schedule(new AgentCheckTimerTask(), DEFAULT_AGENT_CHECk_DELAY); + TimerTask agentCheckTimerTask = timerTaskDecorator.decorate(new AgentCheckTimerTask()); + timer.schedule(agentCheckTimerTask, DEFAULT_AGENT_CHECK_DELAY); } } @@ -170,7 +176,8 @@ public void run() { } } finally { if (timer != null && onAgentCheckTimerTask.get() && !isStopped.get()) { - timer.schedule(new AgentCheckTimerTask(), DEFAULT_AGENT_CHECk_DELAY); + TimerTask agentCheckTimerTask = timerTaskDecorator.decorate(new AgentCheckTimerTask()); + timer.schedule(agentCheckTimerTask, DEFAULT_AGENT_CHECK_DELAY); } } } diff --git a/web/src/main/resources-local/log4j.xml b/web/src/main/resources-local/log4j.xml index 2c75e8570e58..c15d266d8410 100644 --- a/web/src/main/resources-local/log4j.xml +++ b/web/src/main/resources-local/log4j.xml @@ -1,4 +1,20 @@ + + @@ -54,25 +70,21 @@ - + - - + - - - - - + - + + diff --git a/web/src/main/resources-release/log4j.xml b/web/src/main/resources-release/log4j.xml index acde37c2e08d..6f9f4fa24e1c 100644 --- a/web/src/main/resources-release/log4j.xml +++ b/web/src/main/resources-release/log4j.xml @@ -1,4 +1,20 @@ + + @@ -39,7 +55,7 @@ - + @@ -54,26 +70,21 @@ - + - - + - - - - - - + - + + diff --git a/web/src/main/resources/applicationContext-dao-config.xml b/web/src/main/resources/applicationContext-dao-config.xml index 914c11b79b01..8246c29b4cf3 100644 --- a/web/src/main/resources/applicationContext-dao-config.xml +++ b/web/src/main/resources/applicationContext-dao-config.xml @@ -16,34 +16,21 @@ - - - - - - - - - - - - - + + + + - - - - diff --git a/web/src/main/resources/applicationContext-datasource.xml b/web/src/main/resources/applicationContext-datasource.xml index 37699697443c..7483559a285e 100644 --- a/web/src/main/resources/applicationContext-datasource.xml +++ b/web/src/main/resources/applicationContext-datasource.xml @@ -30,4 +30,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/main/resources/applicationContext-hbase.xml b/web/src/main/resources/applicationContext-hbase.xml index 798e3111b9fe..e8f7683d2e2e 100644 --- a/web/src/main/resources/applicationContext-hbase.xml +++ b/web/src/main/resources/applicationContext-hbase.xml @@ -23,12 +23,6 @@ ${hbase.ipc.client.socket.timeout.read} ${hbase.ipc.client.socket.timeout.write} - - - ${hbase.client.async.enable:false} - ${hbase.client.async.in.queuesize:10000} - ${hbase.client.async.flush.period.ms:100} - ${hbase.client.async.max.retries.in.queue:10} @@ -44,21 +38,29 @@ - - - + + + + + + + - + - - - + + + + + + + diff --git a/web/src/main/resources/applicationContext-web-namespace.xml b/web/src/main/resources/applicationContext-web-namespace.xml new file mode 100644 index 000000000000..6ca8acb04f96 --- /dev/null +++ b/web/src/main/resources/applicationContext-web-namespace.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/web/src/main/resources/applicationContext-web.xml b/web/src/main/resources/applicationContext-web.xml index 8b719882cba5..d78eecc2378c 100644 --- a/web/src/main/resources/applicationContext-web.xml +++ b/web/src/main/resources/applicationContext-web.xml @@ -2,25 +2,13 @@ - - - + @@ -92,10 +81,13 @@ + + - + + @@ -128,9 +120,7 @@ - - - + @@ -164,4 +154,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/resources/batch/applicationContext-agentCountJob.xml b/web/src/main/resources/batch/applicationContext-agentCountJob.xml index 117ba541fc54..367ce278bcf9 100644 --- a/web/src/main/resources/batch/applicationContext-agentCountJob.xml +++ b/web/src/main/resources/batch/applicationContext-agentCountJob.xml @@ -13,21 +13,31 @@ - - - - - - - - - - - + + + + + + + + + + - + + + + + + + + + + + - + + \ No newline at end of file diff --git a/web/src/main/resources/batch/applicationContext-alarmJob.xml b/web/src/main/resources/batch/applicationContext-alarmJob.xml index 5c481b16b12f..db5da8a58729 100644 --- a/web/src/main/resources/batch/applicationContext-alarmJob.xml +++ b/web/src/main/resources/batch/applicationContext-alarmJob.xml @@ -13,27 +13,27 @@ - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + - + \ No newline at end of file diff --git a/web/src/main/resources/batch/applicationContext-batch.xml b/web/src/main/resources/batch/applicationContext-batch.xml index 78f6db134ad3..5f6dccfbc373 100644 --- a/web/src/main/resources/batch/applicationContext-batch.xml +++ b/web/src/main/resources/batch/applicationContext-batch.xml @@ -19,7 +19,7 @@ - + diff --git a/web/src/main/resources/batch/applicationContext-flinkCheckJob.xml b/web/src/main/resources/batch/applicationContext-flinkCheckJob.xml index c1283c41bf5a..6d7530edefb8 100644 --- a/web/src/main/resources/batch/applicationContext-flinkCheckJob.xml +++ b/web/src/main/resources/batch/applicationContext-flinkCheckJob.xml @@ -6,14 +6,14 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"> - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/web/src/main/resources/hbase.properties b/web/src/main/resources/hbase.properties index 9766d3647447..b0028132d73b 100644 --- a/web/src/main/resources/hbase.properties +++ b/web/src/main/resources/hbase.properties @@ -4,6 +4,9 @@ hbase.client.port=2181 # hbase default:/hbase hbase.zookeeper.znode.parent=/hbase +# hbase namespace to use default:default +hbase.namespace=default + # hbase timeout option================================================================================== # hbase default:true hbase.ipc.client.tcpnodelay=true diff --git a/web/src/main/resources/jdbc.properties b/web/src/main/resources/jdbc.properties index 099ba3113b5b..6fbfff804543 100644 --- a/web/src/main/resources/jdbc.properties +++ b/web/src/main/resources/jdbc.properties @@ -1,4 +1,4 @@ -#jdbc.driverClassName=com.mysql.jdbc.Driver -#jdbc.url=jdbc:mysql://localhost:13306/pinpoint?characterEncoding=UTF-8 -#jdbc.username=admin -#jdbc.password=admin +jdbc.driverClassName=com.mysql.jdbc.Driver +jdbc.url=jdbc:mysql://localhost:13306/pinpoint?characterEncoding=UTF-8 +jdbc.username=admin +jdbc.password=admin diff --git a/web/src/main/resources/pinpoint-web.properties b/web/src/main/resources/pinpoint-web.properties index c64007993b9f..818877d21591 100644 --- a/web/src/main/resources/pinpoint-web.properties +++ b/web/src/main/resources/pinpoint-web.properties @@ -36,22 +36,24 @@ config.show.activeThread=true config.show.activeThreadDump=true config.enable.activeThreadDump=true config.show.applicationStat=false +config.show.stackTraceOnError=true # This option does not work because it is under development -config.enable.serverMapRealTime=true +config.enable.serverMapRealTime=false web.hbase.selectSpans.limit=500 web.hbase.selectAllSpans.limit=500 web.activethread.activeAgent.duration.days=7 -# server map link creator mode = serial or parallel (default = serial) -web.servermap.creator.mode=parallel -web.servermap.creator.parallel.maxthreads=16 - -# server map appender mode = serial or parallel (default = serial) -web.servermap.appender.mode=parallel -web.servermap.appender.parallel.maxthreads=16 +# number of server map link select worker threads +web.servermap.creator.worker.threadSize=32 +# capacity of server map link select worker queue +web.servermap.creator.worker.queueSize=1024 +# number of server node appender worker threads +web.servermap.appender.worker.threadSize=32 +# capacity of server node appender worker queue +web.servermap.appender.worker.queueSize=1024 # see RFC 6454: The Web Origin Concept(https://tools.ietf.org/html/rfc6454) for more details # 1. Allow only same origin requests (value : websocket.allowedOrigins=) diff --git a/web/src/main/webapp/WEB-INF/web.xml b/web/src/main/webapp/WEB-INF/web.xml index 26bdda282667..5f6490bfc5dc 100644 --- a/web/src/main/webapp/WEB-INF/web.xml +++ b/web/src/main/webapp/WEB-INF/web.xml @@ -57,6 +57,16 @@ com.navercorp.pinpoint.web.servlet.NoCacheFilter + + rewriteFilter + org.springframework.web.filter.DelegatingFilterProxy + + + + rewriteFilter + /v2/* + + encodingFilter /* diff --git a/web/src/main/webapp/common/help/help-content-en.js b/web/src/main/webapp/common/help/help-content-en.js index 3fa4fcd835e8..71d82d7687bb 100644 --- a/web/src/main/webapp/common/help/help-content-en.js +++ b/web/src/main/webapp/common/help/help-content-en.js @@ -4,11 +4,11 @@ configuration: { general: { warning: "(User configuration is stored in browser cache. Server-side storage will be supported in a future release.)", - empty: "Favorite list empty" + empty: "Favorite list is empty" }, alarmRules: { mainStyle: "", - title: "Alarm Rule Type", + title: "Types of Alarm Rule", desc: "The following types of alarm rules are supported by Pinpoint.", category: [{ title: "[Type]", @@ -58,7 +58,7 @@ }] }, installation: { - desc: "* You can check whether the Application Name and Agent Id are duplicated.", + desc: "* You can check if Application Name and Agent Id are duplicated.", lengthGuide: "You can enter up to {{MAX_CHAR}} characters." } }, @@ -75,10 +75,10 @@ title: "[Legend]", items: [{ name: "Icon", - desc: "Application Type" + desc: "Type of the Application" }, { name: "Text", - desc: "Application Name. The value set using -Dpinpoint.applicationName when launching Pinpoint agent." + desc: "Name of the Application. The value of -Dpinpoint.applicationName in Pinpoint agent configuration." }] }] }, @@ -90,7 +90,7 @@ title: "[Legend]", items: [{ name: "Inbound", - desc: "Number of depth to render for requests coming in to the selected node." + desc: "Number of depth to render for requests coming into the selected node." }, { name: "Outbound", desc: "Number of depth to render for requests going out from the selected node" @@ -112,7 +112,7 @@ periodSelector: { mainStyle: "", title: "Period Selector", - desc: "Selects the time period for querying data.", + desc: "Selects the time range for search data.", category: [{ title: "[Usage]", items: [{ @@ -120,7 +120,7 @@ desc: "Query for data traced during the most recent selected time-period.
Auto-refresh is supported for 5m, 10m, 3h time-period." },{ name: "", - desc: "Query for data traced between the two selected times for a maximum of 48 hours." + desc: "Query for traced data between two selected times with the maximum of 48 hours." }] }] } @@ -142,17 +142,17 @@ title: "[Arrow]", list: [ "Each arrow represents a transaction flow.", - "The number shows the transaction count and is displayed in red for transactions with error.", + "The number shows the transaction count. Displayed in red for error counts that exceeds the threshold.", " is shown when a filter is applied.", "Clicking an arrow shows information on all transactions passing through the selected section on the right-hand side of the screen." ] },{ - title: "[Function of the box]", + title: "[Usage of the Node]", list: [ - "When the box is selected, the transaction information flowing into the application is displayed on the right side of the screen." + "When the node is selected, the transaction information flowing into the application is displayed on the right side of the screen." ] },{ - title: "[Function of the arrow]", + title: "[Usage of the Arrow]", list: [ "Select the arrow to show the transaction information that passes through the selected section on the right side of the screen.", "The Filter in the Context menu shows only the transactions that pass through the selected section.", @@ -162,16 +162,16 @@ },{ title: "[Applying Filter]", list: [ - "Right-clicking on an arrow displays a filter menu.", - "'Filter' filters the server map to only show transactions that has passed through the selected section.", + "Right-clicking on an arrow displays the filter menu.", + "'Filter' filters the server map to show transactions that have passed through the selected section.", "'Filter Wizard' allows additional filter configurations." ] },{ title: "[Chart Configuration]", list: [ - "Right-clicking on an empty area displays a chart configuration menu.", - "Node Setting / Merge Unknown : Groups all agent-less applications into a single node.", - "Double-clicking on an empty resets the zoom level of the server map." + "Right-clicking on any blank area displays a chart configuration menu.", + "Node Setting / Merge Unknown : Groups all applications without agent and displays it as a single node.", + "Double-clicking on any blank area resets the zoom level of the server map." ] }] } @@ -478,7 +478,7 @@ title: "[Usage]", items: [{ name: "", - desc: "Open a new window with detailed information on the WAS with Pinpoint installed." + desc: "Open a new window with detailed information on the WAS where Pinpoint is installed." },{ name: "", desc: "Display statistics on transactions carried out by the server instance." @@ -551,7 +551,7 @@ heap: { mainStyle: "", title: "Heap", - desc: "JVM's heap information and full garbage collection times(if any)", + desc: "JVM's heap information and major garbage collection time required", category: [{ title: "[Legend]", items: [{ @@ -559,17 +559,17 @@ desc: "Maximum heap size" },{ name: "Used", - desc: "Heap currently in use" + desc: "Heap size currently in use" },{ - name: "FGC", - desc: "Full garbage collection duration (number of FGCs in parenthesis if it occurred more than once)" + name: "Major GC", + desc: "Time required for major garbage collection (number of Major GCs in parenthesis if it occurred more than once)" }] }] }, permGen: { mainStyle: "", title: "Non-Heap", - desc: "JVM's non-heap information and full garbage collection times(if any)", + desc: "JVM's non-heap information and major garbage collection time required", category: [{ title: "[Legend]", items: [{ @@ -577,10 +577,10 @@ desc: "Maximum non-heap size" },{ name: "Used", - desc: "Non-heap currently in use" + desc: "Non-heap size currently in use" },{ - name: "FGC", - desc: "Full garbage collection duration (number of FGCs in parenthesis if it occurred more than once)" + name: "Major GC", + desc: "Time required for major garbage collection (number of Major GCs in parenthesis if it occurred more than once)" }] }] }, @@ -592,28 +592,28 @@ title: "[Legend]", items: [{ name: "Java 1.6", - desc: "Only the JVM's CPU usage is collected" + desc: "Only JVM's CPU usage is collected" },{ name: "Java 1.7+", - desc: "Both the JVM's and the system's CPU usage are collected" + desc: "Both JVM's and system's CPU usage are collected" }] }] }, tps: { mainStyle: "", title: "TPS", - desc: "Transactions per second received by the server", + desc: "Transactions received by the server per second ", category: [{ title: "[Legend]", items: [{ name: "Sampled New (S.N)", - desc: "Profiled transactions that started from the current agent" + desc: "Profiled transactions that started from the selected agent" },{ name: "Sampled Continuation (S.C)", desc: "Profiled transactions that started from another agent" },{ name: "Unsampled New (U.N)", - desc: "Unprofiled transactions that started from the current agent" + desc: "Unprofiled transactions that started from the selected agent" },{ name: "Unsampled Continuation (U.C)", desc: "Unprofiled transactions that started from another agent" @@ -626,7 +626,7 @@ activeThread: { mainStyle: "", title: "Active Thread", - desc: "Snapshots of the agent's active thread count, categorized by how long they have active for serving a request.", + desc: "Snapshots of the agent's active thread status, categorized by how long they have been active for serving a request.", category: [{ title: "[Legend]", items: [{ @@ -658,10 +658,10 @@ desc: "Maximum number of active connections" },{ name: "Total Max", - desc: "The maximum number of active connections that can be allocated at the same time" + desc: "The maximum number of connections that can be allocated at the same time" },{ name: "Type", - desc: "DB Connection Pool Type" + desc: "Type of DB Connection Pool" }] }] }, @@ -677,28 +677,88 @@ }] }] }, + openFileDescriptor: { + mainStyle: "", + title: "File Descriptor", + desc: "Shows the status of agent's file descriptors.", + category: [{ + title: "[Legend]", + items: [{ + name: "Open File Descriptor", + desc: "Number of open file descriptor currently used" + }] + }] + }, + directBufferCount: { + mainStyle: "", + title: "Direct Buffer", + desc: "Shows the status of agent's direct buffer", + category: [{ + title: "[Legend]", + items: [{ + name: "Direct Buffer Count", + desc: "Number of direct buffer" + }] + }] + }, + directBufferMemory: { + mainStyle: "", + title: "Direct Buffer Memory", + desc: "Shows the status of agent's used direct buffer memory", + category: [{ + title: "[Legend]", + items: [{ + name: "Direct Buffer Memory Used", + desc: "Currently used direct buffer memory" + }] + }] + }, + mappedBufferCount: { + mainStyle: "", + title: "Mapped Buffer", + desc: "Shows the status of agent's Mapped buffer", + category: [{ + title: "[Legend]", + items: [{ + name: "Mapped Buffer Count", + desc: "Number of Mapped buffer" + }] + }] + }, + mappedBufferMemory: { + mainStyle: "", + title: "Mapped Buffer Memory", + desc: "Shows the status of agent's used Mapped buffer memory", + category: [{ + title: "[Legend]", + items: [{ + name: "Mapped Buffer Memory Used", + desc: "Currently used Mapped buffer memory" + }] + }] + }, wrongApp: [ "
The agent is currently registered under {{application2}} due to the following:
", "1. The agent has moved from {{application1}} to {{application2}}
", "2. A different agent with the same agent id has been registered to {{application2}}
", - "For the former case, you should delete the mapping between {{application1}} and {{agentId}}.
", - "For the latter case, the agent id of the duplicate agent must be changed.
" + "For case1, you should delete the mapping between {{application1}} and {{agentId}}.
", + "For case2, the agent id of the duplicate agent must be changed." ].join(""), statHeap: { mainStyle: "", title: "Heap", - desc: "Heap size used by agent JVMs", + desc: "Heap size used by the agent JVMs", category: [{ title: "[Legend]", items: [{ name: "MAX", - desc: "Largest heap size used by agent JVMs" + desc: "Largest heap size used by an agent JVM" },{ name: "AVG", - desc: "Average heap size used by agent JVMs" + desc: "Average heap size used by the agent JVMs" },{ name: "MIN", - desc: "Smallest heap size used by agent JVMs" + desc: "Smallest heap size used by an agent JVM" }] }] }, @@ -710,13 +770,13 @@ title: "[Legend]", items: [{ name: "MAX", - desc: "Largest non-heap size used by agent JVMs" + desc: "Largest non-heap size used by an agent JVM" },{ name: "AVG", - desc: "Average non-heap size used by agent JVMs" + desc: "Average non-heap size used by the agent JVMs" },{ name: "MIN", - desc: "Smallest non-heap size used by agent JVMs" + desc: "Smallest non-heap size used by an agent JVM" }] }] }, @@ -741,7 +801,7 @@ statSystemCpu: { mainStyle: "", title: "System pu Usage", - desc: "CPU usage of agents' whole system - For multi-core CPUs, displays the average CPU usage of all the cores.", + desc: "CPU usage of every agent's system - For multi-core CPUs, displays the average CPU usage of all cores.", category: [{ title: "[Legend]", items: [{ @@ -761,7 +821,7 @@ desc: "Only the JVM's CPU usage is collected" },{ name: "Java 1.7+", - desc: "Both the JVM's and the system's CPU usage are collected" + desc: "Both JVM's and system's CPU usage are collected" }] }] }, @@ -809,13 +869,13 @@ title: "[Legend]", items: [{ name: "MAX", - desc: "Highest average response time of requests served by an agent" + desc: "Highest value of agents' average response time" },{ name: "AVG", - desc: "Average response time of requests served by all agents" + desc: "Average value of agents' average response time" },{ name: "MIN", - desc: "Lowest average response time of requests served by an agent" + desc: "Lowest value of agents' average response time" }] }] }, @@ -836,6 +896,96 @@ desc: "Smallest data source connection count of the agents" }] }] + }, + statOpenFileDescriptor: { + mainStyle: "", + title: "File Descriptor", + desc: "Number of file descriptors used by agents", + category: [{ + title: "[Legend]", + items: [{ + name: "MAX", + desc: "Max number of open file descriptors" + },{ + name: "AVG", + desc: "average open file descriptors" + },{ + name: "MIN", + desc: "Min number of open file descriptors" + }] + }] + }, + statDirectBufferCount: { + mainStyle: "", + title: "Direct Buffer", + desc: "Number of direct buffer used by agents", + category: [{ + title: "[Legend]", + items: [{ + name: "MAX", + desc: "Max number of direct buffer" + },{ + name: "AVG", + desc: "average number of direct buffer" + },{ + name: "MIN", + desc: "Min number of direct buffer" + }] + }] + }, + statDirectBufferMemory: { + mainStyle: "", + title: "Direct Buffer Memory", + desc: "Number of Direct buffer used by agents", + category: [{ + title: "[Legend]", + items: [{ + name: "MAX", + desc: "Max number of direct buffer" + },{ + name: "AVG", + desc: "average number of direct buffer" + },{ + name: "MIN", + desc: "Min number of direct buffer" + }] + }] + }, + statMappedBufferCount: { + mainStyle: "", + title: "Mapped Buffer", + desc: "Number of Mapped buffer used by agents", + category: [{ + title: "[Legend]", + items: [{ + name: "MAX", + desc: "Max number of Mapped buffer" + },{ + name: "AVG", + desc: "average number of Mapped buffer" + },{ + name: "MIN", + desc: "Min number of Mapped buffer" + }] + }] + }, + statMappedBufferMemory: { + mainStyle: "", + title: "Mapped Buffer Memory", + desc: "Number of Mapped buffer used by agents", + category: [{ + title: "[Legend]", + items: [{ + name: "MAX", + desc: "Max number of Mapped buffer" + },{ + name: "AVG", + desc: "average number of Mapped buffer" + },{ + name: "MIN", + desc: "Min number of Mapped buffer" + }] + }] } }, callTree: { @@ -847,10 +997,10 @@ title: "[Column]", items: [{ name: "Gap", - desc: "Time elapsed between the start of the previous method and entry of this method" + desc: "Elapsed time between the start of the previous method and the entry of this method" },{ name: "Exec", - desc: "The overall duration of the method call from method entry until method exit" + desc: "Duration of the method call from entry to exit" },{ name: "Exec(%)", desc: "" @@ -862,7 +1012,7 @@ desc: "Dark blue A percentage of the self execution time" },{ name: "Self", - desc: "The time that was used for execution of this method only, excluding time consumed in nested methods call" + desc: "Duration of the method call from entry to exit, excluding time consumed in nested methods call" }] }] } @@ -872,7 +1022,7 @@ }, transactionList: { openError: { - noParent: "Scatter data of parent window had been changed.\r\nso can\'t scan the data any more.", + noParent: "Unable to scan any more data due to the change of\r\nscatter data in parent window.", noData: "There is no {{application}} scatter data in parent window." } }, diff --git a/web/src/main/webapp/common/help/help-content-ko.js b/web/src/main/webapp/common/help/help-content-ko.js index 03ee11ae0f1f..612644620b7a 100644 --- a/web/src/main/webapp/common/help/help-content-ko.js +++ b/web/src/main/webapp/common/help/help-content-ko.js @@ -540,7 +540,7 @@ heap: { mainStyle: "", title: "Heap", - desc: "JVM의 heap 정보와 full garbage collection 소요 시간", + desc: "JVM의 heap 정보와 major garbage collection 소요 시간", category: [{ title: "[범례]", items: [{ @@ -550,15 +550,15 @@ name: "Used", desc: "현재 사용 중인 heap 사이즈" },{ - name: "FGC", - desc: "Full garbage collection의 총 소요 시간(2번 이상 발생 시, 괄호 안에 발생 횟수 표시)" + name: "Major GC", + desc: "Major garbage collection의 총 소요 시간(2번 이상 발생 시, 괄호 안에 발생 횟수 표시)" }] }] }, permGen: { mainStyle: "", title: "Non-Heap", - desc: "JVM의 non-heap 정보와 full garbage collection 소요 시간", + desc: "JVM의 non-heap 정보와 major garbage collection 소요 시간", category: [{ title: "[범례]", items: [{ @@ -568,8 +568,8 @@ name: "Used", desc: "현재 사용 중인 non-heap 사이즈" },{ - name: "FGC", - desc: "Full garbage collection의 총 소요 시간(2번 이상 발생 시, 괄호 안에 발생 횟수 표시)" + name: "Major GC", + desc: "Major garbage collection의 총 소요 시간(2번 이상 발생 시, 괄호 안에 발생 횟수 표시)" }] }] }, @@ -666,6 +666,66 @@ }] }] }, + openFileDescriptor: { + mainStyle: "", + title: "File Descriptor", + desc: "에이전트의 File Descriptor 현황을 보여줍니다.", + category: [{ + title: "[범례]", + items: [{ + name: "Open File Descriptor", + desc: "현재 열려있는 File Descriptor 개수" + }] + }] + }, + directBufferCount: { + mainStyle: "", + title: "Direct Buffer", + desc: "에이전트의 Direct Buffer 현황을 보여줍니다.", + category: [{ + title: "[범례]", + items: [{ + name: "Direct Buffer Count", + desc: "현재 Direct Buffer 의 개수" + }] + }] + }, + directBufferMemory: { + mainStyle: "", + title: "Direct Buffer Memory", + desc: "에이전트의 Direct Buffer Memory 현황을 보여줍니다.", + category: [{ + title: "[범례]", + items: [{ + name: "Direct Buffer Memory Used", + desc: "현재 Direct Buffer 가 사용중인 메모리" + }] + }] + }, + mappedBufferCount: { + mainStyle: "", + title: "Mapped Buffer", + desc: "에이전트의 Mapped Buffer 현황을 보여줍니다.", + category: [{ + title: "[범례]", + items: [{ + name: "Mapped Buffer Count", + desc: "현재 Mapped Buffer 의 개수" + }] + }] + }, + mappedBufferMemory: { + mainStyle: "", + title: "Mapped Buffer Memory", + desc: "에이전트의 Mapped Buffer Memory 현황을 보여줍니다.", + category: [{ + title: "[범례]", + items: [{ + name: "Mapped Buffer Memory Used", + desc: "현재 Mapped Buffer 가 사용중인 메모리" + }] + }] + }, wrongApp: [ "
해당 agent는 {{application1}}이 아닌 {{application2}}에 포함되어 있습니다.
", "원인은 다음 중 하나입니다.
", @@ -826,6 +886,96 @@ desc: "agent들의 DataSource connection 개수 중 가장 작은 값" }] }] + }, + statOpenFileDescriptor: { + mainStyle: "", + title: "File Descriptor", + desc: "에이전트들의 File Descriptor 현황", + category: [{ + title: "[범례]", + items: [{ + name: "MAX", + desc: "Agent 가 열고 있는 File Descriptor 개수 중 가장 큰 값" + },{ + name: "AVG", + desc: "Agent 가 열고 있는 File Descriptor 개수의 평균 값" + },{ + name: "MIN", + desc: "Agent 가 열고 있는 File Descriptor 개수 중 가장 작은 값" + }] + }] + }, + statDirectBufferCount: { + mainStyle: "", + title: "Direct Buffer", + desc: "Agent들의 Direct Buffer 현황", + category: [{ + title: "[범례]", + items: [{ + name: "MAX", + desc: "Agent 가 사용 중인 Direct Buffer 개수 중 가장 큰 값" + },{ + name: "AVG", + desc: "Agent 가 사용 중인 Direct Buffer 개수의 평균 값" + },{ + name: "MIN", + desc: "Agent 가 사용 중인 Direct Buffer 개수 중 가장 작은 값" + }] + }] + }, + statDirectBufferMemory: { + mainStyle: "", + title: "Direct Buffer Memory", + desc: "Agent들의 Direct Buffer Memory 사용 현황", + category: [{ + title: "[범례]", + items: [{ + name: "MAX", + desc: "Agent 가 사용 중인 Direct Buffer Memory 중 가장 큰 값" + },{ + name: "AVG", + desc: "Agent 가 사용 중인 Direct Buffer Memory 의 평균 값" + },{ + name: "MIN", + desc: "Agent 가 사용 중인 Direct Buffer Memory 중 가장 작은 값" + }] + }] + }, + statMappedBufferCount: { + mainStyle: "", + title: "Mapped Buffer", + desc: "Agent들의 Mapped Buffer 현황", + category: [{ + title: "[범례]", + items: [{ + name: "MAX", + desc: "Agent 가 사용 중인 Mapped Buffer 개수 중 가장 큰 값" + },{ + name: "AVG", + desc: "Agent 가 사용 중인 Mapped Buffer 개수의 평균 값" + },{ + name: "MIN", + desc: "Agent 가 사용 중인 Mapped Buffer 개수 중 가장 작은 값" + }] + }] + }, + statMappedBufferMemory: { + mainStyle: "", + title: "Mapped Buffer Memory", + desc: "Agent들의 Mapped Buffer Memory 사용 현황", + category: [{ + title: "[범례]", + items: [{ + name: "MAX", + desc: "Agent 가 사용 중인 Mapped Buffer Memory 중 가장 큰 값" + },{ + name: "AVG", + desc: "Agent 가 사용 중인 Mapped Buffer Memory 의 평균 값" + },{ + name: "MIN", + desc: "Agent 가 사용 중인 Mapped Buffer Memory 중 가장 작은 값" + }] + }] } }, callTree: { diff --git a/web/src/main/webapp/common/services/agent-ajax.service.js b/web/src/main/webapp/common/services/agent-ajax.service.js index b14d554b03b6..722085fb42db 100644 --- a/web/src/main/webapp/common/services/agent-ajax.service.js +++ b/web/src/main/webapp/common/services/agent-ajax.service.js @@ -19,13 +19,17 @@ "tpsChart" : "getAgentStat/transaction/chart.pinpoint", "activeTraceChart" : "getAgentStat/activeTrace/chart.pinpoint", "dataSourceChart" : "getAgentStat/dataSource/chartList.pinpoint", + "openFileDescriptor": "getAgentStat/fileDescriptor/chart.pinpoint", + "directBuffer" : "getAgentStat/directBuffer/chart.pinpoint", "responseTimeChart" : "getAgentStat/responseTime/chart.pinpoint", "statMemory" : "getApplicationStat/memory/chart.pinpoint", "statCpuLoad" : "getApplicationStat/cpuLoad/chart.pinpoint", "statTPS" : "getApplicationStat/transaction/chart.pinpoint", "statActiveThread" : "getApplicationStat/activeTrace/chart.pinpoint", "statResponseTime" : "getApplicationStat/responseTime/chart.pinpoint", - "statDataSource" : "getApplicationStat/dataSource/chart.pinpoint" + "statDataSource" : "getApplicationStat/dataSource/chart.pinpoint", + "statOpenFileDescriptor": "getApplicationStat/fileDescriptor/chart.pinpoint", + "statDirectBuffer" : "getApplicationStat/directBuffer/chart.pinpoint" }); pinpointApp.service("AgentAjaxService", [ "AgentAjaxServiceConfig", "$http", function ($config, $http) { @@ -50,6 +54,12 @@ this.getDataSourceChartData = function( data, callback ) { retrieve($config.dataSourceChart, data, callback); }; + this.getOpenFileDescriptorChartData = function( data, callback ) { + retrieve($config.openFileDescriptor, data, callback); + }; + this.getDirectBufferChartData = function( data, callback ) { + retrieve($config.directBuffer, data, callback); + }; this.getAgentInfo = function( data, callback ) { retrieve($config.agentInfo, data, callback); }; @@ -82,6 +92,12 @@ this.getStatDataSource = function( data, callback ) { retrieve($config.statDataSource, data, callback); }; + this.getStatOpenFileDescriptor = function( data, callback ) { + retrieve($config.statOpenFileDescriptor, data, callback); + }; + this.getStatDirectBuffer = function( data, callback ) { + retrieve($config.statDirectBuffer, data, callback); + }; function retrieve(url, data, callback) { $http.get(url + getQueryStr( data ) ).then(function(result) { diff --git a/web/src/main/webapp/common/services/alarm-util.service.js b/web/src/main/webapp/common/services/alarm-util.service.js index a9ee8f1a1ea0..1675c41014ac 100644 --- a/web/src/main/webapp/common/services/alarm-util.service.js +++ b/web/src/main/webapp/common/services/alarm-util.service.js @@ -22,17 +22,19 @@ data = { "userId" : ( config["userId"] || "" ) }; + self.load( funcName, data, successCallback, failCallback ); }); + } else { + this.load( funcName, data, successCallback, failCallback ); } - - $timeout(function() { - $ajaxService[funcName](data, function (resultData) { - if (resultData.errorCode || resultData.status) { - failCallback(resultData); - } else { - successCallback(resultData); - } - }); + }; + this.load = function( funcName, data, successCallback, failCallback ) { + $ajaxService[funcName](data, function (resultData) { + if (resultData.errorCode || resultData.status) { + failCallback(resultData); + } else { + successCallback(resultData); + } }); }; this.setTotal = function( $elTotal, n ) { diff --git a/web/src/main/webapp/common/services/alerts.service.js b/web/src/main/webapp/common/services/alerts.service.js index bca695c85bb3..0f403673804e 100644 --- a/web/src/main/webapp/common/services/alerts.service.js +++ b/web/src/main/webapp/common/services/alerts.service.js @@ -32,7 +32,11 @@ this.getElement('.error .header').html(this._transTableFormat(vResult.request.heads)); this.getElement('.error .parameters').html(this._transTableFormat(vResult.request.parameters)); this.getElement('.error .url').text(vResult.request.url); - this.getElement('.error .stacktrace').text(vResult.stacktrace); + if ( vResult.stacktrace ) { + this.getElement('.error .stacktrace').text(vResult.stacktrace).parent().parent().show(); + } else { + this.getElement('.error .stacktrace').parent().parent().hide(); + } } }.bind(this), 300); }.bind(this); diff --git a/web/src/main/webapp/common/services/direct-buffer-chart-dao.service.js b/web/src/main/webapp/common/services/direct-buffer-chart-dao.service.js new file mode 100644 index 000000000000..f8826bc070fb --- /dev/null +++ b/web/src/main/webapp/common/services/direct-buffer-chart-dao.service.js @@ -0,0 +1,140 @@ +(function() { + 'use strict'; + + pinpointApp.constant( "DirectBufferDaoServiceConfig", { + dateFormat: "YYYY-MM-DD HH:mm:ss" + }); + + pinpointApp.service( "DirectBufferDaoService", [ "DirectBufferDaoServiceConfig", + function DirectBufferDaoService( cfg ) { + + this.parseData = function( aChartData ) { + var aX = aChartData.charts.x; + var pointsDirectCount = aChartData.charts.y["DIRECT_COUNT"]; + var pointsMappedCount = aChartData.charts.y["MAPPED_COUNT"]; + var pointsDirectMemoryUsed = aChartData.charts.y["DIRECT_MEMORY_USED"]; + var pointsMappedMemoryUsed = aChartData.charts.y["MAPPED_MEMORY_USED"]; + var xLen = aX.length; + var directCountLen = pointsDirectCount.length; + var mappedCountLen = pointsMappedCount.length; + var directMemoryUsedLen = pointsDirectMemoryUsed.length; + var mappedMemoryUsedLen = pointsMappedMemoryUsed.length; + + var refinedChartData = { + data: [], + empty: false, + forceMax: false, + defaultMax: 100 + }; + if ( directCountLen === 0 && mappedCountLen === 0 ) { + refinedChartData.empty = true; + } + for (var i = 0; i < xLen; ++i) { + var thisData = { + time: moment(aX[i]).format( cfg.dateFormat ) + }; + if ( directCountLen > i ) { + thisData["directCount"] = pointsDirectCount[i][2] === -1 ? null : pointsDirectCount[i][2].toFixed(2); + } + if ( mappedCountLen > i ) { + thisData["mappedCount"] = pointsMappedCount[i][2] === -1 ? null : pointsMappedCount[i][2].toFixed(2); + } + if ( directMemoryUsedLen > i ) { + thisData["directMemoryUsed"] = pointsDirectMemoryUsed[i][2] === -1 ? null : pointsDirectMemoryUsed[i][2].toFixed(2); + } + if ( mappedMemoryUsedLen > i ) { + thisData["mappedMemoryUsed"] = pointsMappedMemoryUsed[i][2] === -1 ? null : pointsMappedMemoryUsed[i][2].toFixed(2); + } + refinedChartData.data.push(thisData); + } + return refinedChartData; + }; + this.getDirectBufferCountChartOptions = function( oChartData ) { + return this.getCommonChartOptions( oChartData, "Buffer (counts)", { + "valueAxis": "v1", + "balloonText": "Count : [[value]]", + "legendValueText": "[[value]]", + "lineColor": "rgb(31, 119, 180)", + "title": "Direct", + "valueField": "directCount", + "fillAlphas": 0, + "connect": false + }); + }; + this.getDirectBufferMemoryChartOptions = function( oChartData ) { + return this.getCommonChartOptions( oChartData, "Memory (bytes)", { + "valueAxis": "v1", + "balloonText": "Memory : [[value]]", + "legendValueText": "[[value]]", + "lineColor": "rgb(31, 119, 180)", + "title": "Direct", + "valueField": "directMemoryUsed", + "fillAlphas": 0, + "connect": false + }); + }; + this.getMappedBufferCountChartOptions = function( oChartData ) { + return this.getCommonChartOptions( oChartData, "Buffer (counts)", { + "valueAxis": "v1", + "balloonText": "Count : [[value]]", + "legendValueText": "[[value]]", + "lineColor": "rgb(31, 119, 180)", + "title": "Direct", + "valueField": "mappedCount", + "fillAlphas": 0, + "connect": false + }); + }; + this.getMappedBufferMemoryChartOptions = function( oChartData ) { + return this.getCommonChartOptions( oChartData, "Memory (bytes)", { + "valueAxis": "v1", + "balloonText": "Memory : [[value]]", + "legendValueText": "[[value]]", + "lineColor": "rgb(31, 119, 180)", + "title": "Direct", + "valueField": "mappedMemoryUsed", + "fillAlphas": 0, + "connect": false + }); + }; + this.getCommonChartOptions = function( oChartData, title, graph ) { + return { + "type": "serial", + "theme": "light", + "autoMargins": false, + "marginTop": 10, + "marginLeft": 70, + "marginRight": 70, + "marginBottom": 40, + "usePrefixes": true, + "dataProvider": oChartData.data, + "valueAxes": [ + { + "id": "v1", + "gridAlpha": 0, + "axisAlpha": 1, + "position": "left", + "title": title, + "minimum" : 0 + } + ], + "graphs": [ graph ], + "categoryField": "time", + "categoryAxis": { + "axisColor": "#DADADA", + "startOnAxis": true, + "gridPosition": "start", + "labelFunction": function (valueText) { + return valueText.replace(/\s/, "
").replace(/-/g, ".").substring(2); + } + }, + "chartCursor": { + "categoryBalloonAlpha": 0.7, + "fullWidth": true, + "cursorAlpha": 0.1 + } + }; + }; + } + ]); +})(); diff --git a/web/src/main/webapp/common/services/memory-chart-dao.service.js b/web/src/main/webapp/common/services/memory-chart-dao.service.js index 7de5dce7c85c..07a736143c91 100644 --- a/web/src/main/webapp/common/services/memory-chart-dao.service.js +++ b/web/src/main/webapp/common/services/memory-chart-dao.service.js @@ -32,7 +32,8 @@ data: [], empty: false, forceMax: false, - defaultMax: 100 + defaultMax: 100, + defaultMax2: 10000000 }; var cumulativeGcTime = 0; @@ -146,7 +147,7 @@ }, "legendValueText": "[[value]]ms", "lineColor": "#FF6600", - "title": "FGC", + "title": "Major GC", "valueField": "FGCTime", "type": "column", "fillAlphas": 0.3, diff --git a/web/src/main/webapp/common/services/open-file-descriptor-chart-dao.service.js b/web/src/main/webapp/common/services/open-file-descriptor-chart-dao.service.js new file mode 100644 index 000000000000..720cde9ecb30 --- /dev/null +++ b/web/src/main/webapp/common/services/open-file-descriptor-chart-dao.service.js @@ -0,0 +1,92 @@ +(function() { + 'use strict'; + + pinpointApp.constant( "OpenFileDescriptorDaoServiceConfig", { + dateFormat: "YYYY-MM-DD HH:mm:ss" + }); + + pinpointApp.service( "OpenFileDescriptorDaoService", [ "OpenFileDescriptorDaoServiceConfig", + function OpenFileDescriptorDaoService( cfg ) { + + this.parseData = function( aChartData ) { + var aX = aChartData.charts.x; + var pointsOpenFileDescriptor = aChartData.charts.y["OPEN_FILE_DESCRIPTOR_COUNT"]; + var xLen = aX.length; + var len = pointsOpenFileDescriptor.length; + + var refinedChartData = { + data: [], + empty: false, + forceMax: false, + defaultMax: 100 + }; + if ( len === 0 ) { + refinedChartData.empty = true; + } + for (var i = 0; i < xLen; ++i) { + var thisData = { + time: moment(aX[i]).format( cfg.dateFormat ) + }; + if ( len > i ) { + thisData["count"] = pointsOpenFileDescriptor[i][2] === -1 ? null : pointsOpenFileDescriptor[i][2].toFixed(2); + } + refinedChartData.data.push(thisData); + } + return refinedChartData; + }; + this.getChartOptions = function( oChartData ) { + return { + "type": "serial", + "theme": "light", + "autoMargins": false, + "marginTop": 10, + "marginLeft": 70, + "marginRight": 70, + "marginBottom": 40, + "usePrefixes": true, + "dataProvider": oChartData.data, + "valueAxes": [ + { + "id": "v1", + "gridAlpha": 0, + "axisAlpha": 1, + "position": "left", + "title": "File Descriptor(count)", + "minimum" : 0, + "labelFunction": function(value) { + return value; + } + } + ], + "graphs": [ + { + "valueAxis": "v1", + "balloonText": "[[value]]", + "legendValueText": "[[value]]", + "lineColor": "rgb(31, 119, 180)", + "fillColor": "rgb(31, 119, 180)", + "title": "Open File Descriptor", + "valueField": "count", + "fillAlphas": 0.4, + "connect": false + } + ], + "categoryField": "time", + "categoryAxis": { + "axisColor": "#DADADA", + "startOnAxis": true, + "gridPosition": "start", + "labelFunction": function (valueText) { + return valueText.replace(/\s/, "
").replace(/-/g, ".").substring(2); + } + }, + "chartCursor": { + "categoryBalloonAlpha": 0.7, + "fullWidth": true, + "cursorAlpha": 0.1 + } + }; + }; + } + ]); +})(); diff --git a/web/src/main/webapp/common/services/server-map-dao.service.js b/web/src/main/webapp/common/services/server-map-dao.service.js index 0d5f83348145..5760d7f604a9 100644 --- a/web/src/main/webapp/common/services/server-map-dao.service.js +++ b/web/src/main/webapp/common/services/server-map-dao.service.js @@ -197,7 +197,7 @@ */ this.addFilterProperty = function (filters, applicationMapData) { var parsedFilters = this.parseFilterText(filters, applicationMapData); - + // node angular.forEach(applicationMapData.nodeDataArray, function (val) { if (angular.isDefined(_.findWhere(parsedFilters, {nodeKey: val.key}))) { diff --git a/web/src/main/webapp/common/services/tooltip.service.js b/web/src/main/webapp/common/services/tooltip.service.js index 8420cd6b68a4..078b709fec03 100644 --- a/web/src/main/webapp/common/services/tooltip.service.js +++ b/web/src/main/webapp/common/services/tooltip.service.js @@ -53,6 +53,26 @@ "position": "top", "trigger": "click" }, + "openFileDescriptor": { + "position": "top", + "trigger": "click" + }, + "directBufferCount": { + "position": "top", + "trigger": "click" + }, + "directBufferMemory": { + "position": "top", + "trigger": "click" + }, + "mappedBufferCount": { + "position": "top", + "trigger": "click" + }, + "mappedBufferMemory": { + "position": "top", + "trigger": "click" + }, "responseSummaryChart": { "position": "top", "trigger": "click" @@ -108,6 +128,26 @@ "statDataSource": { "position": "top", "trigger": "click" + }, + "statOpenFileDescriptor": { + "position": "top", + "trigger": "click" + }, + "statDirectBufferCount": { + "position": "top", + "trigger": "click" + }, + "statDirectBufferMemory": { + "position": "top", + "trigger": "click" + }, + "statMappedBufferCount": { + "position": "top", + "trigger": "click" + }, + "statMappedBufferMemory": { + "position": "top", + "trigger": "click" } }); @@ -150,6 +190,16 @@ return function() { return helpContentTemplate(helpContentService.inspector.dataSource); }; case "responseTime": return function() { return helpContentTemplate(helpContentService.inspector.responseTime); }; + case "openFileDescriptor": + return function() { return helpContentTemplate(helpContentService.inspector.openFileDescriptor); }; + case "directBufferCount": + return function() { return helpContentTemplate(helpContentService.inspector.directBufferCount); }; + case "directBufferMemory": + return function() { return helpContentTemplate(helpContentService.inspector.directBufferMemory); }; + case "mappedBufferCount": + return function() { return helpContentTemplate(helpContentService.inspector.mappedBufferCount); }; + case "mappedBufferMemory": + return function() { return helpContentTemplate(helpContentService.inspector.mappedBufferMemory); }; case "responseSummaryChart": return function() { return helpContentTemplate(helpContentService.nodeInfoDetails.responseSummary); }; case "loadChart": @@ -178,6 +228,16 @@ return function() { return helpContentTemplate(helpContentService.inspector.statResponseTime); }; case "statDataSource": return function() { return helpContentTemplate(helpContentService.inspector.statDataSource); }; + case "statOpenFileDescriptor": + return function() { return helpContentTemplate(helpContentService.inspector.statOpenFileDescriptor); }; + case "statDirectBufferCount": + return function() { return helpContentTemplate(helpContentService.inspector.statDirectBufferCount); }; + case "statDirectBufferMemory": + return function() { return helpContentTemplate(helpContentService.inspector.statDirectBufferMemory); }; + case "statMappedBufferCount": + return function() { return helpContentTemplate(helpContentService.inspector.statMappedBufferCount); }; + case "statMappedBufferMemory": + return function() { return helpContentTemplate(helpContentService.inspector.statMappedBufferMemory); }; } } }]); diff --git a/web/src/main/webapp/features/agentInfo/agent-info.directive.js b/web/src/main/webapp/features/agentInfo/agent-info.directive.js index 3c9c4cf77c86..cfd59b6d6284 100644 --- a/web/src/main/webapp/features/agentInfo/agent-info.directive.js +++ b/web/src/main/webapp/features/agentInfo/agent-info.directive.js @@ -3,8 +3,8 @@ ID: "AGENT_INFO_DRTV_" }); - pinpointApp.directive( "agentInfoDirective", [ "agentInfoDirectiveConfig", "$sce", "$timeout", "CommonUtilService", "UrlVoService", "AlertsService", "ProgressBarService", "AgentDaoService", "ResponseTimeChartDaoService", "ActiveThreadChartDaoService", "TPSChartDaoService", "CPULoadChartDaoService", "MemoryChartDaoService", "AgentAjaxService", "TooltipService", "AnalyticsService", "helpContentService", - function ( cfg, $sce, $timeout, CommonUtilService, UrlVoService, AlertsService, ProgressBarService, AgentDaoService, ResponseTimeChartDaoService, ActiveThreadChartDaoService, TPSChartDaoService, CPULoadChartDaoService, MemoryChartDaoService, AgentAjaxService, TooltipService, AnalyticsService, helpContentService ) { + pinpointApp.directive( "agentInfoDirective", [ "agentInfoDirectiveConfig", "$sce", "$timeout", "CommonUtilService", "UrlVoService", "AlertsService", "ProgressBarService", "AgentDaoService", "ResponseTimeChartDaoService", "ActiveThreadChartDaoService", "TPSChartDaoService", "CPULoadChartDaoService", "MemoryChartDaoService", "OpenFileDescriptorDaoService", "DirectBufferDaoService","AgentAjaxService", "TooltipService", "AnalyticsService", "helpContentService", + function ( cfg, $sce, $timeout, CommonUtilService, UrlVoService, AlertsService, ProgressBarService, AgentDaoService, ResponseTimeChartDaoService, ActiveThreadChartDaoService, TPSChartDaoService, CPULoadChartDaoService, MemoryChartDaoService, OpenFileDescriptorDaoService, DirectBufferDaoService, AgentAjaxService, TooltipService, AnalyticsService, helpContentService ) { return { restrict: 'EA', replace: true, @@ -33,7 +33,7 @@ "handleSrc": "images/handle.png", "timeSeries": aFromTo ? aFromTo : calcuSliderTimeSeries(aSelectionFromTo), "handleTimeSeries": aSelectionFromTo, - "selectTime": aSelectionFromTo[1], + "selectTime": selectedTime || aSelectionFromTo[1], "timelineData": {} }).addEvent("clickEvent", function (aEvent) {// [x, y, obj] loadEventInfo(aEvent[2]); @@ -88,12 +88,46 @@ dataSourceChartData = result; showDataSourceChart(); }); + AgentAjaxService.getOpenFileDescriptorChartData( oParam, function (result) { + showOpenFileDescriptorChart(result); + }); + AgentAjaxService.getDirectBufferChartData( oParam, function (result) { + var refinedChartData = DirectBufferDaoService.parseData( result ); + showDirectBufferCountChart(refinedChartData); + showDirectBufferMemoryChart(refinedChartData); + showMappedBufferCountChart(refinedChartData); + showMappedBufferMemoryChart(refinedChartData); + }); } function loadAgentInfo( time ) { AgentAjaxService.getAgentInfo({ "agentId": scope.agent.agentId, "timestamp": time }, function( result ) { + if ( result === '' ) { + result = { + "agentId": scope.agent.agentId, + "agentVersion": "", + "applicationName": "", + "hostName": "", + "initialStartTimestamp": 0, + "ip": "", + "jvmInfo": { + "gcTypeName": "", + "jvmVersion": "" + }, + "pid": "", + "ports": "", + "status": { + "agentId": "", + "state": { + "desc": "" + } + }, + "jvmGcType": "", + "vmVersion": "" + }; + } var jvmGcType = scope.agent.jvmGcType; scope.agent = result; scope.agent.jvmGcType = jvmGcType; @@ -131,7 +165,7 @@ } function initTooltip() { if ( bInitTooltip === false ) { - ["heap", "permGen", "cpuUsage", "tps", "activeThread", "responseTime", "dataSource"].forEach(function(value) { + ["heap", "permGen", "cpuUsage", "tps", "activeThread", "responseTime", "dataSource", "openFileDescriptor", "directBufferCount", "directBufferMemory", "mappedBufferCount", "mappedBufferMemory"].forEach(function(value) { TooltipService.init( value ); }); bInitTooltip = true; @@ -216,6 +250,52 @@ "270px" ); } + function showOpenFileDescriptorChart( chartData ) { + var refinedChartData = OpenFileDescriptorDaoService.parseData( chartData ); + scope.$broadcast( + "agentInspectorChartDirective.initAndRenderWithData.agent-open-file-descriptor", + refinedChartData, + OpenFileDescriptorDaoService.getChartOptions( refinedChartData ), + "100%", + "270px" + ); + } + function showDirectBufferCountChart( refinedChartData ) { + scope.$broadcast( + "agentInspectorChartDirective.initAndRenderWithData.agent-direct-buffer-count", + refinedChartData, + DirectBufferDaoService.getDirectBufferCountChartOptions( refinedChartData ), + "100%", + "270px" + ); + } + function showDirectBufferMemoryChart( refinedChartData ) { + scope.$broadcast( + "agentInspectorChartDirective.initAndRenderWithData.agent-direct-buffer-memory", + refinedChartData, + DirectBufferDaoService.getDirectBufferMemoryChartOptions( refinedChartData ), + "100%", + "270px" + ); + } + function showMappedBufferCountChart( refinedChartData ) { + scope.$broadcast( + "agentInspectorChartDirective.initAndRenderWithData.agent-mapped-buffer-count", + refinedChartData, + DirectBufferDaoService.getMappedBufferCountChartOptions( refinedChartData ), + "100%", + "270px" + ); + } + function showMappedBufferMemoryChart( refinedChartData ) { + scope.$broadcast( + "agentInspectorChartDirective.initAndRenderWithData.agent-mapped-buffer-memory", + refinedChartData, + DirectBufferDaoService.getMappedBufferMemoryChartOptions( refinedChartData ), + "100%", + "270px" + ); + } var dataSourceChartData = []; var dataSourceIdPrefix = "source_"; scope.dataSourceChartKeys = []; @@ -293,6 +373,7 @@ oAlertService.showError('There is some error.'); } else { timeSlider.addData(result); + sendUpTimeSliderTimeInfo(timeSlider.getSliderTimeSeries(), timeSlider.getSelectionTimeSeries(), scope.selectTime); } }); } @@ -399,19 +480,25 @@ scope.currentServiceInfo = initServiceInfo(agent); var aFromTo, period, aSelectionFromTo = [], selectedTime; - if ( timeSlider === null || bInvokedByTop ) { + if ( bInvokedByTop ) { aSelectionFromTo[0] = UrlVoService.getQueryStartTime(); aSelectionFromTo[1] = UrlVoService.getQueryEndTime(); period = UrlVoService.getPeriod(); } else { if ( sliderTimeSeriesOption === undefined || sliderTimeSeriesOption === null ) { - aSelectionFromTo = timeSlider.getSelectionTimeSeries(); - aFromTo = timeSlider.getSliderTimeSeries(); + if ( timeSlider === null ) { + aSelectionFromTo[0] = UrlVoService.getQueryStartTime(); + aSelectionFromTo[1] = UrlVoService.getQueryEndTime(); + } else { + aSelectionFromTo = timeSlider.getSelectionTimeSeries(); + aFromTo = timeSlider.getSliderTimeSeries(); + } period = UrlVoService.getPeriod(); } else { aSelectionFromTo = sliderTimeSeriesOption["selectionTimeSeries"]; aFromTo = sliderTimeSeriesOption["timeSeries"]; selectedTime = sliderTimeSeriesOption["selectedTime"]; + scope.selectTime = selectedTime; } } if ( scope.selectTime === -1 || bInvokedByTop ) { diff --git a/web/src/main/webapp/features/agentInfo/agentInfoMain.html b/web/src/main/webapp/features/agentInfo/agentInfoMain.html index 7156a94f1169..7bac1629d3c8 100644 --- a/web/src/main/webapp/features/agentInfo/agentInfoMain.html +++ b/web/src/main/webapp/features/agentInfo/agentInfoMain.html @@ -62,7 +62,7 @@

Event - {{eventInfo.length}}Application Name {{agent.applicationName}} - {{agent.applicationName}} + {{agent.applicationName}} Agent Version {{agent.agentVersion}} @@ -83,7 +83,7 @@

Event - {{eventInfo.length}}{{agent.linkName}} JVM (GC Type) - {{agent.vmVersion}} ({{agent.jvmGcType}}) + {{agent.vmVersion}} ({{agent.jvmInfo.gcTypeName || agent.jvmGcType}}) {{agent.jvmGcType}} @@ -92,7 +92,7 @@

Event - {{eventInfo.length}}Start Time - {{formatDate( agent.startTimestamp )}} + {{agent.startTimestamp ? formatDate( agent.startTimestamp ) : ""}} Service Type @@ -104,7 +104,7 @@

Event - {{eventInfo.length}}End Status - {{agent.status.state.desc}} (last checked : {{formatDate( agent.status.eventTimestamp )}}) + {{agent.status.state.desc}} (last checked : {{agent.status.eventTimestamp ? formatDate( agent.status.eventTimestamp ) : ""}}) @@ -196,6 +196,28 @@

+
+

Direct Buffer Count

+ +
+
+

Direct Buffer Memory

+ +
+

+
+
+
+

Mapped Buffer Count

+ +
+
+

Mapped Buffer Memory

+ +
+
+

@@ -252,7 +274,10 @@

-
+
+

Open File Descriptor

+ +
\ No newline at end of file diff --git a/web/src/main/webapp/features/applicationStatistic/application-statistic.directive.js b/web/src/main/webapp/features/applicationStatistic/application-statistic.directive.js index 5585928d9e0e..a1b1005aac34 100644 --- a/web/src/main/webapp/features/applicationStatistic/application-statistic.directive.js +++ b/web/src/main/webapp/features/applicationStatistic/application-statistic.directive.js @@ -40,14 +40,9 @@ } function initTooltip() { - TooltipService.init( "statHeap" ); - TooltipService.init( "statPermGen" ); - TooltipService.init( "statJVMCpu" ); - TooltipService.init( "statSystemCpu" ); - TooltipService.init( "statTPS" ); - TooltipService.init( "statActiveThread" ); - TooltipService.init( "statResponseTime" ); - TooltipService.init( "statDataSource" ); + [ "statHeap", "statPermGen", "statJVMCpu", "statSystemCpu", "statTPS", "statActiveThread", "statResponseTime", "statDataSource", "statOpenFileDescriptor", "statDirectBufferCount", "statDirectBufferMemory", "statMappedBufferCount", "statMappedBufferMemory" ].forEach(function( name ) { + TooltipService.init( name ); + }); } function loadStatChart(from, to) { var oParam = { @@ -160,6 +155,63 @@ console.log("error"); } }); + AgentAjaxService.getStatOpenFileDescriptor( oParam, function(chartData) { + if ( angular.isUndefined(chartData.exception) ) { + scope.$broadcast("statisticChartDirective.initAndRenderWithData.application-open-file-descriptor", makeChartData({ + title: "Open File Descriptor", + fixMax: false, + defaultMax: 100, + yAxisTitle: "File Descriptor(count)", + labelFunc: function(value) { + return value; + } + }, chartData.charts.x, chartData.charts.y["OPEN_FILE_DESCRIPTOR_COUNT"]), "100%", "270px"); + } else { + console.log("error"); + } + }); + AgentAjaxService.getStatDirectBuffer( oParam, function(chartData) { + if ( angular.isUndefined(chartData.exception) ) { + scope.$broadcast("statisticChartDirective.initAndRenderWithData.application-direct-buffer-count", makeChartData({ + title: "Direct Buffer Count", + fixMax: false, + defaultMax: 100, + yAxisTitle: "Buffer (count)", + labelFunc: function(value) { + return value; + } + }, chartData.charts.x, chartData.charts.y["DIRECT_COUNT"]), "100%", "270px"); + scope.$broadcast("statisticChartDirective.initAndRenderWithData.application-mapped-buffer-count", makeChartData({ + title: "Mapped Buffer Count", + fixMax: false, + defaultMax: 100, + yAxisTitle: "Buffer (count)", + labelFunc: function(value) { + return value; + } + }, chartData.charts.x, chartData.charts.y["MAPPED_COUNT"]), "100%", "270px"); + scope.$broadcast("statisticChartDirective.initAndRenderWithData.application-direct-buffer-memory", makeChartData({ + title: "Direct Buffer memory", + fixMax: false, + defaultMax: 100, + yAxisTitle: "Memory (bytes)", + labelFunc: function(value) { + return convertWithUnits(value, ["", "K", "M", "G"]); + } + }, chartData.charts.x, chartData.charts.y["DIRECT_MEMORY_USED"]), "100%", "270px"); + scope.$broadcast("statisticChartDirective.initAndRenderWithData.application-mapped-buffer-memory", makeChartData({ + title: "Mapped Buffer Memory", + fixMax: false, + defaultMax: 100, + yAxisTitle: "Memory (bytes)", + labelFunc: function(value) { + return convertWithUnits(value, ["", "K", "M", "G"]); + } + }, chartData.charts.x, chartData.charts.y["MAPPED_MEMORY_USED"]), "100%", "270px"); + } else { + console.log("error"); + } + }); } } function broadcastToDataSource( xData, yData ) { @@ -259,6 +311,7 @@ scope.selectTime = time; initTime( time ); sendUpTimeSliderTimeInfo( timeSlider.getSliderTimeSeries(), timeSlider.getSelectionTimeSeries(), time ); + scope.$apply(); }).addEvent("changeSelectionZone", function( aTime ) { loadStatChart( aTime[0], aTime[1] ); sendUpTimeSliderTimeInfo( timeSlider.getSliderTimeSeries(), aTime, timeSlider.getSelectTime() ); @@ -293,6 +346,7 @@ }, "agentEventTimeline":{"timelineSegments":[]} }); + sendUpTimeSliderTimeInfo( timeSlider.getSliderTimeSeries(), timeSlider.getSelectionTimeSeries(), scope.selectTime ); } scope.selectDataSource = function(event) { var target = event.target; diff --git a/web/src/main/webapp/features/applicationStatistic/applicationStatistic.html b/web/src/main/webapp/features/applicationStatistic/applicationStatistic.html index 0b89676800c8..7fe4ec0feca5 100644 --- a/web/src/main/webapp/features/applicationStatistic/applicationStatistic.html +++ b/web/src/main/webapp/features/applicationStatistic/applicationStatistic.html @@ -61,7 +61,32 @@

Response Time

-
+
+

Open File Descriptor

+ +
+ +
+
+
+

Direct Buffer Count

+ +
+
+

Direct Buffer Memory

+ +
+
+
+
+
+

Mapped Buffer Count

+ +
+
+

Mapped Buffer Memory

+ +

diff --git a/web/src/main/webapp/features/configuration/help/help.directive.js b/web/src/main/webapp/features/configuration/help/help.directive.js index fb63d5252c1e..4e802d10b182 100644 --- a/web/src/main/webapp/features/configuration/help/help.directive.js +++ b/web/src/main/webapp/features/configuration/help/help.directive.js @@ -16,11 +16,11 @@ $element[ attr["initState"] ](); scope.enHelpList = [ - { "title": "Quick start guide", "link": "https://github.com/naver/pinpoint/blob/master/quickstart/README.md" }, - { "title": "Technical Overview of Pinpoint", "link": "https://github.com/naver/pinpoint/wiki/Technical-Overview-Of-Pinpoint" }, - { "title": "Using Pinpont with Docker", "link": "http://yous.be/2015/05/05/using-pinpoint-with-docker/" }, + { "title": "Quick start guide", "link": "https://naver.github.io/pinpoint/quickstart.html" }, + { "title": "Technical Overview of Pinpoint", "link": "https://naver.github.io/pinpoint/techdetail.html" }, + { "title": "Using Pinpont with Docker", "link": "https://github.com/naver/pinpoint-docker" }, { "title": "Notes on Jetty Plugin for Pinpoint ", "link": "https://github.com/cijung/Docs/blob/master/JettyPluginNotes.md" }, - { "title": "About Alarm", "link": "https://github.com/naver/pinpoint/blob/master/doc/alarm.md#alarm" } + { "title": "About Alarm", "link": "https://naver.github.io/pinpoint/alarm.html#alarm" } ]; scope.koHelpList = [ { "title": "Pinpoint 개발자가 작성한 Pinpoint 기술문서", "link": "http://helloworld.naver.com/helloworld/1194202" }, @@ -29,7 +29,7 @@ { "title": "설치 가이드 동영상 강좌 1", "link": "https://www.youtube.com/watch?v=hrvKaEaDEGs" }, { "title": "설치 가이드 동영상 강좌 2", "link": "https://www.youtube.com/watch?v=fliKPGHGXK4" }, { "title": "AWS Ubuntu 14.04 설치 가이드 ", "link": "http://lky1001.tistory.com/132" }, - { "title": "Alarm 가이드", "link": "https://github.com/naver/pinpoint/blob/master/doc/alarm.md#alarm-1" } + { "title": "Alarm 가이드", "link": "https://naver.github.io/pinpoint/alarm.html#alarm-1" } ]; scope.$on( "configuration.selectMenu", function( event, selectedName ) { diff --git a/web/src/main/webapp/features/configuration/help/help.html b/web/src/main/webapp/features/configuration/help/help.html index fc27b64e1dcb..555c76cd14cb 100644 --- a/web/src/main/webapp/features/configuration/help/help.html +++ b/web/src/main/webapp/features/configuration/help/help.html @@ -1,7 +1,7 @@
diff --git a/web/src/main/webapp/features/configuration/userGroup/group-member.directive.js b/web/src/main/webapp/features/configuration/userGroup/group-member.directive.js index b882b92a59a7..9fe6fb34a62e 100644 --- a/web/src/main/webapp/features/configuration/userGroup/group-member.directive.js +++ b/web/src/main/webapp/features/configuration/userGroup/group-member.directive.js @@ -143,10 +143,8 @@ scope.$emit( "groupMember.sendCallbackAddedUser", true, oUser.userId ); AlarmUtilService.setTotal( $elTotal, oGroupMemberList.length ); AlarmUtilService.hide( $elLoading ); - }, function() { - showAlert({ - message: CONSTS.EXIST_A_SAME - }); + }, function(oServerError) { + showAlert(oServerError); scope.$emit( "groupMember.sendCallbackAddedUser", false, oUser.userId ); }); }); @@ -166,14 +164,6 @@ } scope.groupMemberList = oGroupMemberList; } - scope.$on( "groupMember.removeUser", function( event, userId ) { - if ( hasUser( userId ) ) { - cancelPreviousWork(); - // scope.$apply(function() { - removeGroupMember( userId ); - // }); - } - }); } }; }]); @@ -220,10 +210,10 @@ this._bIng = false; } }, - applyAction: function( AlarmUtilService, currentUserGroupId, $node, $elLoading, cbSuccess, cbFail ) { + applyAction: function( AlarmUtilService, currentUserGroupId, $node, $elLoading, cbSuccess, cbFail, userId ) { AlarmUtilService.show( $elLoading ); var self = this; - var memberId = AlarmUtilService.extractID( $node ); + var memberId = userId || AlarmUtilService.extractID( $node ); AlarmUtilService.sendCRUD( "removeMemberInGroup", { "userGroupId": currentUserGroupId, "memberId": memberId diff --git a/web/src/main/webapp/features/configuration/userGroup/pinpoint-user.directive.js b/web/src/main/webapp/features/configuration/userGroup/pinpoint-user.directive.js index 0712f6b46c26..deb41e3064b3 100644 --- a/web/src/main/webapp/features/configuration/userGroup/pinpoint-user.directive.js +++ b/web/src/main/webapp/features/configuration/userGroup/pinpoint-user.directive.js @@ -199,7 +199,7 @@ if ( oPinpointUserList[i].userId == oPinpointUser.userId ) { oPinpointUserList[i].name = oPinpointUser.name; oPinpointUserList[i].department = oPinpointUser.department; - oPinpointUserList[i].phoneNumber = oPinpointUser.phone; + oPinpointUserList[i].phoneNumber = oPinpointUser.phoneNumber; oPinpointUserList[i].email = oPinpointUser.email; break; } @@ -249,11 +249,7 @@ AlarmUtilService.show( $elLoading ); var $node = AlarmUtilService.getNode( $event, "li" ); var userId = AlarmUtilService.extractID( $node ); - if ( $node.find("input").get(0).checked ) { - scope.$emit( "pinpointUser.sendUserAdd", getUser( userId ) ); - } else { - scope.$emit( "pinpointUser.sendUserRemoved", userId ); - } + scope.$emit( "pinpointUser.sendUserAdd", getUser( userId ) ); }; scope.$on( "pinpointUser.changeSelectedMember", function( event, list ) { resetList( list ); @@ -261,6 +257,7 @@ scope.pinpointUserList = oPinpointUserList; }); AlarmUtilService.setTotal( $elTotal, getTotal() ); + AlarmUtilService.hide( $elLoading ); }); scope.$on( "pinpointUser.checkSelectedMember", function( event, list ) { $elWrapper.removeClass( "_disable-check" ); diff --git a/web/src/main/webapp/features/configuration/userGroup/pinpointUser.html b/web/src/main/webapp/features/configuration/userGroup/pinpointUser.html index cc16363f79bd..3440e076c4fe 100644 --- a/web/src/main/webapp/features/configuration/userGroup/pinpointUser.html +++ b/web/src/main/webapp/features/configuration/userGroup/pinpointUser.html @@ -40,7 +40,7 @@
  • {{"("+pinpointUser.department + ")" + pinpointUser.name}} - +
    diff --git a/web/src/main/webapp/features/configuration/userGroup/user-group-container.directive.js b/web/src/main/webapp/features/configuration/userGroup/user-group-container.directive.js index 141aa1722d7f..db498a565024 100644 --- a/web/src/main/webapp/features/configuration/userGroup/user-group-container.directive.js +++ b/web/src/main/webapp/features/configuration/userGroup/user-group-container.directive.js @@ -46,11 +46,6 @@ scope.$broadcast( "pinpointUser.addUserCallback", bIsSuccess, userId ); event.stopPropagation(); }); - // pinpointUser > groupMember - scope.$on( "pinpointUser.sendUserRemoved", function( event, userId ) { - scope.$broadcast( "groupMember.removeUser", userId ); - event.stopPropagation(); - }); scope.$on( "pinpointUser.sendUserUpdated", function( event, oPinpointUser ) { scope.$broadcast( "groupMember.updateUser", oPinpointUser ); event.stopPropagation(); diff --git a/web/src/main/webapp/features/configuration/userGroup/user-group.directive.js b/web/src/main/webapp/features/configuration/userGroup/user-group.directive.js index 252cdb5fdf84..1c3757dd0075 100644 --- a/web/src/main/webapp/features/configuration/userGroup/user-group.directive.js +++ b/web/src/main/webapp/features/configuration/userGroup/user-group.directive.js @@ -58,6 +58,13 @@ addSelectClass( AlarmUtilService.extractID( $el ) ); scope.$emit( "userGroup.selectedUserGroup", $el.find(".contents").html() ); } + function releaseGroup( groupNumber ) { + if ( selectedGroupNumber !== groupNumber ) { + return; + } + selectedGroupNumber = ""; + scope.$emit( "userGroup.selectedNone" ); + } function addSelectClass( newSelectedGroupNumber ) { $( "#" + scope.prefix + selectedGroupNumber ).removeClass("selected"); $( "#" + scope.prefix + newSelectedGroupNumber ).addClass("selected"); @@ -81,7 +88,7 @@ cancelPreviousWork(); var query = $.trim( $elSearchInput.val() ); if ( query === "" ) { - loadData({}); + loadData(""); } else { if ( query.length < CONSTS.MIN_GROUPNAME_LENGTH ) { $elSearchInput.val(""); @@ -134,6 +141,7 @@ }; scope.onApplyRemoveUserGroup = function() { SystemConfigService.getConfig().then(function(config) { + var groupNumber = AlarmUtilService.extractID($workingNode); RemoveUserGroup.applyAction( AlarmUtilService, $workingNode, $elLoading, config["userId"], function( groupId ) { for (var i = 0; i < oUserGroupList.length; i++) { if ( oUserGroupList[i].id == groupId ) { @@ -141,6 +149,7 @@ break; } } + releaseGroup( groupNumber ); scope.$apply(function () { scope.userGroupList = oUserGroupList; }); @@ -171,7 +180,7 @@ }; scope.$on("configuration.userGroup.show", function() { if ( bIsLoaded === false ) { - loadData({}); + loadData(""); } }); } diff --git a/web/src/main/webapp/features/distributedCallFlow/distributed-call-flow.directive.js b/web/src/main/webapp/features/distributedCallFlow/distributed-call-flow.directive.js index 15c9e769a6e4..04e001436716 100644 --- a/web/src/main/webapp/features/distributedCallFlow/distributed-call-flow.directive.js +++ b/web/src/main/webapp/features/distributedCallFlow/distributed-call-flow.directive.js @@ -105,7 +105,9 @@ html.push(' '); } else if (!item.isMethod) { if( item.method === "SQL" ) { - html.push(' '); + html.push(' '); + } else if( item.method === "MONGO-JSON" ) { + html.push(' '); } else { html.push(' '); } @@ -340,7 +342,7 @@ grid = new Slick.Grid(element.get(0), dataView, columns, options); grid.setSelectionModel(new Slick.RowSelectionModel()); - var isSingleClick = true, clickTimeout = false; + var isSingleSQ = true, clickTimeout = false; grid.onClick.subscribe(function (e, args) { var item; if ($(e.target).hasClass("toggle")) { @@ -358,12 +360,12 @@ if ( $(e.target).hasClass("sql") ) { item = dataView.getItem(args.row); var itemNext = dataView.getItem(args.row+1); - var data = "sql=" + encodeURIComponent( item.argument ); + var data = "type=sql&metaData=" + encodeURIComponent( item.argument ); if ( item.isAuthorized ) { if ( angular.isDefined( itemNext ) && itemNext.method === "SQL-BindValue" ) { data += "&bind=" + encodeURIComponent( itemNext.argument ); - CommonAjaxService.getSQLBind( "sqlBind.pinpoint", data, function( result ) { + CommonAjaxService.getSQLBind( "bind.pinpoint", data, function( result ) { $("#customLogPopup").find("h4").html("SQL").end().find("div.modal-body").html( '

    Binded SQL

    ' + '
    ' + result + '
    ' + @@ -393,6 +395,44 @@ ).end().modal("show"); } } + if ( $(e.target).hasClass("json") ) { + item = dataView.getItem(args.row); + var itemNext = dataView.getItem(args.row+1); + var data = "type=mongoJson&metaData=" + encodeURIComponent( item.argument ); + + if ( item.isAuthorized ) { + if ( angular.isDefined( itemNext ) && itemNext.method === "MONGO-JSON-BindValue" ) { + data += "&bind=" + encodeURIComponent( itemNext.argument ); + CommonAjaxService.getSQLBind( "bind.pinpoint", data, function( result ) { + $("#customLogPopup").find("h4").html("JSON").end().find("div.modal-body").html( + '

    Binded JSON

    ' + + '
    ' + result + '
    ' + + '
    ' + result.replace(/\t\t/g, "") + '
    ' + + '
    ' + + '

    Original JSON

    ' + + '
    ' + item.argument + '
    ' + + '
    ' + item.argument.replace(/\t\t/g, "") + '
    ' + + '

    JSON Bind Value

    ' + + '
    ' + itemNext.argument + '
    ' + + '
    ' + itemNext.argument + '
    ' + ).end().modal("show"); + prettyPrint(); + }); + } else { + $("#customLogPopup").find("h4").html("JSON").end().find("div.modal-body").html( + '

    Original JSON

    ' + + '
    ' + item.argument + '
    ' + + '
    ' + item.argument.replace(/\t\t/g, "") + '
    ' + ).end().modal("show"); + prettyPrint(); + } + } else { + $("#customLogPopup").find("h4").html("JSON").end().find("div.modal-body").html( + '

    Original JSON

    ' + + '
    ' + item.argument.replace(/\t\t/g, "") + '
    ' + ).end().modal("show"); + } + } if (!clickTimeout) { clickTimeout = $timeout(function () { @@ -582,7 +622,7 @@ grid.scrollRowIntoView( row, true ); }; } - }; + } } ]); })(); \ No newline at end of file diff --git a/web/src/main/webapp/features/loadChart/load-chart.directive.js b/web/src/main/webapp/features/loadChart/load-chart.directive.js index af34ba527837..1d6a33b8dfc0 100644 --- a/web/src/main/webapp/features/loadChart/load-chart.directive.js +++ b/web/src/main/webapp/features/loadChart/load-chart.directive.js @@ -5,16 +5,15 @@ pinpointApp.directive("loadChartDirective", ["loadChartDirectiveConfig", "$rootScope", "$timeout", "AnalyticsService", "PreferenceService", "CommonUtilService", function (cfg, $rootScope, $timeout, AnalyticsService, PreferenceService, CommonUtilService ) { var responseTypeColor = PreferenceService.getResponseTypeColor(); return { - template: "
    ", + template: "
    ", replace: true, restrict: 'EA', scope: { namespace: '@' // string value }, - link: function postLink(scope, element, attrs) { - - // define variables - var id, aDynamicKey, oChart; + link: function postLink(scope, element) { + var id, oChart = null; + var elCanvas = element.find("canvas"); function setIdAutomatically() { id = 'loadId-' + scope.namespace; @@ -25,9 +24,11 @@ element.css('width', w || '100%'); element.css('height', h || '220px'); } - function renderChart(data, yMax, useChartCursor) { - element.empty().append(""); - oChart = new Chart(element.find("canvas"), { + function renderChart(data, yMax) { + if ( oChart !== null ) { + oChart.destroy(); + } + oChart = new Chart(elCanvas, { type: "bar", data: { labels: data.labels, @@ -158,6 +159,8 @@ element.find("h4").hide().end().find("canvas").show(); if ( yMax ) { oChart.config.options.scales.yAxes[0].ticks.max = yMax; + } else { + delete oChart.config.options.scales.yAxes[0].ticks.max; } oChart.data.labels = data.labels; oChart.data.datasets[0].data = data.keyValues[0].values; @@ -211,7 +214,11 @@ }); scope.$on("loadChartDirective.updateData." + scope.namespace, function (event, data, yMax) { - updateChart(parseTimeSeriesHistogram(data), yMax); + if ( scope.namespace === "forServerList" ) { + updateChart(parseTimeSeriesHistogram(data), yMax); + } else { + updateChart(parseTimeSeriesHistogram(data)); + } }); } }; diff --git a/web/src/main/webapp/features/realtimeChart/realtime-chart.controller.js b/web/src/main/webapp/features/realtimeChart/realtime-chart.controller.js index 9f095133ca3b..0b6a793ec459 100644 --- a/web/src/main/webapp/features/realtimeChart/realtime-chart.controller.js +++ b/web/src/main/webapp/features/realtimeChart/realtime-chart.controller.js @@ -310,7 +310,7 @@ } function stopReceive() { bShowRealtimeChart = false; - webSocketService.stopReceive( makeRequest("") ); + webSocketService.close(); } function stopChart() { $rootScope.$broadcast("realtimeChartDirective.clear.sum"); diff --git a/web/src/main/webapp/features/responseTimeSummaryChart/response-time-summary-chart.directive.js b/web/src/main/webapp/features/responseTimeSummaryChart/response-time-summary-chart.directive.js index 59d1bf9742d0..ec9f4a71e89c 100644 --- a/web/src/main/webapp/features/responseTimeSummaryChart/response-time-summary-chart.directive.js +++ b/web/src/main/webapp/features/responseTimeSummaryChart/response-time-summary-chart.directive.js @@ -13,14 +13,15 @@ return "rgba(" + r + ", " + g + ", " + b + ", " + chartBackgroundAlpha[index] + ")"; }); return { - template: "
    ", + template: "
    ", replace: true, restrict: "EA", scope: { namespace: "@" // string value }, link: function postLink( scope, element ) { - var id, oChart; + var id, oChart = null; + var elCanvas = element.find("canvas"); function setIdAutomatically() { id = "responseTimeId-" + scope.namespace; @@ -30,9 +31,11 @@ element.css("width", w || "100%"); element.css("height", h || "150px"); } - function renderChart(data, yMax, useFilterTransaction, useChartCursor) { - element.empty().append(""); - oChart = new Chart(element.find("canvas"), { + function renderChart(data, yMax, useFilterTransaction) { + if ( oChart !== null ) { + oChart.destroy(); + } + oChart = new Chart(elCanvas, { type: "bar", data: { labels: data.keys, @@ -148,6 +151,8 @@ function updateChart(data, yMax) { if ( yMax ) { oChart.config.options.scales.yAxes[0].ticks.max = yMax; + } else { + delete oChart.config.options.scales.yAxes[0].ticks.max; } oChart.data.labels = data.keys; oChart.data.datasets[0].data = data.values; @@ -178,7 +183,11 @@ }); scope.$on("responseTimeSummaryChartDirective.updateData." + scope.namespace, function (event, data, yMax) { - updateChart( parseHistogram(data), yMax ); + if ( scope.namespace === "forServerList" ) { + updateChart(parseHistogram(data), yMax); + } else { + updateChart(parseHistogram(data)); + } }); } diff --git a/web/src/main/webapp/features/serverMap/server-map.directive.js b/web/src/main/webapp/features/serverMap/server-map.directive.js index 014e2ecd9e63..186151fef32a 100644 --- a/web/src/main/webapp/features/serverMap/server-map.directive.js +++ b/web/src/main/webapp/features/serverMap/server-map.directive.js @@ -377,7 +377,7 @@ var selectedNode; for( var i = 0 ; i < htLastMergedMapData.nodeDataArray.length ; i++ ) { var node = htLastMergedMapData.nodeDataArray[i]; - if ( node.applicationName === query.applicationName ) { + if ( node.applicationName === query.applicationName && node.serviceType === query.serviceTypeName ) { selectedNode = node; options.sBoldKey = node.key; break; @@ -410,7 +410,7 @@ $timeout(function() { if ( scope.oNavbarVoService.isRealtime() ) { htLastQuery.to = htLastQuery.to + reloadRequestRepeatingTime; - htLastQuery.from = htLastQuery.from - reloadRequestTimeRange; + htLastQuery.from = htLastQuery.to - reloadRequestTimeRange; ServerMapDaoService.getServerMapData(htLastQuery, function (err, query, mapData) { if ( scope.oNavbarVoService.isRealtime() ) { htLastMapData = mapData; @@ -532,7 +532,7 @@ scope.$broadcast('serverMapDirective.openFilteredMap', oServerMapFilterVoService, oServerMapHintVoService); reset(); }; - scope.openFilterWizard = function () { + scope.openFilterWizard2 = function () { AnalyticsService.send(AnalyticsService.CONST.CONTEXT, AnalyticsService.CONST.CLK_FILTER_TRANSACTION_WIZARD); openFilterWizard(); }; diff --git a/web/src/main/webapp/features/serverMap/serverMap.html b/web/src/main/webapp/features/serverMap/serverMap.html index c3cc11839ef1..d719e1897896 100644 --- a/web/src/main/webapp/features/serverMap/serverMap.html +++ b/web/src/main/webapp/features/serverMap/serverMap.html @@ -34,9 +34,9 @@

    To use PinPoint, enable cookies and JavaScript

    + + diff --git a/web/src/main/webapp/pages/transactionDetail/transactionDetail.html b/web/src/main/webapp/pages/transactionDetail/transactionDetail.html index c2be43af777a..24456c126a6a 100644 --- a/web/src/main/webapp/pages/transactionDetail/transactionDetail.html +++ b/web/src/main/webapp/pages/transactionDetail/transactionDetail.html @@ -65,7 +65,7 @@
  • Timeline
  • Mixed View
  • - {{logButtonName}} + {{logButtonName}}
  • +
    + + +
    +
  • +
    + + + +
    + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager-container.component.ts new file mode 100644 index 000000000000..e0921b487a46 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager-container.component.ts @@ -0,0 +1,107 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { DynamicPopupService } from 'app/shared/services'; +import { ApplicationListDataService } from 'app/core/components/application-list/application-list-data.service'; +import { AgentManagerDataService } from './agent-manager-data.service'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; + +@Component({ + selector: 'pp-agent-manager-container', + templateUrl: './agent-manager-container.component.html', + styleUrls: ['./agent-manager-container.component.css'] +}) +export class AgentManagerContainerComponent implements OnInit { + applicationFilter = ''; + showLoading = false; + applicationList$: Observable; + agentList: { + [key: string]: any; + } = {}; + canRemoveInactiveAgent = false; + constructor( + private applicationListDataService: ApplicationListDataService, + private agentManagerDataService: AgentManagerDataService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.applicationList$ = this.applicationListDataService.getApplicationList(); + } + getAgentList(application: IApplication): string[] { + return this.agentList[application.applicationName]; + } + onLoadAgentList(applicationName: string): void { + this.agentManagerDataService.getAgentList(applicationName).subscribe((agentList: IAgentList) => { + const agentInfoList: any[] = []; + Object.keys(agentList).forEach((key: string) => { + agentList[key].forEach((agent: IAgent) => { + agentInfoList.push({ + applicationName: agent.applicationName, + agentId: agent.agentId + }); + }); + }); + this.agentList[applicationName] = agentInfoList; + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent + }); + }); + } + onRemoveAgent([applicationName, agentId]: [string, string]): void { + this.agentManagerDataService.removeAgentId(applicationName, agentId).subscribe((result: string) => { + if (result === 'OK') { + const appInfo = this.agentList[applicationName]; + const index = appInfo.findIndex((app: any) => { + return app.agentId === agentId; + }); + appInfo.splice(index, 1); + } + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent + }); + }); + } + onRemoveInactiveAgents(): void { + if (this.canRemoveInactiveAgent === false) { + return; + } + this.showLoading = true; + this.agentManagerDataService.removeInactiveAgents().subscribe((result: string) => { + if (result === 'OK') { + // 모든 agent 목록 초기화 + } + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent + }); + }); + } + hasFilterStr(appName: string): boolean { + const filter = this.applicationFilter.trim(); + if (filter === '') { + return true; + } + if (appName.indexOf(filter) === -1) { + return false; + } else { + return true; + } + } + onChangeCanRemoveInactiveAgent($event: any): void { + this.canRemoveInactiveAgent = $event.checked; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager-data.service.ts new file mode 100644 index 000000000000..4ddebbc6df10 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager-data.service.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@angular/core'; +import { HttpParams } from '@angular/common/http'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + + +@Injectable() +export class AgentManagerDataService { + private listUrl = 'getAgentList.pinpoint'; + private removeUrl = 'admin/removeAgentId.pinpoint'; + private removeInactiveUrl = 'admin/removeInactiveAgents.pinpoint'; + + constructor(private http: HttpClient) {} + getAgentList(appName: string): Observable { + return this.http.get(this.listUrl, { + params: new HttpParams().set('application', appName) + }).pipe( + retry(3) + ); + } + removeAgentId(appName: string, agentId: string): Observable { + return this.http.post(this.removeUrl, { + params: new HttpParams().set('applicationName', appName).set('agentId', agentId) + }).pipe( + retry(3) + ); + } + removeInactiveAgents(): Observable { + return this.http.get(this.removeInactiveUrl).pipe( + retry(3) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager.component.css b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager.component.css new file mode 100644 index 000000000000..fcc6b610c5ca --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager.component.css @@ -0,0 +1,62 @@ +.l-out-wrapper { + background: #FFF; + width: 95%; + position: relative; + z-index: 2; + overflow: hidden; + padding: 4px; + margin: 10px 14px; + box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.23); +} +.l-wrapper { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.l-wrapper button { + color: #4b99e3; + float: right; + font-size: 18px; +} +.l-wrapper button.l-remove { + color: #b5213c; + height: 20px; + width: 20px; + font-size: 16px; +} +.l-none { + float: right; + height: 18px; +} +.l-agent-list { + color: #000; + background-color: #F1F1F1; + padding: 6px; + height: 120px; + overflow: auto; + min-height: 120px; + max-height: 120px; + margin-top: 12px; +} +.l-agent { + padding: 2px 6px; +} +.l-loading { + height: 120px; + position: relative; + margin-top: 12px; +} +.l-empty { + color: #AAA; + background-color: #DDD; +} +.l-dup { + color: #F00; +} +.l-has { + +} +.l-yet { + +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager.component.html b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager.component.html new file mode 100644 index 000000000000..22a96417ef87 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager.component.html @@ -0,0 +1,17 @@ +
    +
    + + empty + {{application.applicationName + '@' + application.serviceType}} +
    +
    + +
    +
    +
    + + + {{agent.agentId}} +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager.component.ts b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager.component.ts new file mode 100644 index 000000000000..ee7bed36ec99 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-manager/agent-manager.component.ts @@ -0,0 +1,49 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +interface IAgentShortInfo { + applicationName: string; + agentId: string; +} + +@Component({ + selector: 'pp-agent-manager', + templateUrl: './agent-manager.component.html', + styleUrls: ['./agent-manager.component.css'] +}) +export class AgentManagerComponent implements OnInit { + @Input() application: IApplication; + @Input() + set agentList(value: IAgentShortInfo[]) { + this._agentList = value; + this.showLoading = false; + } + @Output() outLoadAgentList: EventEmitter = new EventEmitter(); + @Output() outRemoveAgent: EventEmitter = new EventEmitter(); + _agentList: IAgentShortInfo[]; + showLoading = false; + constructor() {} + ngOnInit() {} + onLoadAgentList(): void { + if (this.showLoading === true) { + return; + } + this.showLoading = true; + this.outLoadAgentList.emit(this.application.applicationName); + } + onRemoveAgent(agentId: string): void { + this.outRemoveAgent.emit([this.application.applicationName, agentId]); + } + getAgentStateClass(): string { + return 'l-' + this.getAgentState(); + } + getAgentState(): string { + if (this._agentList) { + return this._agentList.length > 0 ? 'has' : 'empty'; + } else { + return 'yet'; + } + } + isDup(agent: IAgentShortInfo): boolean { + return this.application.applicationName !== agent.applicationName; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-manager/index.ts b/web/src/main/webapp/v2/src/app/core/components/agent-manager/index.ts new file mode 100644 index 000000000000..5b0fe24e0527 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-manager/index.ts @@ -0,0 +1,30 @@ + +import { NgModule } from '@angular/core'; +import { MatTooltipModule, MatSlideToggleModule } from '@angular/material'; +import { SharedModule } from 'app/shared'; +import { AgentManagerContainerComponent } from './agent-manager-container.component'; +import { AgentManagerComponent } from './agent-manager.component'; +import { AgentManagerDataService } from './agent-manager-data.service'; +import { ApplicationListModule } from 'app/core/components/application-list'; +import { ServerErrorPopupModule } from 'app/core/components/server-error-popup'; + +@NgModule({ + declarations: [ + AgentManagerComponent, + AgentManagerContainerComponent + ], + imports: [ + MatSlideToggleModule, + MatTooltipModule, + SharedModule, + ApplicationListModule, + ServerErrorPopupModule + ], + exports: [ + AgentManagerContainerComponent + ], + providers: [ + AgentManagerDataService + ] +}) +export class AgentManagerModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-search-input/agent-search-input-container.component.css b/web/src/main/webapp/v2/src/app/core/components/agent-search-input/agent-search-input-container.component.css new file mode 100644 index 000000000000..06c6835cc70c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-search-input/agent-search-input-container.component.css @@ -0,0 +1,41 @@ +.l-container-wrapper { + display: flex; + flex-flow: row wrap; + height: 66px; + background: #e0e7ee; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + position: absolute; + width: 100%; + bottom: 0px; + left: 0px; +} +.l-container-wrapper button { + color: #a8acb5; + font-size: 18px; +} +.l-wrapper { + background: #fff; + height: 32px; + width: 183px; + color: #b3b3b4; + position: relative; + margin-right: 10px; +} +.l-wrapper input { + width: 100%; + height: 100%; + border: 1px solid #d7dde4; + padding: 0 10px 0 10px; +} +.l-wrapper button { + position: absolute; + top: 50%; + right: 10px; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-search-input/agent-search-input-container.component.html b/web/src/main/webapp/v2/src/app/core/components/agent-search-input/agent-search-input-container.component.html new file mode 100644 index 000000000000..3dce246abff5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-search-input/agent-search-input-container.component.html @@ -0,0 +1,11 @@ +
    +
    + + +
    + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-search-input/agent-search-input-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/agent-search-input/agent-search-input-container.component.ts new file mode 100644 index 000000000000..3aaa4fa127fc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-search-input/agent-search-input-container.component.ts @@ -0,0 +1,56 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { combineLatest } from 'rxjs'; +import { TranslateService } from '@ngx-translate/core'; + +import { Actions } from 'app/shared/store'; +import { TranslateReplaceService, AnalyticsService, TRACKED_EVENT_LIST, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-agent-search-input-container', + templateUrl: './agent-search-input-container.component.html', + styleUrls: ['./agent-search-input-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentSearchInputContainerComponent implements OnInit { + i18nText: { [key: string]: string } = { + MIN_LENGTH_MSG: '' + }; + searchUseEnter = false; + SEARCH_MIN_LENGTH = 2; + constructor( + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.getI18NText(); + } + private getI18NText(): void { + combineLatest( + this.translateService.get('COMMON.MIN_LENGTH') + ).subscribe((i18n: string[]) => { + this.i18nText.MIN_LENGTH_MSG = this.translateReplaceService.replace(i18n[0], this.SEARCH_MIN_LENGTH); + }); + } + onSearchQuery(query: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SEARCH_AGENT); + this.storeHelperService.dispatch(new Actions.UpdateFilterOfServerAndAgentList(query)); + } + + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.AGENT_LIST); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.AGENT_LIST, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-search-input/index.ts b/web/src/main/webapp/v2/src/app/core/components/agent-search-input/index.ts new file mode 100644 index 000000000000..070acf13c07a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-search-input/index.ts @@ -0,0 +1,21 @@ + +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { AgentSearchInputContainerComponent } from './agent-search-input-container.component'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + AgentSearchInputContainerComponent + ], + imports: [ + SharedModule, + HelpViewerPopupModule + ], + exports: [ + AgentSearchInputContainerComponent + ], + providers: [] +}) +export class AgentSearchInputModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-list-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-list-data.service.ts new file mode 100644 index 000000000000..c8e64223115b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-list-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; +import { Observable, throwError } from 'rxjs'; +import { catchError, tap } from 'rxjs/operators'; + +@Injectable() +export class AgentListDataService { + private url = 'getAgentList.pinpoint'; + + constructor(private http: HttpClient) {} + retrieve(): Observable { + return this.http.get(this.url).pipe( + tap((data: any) => { + if (data.errorCode) { + throw data.errorMessage; + } + }), + catchError(this.handleError) + ); + } + private handleError(error: HttpErrorResponse) { + return throwError(error.statusText || error); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-stat-contents-container.component.css b/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-stat-contents-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-stat-contents-container.component.html b/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-stat-contents-container.component.html new file mode 100644 index 000000000000..123e342d62d0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-stat-contents-container.component.html @@ -0,0 +1,2 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-stat-contents-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-stat-contents-container.component.ts new file mode 100644 index 000000000000..8d1b6531b3b9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/agent-stat-contents-container.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit } from '@angular/core'; + +import { StoreHelperService } from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { AgentListDataService } from './agent-list-data.service'; + +@Component({ + selector: 'pp-agent-stat-contents-container', + templateUrl: './agent-stat-contents-container.component.html', + styleUrls: ['./agent-stat-contents-container.component.css'] +}) +export class AgentStatContentsContainerComponent implements OnInit { + constructor( + private storeHelperService: StoreHelperService, + private agentListDataService: AgentListDataService + ) {} + + ngOnInit() { + this.agentListDataService.retrieve().subscribe((agentList: { [key: string]: IAgent[] }) => { + this.storeHelperService.dispatch(new Actions.UpdateAdminAgentList(agentList)); + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/index.ts b/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/index.ts new file mode 100644 index 000000000000..3d8a7805aea6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/agent-stat-contents/index.ts @@ -0,0 +1,26 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { AgentStatContentsContainerComponent } from './agent-stat-contents-container.component'; +import { AgentListModule } from 'app/core/components/agent-list'; +import { AgentAdminChartModule } from 'app/core/components/agent-admin-chart'; + +import { AgentListDataService } from './agent-list-data.service'; + +@NgModule({ + declarations: [ + AgentStatContentsContainerComponent + ], + imports: [ + SharedModule, + AgentListModule, + AgentAdminChartModule + ], + exports: [ + AgentStatContentsContainerComponent + ], + providers: [ + AgentListDataService + ] +}) +export class AgentStatContentsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-create-and-update.component.css b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-create-and-update.component.css new file mode 100644 index 000000000000..99e611fac28e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-create-and-update.component.css @@ -0,0 +1,88 @@ +.l-wrapper { + top: 0px; + left: 0px; + width: 100%; + height: 100%; + z-index: 15; + display: flex; + padding: 0px 20px; + position: absolute; + align-items: center; + flex-direction: column; + justify-content: center; + background-color: rgba(226, 226, 226, 0.8); +} +.l-wrapper h1 { + margin-bottom: 6px; +} +form { + width: 100%; +} +.l-form-grid { + color: #333; + border: 1px solid #e5e8f0; + height: 100%; + display: grid; + position: relative; + font-size: 13px; + font-family: 'Open Sans', sans-serif; + font-weight: 600; + grid-template-columns: 50% 50%; + grid-template-rows: auto; +} +.l-form-grid > div { + position: relative; + margin-bottom: 10px; +} +.l-form-grid > div:nth-child(odd) { + margin-right: 10px; +} +.l-wrapper input { + width: 100%; + border: 1px solid #469ae4; + padding: 6px 11px; + font-size: 13px; + margin-bottom: 2px; + background-color: #FFF; +} +.l-wrapper .l-create { + width: 100%; + margin-top: 6px; +} +.l-wrapper .l-close { + top: 0px; + right: 0px; + position: absolute; +} +.l-wrapper .l-alert { + color: #FFF; + padding: 4px; + margin-bottom: 4px; + background-color: #000; +} +select { + width: 100%; + appearance: none; + -webkit-appearance: none; + border-radius: 0px; + background-color: #FFF; + height: 32px; + padding: 0 9px; + border:1px solid #4488cb; + font-size:13px; + color:#666; +} +textarea { + width: 100%; + height: 120px; + background-color: #FFF; +} +.fa-angle-down { + position: absolute; + top: 26px; + right: 8px; + font-size: 15px; +} +input[disabled] { + border: 1px solid #DDD !important; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-create-and-update.component.html b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-create-and-update.component.html new file mode 100644 index 000000000000..84d2711476c1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-create-and-update.component.html @@ -0,0 +1,56 @@ +
    + +

    {{title}}

    +
    +
    +
    +
    {{i18nLabel.CHECKER_LABEL}}
    + + +
    +
    + {{i18nGuide.CHECKER_REQUIRED}} +
    +
    +
    +
    +
    {{i18nLabel.USER_GROUP_LABEL}}
    + + +
    +
    + {{i18nGuide.USER_GROUP_REQUIRED}} +
    +
    +
    +
    +
    {{i18nLabel.THRESHOLD_LABEL}}
    + +
    +
    + Must be greater than 0 +
    +
    +
    +
    +
    {{i18nLabel.TYPE_LABEL}}
    + + +
    +
    +
    {{i18nLabel.NOTES_LABEL}}
    + + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-create-and-update.component.ts b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-create-and-update.component.ts new file mode 100644 index 000000000000..faa2881d0296 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-create-and-update.component.ts @@ -0,0 +1,118 @@ +import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; + +export class Alarm { + public applicationId: string; + public ruleId: string; + public smsSend: boolean; + public emailSend: boolean; + constructor( + public checkerName: string, + public userGroupId: string, + public threshold: number, + public type: string, + public notes?: string + ) { + this.setTypeInternalStatus(); + } + setTypeInternalStatus(): void { + this.smsSend = this.type === 'all' || this.type === 'sms' ? true : false; + this.emailSend = this.type === 'all' || this.type === 'email' ? true : false; + } +} + +@Component({ + selector: 'pp-alarm-rule-create-and-update', + templateUrl: './alarm-rule-create-and-update.component.html', + styleUrls: ['./alarm-rule-create-and-update.component.css'] +}) +export class AlarmRuleCreateAndUpdateComponent implements OnInit, OnChanges { + @Input() showCreate: boolean; + @Input() checkerList: string[]; + @Input() userGroupList: string[]; + @Input() i18nLabel: any; + @Input() i18nGuide: any; + @Input() editAlarm: Alarm = null; + @Output() outUpdateAlarm: EventEmitter = new EventEmitter(); + @Output() outCreateAlarm: EventEmitter = new EventEmitter(); + @Output() outClose: EventEmitter = new EventEmitter(); + newAlarmModel = new Alarm('', '', 1, 'all', ''); + alarmForm: FormGroup; + title = 'Alarm'; + + constructor() {} + ngOnInit() { + this.alarmForm = new FormGroup({ + 'checkerName': new FormControl(this.newAlarmModel.checkerName, [ + Validators.required + ]), + 'userGroupId': new FormControl(this.newAlarmModel.userGroupId, [ + Validators.required + ]), + 'threshold': new FormControl(this.newAlarmModel.threshold, [ + Validators.required, + Validators.min(1) + ]), + 'type': new FormControl(this.newAlarmModel.type, []), + 'notes': new FormControl(this.newAlarmModel.notes, []), + 'applicationId': new FormControl(this.newAlarmModel.applicationId, []), + 'ruleId': new FormControl(this.newAlarmModel.ruleId, []) + }); + } + ngOnChanges(changes: SimpleChanges) { + if (changes['showCreate'] && changes['showCreate'].currentValue === true) { + this.setValue('', '', 1, 'all', ''); + } + if (changes['editAlarm'] && changes['editAlarm'].currentValue) { + this.setValue( + this.editAlarm.checkerName, + this.editAlarm.userGroupId, + this.editAlarm.threshold, + this.editAlarm.type, + this.editAlarm.notes + ); + } + } + private setValue(checkerName: string, userGroupId: string, threshold: number, type: string, notes: string): void { + this.alarmForm.get('checkerName').setValue(checkerName); + this.alarmForm.get('userGroupId').setValue(userGroupId); + this.alarmForm.get('threshold').setValue(threshold); + this.alarmForm.get('type').setValue(type); + this.alarmForm.get('notes').setValue(notes); + } + onCreateOrUpdate() { + const alarm = new Alarm( + this.alarmForm.get('checkerName').value, + this.alarmForm.get('userGroupId').value, + this.alarmForm.get('threshold').value, + this.alarmForm.get('type').value, + this.alarmForm.get('notes').value + ); + if (this.editAlarm) { + this.outUpdateAlarm.emit(alarm); + } else { + this.outCreateAlarm.emit(alarm); + } + this.onClose(); + } + onClose() { + this.editAlarm = null; + this.outClose.emit(); + this.alarmForm.reset(); + } + get checkerName() { + return this.alarmForm.get('checkerName'); + } + get userGroupId() { + return this.alarmForm.get('userGroupId'); + } + get threshold() { + return this.alarmForm.get('threshold'); + } + get type() { + return this.alarmForm.get('type'); + } + get notes() { + return this.alarmForm.get('notes'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-data.service.ts new file mode 100644 index 000000000000..36d7f94cd649 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-data.service.ts @@ -0,0 +1,67 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry, shareReplay } from 'rxjs/operators'; + +export interface IAlarmRule { + applicationId: string; + checkerName: string; + emailSend: boolean; + notes: string; + ruleId: string; + serviceType: string; + smsSend: boolean; + threshold: number; + userGroupId: string; +} +export interface IAlarmRuleCreated { + number: string; +} +export interface IAlarmRuleResponse { + result: string; +} + +@Injectable() +export class AlarmRuleDataService { + private alarmRuleURL = 'application/alarmRule.pinpoint'; + private checkerListURL = 'application/alarmRule/checker.pinpoint'; + private cache$: Observable; + + constructor(private http: HttpClient) {} + getCheckerList(): Observable { + if (!this.cache$) { + const httpRequest$ = this.http.get(this.checkerListURL); + this.cache$ = httpRequest$.pipe( + shareReplay(1) + ); + } + return this.cache$; + } + retrieve(applicationId: string): Observable { + return this.http.get(this.alarmRuleURL, this.makeRequestOptionsArgs(applicationId)).pipe( + retry(3) + ); + } + create(params: IAlarmRule): Observable { + return this.http.post(this.alarmRuleURL, params).pipe( + retry(3) + ); + } + update(params: IAlarmRule): Observable { + return this.http.put(this.alarmRuleURL, params).pipe( + retry(3) + ); + } + remove(ruleId: string): Observable { + return this.http.request('delete', this.alarmRuleURL, { + body: { ruleId } + }).pipe( + retry(3) + ); + } + private makeRequestOptionsArgs(applicationId: string): object { + return applicationId ? { + params: new HttpParams().set('applicationId', applicationId) + } : {}; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list-container.component.css b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list-container.component.css new file mode 100644 index 000000000000..77856c45074e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list-container.component.css @@ -0,0 +1,84 @@ +:host { + position: relative; +} +.l-wrapper { + position: relative; +} +.l-alarm-rules-table th { + color:#333; + font-size: 13px; +} +.l-alarm-rules-table td { + padding:10px 15px; + height:auto; + font-size: 13px; +} +.l-alarm-rules-table th .l-table-title { + height: 47px; + justify-content: space-between; + display: flex; + align-items: center; +} +.l-table-title button:last-child { + margin-left: 2px; +} +.l-alarm-rules-tr-wrap { + height: 440px; + overflow-y: scroll; + position: relative; +} +.l-alarm-rules-th { + display: flex; + height: 30px; + align-items: center; + padding: 0 15px; + position:relative; + color: #777879; + font-weight: 600; + border-bottom: 1px solid #e6e8ec; + background: #fff; + margin: 0 -21px; +} +.l-alarm-rules-th div { + float :left; +} +.l-alarm-rules-th div:nth-child(1) { + width: 50%; +} +.l-alarm-rules-th div:nth-child(2) { + width: 16.66666667%; +} +.l-alarm-rules-th div:nth-child(3) { + width: 16.66666667%; +} +.l-alarm-rules-th div:nth-child(4) { + width: 25%; + margin-right: 22px; +} +.l-message { + top: 0px; + width: 100%; + height: 100%; + z-index: 15; + display: flex; + position: absolute; + align-items: center; + justify-content: center; + background-color: rgba(226, 226, 226, 0.8); +} +.l-message span { + color: #ff8c00; + text-align: center; +} +.l-message button { + top: 0px; + right: 0px; + position: absolute; +} +.l-not-selected { + padding-top: 30%; + text-align: center; +} +.l-threshold { + text-align: center; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list-container.component.html b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list-container.component.html new file mode 100644 index 000000000000..f0096ffe377c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list-container.component.html @@ -0,0 +1,57 @@ +
    + + + + + + + + + + + + + + +
    +
    + Alarm +
    + + +
    +
    +
    +
    Rule Name
    +
    User Group
    +
    Threshold
    +
    Type
    +
    +
    +
    + +
    Select Application
    +
    +
    +
    + + {{message}} +
    + + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list-container.component.ts new file mode 100644 index 000000000000..562fa2f6c968 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list-container.component.ts @@ -0,0 +1,256 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject, combineLatest } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { TranslateReplaceService } from 'app/shared/services'; +import { UserGroupDataService, IUserGroup } from 'app/core/components/user-group/user-group-data.service'; +import { ApplicationListInteractionForConfigurationService } from 'app/core/components/application-list/application-list-interaction-for-configuration.service'; +import { Alarm } from './alarm-rule-create-and-update.component'; +import { AlarmRuleDataService, IAlarmRule, IAlarmRuleCreated, IAlarmRuleResponse } from './alarm-rule-data.service'; + +@Component({ + selector: 'pp-alarm-rule-list-container', + templateUrl: './alarm-rule-list-container.component.html', + styleUrls: ['./alarm-rule-list-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AlarmRuleListContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private editAlarmIndex: number; + currentApplication: IApplication = null; + useDisable = false; + showLoading = false; + showCreate = false; + message = ''; + checkerList: string[]; + userGroupList: string[]; + alarmRuleList: IAlarmRule[]; + + i18nLabel = { + CHECKER_LABEL: '', + USER_GROUP_LABEL: '', + THRESHOLD_LABEL: '', + TYPE_LABEL: '', + NOTES_LABEL: '', + }; + i18nGuide = { + CHECKER_REQUIRED: '', + USER_GROUP_REQUIRED: '', + THRESHOLD_REQUIRED: '', + TYPE_REQUIRED: '' + }; + editAlarm: any; + + constructor( + private changeDetectorRef: ChangeDetectorRef, + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + private alarmRuleDataService: AlarmRuleDataService, + private userGroupDataSerivce: UserGroupDataService, + private applicationListInteractionForConfigurationService: ApplicationListInteractionForConfigurationService + ) {} + ngOnInit() { + this.alarmRuleDataService.getCheckerList().pipe( + takeUntil(this.unsubscribe) + ).subscribe((checkerList: string[] | IServerErrorShortFormat) => { + if ((checkerList as IServerErrorShortFormat).errorCode) { + } else { + this.checkerList = checkerList as string[]; + } + }); + this.userGroupDataSerivce.retrieve().pipe( + takeUntil(this.unsubscribe) + ).subscribe((userGroupList: IUserGroup[] | IServerErrorShortFormat) => { + if ((userGroupList as IServerErrorShortFormat).errorCode) { + // (userGroupList as IServerErrorShortFormat).errorMessage; + } else { + this.userGroupList = (userGroupList as IUserGroup[]).map((userGroup: IUserGroup) => { + return userGroup.id; + }); + } + }, (error: IServerErrorFormat) => { + + }); + this.applicationListInteractionForConfigurationService.onSelectApplication$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((selectedApplication: IApplication) => { + this.currentApplication = selectedApplication; + this.onCloseCreateAlarmPopup(); + this.getAlarmData(); + }); + this.getI18NText(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private getI18NText(): void { + combineLatest( + this.translateService.get('COMMON.REQUIRED_SELECT'), + this.translateService.get('CONFIGURATION.COMMON.CHECKER'), + this.translateService.get('CONFIGURATION.COMMON.USER_GROUP'), + this.translateService.get('CONFIGURATION.COMMON.THRESHOLD'), + this.translateService.get('CONFIGURATION.COMMON.TYPE'), + this.translateService.get('CONFIGURATION.COMMON.NOTES'), + ).subscribe((i18n: string[]) => { + this.i18nGuide.CHECKER_REQUIRED = this.translateReplaceService.replace(i18n[0], i18n[1]); + this.i18nGuide.USER_GROUP_REQUIRED = this.translateReplaceService.replace(i18n[0], i18n[2]); + this.i18nGuide.THRESHOLD_REQUIRED = this.translateReplaceService.replace(i18n[0], i18n[3]); + this.i18nGuide.TYPE_REQUIRED = this.translateReplaceService.replace(i18n[0], i18n[4]); + + this.i18nLabel.CHECKER_LABEL = i18n[1]; + this.i18nLabel.USER_GROUP_LABEL = i18n[2]; + this.i18nLabel.THRESHOLD_LABEL = i18n[3]; + this.i18nLabel.TYPE_LABEL = i18n[4]; + this.i18nLabel.NOTES_LABEL = i18n[5]; + }); + } + private getAlarmData(): void { + this.showProcessing(); + this.alarmRuleDataService.retrieve(this.currentApplication.getApplicationName()).subscribe((alarmRuleList: IAlarmRule[] | IServerErrorShortFormat) => { + if ((alarmRuleList as IServerErrorShortFormat).errorCode) { + this.message = (alarmRuleList as IServerErrorShortFormat).errorMessage; + } else { + this.alarmRuleList = alarmRuleList as IAlarmRule[]; + } + this.hideProcessing(); + this.changeDetectorRef.detectChanges(); + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + this.changeDetectorRef.detectChanges(); + }); + } + private getAlarmIndexByRuleId(ruleId: string): number { + let index = -1; + for (let i = 0 ; i < this.alarmRuleList.length ; i++) { + if (this.alarmRuleList[i].ruleId === ruleId) { + index = i; + break; + } + } + return index; + } + private getTypeStr(smsSend: boolean, emailSend: boolean): string { + if (smsSend && emailSend) { + return 'all'; + } else { + if (smsSend) { + return 'sms'; + } + if (emailSend) { + return 'email'; + } + return 'none'; + } + } + onCreateAlarm(alarm: Alarm): void { + this.showProcessing(); + this.alarmRuleDataService.create({ + applicationId: this.currentApplication.getApplicationName(), + serviceType: this.currentApplication.getServiceType(), + userGroupId: alarm.userGroupId, + checkerName: alarm.checkerName, + threshold: alarm.threshold, + smsSend: alarm.smsSend, + emailSend: alarm.emailSend, + notes: alarm.notes + } as IAlarmRule).subscribe((response: IAlarmRuleCreated | IServerErrorShortFormat) => { + if ((response as IServerErrorShortFormat).errorCode) { + this.hideProcessing(); + this.message = (response as IServerErrorShortFormat).errorMessage; + } else { + this.getAlarmData(); + } + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + }); + } + onUpdateAlarm(alarm: Alarm): void { + const editAlarm = this.alarmRuleList[this.editAlarmIndex]; + this.alarmRuleDataService.update({ + applicationId: editAlarm.applicationId, + ruleId: editAlarm.ruleId, + serviceType: editAlarm.serviceType, + checkerName: alarm.checkerName, + userGroupId: alarm.userGroupId, + threshold: alarm.threshold, + smsSend: alarm.smsSend, + emailSend: alarm.emailSend, + notes: alarm.notes + } as IAlarmRule).subscribe((response: IAlarmRuleResponse | IServerErrorShortFormat) => { + if ((response as IServerErrorShortFormat).errorCode) { + this.hideProcessing(); + this.message = (response as IServerErrorShortFormat).errorMessage; + } else { + this.getAlarmData(); + } + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + }); + } + onShowCreateAlarmPopup(): void { + if (this.isApplicationSelected() === false) { + return; + } + this.showCreate = true; + } + onCloseCreateAlarmPopup(): void { + this.showCreate = false; + } + onCloseMessage(): void { + this.message = ''; + } + onReload(): void { + this.getAlarmData(); + } + onRemoveAlarm(ruleId: string): void { + this.showProcessing(); + this.alarmRuleDataService.remove(ruleId).subscribe((response: IAlarmRuleResponse | IServerErrorShortFormat) => { + if ((response as IServerErrorShortFormat).errorCode) { + this.hideProcessing(); + this.message = (response as IServerErrorShortFormat).errorMessage; + } else { + this.getAlarmData(); + } + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + }); + } + onEditAlarm(ruleId: string): void { + this.editAlarmIndex = this.getAlarmIndexByRuleId(ruleId); + const editAlarm = this.alarmRuleList[this.editAlarmIndex]; + this.editAlarm = new Alarm( + editAlarm.checkerName, + editAlarm.userGroupId, + editAlarm.threshold, + this.getTypeStr(editAlarm.smsSend, editAlarm.emailSend), + editAlarm.notes + ); + this.onShowCreateAlarmPopup(); + } + hasMessage(): boolean { + return this.message !== ''; + } + isApplicationSelected(): boolean { + return this.currentApplication !== null; + } + getAddButtonClass(): object { + return { + 'btn-blue': this.isApplicationSelected(), + 'btn-gray': !this.isApplicationSelected() + }; + } + private showProcessing(): void { + this.useDisable = true; + this.showLoading = true; + } + private hideProcessing(): void { + this.useDisable = false; + this.showLoading = false; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list.component.css b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list.component.css new file mode 100644 index 000000000000..67150bd4a9b6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list.component.css @@ -0,0 +1,52 @@ +.l-alarm-rules-tr { + display: flex; + height: 30px; + align-items: center; + padding: 0 15px; + position: relative; +} +.l-alarm-rules-tr div { + float: left; +} +.l-alarm-rules-tr div:nth-child(1) { + width: 41.66666667%; +} +.l-alarm-rules-tr div:nth-child(2) { + width: 16.66666667%; +} +.l-alarm-rules-tr div:nth-child(3) { + width: 16.66666667%; +} +.l-alarm-rules-tr div:nth-child(4) { + width: 16.66666667%; +} +.l-alarm-rules-tr div:nth-child(5) { + width: 8.33333333% +} +.l-alarm-rules-btn-group { + display: flex; + color: #b3b6bf; + font-size: 13px; + align-items: center; + justify-content: flex-end; +} +.l-alarm-rules-btn-group button { + margin-left: 11px; +} +.l-alarm-rules-btn-group button:first-child { + margin-left: 0; +} +.l-threshold { + text-align: center; +} +.fa-trash-alt { + color: #b3b6bf; + font-size: 14px; +} +.fa-edit { + margin-left: 10px; +} +.fa-check { + color: #F00; + margin-left: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list.component.html b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list.component.html new file mode 100644 index 000000000000..f738115e03de --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list.component.html @@ -0,0 +1,12 @@ +
    +
    {{alarm.checkerName}}
    +
    {{alarm.userGroupId}}
    +
    {{alarm.threshold}}
    +
    {{getNotificationType(alarm.emailSend, alarm.smsSend)}}
    +
    + + + + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list.component.ts b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list.component.ts new file mode 100644 index 000000000000..05014cb11d11 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/alarm-rule-list.component.ts @@ -0,0 +1,45 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-alarm-rule-list', + templateUrl: './alarm-rule-list.component.html', + styleUrls: ['./alarm-rule-list.component.css'] +}) +export class AlarmRuleListComponent implements OnInit { + @Input() alarmRuleList: any; + @Output() outRemove: EventEmitter = new EventEmitter(); + @Output() outEdit: EventEmitter = new EventEmitter(); + private removeConformId = ''; + constructor() { } + ngOnInit() {} + getNotificationType(emailSend: boolean, smsSend: boolean): string { + const returnStr = []; + if (emailSend === false && smsSend === false) { + return 'None'; + } else { + if (emailSend) { + returnStr.push('Email'); + } + if (smsSend) { + returnStr.push('SMS'); + } + return returnStr.join(','); + } + } + onRemove(ruleId: string): void { + this.removeConformId = ruleId; + } + onEdit(ruleId: string): void { + this.outEdit.emit(ruleId); + } + onCancelRemove(): void { + this.removeConformId = ''; + } + onConfirmRemove(): void { + this.outRemove.emit(this.removeConformId); + this.removeConformId = ''; + } + isRemoveTarget(ruleId: string): boolean { + return this.removeConformId === ruleId; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/index.ts b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/index.ts new file mode 100644 index 000000000000..b348dab7b302 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/alarm-rule-list/index.ts @@ -0,0 +1,29 @@ + +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { SharedModule } from 'app/shared'; +import { AlarmRuleListComponent } from './alarm-rule-list.component'; +import { AlarmRuleListContainerComponent } from './alarm-rule-list-container.component'; +import { AlarmRuleCreateAndUpdateComponent } from './alarm-rule-create-and-update.component'; +import { AlarmRuleDataService } from './alarm-rule-data.service'; + +@NgModule({ + declarations: [ + AlarmRuleListComponent, + AlarmRuleListContainerComponent, + AlarmRuleCreateAndUpdateComponent + ], + imports: [ + FormsModule, + ReactiveFormsModule, + SharedModule + ], + exports: [ + AlarmRuleListContainerComponent, + AlarmRuleCreateAndUpdateComponent + ], + providers: [ + AlarmRuleDataService + ] +}) +export class AlarmRuleListModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/angular-split/angular-split.ts b/web/src/main/webapp/v2/src/app/core/components/angular-split/angular-split.ts new file mode 100644 index 000000000000..8f5d8143a9bb --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/angular-split/angular-split.ts @@ -0,0 +1,4 @@ +// Public classes. +export { AngularSplitModule } from './modules/angularSplit.module'; +export { SplitComponent } from './components/split.component'; +export { SplitAreaDirective } from './components/splitArea.directive'; diff --git a/web/src/main/webapp/v2/src/app/core/components/angular-split/components/split.component.ts b/web/src/main/webapp/v2/src/app/core/components/angular-split/components/split.component.ts new file mode 100644 index 000000000000..1b9610542ff1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/angular-split/components/split.component.ts @@ -0,0 +1,594 @@ +import { Component, ChangeDetectorRef, Input, Output, HostBinding, ChangeDetectionStrategy, EventEmitter, Renderer2, OnDestroy, ElementRef, AfterViewInit, NgZone } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { debounceTime } from 'rxjs/operators'; + +import { IArea } from './../interface/IArea'; +import { IPoint } from './../interface/IPoint'; +import { SplitAreaDirective } from './splitArea.directive'; + +@Component({ + selector: 'split', + changeDetection: ChangeDetectionStrategy.OnPush, + styles: [` + :host { + display: flex; + flex-wrap: nowrap; + justify-content: flex-start; + align-items: stretch; + overflow: hidden; + /* + Important to keep following rules even if overrided later by 'HostBinding' + because if [width] & [height] not provided, when build() is executed, + 'HostBinding' hasn't been applied yet so code: + this.elRef.nativeElement["offsetHeight"] gives wrong value! + */ + width: 100%; + height: 100%; + } + split-gutter { + flex-grow: 0; + flex-shrink: 0; + background-position: center center; + background-repeat: no-repeat; + } + `], + template: ` + + + + `, +}) +export class SplitComponent implements AfterViewInit, OnDestroy { + + private _direction: 'horizontal' | 'vertical' = 'horizontal'; + + @Input() set direction(v: 'horizontal' | 'vertical') { + v = (v === 'vertical') ? 'vertical' : 'horizontal'; + this._direction = v; + + [...this.displayedAreas, ...this.hidedAreas].forEach(area => { + area.comp.setStyleVisibleAndDir(area.comp.visible, this.isDragging, this.direction); + }); + + this.build(false, false); + } + + get direction(): 'horizontal' | 'vertical' { + return this._direction; + } + + //// + private _useTransition: boolean = false; + + @Input() set useTransition(v: boolean) { + v = (typeof(v) === 'boolean') ? v : (v === 'false' ? false : true); + this._useTransition = v; + } + + get useTransition(): boolean { + return this._useTransition; + } + + //// + private _disabled: boolean = false; + + @Input() set disabled(v: boolean) { + v = (typeof(v) === 'boolean') ? v : (v === 'false' ? false : true); + this._disabled = v; + + // Force repaint if modified from TS class (instead of the template) + this.cdRef.markForCheck(); + } + + get disabled(): boolean { + return this._disabled; + } + + //// + private _width: number | null = null; + + @Input() set width(v: number | null) { + v = Number(v); + this._width = (!isNaN(v) && v > 0) ? v : null; + + this.build(false, false); + } + + get width(): number | null { + return this._width; + } + + //// + private _height: number | null = null; + + @Input() set height(v: number | null) { + v = Number(v); + this._height = (!isNaN(v) && v > 0) ? v : null; + + this.build(false, false); + } + + get height(): number | null { + return this._height; + } + + //// + private _gutterSize: number = 11; + + @Input() set gutterSize(v: number) { + v = Number(v); + this._gutterSize = (!isNaN(v) && v > 0) ? v : 11; + + this.build(false, false); + } + + get gutterSize(): number { + return this._gutterSize; + } + + //// + private _gutterColor: string = ''; + + @Input() set gutterColor(v: string) { + this._gutterColor = (typeof v === 'string' && v !== '') ? v : ''; + + // Force repaint if modified from TS class (instead of the template) + this.cdRef.markForCheck(); + } + + get gutterColor(): string { + return this._gutterColor; + } + + //// + private _gutterImageH: string = ''; + + @Input() set gutterImageH(v: string) { + this._gutterImageH = (typeof v === 'string' && v !== '') ? v : ''; + + // Force repaint if modified from TS class (instead of the template) + this.cdRef.markForCheck(); + } + + get gutterImageH(): string { + return this._gutterImageH; + } + + //// + private _gutterImageV: string = ''; + + @Input() set gutterImageV(v: string) { + this._gutterImageV = (typeof v === 'string' && v !== '') ? v : ''; + + // Force repaint if modified from TS class (instead of the template) + this.cdRef.markForCheck(); + } + + get gutterImageV(): string { + return this._gutterImageV; + } + + //// + private _dir: 'ltr' | 'rtl' = 'ltr'; + + @Input() set dir(v: 'ltr' | 'rtl') { + v = (v === 'rtl') ? 'rtl' : 'ltr'; + this._dir = v; + } + + get dir(): 'ltr' | 'rtl' { + return this._dir; + } + + //// + @Output() dragStart = new EventEmitter<{gutterNum: number, sizes: Array}>(false); + @Output() dragProgress = new EventEmitter<{gutterNum: number, sizes: Array}>(false); + @Output() dragEnd = new EventEmitter<{gutterNum: number, sizes: Array}>(false); + @Output() gutterClick = new EventEmitter<{gutterNum: number, sizes: Array}>(false); + + private transitionEndInternal = new Subject>(); + @Output() transitionEnd = (>> this.transitionEndInternal.asObservable()).pipe( + debounceTime(20) + ); + + @HostBinding('style.flex-direction') get cssFlexdirection() { + return (this.direction === 'horizontal') ? 'row' : 'column'; + } + + @HostBinding('style.width') get cssWidth() { + return this.width ? `${ this.width }px` : '100%'; + } + + @HostBinding('style.height') get cssHeight() { + return this.height ? `${ this.height }px` : '100%'; + } + + @HostBinding('style.min-width') get cssMinwidth() { + return (this.direction === 'horizontal') ? `${ this.getNbGutters() * this.gutterSize }px` : null; + } + + @HostBinding('style.min-height') get cssMinheight() { + return (this.direction === 'vertical') ? `${ this.getNbGutters() * this.gutterSize }px` : null; + } + + public isViewInitialized: boolean = false; + private isDragging: boolean = false; + private draggingWithoutMove: boolean = false; + private currentGutterNum: number = 0; + + public readonly displayedAreas: Array = []; + private readonly hidedAreas: Array = []; + + private readonly dragListeners: Array = []; + private readonly dragStartValues = { + sizePixelContainer: 0, + sizePixelA: 0, + sizePixelB: 0, + sizePercentA: 0, + sizePercentB: 0, + }; + + constructor(private ngZone: NgZone, + private elRef: ElementRef, + private cdRef: ChangeDetectorRef, + private renderer: Renderer2) {} + + public ngAfterViewInit() { + this.isViewInitialized = true; + } + + private getNbGutters(): number { + return this.displayedAreas.length - 1; + } + + public addArea(comp: SplitAreaDirective): void { + const newArea: IArea = { + comp, + order: 0, + size: 0, + }; + + if (comp.visible === true) { + this.displayedAreas.push(newArea); + } else { + this.hidedAreas.push(newArea); + } + + comp.setStyleVisibleAndDir(comp.visible, this.isDragging, this.direction); + + this.build(true, true); + } + + public removeArea(comp: SplitAreaDirective): void { + if (this.displayedAreas.some(a => a.comp === comp)) { + const area = this.displayedAreas.find(a => a.comp === comp) + this.displayedAreas.splice(this.displayedAreas.indexOf(area), 1); + + this.build(true, true); + } else if(this.hidedAreas.some(a => a.comp === comp)) { + const area = this.hidedAreas.find(a => a.comp === comp) + this.hidedAreas.splice(this.hidedAreas.indexOf(area), 1); + } + } + + public updateArea(comp: SplitAreaDirective, resetOrders: boolean, resetSizes: boolean): void { + // Only refresh if area is displayed (No need to check inside 'hidedAreas') + const item = this.displayedAreas.find(a => a.comp === comp); + + if (item) { + this.build(resetOrders, resetSizes); + } + } + + public showArea(comp: SplitAreaDirective): void { + const area = this.hidedAreas.find(a => a.comp === comp); + + if (area) { + comp.setStyleVisibleAndDir(comp.visible, this.isDragging, this.direction); + + const areas = this.hidedAreas.splice(this.hidedAreas.indexOf(area), 1); + this.displayedAreas.push(...areas); + + this.build(true, true); + } + } + + public hideArea(comp: SplitAreaDirective): void { + const area = this.displayedAreas.find(a => a.comp === comp); + + if (area) { + comp.setStyleVisibleAndDir(comp.visible, this.isDragging, this.direction); + + const areas = this.displayedAreas.splice(this.displayedAreas.indexOf(area), 1); + areas.forEach(area => { + area.order = 0; + area.size = 0; + }) + this.hidedAreas.push(...areas); + + this.build(true, true); + } + } + + private build(resetOrders: boolean, resetSizes: boolean): void { + this.stopDragging(); + + // ¤ AREAS ORDER + + if (resetOrders === true) { + + // If user provided 'order' for each area, use it to sort them. + if (this.displayedAreas.every(a => a.comp.order !== null)) { + this.displayedAreas.sort((a, b) => ( a.comp.order) - ( b.comp.order)); + } + + // Then set real order with multiples of 2, numbers between will be used by gutters. + this.displayedAreas.forEach((area, i) => { + area.order = i * 2; + area.comp.setStyleOrder(area.order); + }); + + } + + // ¤ AREAS SIZE PERCENT + + if (resetSizes === true) { + + const totalUserSize = this.displayedAreas.reduce((total: number, s: IArea) => s.comp.size ? total + s.comp.size : total, 0); + + // If user provided 'size' for each area and total == 1, use it. + if (this.displayedAreas.every(a => a.comp.size !== null) && totalUserSize > .999 && totalUserSize < 1.001 ) { + + this.displayedAreas.forEach(area => { + area.size = area.comp.size; + }); + } else { + const size = 1 / this.displayedAreas.length; + + this.displayedAreas.forEach(area => { + area.size = size; + }); + } + } + + // + // If some real area sizes are less than gutterSize, + // set them to zero and dispatch size to others. + let percentToDispatch = 0; + + // Get container pixel size + let containerSizePixel = this.getNbGutters() * this.gutterSize; + if (this.direction === 'horizontal') { + containerSizePixel = this.width ? this.width : this.elRef.nativeElement['offsetWidth']; + } else { + containerSizePixel = this.height ? this.height : this.elRef.nativeElement['offsetHeight']; + } + + this.displayedAreas.forEach(area => { + if (area.size * containerSizePixel < this.gutterSize) { + percentToDispatch += area.size; + area.size = 0; + } + }); + + if (percentToDispatch > 0 && this.displayedAreas.length > 0) { + const nbAreasNotZero = this.displayedAreas.filter(a => a.size !== 0).length; + + if (nbAreasNotZero > 0) { + const percentToAdd = percentToDispatch / nbAreasNotZero; + + this.displayedAreas.filter(a => a.size !== 0).forEach(area => { + area.size += percentToAdd; + }); + } else { + this.displayedAreas[this.displayedAreas.length - 1].size = 1; + } + } + + + this.refreshStyleSizes(); + this.cdRef.markForCheck(); + } + + private refreshStyleSizes(): void { + const sumGutterSize = this.getNbGutters() * this.gutterSize; + + this.displayedAreas.forEach(area => { + area.comp.setStyleFlexbasis(`calc( ${ area.size * 100 }% - ${ area.size * sumGutterSize }px )`, this.isDragging); + }); + } + + public startDragging(startEvent: MouseEvent | TouchEvent, gutterOrder: number, gutterNum: number): void { + startEvent.preventDefault(); + + // Place code here to allow '(gutterClick)' event even if '[disabled]="true"'. + this.currentGutterNum = gutterNum; + this.draggingWithoutMove = true; + this.ngZone.runOutsideAngular(() => { + this.dragListeners.push( this.renderer.listen('document', 'mouseup', (e: MouseEvent) => this.stopDragging()) ); + this.dragListeners.push( this.renderer.listen('document', 'touchend', (e: TouchEvent) => this.stopDragging()) ); + this.dragListeners.push( this.renderer.listen('document', 'touchcancel', (e: TouchEvent) => this.stopDragging()) ); + }); + + if(this.disabled) { + return; + } + + const areaA = this.displayedAreas.find(a => a.order === gutterOrder - 1); + const areaB = this.displayedAreas.find(a => a.order === gutterOrder + 1); + + if (!areaA || !areaB) { + return; + } + + const prop = (this.direction === 'horizontal') ? 'offsetWidth' : 'offsetHeight'; + this.dragStartValues.sizePixelContainer = this.elRef.nativeElement[prop]; + this.dragStartValues.sizePixelA = areaA.comp.getSizePixel(prop); + this.dragStartValues.sizePixelB = areaB.comp.getSizePixel(prop); + this.dragStartValues.sizePercentA = areaA.size; + this.dragStartValues.sizePercentB = areaB.size; + + let start: IPoint; + if (startEvent instanceof MouseEvent) { + start = { + x: startEvent.screenX, + y: startEvent.screenY, + }; + } else if (startEvent instanceof TouchEvent) { + start = { + x: startEvent.touches[0].screenX, + y: startEvent.touches[0].screenY, + }; + } else { + return; + } + + this.ngZone.runOutsideAngular(() => { + this.dragListeners.push( this.renderer.listen('document', 'mousemove', (e: MouseEvent) => this.dragEvent(e, start, areaA, areaB)) ); + this.dragListeners.push( this.renderer.listen('document', 'touchmove', (e: TouchEvent) => this.dragEvent(e, start, areaA, areaB)) ); + }); + + areaA.comp.lockEvents(); + areaB.comp.lockEvents(); + + this.isDragging = true; + + this.notify('start'); + } + + private dragEvent(event: MouseEvent | TouchEvent, start: IPoint, areaA: IArea, areaB: IArea): void { + if (!this.isDragging) { + return; + } + + let end: IPoint; + if (event instanceof MouseEvent) { + end = { + x: event.screenX, + y: event.screenY, + }; + } else if (event instanceof TouchEvent) { + end = { + x: event.touches[0].screenX, + y: event.touches[0].screenY, + }; + } else { + return; + } + + this.draggingWithoutMove = false; + this.drag(start, end, areaA, areaB); + } + + private drag(start: IPoint, end: IPoint, areaA: IArea, areaB: IArea): void { + + // ¤ AREAS SIZE PIXEL + const devicePixelRatio = window.devicePixelRatio || 1; + let offsetPixel = (this.direction === 'horizontal') ? (start.x - end.x) : (start.y - end.y); + offsetPixel = offsetPixel / devicePixelRatio; + + if(this.dir === 'rtl') { + offsetPixel = -offsetPixel; + } + + let newSizePixelA = this.dragStartValues.sizePixelA - offsetPixel; + let newSizePixelB = this.dragStartValues.sizePixelB + offsetPixel; + + if (newSizePixelA < this.gutterSize && newSizePixelB < this.gutterSize) { + // WTF.. get out of here! + return; + } else if (newSizePixelA < this.gutterSize) { + newSizePixelB += newSizePixelA; + newSizePixelA = 0; + } else if (newSizePixelB < this.gutterSize) { + newSizePixelA += newSizePixelB; + newSizePixelB = 0; + } + + // ¤ AREAS SIZE PERCENT + if (newSizePixelA === 0) { + areaB.size += areaA.size; + areaA.size = 0; + } else if (newSizePixelB === 0) { + areaA.size += areaB.size; + areaB.size = 0; + } else { + // NEW_PERCENT = START_PERCENT / START_PIXEL * NEW_PIXEL; + if (this.dragStartValues.sizePercentA === 0) { + areaB.size = this.dragStartValues.sizePercentB / this.dragStartValues.sizePixelB * newSizePixelB; + areaA.size = this.dragStartValues.sizePercentB - areaB.size; + } else if (this.dragStartValues.sizePercentB === 0) { + areaA.size = this.dragStartValues.sizePercentA / this.dragStartValues.sizePixelA * newSizePixelA; + areaB.size = this.dragStartValues.sizePercentA - areaA.size; + } else { + areaA.size = this.dragStartValues.sizePercentA / this.dragStartValues.sizePixelA * newSizePixelA; + areaB.size = (this.dragStartValues.sizePercentA + this.dragStartValues.sizePercentB) - areaA.size; + } + } + + this.refreshStyleSizes(); + this.notify('progress'); + } + + private stopDragging(): void { + if (this.isDragging === false && this.draggingWithoutMove === false) { + return; + } + + this.displayedAreas.forEach(area => { + area.comp.unlockEvents(); + }); + + while (this.dragListeners.length > 0) { + const fct = this.dragListeners.pop(); + if (fct) { + fct(); + } + } + + if (this.draggingWithoutMove === true) { + this.notify('click'); + } else { + this.notify('end'); + } + + this.isDragging = false; + this.draggingWithoutMove = false; + } + + + public notify(type: 'start' | 'progress' | 'end' | 'click' | 'transitionEnd'): void { + const areasSize: Array = this.displayedAreas.map(a => a.size * 100); + + switch (type) { + case 'start': + return this.dragStart.emit({gutterNum: this.currentGutterNum, sizes: areasSize}); + + case 'progress': + return this.dragProgress.emit({gutterNum: this.currentGutterNum, sizes: areasSize}); + + case 'end': + return this.dragEnd.emit({gutterNum: this.currentGutterNum, sizes: areasSize}); + + case 'click': + return this.gutterClick.emit({gutterNum: this.currentGutterNum, sizes: areasSize}); + + case 'transitionEnd': + return this.transitionEndInternal.next(areasSize); + } + } + + public ngOnDestroy(): void { + this.stopDragging(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/angular-split/components/splitArea.directive.ts b/web/src/main/webapp/v2/src/app/core/components/angular-split/components/splitArea.directive.ts new file mode 100644 index 000000000000..ad3b9ed8408b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/angular-split/components/splitArea.directive.ts @@ -0,0 +1,176 @@ +import { Directive, Input, ElementRef, Renderer2, OnInit, OnDestroy, NgZone } from '@angular/core'; + +import { SplitComponent } from './split.component'; + +@Directive({ + selector: 'split-area' +}) +export class SplitAreaDirective implements OnInit, OnDestroy { + + private _order: number | null = null; + + @Input() set order(v: number | null) { + v = Number(v); + this._order = !isNaN(v) ? v : null; + + this.split.updateArea(this, true, false); + } + + get order(): number | null { + return this._order; + } + + //// + private _size: number | null = null; + + @Input() set size(v: number | null) { + v = Number(v); + this._size = (!isNaN(v) && v >= 0 && v <= 100) ? (v/100) : null; + + this.split.updateArea(this, false, true); + } + + get size(): number | null { + return this._size; + } + + //// + private _minSize: number = 0; + + @Input() set minSize(v: number) { + v = Number(v); + this._minSize = (!isNaN(v) && v > 0 && v < 100) ? v/100 : 0; + + this.split.updateArea(this, false, true); + } + + get minSize(): number { + return this._minSize; + } + + //// + private _visible: boolean = true; + + @Input() set visible(v: boolean) { + v = (typeof(v) === 'boolean') ? v : (v === 'false' ? false : true); + this._visible = v; + + if(this.visible) { + this.split.showArea(this); + } + else { + this.split.hideArea(this); + } + } + + get visible(): boolean { + return this._visible; + } + + //// + private transitionListener: Function; + private readonly lockListeners: Array = []; + + constructor(private ngZone: NgZone, + private elRef: ElementRef, + private renderer: Renderer2, + private split: SplitComponent) {} + + public ngOnInit(): void { + this.split.addArea(this); + + this.renderer.setStyle(this.elRef.nativeElement, 'flex-grow', '0'); + this.renderer.setStyle(this.elRef.nativeElement, 'flex-shrink', '0'); + + this.ngZone.runOutsideAngular(() => { + this.transitionListener = this.renderer.listen(this.elRef.nativeElement, 'transitionend', (e: TransitionEvent) => this.onTransitionEnd(e)); + }); + } + + public getSizePixel(prop: 'offsetWidth' | 'offsetHeight'): number { + return this.elRef.nativeElement[prop]; + } + + public setStyleVisibleAndDir(isVisible: boolean, isDragging: boolean, direction: 'horizontal' | 'vertical'): void { + if(isVisible === false) { + this.setStyleFlexbasis('0', isDragging); + this.renderer.setStyle(this.elRef.nativeElement, 'overflow-x', 'hidden'); + this.renderer.setStyle(this.elRef.nativeElement, 'overflow-y', 'hidden'); + + if(direction === 'vertical') { + this.renderer.setStyle(this.elRef.nativeElement, 'max-width', '0'); + } + } + else { + this.renderer.setStyle(this.elRef.nativeElement, 'overflow-x', 'hidden'); + this.renderer.setStyle(this.elRef.nativeElement, 'overflow-y', 'auto'); + this.renderer.removeStyle(this.elRef.nativeElement, 'max-width'); + } + + if(direction === 'horizontal') { + this.renderer.setStyle(this.elRef.nativeElement, 'height', '100%'); + this.renderer.removeStyle(this.elRef.nativeElement, 'width'); + } + else { + this.renderer.setStyle(this.elRef.nativeElement, 'width', '100%'); + this.renderer.removeStyle(this.elRef.nativeElement, 'height'); + } + } + + public setStyleOrder(value: number): void { + this.renderer.setStyle(this.elRef.nativeElement, 'order', value); + } + + public setStyleFlexbasis(value: string, isDragging: boolean): void { + // If component not yet initialized or gutter being dragged, disable transition + if(this.split.isViewInitialized === false || isDragging === true) { + this.setStyleTransition(false); + } + // Or use 'useTransition' to know if transition. + else { + this.setStyleTransition(this.split.useTransition); + } + + this.renderer.setStyle(this.elRef.nativeElement, 'flex-basis', value); + } + + private setStyleTransition(useTransition: boolean): void { + if (useTransition) { + this.renderer.setStyle(this.elRef.nativeElement, 'transition', `flex-basis 0.3s`); + } else { + this.renderer.removeStyle(this.elRef.nativeElement, 'transition'); + } + } + private onTransitionEnd(event: TransitionEvent): void { + // Limit only flex-basis transition to trigger the event + if (event.propertyName === 'flex-basis') { + this.split.notify('transitionEnd'); + } + } + + public lockEvents(): void { + this.ngZone.runOutsideAngular(() => { + this.lockListeners.push( this.renderer.listen(this.elRef.nativeElement, 'selectstart', (e: Event) => false) ); + this.lockListeners.push( this.renderer.listen(this.elRef.nativeElement, 'dragstart', (e: Event) => false) ); + }); + } + + public unlockEvents(): void { + while (this.lockListeners.length > 0) { + const fct = this.lockListeners.pop(); + if (fct) { + fct(); + } + } + } + + public ngOnDestroy(): void { + this.unlockEvents(); + + if (this.transitionListener) { + this.transitionListener(); + } + + this.split.removeArea(this); + } +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/angular-split/components/splitGutter.directive.ts b/web/src/main/webapp/v2/src/app/core/components/angular-split/components/splitGutter.directive.ts new file mode 100644 index 000000000000..3cb0aee974e4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/angular-split/components/splitGutter.directive.ts @@ -0,0 +1,139 @@ +import { Directive, Input, ElementRef, Renderer2 } from '@angular/core'; + +@Directive({ + selector: 'split-gutter' +}) +export class SplitGutterDirective { + + @Input() set order(v: number) { + this.renderer.setStyle(this.elRef.nativeElement, 'order', v); + } + + //// + private _direction: 'vertical' | 'horizontal'; + + @Input() set direction(v: 'vertical' | 'horizontal') { + this._direction = v; + this.refreshStyle(); + } + + get direction(): 'vertical' | 'horizontal' { + return this._direction; + } + + //// + @Input() set useTransition(v: boolean) { + if (v) { + this.renderer.setStyle(this.elRef.nativeElement, 'transition', `flex-basis 0.3s`); + } else { + this.renderer.removeStyle(this.elRef.nativeElement, 'transition'); + } + } + + //// + private _size: number; + + @Input() set size(v: number) { + this._size = v; + this.refreshStyle(); + } + + get size(): number { + return this._size; + } + + //// + private _color: string; + + @Input() set color(v: string) { + this._color = v; + this.refreshStyle(); + } + + get color(): string { + return this._color; + } + + //// + private _imageH: string; + + @Input() set imageH(v: string) { + this._imageH = v; + this.refreshStyle(); + } + + get imageH(): string { + return this._imageH; + } + + //// + private _imageV: string; + + @Input() set imageV(v: string) { + this._imageV = v; + this.refreshStyle(); + } + + get imageV(): string { + return this._imageV; + } + + //// + private _disabled: boolean = false; + + @Input() set disabled(v: boolean) { + this._disabled = v; + this.refreshStyle(); + } + + get disabled(): boolean { + return this._disabled; + } + + //// + constructor(private elRef: ElementRef, + private renderer: Renderer2) {} + + private refreshStyle(): void { + this.renderer.setStyle(this.elRef.nativeElement, 'flex-basis', `${ this.size }px`); + + // fix safari bug about gutter height when direction is horizontal + this.renderer.setStyle(this.elRef.nativeElement, 'height', (this.direction === 'vertical') ? `${ this.size }px` : `100%`); + + this.renderer.setStyle(this.elRef.nativeElement, 'background-color', (this.color !== '') ? this.color : `#eeeeee`); + + const state: 'disabled' | 'vertical' | 'horizontal' = (this.disabled === true) ? 'disabled' : this.direction; + this.renderer.setStyle(this.elRef.nativeElement, 'background-image', this.getImage(state)); + this.renderer.setStyle(this.elRef.nativeElement, 'cursor', this.getCursor(state)); + } + + private getCursor(state: 'disabled' | 'vertical' | 'horizontal'): string { + switch (state) { + case 'horizontal': + return 'col-resize'; + + case 'vertical': + return 'row-resize'; + + case 'disabled': + return 'default'; + } + } + + private getImage(state: 'disabled' | 'vertical' | 'horizontal'): string { + switch (state) { + case 'horizontal': + return (this.imageH !== '') ? this.imageH : defaultImageH; + + case 'vertical': + return (this.imageV !== '') ? this.imageV : defaultImageV; + + case 'disabled': + return ''; + } + } +} + + +const defaultImageH = 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==")'; +const defaultImageV = 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFCAMAAABl/6zIAAAABlBMVEUAAADMzMzIT8AyAAAAAXRSTlMAQObYZgAAABRJREFUeAFjYGRkwIMJSeMHlBkOABP7AEGzSuPKAAAAAElFTkSuQmCC")'; diff --git a/web/src/main/webapp/v2/src/app/core/components/angular-split/interface/IArea.ts b/web/src/main/webapp/v2/src/app/core/components/angular-split/interface/IArea.ts new file mode 100644 index 000000000000..20b02201782a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/angular-split/interface/IArea.ts @@ -0,0 +1,7 @@ +import { SplitAreaDirective } from '../components/splitArea.directive'; + +export interface IArea { + comp: SplitAreaDirective; + size: number; + order: number; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/angular-split/interface/IPoint.ts b/web/src/main/webapp/v2/src/app/core/components/angular-split/interface/IPoint.ts new file mode 100644 index 000000000000..a22340cd5ea1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/angular-split/interface/IPoint.ts @@ -0,0 +1,4 @@ +export interface IPoint { + x: number; + y: number; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/angular-split/modules/angularSplit.module.ts b/web/src/main/webapp/v2/src/app/core/components/angular-split/modules/angularSplit.module.ts new file mode 100644 index 000000000000..3f004786409e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/angular-split/modules/angularSplit.module.ts @@ -0,0 +1,38 @@ +import { NgModule, ModuleWithProviders } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { SplitComponent } from '../components/split.component'; +import { SplitAreaDirective } from '../components/splitArea.directive'; +import { SplitGutterDirective } from '../components/splitGutter.directive'; + +@NgModule({ + imports: [ + CommonModule + ], + declarations: [ + SplitComponent, + SplitAreaDirective, + SplitGutterDirective, + ], + exports: [ + SplitComponent, + SplitAreaDirective, + ] +}) +export class AngularSplitModule { + + public static forRoot(): ModuleWithProviders { + return { + ngModule: AngularSplitModule, + providers: [] + }; + } + + public static forChild(): ModuleWithProviders { + return { + ngModule: AngularSplitModule, + providers: [] + }; + } + +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/application-inspector-contents-container.component.css b/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/application-inspector-contents-container.component.css new file mode 100644 index 000000000000..ae10a3ace93a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/application-inspector-contents-container.component.css @@ -0,0 +1,24 @@ +:host { + display: flex; + flex-flow: column nowrap; + height: 100%; +} +.l-date-range { + border-bottom: 1px solid #e5e8f0; + background-color: #FFF; + min-height: 161px; + max-height: 1000px +} +.l-main-contents { + height: 100%; + position: relative; + overflow: auto; +} +.l-chart-group-wrap { + display: flex; + flex-flow: row wrap; +} +.l-empty-content { + width: calc(50% - 20px); + margin: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/application-inspector-contents-container.component.html b/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/application-inspector-contents-container.component.html new file mode 100644 index 000000000000..1efd551ded39 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/application-inspector-contents-container.component.html @@ -0,0 +1,27 @@ + +
    + + +
    +
    +
    + + + + + + + + + +
    + + + + +
    +
    +
    + + + diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/application-inspector-contents-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/application-inspector-contents-container.component.ts new file mode 100644 index 000000000000..db5e46fe17cf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/application-inspector-contents-container.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { WebAppSettingDataService } from 'app/shared/services'; + +@Component({ + selector: 'pp-application-inspector-contents-container', + templateUrl: './application-inspector-contents-container.component.html', + styleUrls: ['./application-inspector-contents-container.component.css'] +}) +export class ApplicationInspectorContentsContainerComponent implements OnInit { + isApplicationInspectorActivated$: Observable; + + constructor( + private webAppSettingDataService: WebAppSettingDataService + ) {} + + ngOnInit() { + this.isApplicationInspectorActivated$ = this.webAppSettingDataService.isApplicationInspectorActivated(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/index.ts b/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/index.ts new file mode 100644 index 000000000000..59ae264062ef --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-contents/index.ts @@ -0,0 +1,28 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { ApplicationInspectorUsageGuideModule } from 'app/core/components/application-inspector-usage-guide'; +import { ApplicationInspectorContentsContainerComponent } from './application-inspector-contents-container.component'; +import { TimelineCommandGroupModule } from 'app/core/components/timeline-command-group'; +import { AgentEventViewModule } from 'app/core/components/agent-event-view'; +import { TimelineModule } from 'app/core/components/timeline'; +import { InspectorChartModule } from 'app/core/components/inspector-chart'; + +@NgModule({ + declarations: [ + ApplicationInspectorContentsContainerComponent + ], +imports: [ + SharedModule, + TimelineCommandGroupModule, + AgentEventViewModule, + TimelineModule, + InspectorChartModule, + ApplicationInspectorUsageGuideModule + ], + exports: [ + ApplicationInspectorContentsContainerComponent + ], + providers: [] +}) +export class ApplicationInspectorContentsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/application-inspector-title-container.component.css b/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/application-inspector-title-container.component.css new file mode 100644 index 000000000000..27429901956c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/application-inspector-title-container.component.css @@ -0,0 +1,25 @@ +.l-wrapper { + cursor: pointer; + display: block; + padding: 8px 6px 6px 8px; + overflow: hidden; + font-size: 12px; + white-space: nowrap; + text-overflow: ellipsis; +} +.l-wrapper img { + float: left; + width: 22px; + height: 18px; + margin-right: 10px; +} +.l-wrapper.active { + color: #418CD3; + font-weight: 600; + box-shadow: 2px 2px 5px 0px rgba(53,61,117,1); +} +.l-wrapper:hover { + color: #FFF; + cursor: pointer; + background-color: #418CD3; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/application-inspector-title-container.component.html b/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/application-inspector-title-container.component.html new file mode 100644 index 000000000000..37c4b7cab06f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/application-inspector-title-container.component.html @@ -0,0 +1,3 @@ +
    + {{applicationName}} +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/application-inspector-title-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/application-inspector-title-container.component.ts new file mode 100644 index 000000000000..2d6ed9abaa3c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/application-inspector-title-container.component.ts @@ -0,0 +1,74 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { + UrlRouteManagerService, + WebAppSettingDataService, + NewUrlStateNotificationService, + AnalyticsService, + TRACKED_EVENT_LIST +} from 'app/shared/services'; + +@Component({ + selector: 'pp-application-inspector-title-container', + templateUrl: './application-inspector-title-container.component.html', + styleUrls: ['./application-inspector-title-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationInspectorTitleContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + agentId: string; + funcImagePath: Function; + applicationServiceType: string; + applicationName: string; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private analyticsService: AnalyticsService, + ) {} + + ngOnInit() { + this.funcImagePath = this.webAppSettingDataService.getIconPathMakeFunc(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.APPLICATION)) { + this.applicationName = urlService.getPathValue(UrlPathId.APPLICATION).getApplicationName(); + this.applicationServiceType = urlService.getPathValue(UrlPathId.APPLICATION).getServiceType(); + } + if (urlService.hasValue(UrlPathId.AGENT_ID)) { + this.agentId = urlService.getPathValue(UrlPathId.AGENT_ID); + } else { + this.agentId = ''; + } + this.changeDetectorRef.detectChanges(); + }); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + isEmptyAgentId(): boolean { + return this.agentId === ''; + } + getApplicationIcon(): string { + return this.funcImagePath(this.applicationServiceType); + } + onSelectApplication() { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.GO_TO_APPLICATION_INSPECTOR); + this.urlRouteManagerService.moveOnPage({ + url: [ + UrlPath.INSPECTOR, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ] + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/index.ts b/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/index.ts new file mode 100644 index 000000000000..87c5d4d0f1f3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-title/index.ts @@ -0,0 +1,20 @@ + +import { NgModule } from '@angular/core'; +import { MatTooltipModule } from '@angular/material'; +import { SharedModule } from 'app/shared'; +import { ApplicationInspectorTitleContainerComponent } from './application-inspector-title-container.component'; + +@NgModule({ + declarations: [ + ApplicationInspectorTitleContainerComponent + ], + imports: [ + MatTooltipModule, + SharedModule + ], + exports: [ + ApplicationInspectorTitleContainerComponent + ], + providers: [] +}) +export class ApplicationInspectorTitleModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/application-inspector-usage-guide-container.component.css b/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/application-inspector-usage-guide-container.component.css new file mode 100644 index 000000000000..41eb703a5156 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/application-inspector-usage-guide-container.component.css @@ -0,0 +1,31 @@ +:host { + display: block; + height: 100%; +} + +.l-guide-wrapper { + width: 480px; + height: 200px; + margin: auto; + position: relative; + top: 35%; + background-color: #fff; + padding: 15px 20px; + border-radius: 3px; + line-height: 200%; +} + +.l-guide-title { + text-align: center; + font-size: 30px; + padding: 25px 0; +} + +.l-guide-title > .fas { + font-size: 30px; + margin-right: 5px; +} + +.l-guide-text { + text-align: center; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/application-inspector-usage-guide-container.component.html b/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/application-inspector-usage-guide-container.component.html new file mode 100644 index 000000000000..42e306ffcec9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/application-inspector-usage-guide-container.component.html @@ -0,0 +1,4 @@ +
    +

    Warning

    +

    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/application-inspector-usage-guide-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/application-inspector-usage-guide-container.component.ts new file mode 100644 index 000000000000..5584c5eb0130 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/application-inspector-usage-guide-container.component.ts @@ -0,0 +1,20 @@ +import { Component, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'pp-application-inspector-usage-guide-container', + templateUrl: './application-inspector-usage-guide-container.component.html', + styleUrls: ['./application-inspector-usage-guide-container.component.css'] +}) +export class ApplicationInspectorUsageGuideContainerComponent implements OnInit { + guideMessage$: Observable; + + constructor( + private translateService: TranslateService + ) {} + + ngOnInit() { + this.guideMessage$ = this.translateService.get('INSPECTOR.APPLICATION_INSPECTOR_USAGE_GUIDE_MESSAGE'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/index.ts b/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/index.ts new file mode 100644 index 000000000000..097bb5fcb17e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-inspector-usage-guide/index.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; + +import { ApplicationInspectorUsageGuideContainerComponent } from './application-inspector-usage-guide-container.component'; + +@NgModule({ + declarations: [ + ApplicationInspectorUsageGuideContainerComponent + ], + imports: [ + SharedModule + ], + exports: [ + ApplicationInspectorUsageGuideContainerComponent + ], + providers: [], +}) +export class ApplicationInspectorUsageGuideModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-data.service.ts new file mode 100644 index 000000000000..6a71f2d29e2b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-data.service.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { StoreHelperService } from 'app/shared/services/store-helper.service'; +import { Actions } from 'app/shared/store'; +import { Application } from 'app/core/models/application'; + +@Injectable() +export class ApplicationListDataService { + constructor( + private http: HttpClient, + private storeHelperService: StoreHelperService + ) { } + getApplicationList(): Observable { + return this.http.get('applications.pinpoint').pipe( + map((res: IApplication[]) => { + const body = res || []; + const convertData = body.map(app => new Application(app.applicationName, app.serviceType, app.code)); + + this.storeHelperService.dispatch(new Actions.UpdateApplicationList(convertData)); + return convertData; + }) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-alarm-container.component.css b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-alarm-container.component.css new file mode 100644 index 000000000000..c18ad00430b9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-alarm-container.component.css @@ -0,0 +1,32 @@ +:host { + position: relative; +} +.l-popup-table th { + color:#333; +} +.l-popup-table td { + padding:10px 15px; + height:auto; + border-top:1px solid #e5e8f0; +} +.l-widget-group { + flex:1; + padding: 0 15px; + height: 100%; + align-items: center; +} +.l-search-input { + border:1px solid #469ae4; + font-size:13px; + color:#b3b3b4; + padding:6px 11px; + width:100%; +} +.l-application-list { + padding: 0 !important; + vertical-align: top; +} +.l-application-list > div { + overflow-y: auto; + height: 428px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-alarm-container.component.html b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-alarm-container.component.html new file mode 100644 index 000000000000..01d05ca656e2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-alarm-container.component.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + +
    Application
    +
    + +
    +
    +
    + +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-alarm-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-alarm-container.component.ts new file mode 100644 index 000000000000..27b8aa5b8720 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-alarm-container.component.ts @@ -0,0 +1,164 @@ +import { Component, OnInit, AfterViewInit, ViewChild, ElementRef, ChangeDetectorRef, ChangeDetectionStrategy, OnDestroy, Renderer2 } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Subject, combineLatest, fromEvent } from 'rxjs'; +import { debounceTime, distinctUntilChanged, filter, pluck } from 'rxjs/operators'; + +import { WebAppSettingDataService, StoreHelperService } from 'app/shared/services'; +import { ApplicationListInteractionForConfigurationService } from './application-list-interaction-for-configuration.service'; +import { FOCUS_TYPE } from './application-list-for-header.component'; + +@Component({ + selector: 'pp-application-list-for-configuration-alarm-container', + templateUrl: './application-list-for-configuration-alarm-container.component.html', + styleUrls: ['./application-list-for-configuration-alarm-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationListForConfigurationAlarmContainerComponent implements OnInit, AfterViewInit, OnDestroy { + @ViewChild('inputQuery') inputQuery: ElementRef; + i18nText: { [key: string]: string } = { + INPUT_APPLICATION_NAME: '', + SELECTED_APPLICATION_NAME: '', + EMPTY_LIST: '' + }; + private unsubscribe: Subject = new Subject(); + private minLength = 3; + private filterStr = ''; + private applicationList: IApplication[]; + filteredApplicationList: IApplication[]; + selectedApplication: IApplication; + showTitle = false; + focusType: FOCUS_TYPE = FOCUS_TYPE.KEYBOARD; + restCount = 0; + focusIndex = -1; + funcImagePath: Function; + + constructor( + private changeDetector: ChangeDetectorRef, + private renderer: Renderer2, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private translateService: TranslateService, + private applicationListInteractionForConfigurationService: ApplicationListInteractionForConfigurationService + ) {} + ngOnInit() { + this.initI18nText(); + this.funcImagePath = this.webAppSettingDataService.getIconPathMakeFunc(); + // this.initIconData(); + + this.storeHelperService.getApplicationList(this.unsubscribe).subscribe((applicationList: IApplication[]) => { + this.applicationList = applicationList; + this.filteredApplicationList = this.filterList(this.applicationList); + this.changeDetector.detectChanges(); + }); + } + ngAfterViewInit() { + this.bindUserInputEvent(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private bindUserInputEvent(): void { + fromEvent(this.inputQuery.nativeElement, 'keyup').pipe( + debounceTime(300), + filter((event: KeyboardEvent) => { + return !this.isArrowKey(event.keyCode); + }), + pluck('target', 'value'), + filter((value: string) => { + return this.isLengthValid(value.trim().length); + }), + distinctUntilChanged() + ).subscribe((value: string) => { + this.applyQuery(value); + }); + } + private initI18nText(): void { + combineLatest( + this.translateService.get('MAIN.INPUT_APP_NAME_PLACE_HOLDER'), + this.translateService.get('MAIN.APP_LIST'), + this.translateService.get('CONFIGURATION.GENERAL.EMPTY') + ).subscribe((i18n: string[]) => { + this.i18nText.INPUT_APPLICATION_NAME = i18n[0]; + this.i18nText.APPLICATION_LIST_TITLE = i18n[1]; + this.i18nText.EMPTY_LIST = i18n[2]; + }); + } + private selectApplication(application: IApplication): void { + if (application) { + this.selectedApplication = application; + this.changeDetector.detectChanges(); + } + } + private filterList(appList: IApplication[]): IApplication[] { + if (this.filterStr === '') { + return appList; + } else { + return appList.filter((application: IApplication) => { + return new RegExp(this.filterStr, 'i').test(application.getApplicationName()); + }); + } + } + private applyQuery(query: string): void { + this.filterStr = query; + this.filteredApplicationList = this.filterList(this.applicationList); + this.focusIndex = -1; + this.changeDetector.detectChanges(); + } + + getSelectedApplicationIcon(): string { + return this.funcImagePath(this.selectedApplication.getServiceType()); + } + + getSelectedApplicationName(): string { + if (this.selectedApplication) { + return this.selectedApplication.getApplicationName(); + } else { + return this.i18nText.SELECTED_APPLICATION_NAME; + } + } + onSelectApplication(selectedApplication: IApplication): void { + this.selectApplication(selectedApplication); + this.applicationListInteractionForConfigurationService.setSelectedApplication(selectedApplication); + } + onFocused(index: number): void { + this.focusIndex = index; + this.focusType = FOCUS_TYPE.MOUSE; + this.changeDetector.detectChanges(); + } + onKeyDown(keyCode: number): void { + switch (keyCode) { + case 27: // ESC + this.renderer.setProperty(this.inputQuery.nativeElement, 'value', ''); + this.applyQuery(''); + this.changeDetector.detectChanges(); + break; + // case 13: // Enter + // if (this.focusIndex !== -1) { + // this.onSelectApplication(this.filteredApplicationList[this.focusIndex]); + // this.changeDetector.detectChanges(); + // } + // break; + // case 38: // ArrowUp + // if (this.focusIndex - 1 >= 0) { + // this.focusIndex -= 1; + // this.focusType = FOCUS_TYPE.KEYBOARD; + // this.changeDetector.detectChanges(); + // } + // break; + // case 40: // ArrowDown + // if (this.focusIndex + 1 < this.filteredApplicationList.length) { + // this.focusIndex += 1; + // this.focusType = FOCUS_TYPE.KEYBOARD; + // this.changeDetector.detectChanges(); + // } + // break; + } + } + private isArrowKey(key: number): boolean { + return key >= 37 && key <= 40; + } + private isLengthValid(length: number): boolean { + return length === 0 || length >= this.minLength; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-container.component.css b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-container.component.css new file mode 100644 index 000000000000..7f26ddcb5503 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-container.component.css @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-container.component.html b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-container.component.html new file mode 100644 index 000000000000..2b5c6ed3f709 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-container.component.html @@ -0,0 +1,7 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-container.component.ts new file mode 100644 index 000000000000..265210ef022c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration-container.component.ts @@ -0,0 +1,60 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable, combineLatest, Subject } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { StoreHelperService, WebAppSettingDataService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; + +@Component({ + selector: 'pp-application-list-for-configuration-container', + templateUrl: './application-list-for-configuration-container.component.html', + styleUrls: ['./application-list-for-configuration-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationListForConfigurationContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + applicationList$: Observable; + funcImagePath: Function; + emptyText$: Observable; + iconBtnClassName = 'fas fa-arrow-right'; + + constructor( + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private translateService: TranslateService, + private analyticsService: AnalyticsService, + ) {} + + ngOnInit() { + this.initList(); + this.funcImagePath = this.webAppSettingDataService.getIconPathMakeFunc(); + this.initEmptyText(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + private initList(): void { + this.applicationList$ = combineLatest( + this.storeHelperService.getApplicationList(this.unsubscribe), + this.storeHelperService.getFavoriteApplicationList(this.unsubscribe), + ).pipe( + map(([appList, favAppList]: IApplication[][]) => { + return appList.filter((app: IApplication) => { + return favAppList.findIndex((favApp: IApplication) => { + return favApp.equals(app); + }) === -1; + }); + }) + ); + } + private initEmptyText(): void { + this.emptyText$ = this.translateService.get('CONFIGURATION.GENERAL.EMPTY'); + } + + onSelectApp(app: IApplication): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SET_FAVORITE_APPLICATION_IN_CONFIGURATION); + this.webAppSettingDataService.addFavoriteApplication(app); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration.component.css b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration.component.css new file mode 100644 index 000000000000..d093c6fef980 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration.component.css @@ -0,0 +1,46 @@ +:host { + display: block; + max-height: 240px; + overflow-y: auto; +} + +.l-application-list { + font-size: 13px; +} + +.l-application-list-item { + padding: 12px 12px 12px 18px; + color: #666 !important; + font-weight: 400 !important; + display: flex; + align-items: center; + justify-content: flex-start; +} + +.l-application-list-item:hover { + background-color: #e4f3eb; +} + +.l-application-name-wrapper { + flex: auto; + margin-right: 5px; +} + +.l-icon-img { + margin-right: 5px; +} + +.l-select-button > .fas, +.l-select-button > .far { + font-size: 18px; +} + +.l-select-button > .fa-arrow-right { + color: #4a8fd2; +} + +.l-empty-text { + text-align: center; + color: #333; + font-size: 16px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration.component.html b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration.component.html new file mode 100644 index 000000000000..19021e5f6f3a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration.component.html @@ -0,0 +1,8 @@ +
      +
    • + + {{app.getApplicationName()}} + +
    • +
    +

    {{emptyText}}

    diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration.component.ts new file mode 100644 index 000000000000..79cbb6ba987b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-configuration.component.ts @@ -0,0 +1,29 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-application-list-for-configuration', + templateUrl: './application-list-for-configuration.component.html', + styleUrls: ['./application-list-for-configuration.component.css'] +}) +export class ApplicationListForConfigurationComponent implements OnInit { + @Input() applicationList: IApplication[]; + @Input() emptyText: string; + @Input() funcImagePath: Function; + @Input() iconBtnClassName: string; + @Output() outSelectApp = new EventEmitter(); + + constructor() {} + ngOnInit() {} + + getIconPath(serviceType: string): string { + return this.funcImagePath(serviceType); + } + + onSelectApp(app: IApplication): void { + this.outSelectApp.emit(app); + } + + isListEmpty(): boolean { + return this.applicationList.length === 0; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header-container.component.css b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header-container.component.css new file mode 100644 index 000000000000..74a8c2eee7db --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header-container.component.css @@ -0,0 +1,89 @@ +:host { + display: block; + position: relative; +} +.l-wrapper { + display: flex; + flex-flow: row wrap; + margin-right: 10px; + width: 310px; + position: relative; +} +.l-app-select { + display: flex; + flex-flow: row nowrap; + width: 100%; + align-items: center; + justify-content: space-between; + cursor: pointer; + height: 32px; + padding: 0 9px; + border: 1px solid #4488CB; + background: #F6FAFE; + font-size: 13px; + border-radius: 0px; + color: #666; +} +.l-app-select img { + margin-right: 6px; +} +.l-app-select > div { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.l-app-select > div img { + float: left; +} +.l-app-select > div span { + line-height: 1.4; +} +.l-input-layer { + position: absolute; + top: 32px; + width: 100%; + border: 1px solid #4488CB; + background: #FFF; + z-index: 10; +} +.l-search-group-wrap { + display: flex; + flex-flow: row wrap; + padding: 11px; + font-size: 13px; + justify-content: flex-end; + position: relative; +} +.l-search-group { + width: 100%; + background: #FFF; + height: 32px; + color: #B3B3B4; + position: relative; +} +.l-search-group input { + color: #000; + width: 100%; + height: 100%; + border: 1px solid #D7DDE4; + padding: 0 10px; + font-weight: 600; +} +.l-app-list { + display: flex; + flex-flow: column nowrap; + max-height: 418px; + overflow-y: auto; + height: 100%; +} +.l-bottom { + display: flex; + flex-flow: row wrap; + padding: 4px; + border-top: 1px solid #d7dde4; +} +.l-bottom button { + font-weight: 100; + flex: 1; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header-container.component.html b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header-container.component.html new file mode 100644 index 000000000000..cbd3e620e214 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header-container.component.html @@ -0,0 +1,46 @@ +
    +
    +
    + + {{getSelectedApplicationName()}} +
    + +
    +
    +
    +
    + +
    +
    +
    + + +
    +
    + +
    +
    + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header-container.component.ts new file mode 100644 index 000000000000..4fc2b0f92aad --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header-container.component.ts @@ -0,0 +1,265 @@ +import { Component, OnInit, AfterViewInit, ViewChild, ElementRef, ChangeDetectorRef, ChangeDetectionStrategy, OnDestroy, Renderer2 } from '@angular/core'; +import { Subject, combineLatest, fromEvent, of } from 'rxjs'; +import { debounceTime, distinctUntilChanged, filter, takeUntil, pluck, delay } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { + StoreHelperService, + WebAppSettingDataService, + UrlRouteManagerService, + NewUrlStateNotificationService, + AnalyticsService, + TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { ApplicationListDataService } from './application-list-data.service'; +import { FOCUS_TYPE } from './application-list-for-header.component'; + +@Component({ + selector: 'pp-application-list-for-header-container', + templateUrl: './application-list-for-header-container.component.html', + styleUrls: ['./application-list-for-header-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationListForHeaderContainerComponent implements OnInit, AfterViewInit, OnDestroy { + @ViewChild('inputQuery') inputQuery: ElementRef; + private unsubscribe: Subject = new Subject(); + private maxIndex: number; + private minLength = 3; + private filterStr = ''; + private initApplication: IApplication; + private applicationList: IApplication[]; + private favoriteApplicationList: IApplication[]; + i18nText: { [key: string]: string } = { + FAVORITE_LIST_TITLE: '', + APPLICATION_LIST_TITLE: '', + INPUT_APPLICATION_NAME: '', + SELECTED_APPLICATION_NAME: '', + EMPTY_LIST: '' + }; + showTitle = true; + selectedApplication: IApplication; + focusType: FOCUS_TYPE = FOCUS_TYPE.KEYBOARD; + focusIndex = -1; + hiddenComponent = true; + filteredApplicationList: IApplication[] = []; + filteredFavoriteApplicationList: IApplication[] = []; + funcImagePath: Function; + showLoading = false; + + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private applicationListDataService: ApplicationListDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private translateService: TranslateService, + private analyticsService: AnalyticsService, + private renderer: Renderer2 + ) {} + + ngOnInit() { + this.initI18nText(); + this.funcImagePath = this.webAppSettingDataService.getIconPathMakeFunc(); + + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.APPLICATION)) { + this.initApplication = urlService.getPathValue(UrlPathId.APPLICATION); + this.selectApplication(this.initApplication); + this.hiddenComponent = true; + } else { + this.hiddenComponent = false; + this.selectedApplication = null; + this.changeDetector.detectChanges(); + } + }); + this.connectStore(); + } + + ngAfterViewInit() { + this.setFocusToInput(); + this.bindUserInputEvent(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + combineLatest( + this.storeHelperService.getApplicationList(this.unsubscribe), + this.storeHelperService.getFavoriteApplicationList(this.unsubscribe) + ).subscribe((responseData: any[]) => { + this.refreshList(responseData[0], responseData[1]); + this.showLoading = true; + this.changeDetector.detectChanges(); + }); + } + private bindUserInputEvent(): void { + fromEvent(this.inputQuery.nativeElement, 'keyup').pipe( + debounceTime(300), + distinctUntilChanged(), + filter((event: KeyboardEvent) => { + return !this.isArrowKey(event.keyCode); + }), + pluck('target', 'value'), + filter((value: string) => { + return this.isLengthValid(value.trim().length); + }) + ).subscribe((value: string) => { + this.applyQuery(value); + }); + } + private initI18nText(): void { + combineLatest( + this.translateService.get('MAIN.INPUT_APP_NAME_PLACE_HOLDER'), + this.translateService.get('MAIN.APP_LIST'), + this.translateService.get('MAIN.FAVORITE_APP_LIST'), + this.translateService.get('MAIN.SELECT_YOUR_APP'), + this.translateService.get('CONFIGURATION.GENERAL.EMPTY') + ).subscribe((i18n: string[]) => { + this.i18nText.INPUT_APPLICATION_NAME = i18n[0]; + this.i18nText.APPLICATION_LIST_TITLE = i18n[1]; + this.i18nText.FAVORITE_LIST_TITLE = i18n[2]; + this.i18nText.SELECTED_APPLICATION_NAME = i18n[3]; + this.i18nText.EMPTY_LIST = i18n[4]; + }); + } + + private refreshList(applicationList: IApplication[], favoriteList: IApplication[]): void { + this.applicationList = applicationList; + this.favoriteApplicationList = favoriteList; + this.filteredApplicationList = this.filterList(this.applicationList); + this.filteredFavoriteApplicationList = this.filterList(this.favoriteApplicationList); + this.maxIndex = this.filteredApplicationList.length + this.filteredFavoriteApplicationList.length; + } + + private selectApplication(application: IApplication): void { + if (application) { + this.selectedApplication = application; + this.changeDetector.detectChanges(); + } + } + + private filterList(appList: IApplication[]): IApplication[] { + if (this.filterStr === '') { + return appList; + } else { + return appList.filter((application: IApplication) => { + return new RegExp(this.filterStr, 'i').test(application.getApplicationName()); + }); + } + } + + private setFocusToInput(): void { + of(1).pipe(delay(0)).subscribe((v: number) => { + this.inputQuery.nativeElement.select(); + }); + } + + private applyQuery(query: string): void { + this.filterStr = query; + this.filteredFavoriteApplicationList = this.filterList(this.favoriteApplicationList); + this.filteredApplicationList = this.filterList(this.applicationList); + this.maxIndex = this.filteredApplicationList.length + this.filteredFavoriteApplicationList.length; + this.focusIndex = -1; + this.changeDetector.detectChanges(); + } + + getSelectedApplicationIcon(): string { + return this.funcImagePath(this.selectedApplication.getServiceType()); + } + + getSelectedApplicationName(): string { + if (this.selectedApplication) { + return this.selectedApplication.getApplicationName(); + } else { + return this.i18nText.SELECTED_APPLICATION_NAME; + } + } + + toggleApplicationList(): void { + this.hiddenComponent = !this.hiddenComponent; + if (this.hiddenComponent === false) { + this.setFocusToInput(); + } + } + + onClose(): void { + this.hiddenComponent = true; + } + + onSelectApplication(selectedApplication: IApplication): void { + this.hiddenComponent = true; + if (!selectedApplication.equals(this.selectedApplication)) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_APPLICATION); + this.urlRouteManagerService.changeApplication(selectedApplication.getUrlStr()); + this.selectApplication(selectedApplication); + } + } + + onFocused(index: number): void { + this.focusIndex = index; + this.focusType = FOCUS_TYPE.MOUSE; + this.changeDetector.detectChanges(); + } + + onKeyDown(keyCode: number): void { + if (!this.hiddenComponent) { + switch (keyCode) { + case 27: // ESC + this.renderer.setProperty(this.inputQuery.nativeElement, 'value', ''); + this.applyQuery(''); + this.hiddenComponent = true; + this.changeDetector.detectChanges(); + break; + case 13: // Enter + if (this.focusIndex !== -1) { + const favoriteLen = this.filteredFavoriteApplicationList.length; + if (favoriteLen === 0 || this.focusIndex > favoriteLen) { + this.onSelectApplication(this.filteredApplicationList[this.focusIndex - favoriteLen]); + } else { + this.onSelectApplication(this.filteredFavoriteApplicationList[this.focusIndex]); + } + this.changeDetector.detectChanges(); + } + break; + case 38: // ArrowUp + if (this.focusIndex - 1 >= 0) { + this.focusIndex -= 1; + this.focusType = FOCUS_TYPE.KEYBOARD; + this.changeDetector.detectChanges(); + } + break; + case 40: // ArrowDown + if (this.focusIndex + 1 < this.maxIndex) { + this.focusIndex += 1; + this.focusType = FOCUS_TYPE.KEYBOARD; + this.changeDetector.detectChanges(); + } + break; + } + } + } + + onReload(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_RELOAD_APPLICATION_LIST_BUTTON); + this.showLoading = false; + this.refreshList([], []); + this.applicationListDataService.getApplicationList().subscribe((applicationList: IApplication[]) => { + this.showLoading = true; + this.changeDetector.detectChanges(); + }); + } + + private isArrowKey(key: number): boolean { + return key >= 37 && key <= 40; + } + + private isLengthValid(length: number): boolean { + return length === 0 || length >= this.minLength; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header.component.css b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header.component.css new file mode 100644 index 000000000000..60d2071c97ba --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header.component.css @@ -0,0 +1,39 @@ +:host { + display: block; +} + +.l-application-list { + font-size: 13px; +} + +.l-application-list > dt { + padding: 12px; + background-color: #edf2f8; + color: #333; + font-weight: 600; +} +.l-item { + padding: 12px; + color: #666; + display: flex; + align-items: center; + cursor: pointer; +} +.l-item.active { + color: #FFF !important; + background-color: #4b99e3; +} +.l-item.active.focus { + background-color: #4b99e3; +} +.l-item.focus { + background-color: #e4f3eb; +} +.l-icon-img { + margin: 0 10px 0 0; +} +.l-text-ellipsis { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header.component.html b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header.component.html new file mode 100644 index 000000000000..3a7a5b9ec4dd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header.component.html @@ -0,0 +1,12 @@ +
    +
    {{title}}
    +
    + + {{app.getApplicationName()}} +
    +
    {{emptyText}}
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header.component.ts new file mode 100644 index 000000000000..55ab8081f3b2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-for-header.component.ts @@ -0,0 +1,73 @@ +import { Component, OnInit, OnChanges, SimpleChanges, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core'; + +export enum FOCUS_TYPE { + KEYBOARD, + MOUSE +} + +@Component({ + selector: 'pp-application-list-for-header', + templateUrl: './application-list-for-header.component.html', + styleUrls: ['./application-list-for-header.component.css'] +}) +export class ApplicationListForHeaderComponent implements OnInit, OnChanges { + @ViewChild('appList') ele: ElementRef; + @Input() showTitle: boolean; + @Input() title: string; + @Input() restCount: number; + @Input() focusIndex: number; + @Input() focusType: FOCUS_TYPE; + @Input() applicationList: IApplication[]; + @Input() selectedApplication: IApplication; + @Input() emptyText: string; + @Input() funcImagePath: Function; + @Output() outSelected: EventEmitter = new EventEmitter(); + @Output() outFocused: EventEmitter = new EventEmitter(); + private previousFocusIndex = -1; + + constructor() {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if (changes['focusIndex']) { + const eleIndex = this.focusIndex - this.restCount; + if (eleIndex >= 0 && eleIndex < this.applicationList.length && this.focusType === FOCUS_TYPE.KEYBOARD) { + this.ele.nativeElement.querySelectorAll('dd')[eleIndex].scrollIntoView({ + block: 'nearest', + inline: 'nearest', + behavior: 'instant' + }); + } + } + } + + private isSelectedApplication(app: IApplication): boolean { + return this.selectedApplication && this.selectedApplication.equals(app) ? true : false; + } + + getIconPath(serviceType: string): string { + return this.funcImagePath(serviceType); + } + + makeClass(index: number): { [key: string]: boolean } { + const app = this.applicationList[index - this.restCount]; + return { + active: this.isSelectedApplication(app), + focus: this.focusIndex === index + }; + } + + onFocus(index: number): void { + if (this.previousFocusIndex !== index) { + this.outFocused.emit(index); + this.previousFocusIndex = index; + } + } + + onSelectApplication(app: IApplication): void { + this.outSelected.emit(app); + } + + isListEmpty(): boolean { + return this.applicationList.length === 0; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-interaction-for-configuration.service.ts b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-interaction-for-configuration.service.ts new file mode 100644 index 000000000000..fb98c67b27db --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/application-list-interaction-for-configuration.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; + +@Injectable() +export class ApplicationListInteractionForConfigurationService { + private outSelectApplication = new Subject(); + onSelectApplication$: Observable; + + constructor() { + this.onSelectApplication$ = this.outSelectApplication.asObservable(); + } + setSelectedApplication(application: IApplication): void { + this.outSelectApplication.next(application); + } +} + diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/favorite-application-list-for-configuration-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-list/favorite-application-list-for-configuration-container.component.ts new file mode 100644 index 000000000000..0fd57f0f74c7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/favorite-application-list-for-configuration-container.component.ts @@ -0,0 +1,46 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable, Subject } from 'rxjs'; + +import { WebAppSettingDataService, StoreHelperService } from 'app/shared/services'; + +@Component({ + selector: 'pp-favorite-application-list-for-configuration-container', + templateUrl: './application-list-for-configuration-container.component.html', + styleUrls: ['./application-list-for-configuration-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FavoriteApplicationListForConfigurationContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + applicationList$: Observable; + emptyText$: Observable; + funcImagePath: Function; + iconBtnClassName = 'far fa-trash-alt'; + + constructor( + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private webAppSettingDataService: WebAppSettingDataService, + ) {} + + ngOnInit() { + this.initList(); + this.funcImagePath = this.webAppSettingDataService.getIconPathMakeFunc(); + this.initEmptyText(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + private initList(): void { + this.applicationList$ = this.storeHelperService.getFavoriteApplicationList(this.unsubscribe); + } + private initEmptyText(): void { + this.emptyText$ = this.translateService.get('CONFIGURATION.GENERAL.EMPTY'); + } + + onSelectApp(app: IApplication): void { + this.webAppSettingDataService.removeFavoriteApplication(app); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-list/index.ts b/web/src/main/webapp/v2/src/app/core/components/application-list/index.ts new file mode 100644 index 000000000000..c65cafbee2af --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-list/index.ts @@ -0,0 +1,39 @@ + +import { NgModule } from '@angular/core'; +import { MatTooltipModule } from '@angular/material'; +import { SharedModule } from 'app/shared'; + +import { ApplicationListForHeaderContainerComponent } from './application-list-for-header-container.component'; +import { ApplicationListForHeaderComponent } from './application-list-for-header.component'; +import { ApplicationListForConfigurationContainerComponent } from './application-list-for-configuration-container.component'; +import { ApplicationListForConfigurationComponent } from './application-list-for-configuration.component'; +import { FavoriteApplicationListForConfigurationContainerComponent } from './favorite-application-list-for-configuration-container.component'; +import { ApplicationListForConfigurationAlarmContainerComponent } from './application-list-for-configuration-alarm-container.component'; +import { ApplicationListInteractionForConfigurationService } from './application-list-interaction-for-configuration.service'; +import { ApplicationListDataService } from './application-list-data.service'; + +@NgModule({ + declarations: [ + ApplicationListForHeaderContainerComponent, + ApplicationListForHeaderComponent, + ApplicationListForConfigurationContainerComponent, + ApplicationListForConfigurationComponent, + FavoriteApplicationListForConfigurationContainerComponent, + ApplicationListForConfigurationAlarmContainerComponent + ], + imports: [ + MatTooltipModule, + SharedModule + ], + exports: [ + ApplicationListForHeaderContainerComponent, + ApplicationListForConfigurationContainerComponent, + FavoriteApplicationListForConfigurationContainerComponent, + ApplicationListForConfigurationAlarmContainerComponent + ], + providers: [ + ApplicationListInteractionForConfigurationService, + ApplicationListDataService + ] +}) +export class ApplicationListModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup-container.component.css new file mode 100644 index 000000000000..838ad80020e3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup-container.component.css @@ -0,0 +1,5 @@ +:host { + display: block; + width: 300px; + border-radius: 3px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup-container.component.html new file mode 100644 index 000000000000..d74bbf542726 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup-container.component.html @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup-container.component.ts new file mode 100644 index 000000000000..1ec62a8d53dd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup-container.component.ts @@ -0,0 +1,83 @@ +import { Component, OnInit, ElementRef, AfterViewInit, Input, Output, EventEmitter, OnDestroy } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable, Subject } from 'rxjs'; +import { withLatestFrom, map, takeUntil } from 'rxjs/operators'; + +import { POPUP_CONSTANT } from 'app/core/components/application-name-issue-popup/application-name-issue-popup.component'; +import { DynamicPopup, TranslateReplaceService, NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; + +@Component({ + selector: 'pp-application-name-issue-popup-container', + templateUrl: './application-name-issue-popup-container.component.html', + styleUrls: ['./application-name-issue-popup-container.component.css'] +}) +export class ApplicationNameIssuePopupContainerComponent implements OnInit, OnDestroy, AfterViewInit, DynamicPopup { + @Input() data: {[key: string]: string}; + @Input() coord: ICoordinate; + @Output() outCreated = new EventEmitter(); + @Output() outClose = new EventEmitter(); + + private unsubscribe = new Subject(); + + data$: Observable<{[key: string]: any}>; + + constructor( + private elementRef: ElementRef, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + ) {} + + ngOnInit() { + const urlApplicationName$ = this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + map((urlService: NewUrlStateNotificationService) => { + return urlService.getPathValue(UrlPathId.APPLICATION).getApplicationName(); + }) + ); + + this.data$ = this.translateService.get('INSPECTOR.APPLICAITION_NAME_ISSUE').pipe( + withLatestFrom(urlApplicationName$), + map(([message, urlAppName]: [{[key: string]: any}, string]) => { + const { agentId, applicationName } = this.data; + + return { + prevAppName: urlAppName, + currAppName: applicationName, + message: { + ISSUE_MESSAGE: this.translateReplaceService.replace(message['ISSUE_MESSAGE'], urlAppName, applicationName), + ISSUE_CAUSES: [ + this.translateReplaceService.replace(message['ISSUE_CAUSES'][0], urlAppName, applicationName), + this.translateReplaceService.replace(message['ISSUE_CAUSES'][1], agentId, applicationName) + ], + ISSUE_SOLUTIONS: [ + this.translateReplaceService.replace(message['ISSUE_SOLUTIONS'][0], urlAppName, agentId), + message['ISSUE_SOLUTIONS'][1] + ] + } + }; + }) + ); + } + + ngAfterViewInit() { + this.outCreated.emit({ + coordX: this.coord.coordX - (this.elementRef.nativeElement.offsetWidth / 2), + coordY: this.coord.coordY + POPUP_CONSTANT.SPACE_FROM_BUTTON + POPUP_CONSTANT.TOOLTIP_TRIANGLE_HEIGHT + }); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + onInputChange(): void { + this.outClose.emit(); + } + + onClickOutside(): void { + this.outClose.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup.component.css new file mode 100644 index 000000000000..a85534a09ce7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup.component.css @@ -0,0 +1,51 @@ +:host { + display: block; + width: 100%; +} + +:host::after { + content: ''; + width: 0; + height: 0; + position: absolute; + border-bottom: 7px solid #f6f8fb; + border-right: 7px solid transparent; + border-left: 7px solid transparent; + bottom: 100%; + left: 0; + right: 0; + margin: auto; +} + +.l-popup-title { + background-color: #f6f8fb; + border-bottom: 1px solid #e5e8f0; + padding:10px; + display: flex; + justify-content: space-evenly; + font-weight: 400; +} + +.l-popup-title span { + display: inline-block; +} + +.l-issue-message { + padding: 12px 15px 8px 15px; + font-size: 13px; +} + +.l-cause-list { + padding: 0 12px 12px; + font-size: 13px; + border-bottom: 1px solid #e5e8f0; +} + +.l-cause-list-item, .l-solution-list-item { + padding: 3px; +} + +.l-solution-list { + padding: 12px; + font-size: 13px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup.component.html new file mode 100644 index 000000000000..b6fdf2692baf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup.component.html @@ -0,0 +1,12 @@ +

    + {{data.prevAppName}} + + {{data.currAppName}} +

    +

    +
      +
    • {{cause}}
    • +
    +
      +
    • {{solution}}
    • +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup.component.ts new file mode 100644 index 000000000000..3a4bcebb8c13 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/application-name-issue-popup.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit, Input } from '@angular/core'; + +export const enum POPUP_CONSTANT { + TOOLTIP_TRIANGLE_HEIGHT = 7, // 툴팁 삼각형 높이 + SPACE_FROM_BUTTON = 10 // 클릭한 버튼에서 살짝 떨어뜨려줄 길이 +} + +@Component({ + selector: 'pp-application-name-issue-popup', + templateUrl: './application-name-issue-popup.component.html', + styleUrls: ['./application-name-issue-popup.component.css'] +}) +export class ApplicationNameIssuePopupComponent implements OnInit { + @Input() data: {[key: string]: any}; + + constructor() {} + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/index.ts b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/index.ts new file mode 100644 index 000000000000..c0269dd85168 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/application-name-issue-popup/index.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { ApplicationNameIssuePopupContainerComponent } from 'app/core/components/application-name-issue-popup/application-name-issue-popup-container.component'; +import { ApplicationNameIssuePopupComponent } from 'app/core/components/application-name-issue-popup/application-name-issue-popup.component'; + +@NgModule({ + declarations: [ + ApplicationNameIssuePopupContainerComponent, + ApplicationNameIssuePopupComponent + ], + imports: [ + SharedModule + ], + exports: [], + entryComponents: [ + ApplicationNameIssuePopupContainerComponent, + ], + providers: [], +}) +export class ApplicationNameIssuePopupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list-container.component.css b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list-container.component.css new file mode 100644 index 000000000000..9fcef31ebc91 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list-container.component.css @@ -0,0 +1,25 @@ +.authentication-rules-table th .flex-container { + height: 47px; + justify-content: space-between; + display: flex; + align-items: center; +} +.authentication-rules-tr-wrap { + height: 170px; + overflow-y: scroll; + position: relative; +} +.authentication-rules-tr { + display: flex; + height: 30px; + align-items: center; + padding: 0 15px; + position: relative; +} +.authentication-rules-tr-th { + color: #777879; + font-weight: 600; + border-bottom: 1px solid #e6e8ec; + background: #fff; + margin: 0 -21px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list-container.component.html b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list-container.component.html new file mode 100644 index 000000000000..dac0d39174f7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list-container.component.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list-container.component.ts new file mode 100644 index 000000000000..08c96197b2dd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list-container.component.ts @@ -0,0 +1,11 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'pp-authentication-list-container', + templateUrl: './authentication-list-container.component.html', + styleUrls: ['./authentication-list-container.component.css'] +}) +export class AuthenticationListContainerComponent implements OnInit { + constructor() { } + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list.component.css b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list.component.css new file mode 100644 index 000000000000..f2598cf57fe0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list.component.css @@ -0,0 +1,22 @@ +.authentication-rules-tr { + display: flex; + height: 30px; + align-items: center; + padding: 0 15px; + position:relative; +} +.authentication-rules-btn-group { + color: #b3b6bf; + font-size: 13px; + align-items: center; + justify-content: flex-end; +} +.authentication-rules-btn-group button { + margin-left: 11px; +} +.authentication-rules-btn-group button.img-icon { + line-height: 0; +} +.authentication-rules-btn-group button:first-child { + margin-left: 0; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list.component.html b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list.component.html new file mode 100644 index 000000000000..5acb9dbd88fa --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list.component.html @@ -0,0 +1,15 @@ +
    +
    GUEST
    +
    GUEST
    +
    + + + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list.component.ts b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list.component.ts new file mode 100644 index 000000000000..c730e4f6962c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/authentication-list/authentication-list.component.ts @@ -0,0 +1,11 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'pp-authentication-list', + templateUrl: './authentication-list.component.html', + styleUrls: ['./authentication-list.component.css'] +}) +export class AuthenticationListComponent implements OnInit { + constructor() { } + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/authentication-list/index.ts b/web/src/main/webapp/v2/src/app/core/components/authentication-list/index.ts new file mode 100644 index 000000000000..7e2bfdbe5b01 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/authentication-list/index.ts @@ -0,0 +1,21 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { AuthenticationListComponent } from './authentication-list.component'; +import { AuthenticationListContainerComponent } from './authentication-list-container.component'; + + +@NgModule({ + declarations: [ + AuthenticationListComponent, + AuthenticationListContainerComponent, + ], + imports: [ + SharedModule + ], + exports: [ + AuthenticationListContainerComponent, + ], + providers: [] +}) +export class AuthenticationListModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree-container.component.css b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree-container.component.html b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree-container.component.html new file mode 100644 index 000000000000..0df383565773 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree-container.component.html @@ -0,0 +1,11 @@ + diff --git a/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree-container.component.ts new file mode 100644 index 000000000000..dcb18a325758 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree-container.component.ts @@ -0,0 +1,194 @@ +import { Component, Input, OnInit, AfterViewInit, OnDestroy, ViewChild, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { Actions } from 'app/shared/store'; +import { + StoreHelperService, + NewUrlStateNotificationService, + TransactionViewTypeService, + VIEW_TYPE, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { TransactionSearchInteractionService, ISearchParam } from 'app/core/components/transaction-search/transaction-search-interaction.service'; +import { IGridData } from './call-tree.component'; +import { CallTreeComponent } from './call-tree.component'; +import { MessagePopupContainerComponent } from 'app/core/components/message-popup/message-popup-container.component'; +import { SyntaxHighlightPopupContainerComponent } from 'app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component'; + +@Component({ + selector: 'pp-call-tree-container', + templateUrl: './call-tree-container.component.html', + styleUrls: ['./call-tree-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CallTreeContainerComponent implements OnInit, OnDestroy, AfterViewInit { + @ViewChild(CallTreeComponent) private callTreeComponent: CallTreeComponent; + @Input() canSelectRow = false; + @Input() rowSelection = 'multiple'; + private unsubscribe: Subject = new Subject(); + timezone$: Observable; + dateFormat$: Observable; + ratio: number; + searchSelfTime: number; + hiddenComponent = true; + transactionInfo: ITransactionMetaData; + callTreeOriginalData: ITransactionDetailData; + callTreeData: IGridData[]; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private transactionSearchInteractionService: TransactionSearchInteractionService, + private transactionViewTypeService: TransactionViewTypeService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.transactionViewTypeService.onChangeViewType$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((viewType: string) => { + if ( viewType === VIEW_TYPE.CALL_TREE ) { + this.hiddenComponent = false; + } else { + this.hiddenComponent = true; + } + this.changeDetectorRef.detectChanges(); + }); + this.connectStore(); + this.transactionSearchInteractionService.onSearch$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((params: ISearchParam) => { + if (this.hiddenComponent === true) { + return; + } + this.transactionSearchInteractionService.setSearchResult({ + type: params.type, + query: params.query, + result: this.callTreeComponent.searchRow(params) + }); + }); + } + ngAfterViewInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.SEARCH_ID)) { + const searchId = urlService.getPathValue(UrlPathId.SEARCH_ID); + if (searchId !== '' && this.hiddenComponent === false) { + this.callTreeComponent.moveRow(searchId); + } + } + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(); + this.dateFormat$ = this.storeHelperService.getDateFormat(this.unsubscribe, 2); + this.storeHelperService.getTransactionDetailData(this.unsubscribe).pipe( + filter((transactionDetailInfo: ITransactionDetailData) => { + return transactionDetailInfo && transactionDetailInfo.transactionId ? true : false; + }) + ).subscribe((transactionDetailInfo: ITransactionDetailData) => { + this.ratio = this.calcTimeRatio(transactionDetailInfo.callStack[0][transactionDetailInfo.callStackIndex.begin], transactionDetailInfo.callStack[0][transactionDetailInfo.callStackIndex.end]); + this.callTreeOriginalData = transactionDetailInfo; + this.callTreeData = this.makeGridData(transactionDetailInfo.callStack, transactionDetailInfo.callStackIndex); + this.changeDetectorRef.detectChanges(); + }); + } + private calcTimeRatio(begin: number, end: number): number { + return 100 / (end - begin); + } + private makeGridData(callTreeData: any, oIndex: any): IGridData[] { + const newData = []; + const parentRef = {}; + for ( let i = 0 ; i < callTreeData.length ; i++ ) { + const callTree = callTreeData[i]; + const oRow = {}; + parentRef[callTree[oIndex.id]] = oRow; + this.makeRow(callTree, oIndex, oRow, i); + if ( callTree[oIndex.parentId] ) { + const oParentRow = parentRef[callTree[oIndex.parentId]]; + if ( oParentRow.children instanceof Array === false ) { + oParentRow['folder'] = true; + oParentRow['open'] = true; + oParentRow['children'] = []; + } + oParentRow.children.push(oRow); + } else { + newData.push(oRow); + } + } + return newData; + } + private makeRow(callTree: any, oIndex: any, oRow: IGridData, index: number): void { + oRow['index'] = index; + oRow['id'] = callTree[oIndex.id]; + oRow['method'] = callTree[oIndex.title]; + oRow['argument'] = callTree[oIndex.arguments]; + oRow['startTime'] = callTree[oIndex.begin]; + oRow['gap'] = callTree[oIndex.gap]; + oRow['exec'] = callTree[oIndex.elapsedTime]; + oRow['execPer'] = callTree[oIndex.elapsedTime] ? Math.ceil((callTree[oIndex.end] - callTree[oIndex.begin]) * this.ratio) : ''; + oRow['selp'] = callTree[oIndex.executionMilliseconds]; + oRow['selpPer'] = callTree[oIndex.elapsedTime] && callTree[oIndex.executionMilliseconds] ? + ( Math.floor( callTree[oIndex.executionMilliseconds].replace(/,/gi, '') ) / Math.floor( callTree[oIndex.elapsedTime].replace(/,/gi, '') ) ) * 100 + : 0; + oRow['clazz'] = callTree[oIndex.simpleClassName]; + oRow['api'] = callTree[oIndex.apiType]; + oRow['agent'] = callTree[oIndex.agent]; + oRow['application'] = callTree[oIndex.applicationName]; + oRow['isMethod'] = callTree[oIndex.isMethod]; + oRow['methodType'] = callTree[oIndex.methodType]; + oRow['hasException'] = callTree[oIndex.hasException]; + oRow['isAuthorized'] = callTree[oIndex.isAuthorized]; + oRow['isFocused'] = callTree[oIndex.isFocused]; + if ( callTree[oIndex.hasChild] === true ) { + oRow['folder'] = true; + oRow['open'] = true; + oRow['children'] = []; + } + } + outSelectFormatting(info: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_SQL); + const nextRowData = this.callTreeOriginalData.callStack[info.index + 1]; + const nextValue = nextRowData[this.callTreeOriginalData.callStackIndex.title]; + let bindValue; + + if (nextRowData && (nextValue === 'SQL-BindValue' || nextValue === 'MONGO-JSON-BindValue')) { + bindValue = nextRowData[this.callTreeOriginalData.callStackIndex.arguments]; + } + + this.dynamicPopupService.openPopup({ + data: { + type: info.type, + originalContents: info.formatText, + bindValue + }, + component: SyntaxHighlightPopupContainerComponent + }); + } + onRowSelected(rowData: IGridData): void { + if (rowData.startTime !== 0) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: -1, + time: rowData.startTime + })); + } + } + onCellDoubleClicked(contents: string): void { + this.dynamicPopupService.openPopup({ + data: { + title: 'Contents', + contents + }, + component: MessagePopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree.component.css b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree.component.css new file mode 100644 index 000000000000..97545b71bb14 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree.component.css @@ -0,0 +1,97 @@ +#callTree .ag-root { + border: none; + font-size: 12px; + font-family: 'Open Sans', sans-serif; +} +#callTree .ag-cell { + padding: 4px; + border-right: 1px solid #e6e8ec; + font-family: 'Open Sans', sans-serif; +} + +#callTree .ag-column-moving .ag-cell { + transition: left 0.2s; +} +#callTree .ag-header-cell-moving .ag-header-cell-label { + opacity: 0; + filter: alpha(opacity=0); +} +#callTree .ag-header-cell-moving { + background-color: #bebebe; +} +#callTree .ag-header-cell-moving-clone { + border-right: 1px solid #808080; + border-left: 1px solid #808080; + background-color: rgba(220,220,220,0.8); +} +#callTree .ag-header { + background: #f6f8fb; + border-bottom: 1px solid #e6e8ec; + line-height: 2; +} +#callTree .ag-header-cell { + font-size: 12px; + font-weight: 600; + font-family: 'Open Sans', sans-serif; + border-right: 1px solid #e6e8ec; + padding-left: 2px; + padding-right: 2px; +} +#callTree .ag-header-cell:first-child { + border-right: none; +} +#callTree .ag-header-cell-resize:after { + border-right: none; +} +#callTree .ag-header-cell-label { + padding: 4px; +} +#callTree .ag-group-expanded span { + margin-right: 4px; +} +#callTree .ag-row { + line-height: 2; +} +#callTree .ag-row-exception { + background-color: #fff1f1; +} +#callTree .ag-row-focused { + background-color: #e4f5e3; +} +#callTree .ag-body { + background-color: #ffffff; +} +#callTree .ag-body-viewport { + background-color: #ffffff; +} +#callTree .ag-menu { + background-color: #ffffff; + border: 1px solid grey; +} +#callTree .fa { + font-size: 14px; +} +#callTree .ag-row-focused { + background-color: #e4f5e3; +} +#callTree .ag-row-selected { + color: #4a8fd2; + background-color: #e7f5f9; +} +#callTree .div-percent-bar { + display: inline-block; + height: 30%; + position: absolute; +} +#callTree .div-percent-value { + position: absolute; + padding-left: 4px; + font-weight: bold; + font-size: 13px; +} +#callTree .div-outer-div { + display: inline-block; + margin-right: 20px; + height: 30%; + width: 92%; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree.component.html b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree.component.html new file mode 100644 index 000000000000..dd066e77dc3c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree.component.html @@ -0,0 +1,8 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree.component.ts b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree.component.ts new file mode 100644 index 000000000000..dc38a2e495d5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/call-tree/call-tree.component.ts @@ -0,0 +1,352 @@ +import { Component, Input, Output, ViewEncapsulation, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import * as moment from 'moment-timezone'; +import { GridOptions, RowNode } from 'ag-grid'; +import { WindowRefService } from 'app/shared/services'; + +export interface IGridData { + id: string; + index: number; + method: string; + argument: string; + startTime: number; + gap: number; + exec: number; + execPer: number | string; + selp: number; + selpPer: number; + clazz: string; + api: string; + agent: string; + application: string; + isMethod: boolean; + methodType: string; + hasException: boolean; + isAuthorized: boolean; + isFocused: boolean; + folder?: boolean; + open?: boolean; + children?: any[]; +} + +@Component({ + selector: 'pp-call-tree', + templateUrl: './call-tree.component.html', + styleUrls: ['./call-tree.component.css'], + encapsulation: ViewEncapsulation.None +}) +export class CallTreeComponent implements OnInit, OnChanges { + gridOptions: GridOptions; + previousColor: string; + @Input() canSelectRow: boolean; + @Input() rowSelection: string; + @Input() rowData: IGridData[]; + @Input() timezone: string; + @Input() dateFormat: string; + @Output() outSelectFormatting: EventEmitter = new EventEmitter(); + @Output() outRowSelected: EventEmitter = new EventEmitter(); + @Output() outCellDoubleClicked: EventEmitter = new EventEmitter(); + + constructor(private windowRefService: WindowRefService) {} + ngOnInit() { + this.initGridOptions(); + } + ngOnChanges(changes: SimpleChanges) { + if (changes['timezone'] && changes['timezone'].firstChange === false) { + this.gridOptions.api.refreshCells({ + columns: ['startTime'], + force: true + }); + } + if (changes['dateFormat'] && changes['dateFormat'].firstChange === false) { + this.gridOptions.api.refreshCells({ + columns: ['startTime'], + force: true + }); + } + } + private initGridOptions() { + this.gridOptions = { + columnDefs : this.makeColumnDefs(), + headerHeight: 34, + enableColResize: true, + enableSorting: false, + animateRows: true, + rowHeight: 30, + getRowClass: (params: any) => { + if ( params.data.isFocused ) { + return 'ag-row-focused'; + } else if ( params.data.hasException ) { + return 'ag-row-exception'; + } else { + return ''; + } + }, + getNodeChildDetails: (file) => { + if (file.folder) { + return { + group: true, + children: file.children, + expanded: file.open + }; + } else { + return null; + } + }, + onRowClicked: (params: any) => { + if (this.canSelectRow) { + params.node.setSelected(true); + this.outRowSelected.emit(params.data); + } + }, + suppressRowClickSelection: !this.canSelectRow, + rowSelection: this.rowSelection + }; + } + private calcColor(str: string): string { + if ( str ) { + let hash = 0; + let colour = '#'; + for ( let i = 0 ; i < str.length ; i++ ) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + for ( let i = 0 ; i < 3 ; i++ ) { + colour += ('00' + ((hash >> i * 8) & 0xFF).toString(16)).slice(-2); + } + this.previousColor = colour; + } + return this.previousColor; + } + private makeColumnDefs(): any { + return [ + { + headerName: '', + field: 'agent', + width: 10, + minWidth: 10, + maxWidth: 10, + cellStyle: (params: any) => { + return { backgroundColor: this.calcColor(params.value) }; + }, + cellRenderer: (params: any) => { + return ''; + } + }, + { + headerName: 'Method', + field: 'method', + width: 350, + cellRenderer: 'group', + cellRendererParams: { + innerRenderer: this.innerCellRenderer, + suppressCount: true + }, + tooltipField: 'method' + }, + { + headerName: 'Argument', + field: 'argument', + width: 250, + cellStyle: this.argumentCellStyle, + tooltipField: 'argument' + }, + { + headerName: 'StartTime', + field: 'startTime', + width: 170, + valueFormatter: (params: any) => { + return params.value === 0 ? '' : moment(params.value).tz(this.timezone).format(this.dateFormat); + } + }, + { + headerName: 'Gap(ms)', + field: 'gap', + width: 75, + cellStyle: this.alignRightCellStyle, + valueFormatter: (params: any) => { + return params.value === '' ? '' : new Intl.NumberFormat().format(params.value); + } + }, + { + headerName: 'Exec(ms)', + field: 'exec', + width: 78, + cellStyle: this.alignRightCellStyle, + valueFormatter: (params: any) => { + return params.value === '' ? '' : new Intl.NumberFormat().format(params.value); + } + }, + { + headerName: 'Exec(%)', + field: 'execPer', + width: 100, + minWidth: 100, + maxWidth: 100, + cellRenderer: (params: any) => { + if ( params.value === '' ) { + return ''; + } + const adjustRatio = 0.92; + const value = params.value; + const eDivPercentBar = this.windowRefService.nativeWindow.document.createElement('div'); + eDivPercentBar.className = 'div-percent-bar'; + eDivPercentBar.style.width = (value * adjustRatio) + '%'; + eDivPercentBar.style.top = '10px'; + eDivPercentBar.style.backgroundColor = '#5bc0de'; + const eDivSelfBar = this.windowRefService.nativeWindow.document.createElement('div'); + eDivSelfBar.className = 'div-percent-bar'; + eDivSelfBar.style.height = '18%'; + eDivSelfBar.style.top = '12px'; + if ( params.data.selpPer ) { + eDivSelfBar.style.width = (((value * params.data.selpPer) / 100) * adjustRatio) + '%'; + } else { + eDivSelfBar.style.width = '0%'; + } + eDivSelfBar.style.backgroundColor = '#4343C8'; + const eOuterDiv = this.windowRefService.nativeWindow.document.createElement('div'); + eOuterDiv.className = 'div-outer-div'; + eOuterDiv.appendChild(eDivPercentBar); + eOuterDiv.appendChild(eDivSelfBar); + return eOuterDiv; + } + }, + { + headerName: 'Self(ms)', + field: 'selp', + width: 78, + cellStyle: this.alignRightCellStyle, + valueFormatter: function(params: any) { + return params.value === '' ? '' : new Intl.NumberFormat().format(params.value); + } + }, + { + headerName: 'Class', + field: 'clazz', + width: 150, + tooltipField: 'clazz' + }, + { + headerName: 'API', + field: 'api', + width: 150, + tooltipField: 'api' + }, + { + headerName: 'Agent', + field: 'agent', + width: 150, + tooltipField: 'agent' + }, + { + headerName: 'Application', + field: 'application', + width: 150, + tooltipField: 'application' + } + ]; + } + argumentCellStyle(): any { + return {'text-align': 'left'}; + } + alignRightCellStyle(): any { + return {'text-align': 'right'}; + } + timeFormatter(params: any): string { + return params.value === 0 ? '' : moment(params.value).tz(this.timezone).format(this.dateFormat); + } + numberFormatter(params: any): string { + return params.value === '' ? '' : new Intl.NumberFormat().format(params.value); + } + innerCellRenderer(params: any) { + let result = ''; + if (params.data.hasException) { + result += ' '; + } else if (!params.data.isMethod) { + if (params.data.method === 'SQL') { + result += ' '; + return ' ' + result; + } else if (params.data.method === 'MONGO-JSON') { + result += ' '; + return ' ' + result; + } else { + result += ' '; + } + } else { + const itemMethodType = +params.data.methodType; + switch ( itemMethodType ) { + case 100: + result += ' '; + break; + case 200: + result += ' '; + break; + case 900: + result += ' '; + break; + } + } + return ' ' + result + params.data.method; + } + onCellClick(params: any): void { + if (params.colDef.field === 'method') { + let paramValue; + if (params.value === 'SQL' || params.value === 'MONGO-JSON') { + paramValue = params.value.split('-').pop(); + this.outSelectFormatting.next({ + type: paramValue, + formatText: params.data.argument, + index: params.data.index + }); + } + } + } + onCellDoubleClicked(params: any): void { + this.outCellDoubleClicked.next(params.data[params.colDef.field]); + } + searchRow({type, query}: {type: string, query: string | number}): number { + let resultCount = 0; + let targetIndex = -1; + const fnCompare: { [key: string]: Function } = { + 'all': (data: any, value: string): boolean => { + return (data.method && data.method.indexOf(value) !== -1) || + (data.argument && data.argument.indexOf(value) !== -1) || + (data.clazz && data.clazz.indexOf(value) !== -1) || + (data.api && data.api.indexOf(value) !== -1) || + (data.agent && data.agent.indexOf(value) !== -1) || + (data.application && data.application.indexOf(value) !== -1); + }, + 'self': (data: any, value: number): boolean => { + return +data.selp >= +value; + }, + 'argument': (data: any, value: string): boolean => { + return data.argument.indexOf(value) !== -1; + } + }; + this.gridOptions.api.forEachNode((rowNode: RowNode) => { + if (fnCompare[type](rowNode.data, query)) { + if (resultCount === 0) { + targetIndex = rowNode.data.index; + } + resultCount++; + rowNode.setSelected(true); + } else { + rowNode.setSelected(false); + } + }); + if (resultCount > 0) { + this.gridOptions.api.ensureIndexVisible(targetIndex, 'top'); + } + return resultCount; + } + moveRow(id: string): void { + let targetIndex = -1; + this.gridOptions.api.forEachNode((rowNode: RowNode) => { + if (rowNode.data.id === id) { + targetIndex = rowNode.data.index; + rowNode.setSelected(true); + } else { + rowNode.setSelected(false); + } + }); + this.gridOptions.api.ensureIndexVisible(targetIndex, 'top'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/call-tree/index.ts b/web/src/main/webapp/v2/src/app/core/components/call-tree/index.ts new file mode 100644 index 000000000000..b4677910870f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/call-tree/index.ts @@ -0,0 +1,27 @@ + +import { NgModule } from '@angular/core'; +import { AgGridModule } from 'ag-grid-angular/main'; + +import { SharedModule } from 'app/shared'; +import { CallTreeComponent } from './call-tree.component'; +import { CallTreeContainerComponent } from './call-tree-container.component'; +import { MessagePopupModule } from 'app/core/components/message-popup'; +import { SyntaxHighlightPopupModule } from 'app/core/components/syntax-highlight-popup'; + +@NgModule({ + declarations: [ + CallTreeComponent, + CallTreeContainerComponent + ], + imports: [ + SharedModule, + AgGridModule.withComponents([]), + MessagePopupModule, + SyntaxHighlightPopupModule + ], + exports: [ + CallTreeContainerComponent + ], + providers: [] +}) +export class CallTreeModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/command-group/command-group-container.component.css b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group-container.component.css new file mode 100644 index 000000000000..e7a72018d679 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group-container.component.css @@ -0,0 +1,3 @@ +:host { + display: flex; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/command-group/command-group-container.component.html b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group-container.component.html new file mode 100644 index 000000000000..5594dd47ce9c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group-container.component.html @@ -0,0 +1,3 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/command-group/command-group-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group-container.component.ts new file mode 100644 index 000000000000..59e791b7a65e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group-container.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; + +import { AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { ConfigurationPopupContainerComponent } from 'app/core/components/configuration-popup/configuration-popup-container.component'; + +@Component({ + selector: 'pp-command-group-container', + templateUrl: './command-group-container.component.html', + styleUrls: ['./command-group-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CommandGroupContainerComponent implements OnInit { + constructor( + private dynamicPopupService: DynamicPopupService, + private analyticsService: AnalyticsService, + ) {} + + ngOnInit() {} + onOpenConfigurationPopup(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_CONFIGURATION_POPUP); + this.dynamicPopupService.openPopup({ + component: ConfigurationPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/command-group/command-group.component.css b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group.component.css new file mode 100644 index 000000000000..56e7b9de4b5e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group.component.css @@ -0,0 +1,21 @@ +:host { + display: flex; +} + +button { + outline: none; +} + +.fa-cog, .fa-github { + font-size: 18px; +} +.l-tool-group { + width:100px; + display: flex; + justify-content: center; + color:#fff; + font-size: 18px; +} +.l-tool-group button { + margin:0 8px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/command-group/command-group.component.html b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group.component.html new file mode 100644 index 000000000000..b8cfc00a61c9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group.component.html @@ -0,0 +1,4 @@ +
    + + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/command-group/command-group.component.ts b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group.component.ts new file mode 100644 index 000000000000..a30ec31b6b6a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/command-group/command-group.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit, Output, EventEmitter } from '@angular/core'; +/** + * 도움말, 설정, repository 링크등을 제공하는 Component + */ +@Component({ + selector: 'pp-command-group', + templateUrl: './command-group.component.html', + styleUrls: ['./command-group.component.css'] +}) +export class CommandGroupComponent implements OnInit { + @Output() outOpenConfigurationPopup: EventEmitter = new EventEmitter(); + + constructor() {} + ngOnInit() {} + onOpenConfigurationPopup(): void { + this.outOpenConfigurationPopup.emit(); + } + onOpenRepository(): void { + window.open('http://github.com/naver/pinpoint'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/command-group/index.ts b/web/src/main/webapp/v2/src/app/core/components/command-group/index.ts new file mode 100644 index 000000000000..c52a61e01a26 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/command-group/index.ts @@ -0,0 +1,23 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { CommandGroupComponent } from './command-group.component'; +import { CommandGroupContainerComponent } from './command-group-container.component'; +import { ConfigurationPopupModule } from 'app/core/components/configuration-popup'; + +@NgModule({ + declarations: [ + CommandGroupComponent, + CommandGroupContainerComponent + ], + imports: [ + CommonModule, + ConfigurationPopupModule + ], + exports: [ + CommandGroupContainerComponent + ], + providers: [] +}) +export class CommandGroupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-alarm.component.css b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-alarm.component.css new file mode 100644 index 000000000000..64b7eff11466 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-alarm.component.css @@ -0,0 +1,11 @@ +.l-content-section { + display: flex; + padding: 30px 0 0; +} +.l-content-item { + flex:1; + margin-right: 20px; +} +.l-content-item2 { + flex:2; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-alarm.component.html b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-alarm.component.html new file mode 100644 index 000000000000..dec0eccb5d89 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-alarm.component.html @@ -0,0 +1,8 @@ +
    +
    + +
    +
    + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-alarm.component.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-alarm.component.ts new file mode 100644 index 000000000000..098cd6729e51 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-alarm.component.ts @@ -0,0 +1,12 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; + +@Component({ + selector: 'pp-configuration-popup-alarm', + templateUrl: './configuration-popup-alarm.component.html', + styleUrls: ['./configuration-popup-alarm.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ConfigurationPopupAlarmComponent implements OnInit { + constructor() {} + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-container.component.css new file mode 100644 index 000000000000..3c6a97654ec4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-container.component.css @@ -0,0 +1,18 @@ +:host { + display: block; + background-color: transparent; + width: 100%; + height: 100%; +} + +:host::before { + content: ''; + display: block; + height: 100%; + width: 100%; + background: #000; + opacity: 0.6; + position: absolute; + left: 0; + top: 0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-container.component.html new file mode 100644 index 000000000000..b47b78a8f04d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-container.component.html @@ -0,0 +1 @@ + diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-container.component.ts new file mode 100644 index 000000000000..eeb9fc56e3e4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-container.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit, Output, EventEmitter, AfterViewInit } from '@angular/core'; + +import { WebAppSettingDataService, DynamicPopup } from 'app/shared/services'; + +@Component({ + selector: 'pp-configuration-popup-container', + templateUrl: './configuration-popup-container.component.html', + styleUrls: ['./configuration-popup-container.component.css'] +}) +export class ConfigurationPopupContainerComponent implements OnInit, AfterViewInit, DynamicPopup { + @Output() outClose = new EventEmitter(); + @Output() outCreated = new EventEmitter(); + + funcImagePath: Function; + + constructor( + private webAppSettingDataService: WebAppSettingDataService, + ) {} + + ngOnInit() { + this.funcImagePath = this.webAppSettingDataService.getIconPathMakeFunc(); + } + + ngAfterViewInit() { + this.outCreated.emit({ coordX: 0, coordY: 0 }); + } + + onClosePopup(): void { + this.outClose.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-general-container.component.css b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-general-container.component.css new file mode 100644 index 000000000000..69c16a21ef1a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-general-container.component.css @@ -0,0 +1,78 @@ +:host { + display: block; + padding: 25px 10px 0; +} + +.l-desc-text-wrapper { + margin-bottom: 25px; +} + +.l-desc-text { + color: #999; + font-size: 14px; +} + +.l-popup-table { + border: 1px solid #e5e8f0; + width: 100%; + background-color: #fff; + font-family: 'Open Sans', sans-serif; +} + +.l-popup-table thead { + border-bottom: 1px solid #e5e8f0; +} + +.l-popup-table th { + font-size: 13px; + font-weight: 600; + color: #333; + background-color: #f6f8fb; + padding: 8px 20px; +} + +.l-popup-table td { + font-size: 13px; + font-weight: 400; + color: #999; + padding: 8px 20px; + border-left: 1px solid #e5e8f0; +} + +.l-favorite-application-table { + margin-top: 17px; + table-layout: fixed; +} + +.l-favorite-application-table td { + padding: 0; + vertical-align: baseline; +} + +.l-color-blue { + color: #4b99e3; +} + +.l-text-bold { + font-weight: 600; +} + +.l-servermap-span { + color: #666; +} +.l-servermap-span .fas { + color:#d0d0d0; +} + + +.fa-sign-in-alt, .fa-sign-out-alt { + color: #33b692; +} + +.l-timezone-dateformat-table { + margin-top: 17px; +} + +.l-timezone-dateformat-table th { + border-left: 1px solid #e5e8f0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-general-container.component.html b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-general-container.component.html new file mode 100644 index 000000000000..35cb393d28e8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-general-container.component.html @@ -0,0 +1,68 @@ +

    {{desc$ | async}}

    + + + + + + + + + + + + + + + + +
    ServerMap
    + Search Depth + ( Inbound Outbound ) + + + Search Period + +
    + + + + + + + + + + + + + + + + +
    Favorite Application
    + + + +
    + + + + + + + + + + + + + + + + + +
    TimeZoneDate Format
    + + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-general-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-general-container.component.ts new file mode 100644 index 000000000000..7776e2d6586c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-general-container.component.ts @@ -0,0 +1,24 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'pp-configuration-popup-general-container', + templateUrl: './configuration-popup-general-container.component.html', + styleUrls: ['./configuration-popup-general-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ConfigurationPopupGeneralContainerComponent implements OnInit { + desc$: Observable; + + constructor( + private translateService: TranslateService, + ) {} + ngOnInit() { + this.initDescText(); + } + + private initDescText(): void { + this.desc$ = this.translateService.get('CONFIGURATION.GENERAL.DESC'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-help-container.component.css b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-help-container.component.css new file mode 100644 index 000000000000..53af6888bb2a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-help-container.component.css @@ -0,0 +1,88 @@ +:host { + display: block; + padding: 25px 10px 0; +} +.l-card-link-list { + display: flex; + width: 100%; + justify-content: space-between; + margin-bottom: 40px; +} +.l-card-link-list-item { + display: block; + width: 32%; + height: 120px; +} +.l-card-link { + display: flex; + width: 100%; + height: 100%; + justify-content: center; + align-items: center; +} +.l-faq-link { + background-color: #4a8fd2; +} +.l-issue-link { + background-color: #4ab0d2; +} +.l-user-group-link { + background-color: #50cba4; +} +.l-card-text { + font-size: 18px; + font-weight: 400; + color: #fff; +} +.l-card-link .fas, .l-card-link .fab { + font-size: 42px; + margin-right: 7px; +} +.fa-comments { + color: #b4cce9; +} +.fa-github { + color: #b4dae9; +} +.fa-users { + color: #b5e6d5; +} + +h4 { + font-weight: 600; + padding-bottom: 15px; + border-bottom: 1px solid #e5e8f0; +} +.l-guide-contents-wrapper { + display: flex; + position: relative; +} +.l-guide-contents { + width: 50%; + padding-left: 30px; +} +.l-guide-contents:first-child { + border-right: 1px solid #e5e8f0; +} +.l-guide-language-text { + color: #666; + font-size: 22px; + font-weight: 600; + padding: 25px 0; + text-align: center; +} +.l-guide-contents-list li { + padding: 5px 0; +} +.l-guide-contents-list a > .fas { + color: #9ec2e4; + margin-right: 5px; +} + +.l-guide-contents-list a:link { + color: #428bca; +} + +.l-guide-contents-list a:visited { + color: #609; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-help-container.component.html b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-help-container.component.html new file mode 100644 index 000000000000..a18809764360 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-help-container.component.html @@ -0,0 +1,45 @@ + +

    Document & Guide

    + diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-help-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-help-container.component.ts new file mode 100644 index 000000000000..d7741177f29f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-help-container.component.ts @@ -0,0 +1,11 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'pp-configuration-popup-help-container', + templateUrl: 'configuration-popup-help-container.component.html', + styleUrls: ['./configuration-popup-help-container.component.css'], +}) +export class ConfigurationPopupHelpContainerComponent implements OnInit { + constructor() { } + ngOnInit() { } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-container.component.css b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-container.component.css new file mode 100644 index 000000000000..d40cdcfe59d1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-container.component.css @@ -0,0 +1,14 @@ +:host { + display: block; + padding: 25px 10px 0; +} +.l-desc-text-wrapper { + margin-bottom: 25px; +} +.l-desc-text { + color: #999; + font-size: 14px; +} +.l-check-wrapper { + margin-bottom: 40px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-container.component.html b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-container.component.html new file mode 100644 index 000000000000..f9589a0fd5b0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-container.component.html @@ -0,0 +1,12 @@ +

    {{desc$ | async}}

    +
    + + +
    + + + + + diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-container.component.ts new file mode 100644 index 000000000000..edd493753d4b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-container.component.ts @@ -0,0 +1,65 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { ApplicationNameDuplicationCheckInteractionService } from 'app/core/components/duplication-check/application-name-duplication-check-interaction.service'; +import { AgentIdDuplicationCheckInteractionService } from 'app/core/components/duplication-check/agent-id-duplication-check-interaction.service'; +import { ConfigurationPopupInstallationDataService, IInstallationData } from './configuration-popup-installation-data.service'; + +import { Observable, combineLatest, of } from 'rxjs'; +import { filter, catchError, pluck } from 'rxjs/operators'; + +@Component({ + selector: 'pp-configuration-popup-installation-container', + templateUrl: './configuration-popup-installation-container.component.html', + styleUrls: ['./configuration-popup-installation-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ConfigurationPopupInstallationContainerComponent implements OnInit { + desc$: Observable; + installationInfo$: Observable; + jvmArgument$: Observable; + + constructor( + private translateService: TranslateService, + private configurationPopupInstallationDataService: ConfigurationPopupInstallationDataService, + private applicationNameDuplicationCheckInteractionService: ApplicationNameDuplicationCheckInteractionService, + private agentIdDuplicationCheckInteractionService: AgentIdDuplicationCheckInteractionService + ) {} + + ngOnInit() { + this.initDescText(); + this.initInstallationInfo(); + this.initJVMArgument(); + } + + private initDescText(): void { + this.desc$ = this.translateService.get('CONFIGURATION.INSTALLATION.DESC'); + } + + private initInstallationInfo(): void { + this.installationInfo$ = this.configurationPopupInstallationDataService.getData() + .pipe( + filter((data: IInstallationData) => { + return data.code === 0; + }), + pluck('message'), + catchError((err) => { + return this.onAjaxError(err); + }) + ); + } + + private initJVMArgument(): void { + this.jvmArgument$ = combineLatest( + this.applicationNameDuplicationCheckInteractionService.onCheckSuccess$, + this.agentIdDuplicationCheckInteractionService.onCheckSuccess$, + ); + } + + private onAjaxError(err: Error): Observable { + // TODO: Error발생시 띄워줄 팝업 컴포넌트 Call - issue#170 + return of({ + downloadUrl: '', + installationArgument: '' + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-data.service.ts new file mode 100644 index 000000000000..62cb657b42df --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + +export interface IInstallationData { + code: number; + message: { + downloadUrl: string, + installationArgument: string, + version: string + }; +} + +@Injectable() +export class ConfigurationPopupInstallationDataService { + private dataRequestURL = 'getAgentInstallationInfo.pinpoint'; + constructor(private http: HttpClient) {} + getData(): Observable { + return this.http.get(this.dataRequestURL).pipe( + retry(3) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-download-link.component.css b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-download-link.component.css new file mode 100644 index 000000000000..f6a000629050 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-download-link.component.css @@ -0,0 +1,17 @@ +:host { + display: block; + border: 1px solid #e5e8f0; + border-left: 5px solid #4a8fd2; + margin-bottom: 15px; + padding: 25px 20px; +} + +.download-link { + font-size: 14px; + color: #428bca; +} + +h4 { + font-weight: 600; + margin-bottom: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-download-link.component.html b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-download-link.component.html new file mode 100644 index 000000000000..be494e0bf01a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-download-link.component.html @@ -0,0 +1,2 @@ +

    Download Link

    +{{downloadLink}} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-download-link.component.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-download-link.component.ts new file mode 100644 index 000000000000..2499727c3b8a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-download-link.component.ts @@ -0,0 +1,13 @@ +import { Component, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'pp-configuration-popup-installation-download-link', + templateUrl: './configuration-popup-installation-download-link.component.html', + styleUrls: ['./configuration-popup-installation-download-link.component.css'], +}) +export class ConfigurationPopupInstallationDownloadLinkComponent implements OnInit { + @Input() downloadLink: string; + + constructor() {} + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-jvm-argument-info.component.css b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-jvm-argument-info.component.css new file mode 100644 index 000000000000..a5d9867cf8ed --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-jvm-argument-info.component.css @@ -0,0 +1,61 @@ +:host { + display: block; + border: 1px solid #e5e8f0; + border-left: 5px solid #4a8fd2; + padding: 25px 20px; + position: relative; +} + +h4 { + font-weight: 600; + margin-bottom: 10px; +} + +.contents-wrapper { + display: flex; +} + +.textarea-wrapper { + position: relative; + width: 60%; +} + +.copied-noti-text-wrapper { + width: 40%; + position: relative; +} + +.jvm-argument-info { + border: 1px solid #e5e8f0; + font-size: 14px; + width: 100%; + height: 80px; + padding: 10px; + resize: none; +} + +.copy-button { + position: absolute; + right: 5px; + top: 5px; +} + +.copy-button:focus { + outline: 0; +} + +.fa-clone { + font-size: 20px; + color: #ccc; +} + +.fa-clone:hover { + color: #979797; +} + +.copied-noti-text { + position: absolute; + top: 25px; + left: 50%; + font-size: 15px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-jvm-argument-info.component.html b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-jvm-argument-info.component.html new file mode 100644 index 000000000000..dc673a663198 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-jvm-argument-info.component.html @@ -0,0 +1,8 @@ +

    JVM Argument Info

    +
    +
    + + +
    +

    Copied!

    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-jvm-argument-info.component.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-jvm-argument-info.component.ts new file mode 100644 index 000000000000..162962efe5f5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-installation-jvm-argument-info.component.ts @@ -0,0 +1,33 @@ +import { Component, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'pp-configuration-popup-installation-jvm-argument-info', + templateUrl: './configuration-popup-installation-jvm-argument-info.component.html', + styleUrls: ['./configuration-popup-installation-jvm-argument-info.component.css'], +}) +export class ConfigurationPopupInstallationJVMArgumentInfoComponent implements OnInit { + @Input() installationArgument: string; + @Input() jvmArgument: string[]; + + isArgumentInfoCopied: boolean; + + constructor() {} + ngOnInit() {} + + getJVMArgumentInfoInView(): string { + const [applicationName, agentId] = this.jvmArgument; + + return `${this.installationArgument}\n-Dpinpoint.applicationName=${applicationName}\n-Dpinpoint.agentId=${agentId}`; + } + + onCopySuccess(): void { + this.updateCopiedStatus(true); + setTimeout(() => { + this.updateCopiedStatus(false); + }, 2000); + } + + private updateCopiedStatus(status: boolean): void { + this.isArgumentInfoCopied = status; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-usergroup.component.css b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-usergroup.component.css new file mode 100644 index 000000000000..993e89965d5b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-usergroup.component.css @@ -0,0 +1,11 @@ +.l-content-section { + display: flex; + padding: 30px 0 0; +} +.l-content-item { + flex:1; + margin-right: 20px; +} +.l-content-item:last-child { + margin-right: 0px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-usergroup.component.html b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-usergroup.component.html new file mode 100644 index 000000000000..9500e4681f91 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-usergroup.component.html @@ -0,0 +1,11 @@ +
    +
    + +
    +
    + +
    +
    + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-usergroup.component.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-usergroup.component.ts new file mode 100644 index 000000000000..3666c0bd15cf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup-usergroup.component.ts @@ -0,0 +1,11 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; + +@Component({ + selector: 'pp-configuration-popup-usergroup', + templateUrl: './configuration-popup-usergroup.component.html', + styleUrls: ['./configuration-popup-usergroup.component.css'] +}) +export class ConfigurationPopupUsergroupComponent implements OnInit { + constructor() {} + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup.component.css new file mode 100644 index 000000000000..2b8d79f12617 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup.component.css @@ -0,0 +1,82 @@ +:host { + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + width: 100%; + max-width: 1000px; + height: 710px; + background-color: #fff; + border: 1px solid #e5e8f0; + box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.75); + text-align: left; +} +.l-title-group { + padding:20px; + border-bottom:1px solid #e5e8f0; + position:relative; +} + +.l-title-group dt { + font-size:20px; + font-weight:normal; + color:#4a8fd2; +} + +.l-contents-group { + overflow: visible; + padding: 17px 18px; +} +.l-tab-menu { + position: relative; +} +.l-tab-menu ul { + border-bottom: 1px solid #e6e8ec; +} +.l-tab-menu ul:after { + content:""; + display:block; + width:100%; + height:0; + visibility:hidden; + clear:both; +} +.l-tab-menu li { + font-weight: 400 !important; + float: left; +} +.l-tab-menu li a { + cursor: pointer; + display:inline-block; + font-size: 13px; + color: #666; + padding: 14px 15px; + border: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + line-height: 1em; +} +.l-tab-menu li:hover a { + border-color: #e6e8ec #e6e8ec #fff; +} +.l-tab-menu li.active a { + color: #fff; + background: #4a8fd2; +} +.l-tab-menu li.active a:hover { + border-color: transparent; +} +.l-sql-popup-close { + position:absolute; + right:27px; + top:50%; + transform:translateY(-50%); + color:#4a8fd2; + font-size: 30px; + width:20px; + height:20px; + background:url(../../../../assets/img/icon-close.png) no-repeat 0 0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup.component.html new file mode 100644 index 000000000000..d646cc010c07 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup.component.html @@ -0,0 +1,14 @@ +
    +
    +
    Pinpoint Configuration
    +
    + +
    +
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup.component.ts new file mode 100644 index 000000000000..9943cff66cda --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/configuration-popup.component.ts @@ -0,0 +1,124 @@ +import { Component, OnInit, OnDestroy, Input, ViewChild, ViewContainerRef, ComponentFactoryResolver, Output, EventEmitter, HostBinding } from '@angular/core'; + +import { ConfigurationPopupGeneralContainerComponent } from './configuration-popup-general-container.component'; +import { ConfigurationPopupUsergroupComponent } from './configuration-popup-usergroup.component'; +import { ConfigurationPopupAlarmComponent } from './configuration-popup-alarm.component'; +import { ConfigurationPopupInstallationContainerComponent } from './configuration-popup-installation-container.component'; +import { ConfigurationPopupHelpContainerComponent } from './configuration-popup-help-container.component'; + +@Component({ + selector: 'pp-configuration-popup', + templateUrl: './configuration-popup.component.html', + styleUrls: ['./configuration-popup.component.css'] +}) +export class ConfigurationPopupComponent implements OnInit, OnDestroy { + @ViewChild('contentContainer', { read: ViewContainerRef }) contentContainer: ViewContainerRef; + @Input() funcImagePath: Function; + @Output() outClosePopup = new EventEmitter(); + @HostBinding('class.font-opensans') fontFamily = true; + + private componentMap = new Map(); + private componentList = [ + ConfigurationPopupGeneralContainerComponent, + ConfigurationPopupUsergroupComponent, + ConfigurationPopupAlarmComponent, + ConfigurationPopupInstallationContainerComponent, + ConfigurationPopupHelpContainerComponent + ]; + tabList: any[]; + + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + ) {} + + ngOnInit() { + this.initTabList(); + this.initComponentMap(); + this.loadComponent(this.tabList.find((tab) => tab.isActive).id); + } + + ngOnDestroy() { + this.componentMap.forEach((value) => { + if (value.componentRef) { + value.componentRef.destroy(); + } + }); + } + + onTabClick(tabName: string): void { + this.setActiveTab(tabName); + this.contentContainer.detach(0); + if (!this.isComponentLoaded(tabName)) { + this.loadComponent(tabName); + } else { + this.contentContainer.insert(this.componentMap.get(tabName).componentRef.hostView); + } + } + + private initTabList(): void { + this.tabList = [{ + id: 'general', + displayText: 'General', + isActive: true + }, + { + id: 'usergroup', + displayText: 'User Group', + isActive: false + }, + { + id: 'alarm', + displayText: 'Alarm', + isActive: false + }, + { + id: 'installation', + displayText: 'Installation', + isActive: false + }, + { + id: 'help', + displayText: 'Help', + isActive: false + }]; + } + + + private initComponentMap(): void { + this.tabList.forEach((value, i) => { + this.componentMap.set(value.id, { + component: this.componentList[i], + isLoaded: false, + componentRef: undefined + }); + }); + } + + private loadComponent(key: string): void { + const componentObj = this.componentMap.get(key); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentObj.component); + + componentObj.componentRef = this.contentContainer.createComponent(componentFactory); + componentObj.isLoaded = true; + } + + private setActiveTab(tabName: string): void { + this.tabList.forEach((tab) => tab.isActive = tabName === tab.id); + } + + private isComponentLoaded(key: string): boolean { + return this.componentMap.get(key).isLoaded; + } + + onClickFilter(): void { + this.onClickClose(); + } + + onClickClose(): void { + this.outClosePopup.emit(); + } + + getIconFullPath(applicationName: string): string { + return this.funcImagePath(applicationName); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/configuration-popup/index.ts b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/index.ts new file mode 100644 index 000000000000..aafa17527080 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/configuration-popup/index.ts @@ -0,0 +1,68 @@ + +import { NgModule } from '@angular/core'; +import { ClipboardModule } from 'ngx-clipboard'; + +import { SharedModule } from 'app/shared'; +import { AlarmRuleListModule } from 'app/core/components/alarm-rule-list'; +import { ApplicationListModule } from 'app/core/components/application-list'; +import { UserGroupModule } from 'app/core/components/user-group'; +import { GroupMemberModule } from 'app/core/components/group-member'; +import { PinpointUserModule } from 'app/core/components/pinpoint-user'; +import { InboundOutboundRangeSelectorModule } from 'app/core/components/inbound-outbound-range-selector'; +import { SearchPeriodModule } from 'app/core/components/search-period'; +import { TimezoneModule } from 'app/core/components/timezone/index'; +import { DateFormatModule } from 'app/core/components/date-format'; +import { DuplicationCheckModule } from 'app/core/components/duplication-check'; +import { ConfigurationPopupComponent } from './configuration-popup.component'; +import { ConfigurationPopupContainerComponent } from './configuration-popup-container.component'; +import { ConfigurationPopupGeneralContainerComponent } from './configuration-popup-general-container.component'; +import { ConfigurationPopupUsergroupComponent } from './configuration-popup-usergroup.component'; +import { ConfigurationPopupAlarmComponent } from './configuration-popup-alarm.component'; +import { ConfigurationPopupHelpContainerComponent } from './configuration-popup-help-container.component'; +import { ConfigurationPopupInstallationContainerComponent } from './configuration-popup-installation-container.component'; +import { ConfigurationPopupInstallationDownloadLinkComponent } from './configuration-popup-installation-download-link.component'; +import { ConfigurationPopupInstallationJVMArgumentInfoComponent } from './configuration-popup-installation-jvm-argument-info.component'; + +import { ConfigurationPopupInstallationDataService } from './configuration-popup-installation-data.service'; + +@NgModule({ + declarations: [ + ConfigurationPopupComponent, + ConfigurationPopupContainerComponent, + ConfigurationPopupGeneralContainerComponent, + ConfigurationPopupUsergroupComponent, + ConfigurationPopupAlarmComponent, + ConfigurationPopupHelpContainerComponent, + ConfigurationPopupInstallationContainerComponent, + ConfigurationPopupInstallationDownloadLinkComponent, + ConfigurationPopupInstallationJVMArgumentInfoComponent + ], + imports: [ + SharedModule, + ClipboardModule, + AlarmRuleListModule, + ApplicationListModule, + UserGroupModule, + GroupMemberModule, + PinpointUserModule, + InboundOutboundRangeSelectorModule, + SearchPeriodModule, + ApplicationListModule, + TimezoneModule, + DateFormatModule, + DuplicationCheckModule, + ], + exports: [], + entryComponents: [ + ConfigurationPopupContainerComponent, + ConfigurationPopupGeneralContainerComponent, + ConfigurationPopupUsergroupComponent, + ConfigurationPopupAlarmComponent, + ConfigurationPopupInstallationContainerComponent, + ConfigurationPopupHelpContainerComponent + ], + providers: [ + ConfigurationPopupInstallationDataService + ] +}) +export class ConfigurationPopupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-filtered-map-container.component.css b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-filtered-map-container.component.css new file mode 100644 index 000000000000..7a73bb795ec8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-filtered-map-container.component.css @@ -0,0 +1,8 @@ +:host { + width: 100% +} +.l-wrapper { + display: flex; + flex-flow: row wrap; + padding: 10px 10px 0px 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-filtered-map-container.component.html b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-filtered-map-container.component.html new file mode 100644 index 000000000000..08b26408d737 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-filtered-map-container.component.html @@ -0,0 +1,10 @@ +
    + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-filtered-map-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-filtered-map-container.component.ts new file mode 100644 index 000000000000..2471ee3fee75 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-filtered-map-container.component.ts @@ -0,0 +1,58 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService, StoreHelperService } from 'app/shared/services'; +import { ServerMapForFilteredMapDataService } from 'app/core/components/server-map/server-map-for-filtered-map-data.service'; + +@Component({ + selector: 'pp-data-load-indicator-for-filtered-map-container', + templateUrl: './data-load-indicator-for-filtered-map-container.component.html', + styleUrls: ['./data-load-indicator-for-filtered-map-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DataLoadIndicatorForFilteredMapContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + timezone$: Observable; + dateFormat$: Observable; + rangeValue: number[]; + selectedRangeValue: number[]; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private serverMapForFilteredMapDataService: ServerMapForFilteredMapDataService + ) {} + ngOnInit() { + this.connectStore(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.END_TIME, UrlPathId.PERIOD); + } + )).subscribe((urlService: NewUrlStateNotificationService) => { + const endTime = urlService.getEndTimeToNumber(); + this.rangeValue = [urlService.getStartTimeToNumber(), endTime]; + this.selectedRangeValue = [endTime, endTime]; + this.changeDetectorRef.detectChanges(); + }); + this.serverMapForFilteredMapDataService.onServerMapData$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((serverMapAndScatterData: any) => { + this.selectedRangeValue = [ + serverMapAndScatterData['lastFetchedTimestamp'], + serverMapAndScatterData['applicationMapData']['range']['to'] + ]; + this.changeDetectorRef.detectChanges(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + this.dateFormat$ = this.storeHelperService.getDateFormat(this.unsubscribe, 6); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-transaction-list-container.component.css b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-transaction-list-container.component.css new file mode 100644 index 000000000000..7a73bb795ec8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-transaction-list-container.component.css @@ -0,0 +1,8 @@ +:host { + width: 100% +} +.l-wrapper { + display: flex; + flex-flow: row wrap; + padding: 10px 10px 0px 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-transaction-list-container.component.html b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-transaction-list-container.component.html new file mode 100644 index 000000000000..08b26408d737 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-transaction-list-container.component.html @@ -0,0 +1,10 @@ +
    + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-transaction-list-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-transaction-list-container.component.ts new file mode 100644 index 000000000000..e417b200a6c4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/data-load-indicator-for-transaction-list-container.component.ts @@ -0,0 +1,58 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { takeUntil, filter, take } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService, StoreHelperService } from 'app/shared/services'; +import { TransactionMetaDataService } from 'app/core/components/transaction-table-grid/transaction-meta-data.service'; + +@Component({ + selector: 'pp-data-load-indicator-for-transaction-list-container', + templateUrl: './data-load-indicator-for-transaction-list-container.component.html', + styleUrls: ['./data-load-indicator-for-transaction-list-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DataLoadIndicatorForTransactionListContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + timezone$: Observable; + dateFormat$: Observable; + rangeValue: number[]; + selectedRangeValue: number[]; + + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private transactionMetaDataService: TransactionMetaDataService + ) {} + ngOnInit() { + this.connectStore(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.END_TIME, UrlPathId.PERIOD); + }), + take(1) + ).subscribe((urlService: NewUrlStateNotificationService) => { + const endTime = urlService.getEndTimeToNumber(); + this.rangeValue = [urlService.getStartTimeToNumber(), endTime]; + this.selectedRangeValue = [endTime, endTime]; + this.connectMetaDataService(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + this.dateFormat$ = this.storeHelperService.getDateFormat(this.unsubscribe, 6); + } + private connectMetaDataService(): void { + this.transactionMetaDataService.onTransactionDataRange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((range: number[]) => { + this.selectedRangeValue = range; + this.changeDetectorRef.detectChanges(); + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/index.ts b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/index.ts new file mode 100644 index 000000000000..a5e0bc81fd3d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/data-load-indicator/index.ts @@ -0,0 +1,23 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { DataLoadIndicatorForFilteredMapContainerComponent } from './data-load-indicator-for-filtered-map-container.component'; +import { DataLoadIndicatorForTransactionListContainerComponent } from './data-load-indicator-for-transaction-list-container.component'; +import { TransactionTableGridModule } from 'app/core/components/transaction-table-grid'; + +@NgModule({ + declarations: [ + DataLoadIndicatorForFilteredMapContainerComponent, + DataLoadIndicatorForTransactionListContainerComponent + ], + imports: [ + SharedModule, + TransactionTableGridModule + ], + exports: [ + DataLoadIndicatorForFilteredMapContainerComponent, + DataLoadIndicatorForTransactionListContainerComponent + ], + providers: [] +}) +export class DataLoadIndicatorModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/date-format/date-format-container.component.css b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format-container.component.css new file mode 100644 index 000000000000..7f26ddcb5503 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format-container.component.css @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/date-format/date-format-container.component.html b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format-container.component.html new file mode 100644 index 000000000000..30f574a0530e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format-container.component.html @@ -0,0 +1,6 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/date-format/date-format-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format-container.component.ts new file mode 100644 index 000000000000..abc9511e9064 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format-container.component.ts @@ -0,0 +1,41 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; + +import { Actions } from 'app/shared/store'; +import { StoreHelperService, WebAppSettingDataService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; + +@Component({ + selector: 'pp-date-format-container', + templateUrl: './date-format-container.component.html', + styleUrls: ['./date-format-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DateFormatContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + timezone$: Observable; + dateFormatList: string[][]; + currentDateFormatIndex$: Observable; + constructor( + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private analyticsService: AnalyticsService, + ) {} + + ngOnInit() { + this.dateFormatList = this.webAppSettingDataService.getDateFormatList(); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + this.currentDateFormatIndex$ = this.storeHelperService.getDateFormatIndex(this.unsubscribe); + } + onChangeDateFormat(dateFormatIndex: number): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SET_DATE_FORMAT_IN_CONFIGURATION, this.dateFormatList[dateFormatIndex][0]); + this.webAppSettingDataService.setDateFormat(dateFormatIndex); + this.storeHelperService.dispatch(new Actions.ChangeDateFormat(dateFormatIndex)); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/date-format/date-format.component.css b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format.component.css new file mode 100644 index 000000000000..b2b8789c1cdc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format.component.css @@ -0,0 +1,26 @@ +:host { + display: block; + position: relative; + width: 100%; +} + +.fa-angle-down { + position: absolute; + top: 8px; + right: 8px; + font-size: 15px; +} + +.l-app-select { + width: 100%; + cursor: pointer; + padding: 6px 12px; + background-color: #fff; + border: 1px solid #d7dde4 !important; + border-radius: 0px; + font-size: 13px; + color: #666; + appearance: none; + -webkit-appearance: none; + outline: 0; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/date-format/date-format.component.html b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format.component.html new file mode 100644 index 000000000000..c76968771ba7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format.component.html @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/date-format/date-format.component.ts b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format.component.ts new file mode 100644 index 000000000000..76c9a2c821ec --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/date-format/date-format.component.ts @@ -0,0 +1,27 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import * as moment from 'moment-timezone'; + +@Component({ + selector: 'pp-date-format', + templateUrl: './date-format.component.html', + styleUrls: ['./date-format.component.css'], +}) +export class DateFormatComponent implements OnInit { + @Input() timezone: string; + @Input() dateFormatList: string[][]; + @Input() currentDateFormatIndex: number; + @Output() outChangeDateFormat = new EventEmitter(); + private exampleTime = Date.now(); + constructor() {} + ngOnInit() {} + onChangeDateFormat(value: number): void { + this.outChangeDateFormat.emit(value); + } + compareFn(o1: string, o2: string): boolean { + console.log( o1, o2, o1 === o2 ); + return o1 && o2 ? o1 === o2 : false; + } + formatExample(date: string): string { + return moment(this.exampleTime).tz(this.timezone).format(date); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/date-format/index.ts b/web/src/main/webapp/v2/src/app/core/components/date-format/index.ts new file mode 100644 index 000000000000..bc082b3d2695 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/date-format/index.ts @@ -0,0 +1,21 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { DateFormatContainerComponent } from './date-format-container.component'; +import { DateFormatComponent } from './date-format.component'; + +@NgModule({ + declarations: [ + DateFormatContainerComponent, + DateFormatComponent + ], + imports: [ + SharedModule + ], + exports: [ + DateFormatContainerComponent, + ], + providers: [ + ] +}) +export class DateFormatModule {} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/agent-id-duplication-check-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/duplication-check/agent-id-duplication-check-container.component.ts new file mode 100644 index 000000000000..f7858371c2a7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/agent-id-duplication-check-container.component.ts @@ -0,0 +1,103 @@ +import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable, of } from 'rxjs'; +import { map, filter, switchMap, pluck } from 'rxjs/operators'; + +import { TranslateReplaceService } from 'app/shared/services'; +import { AgentIdDuplicationCheckDataService, IAgentIdAvailable } from './agent-id-duplication-check-data.service'; +import { AgentIdDuplicationCheckInteractionService } from './agent-id-duplication-check-interaction.service'; + +@Component({ + selector: 'pp-agent-id-duplication-check-container', + templateUrl: './duplication-check-container.component.html', + styleUrls: ['./duplication-check-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentIdDuplicationCheckContainerComponent implements OnInit { + labelText = 'Agent ID'; + message: string; + isValueValid: boolean; + placeholder$: Observable; + + private lengthGuide: string; + private MAX_CHAR = 24; + + constructor( + private changeDetectorRef: ChangeDetectorRef, + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + private agentIdDuplicationCheckDataService: AgentIdDuplicationCheckDataService, + private agentIdDuplicationCheckInteractionService: AgentIdDuplicationCheckInteractionService + ) {} + + ngOnInit() { + this.initPlaceholder(); + this.initLengthGuide(); + } + + private initPlaceholder(): void { + this.placeholder$ = this.translateService.get('CONFIGURATION.INSTALLATION.AGENT_ID_PLACEHOLDER'); + } + + private initLengthGuide(): void { + this.translateService.get('CONFIGURATION.INSTALLATION.LENGTH_GUIDE').pipe( + map((lengthGuide: string) => { + return this.translateReplaceService.replace(lengthGuide, this.MAX_CHAR.toString()); + }) + ).subscribe((lengthGuide: string) => { + this.lengthGuide = lengthGuide; + }); + } + + onCheckValue(inputValue: string): void { + of(inputValue).pipe( + filter((value: string) => { + return this.isLengthValid(value.length) ? true : (this.onCheckFail(this.lengthGuide), false); + }), + switchMap((value) => { + return this.fetchResponse(value).pipe( + map((res: IAgentIdAvailable) => { + return { value, res }; + }) + ); + }), + filter(({ res }) => { + return this.isValueAvailable(res.code) ? true : (this.onCheckFail(res.message), false); + }), + pluck('value') + ).subscribe((value: string) => { + this.onCheckSuccess(value, ''); + }, (error: IServerErrorFormat) => { + this.onCheckFail(error.exception.message); + }); + } + + private isLengthValid(length: number): boolean { + return !(length === 0 || length > this.MAX_CHAR); + } + + private fetchResponse(value: string): Observable { + return this.agentIdDuplicationCheckDataService.getResponseWithParams(value); + } + + private isValueAvailable(code: number): boolean { + return code === 0; + } + + private onCheckFail(message: string): void { + this.message = message; + this.isValueValid = false; + this.changeDetectorRef.detectChanges(); + } + + private onCheckSuccess(value: string, message: string): void { + this.message = message; + this.isValueValid = true; + this.notifyCheckSuccess(value); + this.changeDetectorRef.detectChanges(); + } + + private notifyCheckSuccess(value: string): void { + this.agentIdDuplicationCheckInteractionService.notifyCheckSuccess(value); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/agent-id-duplication-check-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/duplication-check/agent-id-duplication-check-data.service.ts new file mode 100644 index 000000000000..b72b326b06c3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/agent-id-duplication-check-data.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +export interface IAgentIdAvailable { + code: number; + message: string; +} + +@Injectable() +export class AgentIdDuplicationCheckDataService { + private requestURL = 'isAvailableAgentId.pinpoint'; + + constructor( + private http: HttpClient, + ) {} + + getResponseWithParams(value: string): Observable { + return this.http.get(this.requestURL, { + params: new HttpParams().set('agentId', value) + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/agent-id-duplication-check-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/duplication-check/agent-id-duplication-check-interaction.service.ts new file mode 100644 index 000000000000..fe12007a09b1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/agent-id-duplication-check-interaction.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; + +@Injectable() +export class AgentIdDuplicationCheckInteractionService { + private outCheckSuccess = new BehaviorSubject(''); + + onCheckSuccess$ = this.outCheckSuccess.asObservable(); + + constructor() {} + + notifyCheckSuccess(value: string): void { + this.outCheckSuccess.next(value); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/application-name-duplication-check-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/duplication-check/application-name-duplication-check-container.component.ts new file mode 100644 index 000000000000..6fe7f1c26550 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/application-name-duplication-check-container.component.ts @@ -0,0 +1,103 @@ +import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable, of } from 'rxjs'; +import { map, filter, switchMap, pluck } from 'rxjs/operators'; + +import { TranslateReplaceService } from 'app/shared/services'; +import { ApplicationNameDuplicationCheckDataService, IApplicationAvailable } from './application-name-duplication-check-data.service'; +import { ApplicationNameDuplicationCheckInteractionService } from './application-name-duplication-check-interaction.service'; + +@Component({ + selector: 'pp-application-name-duplication-check-container', + templateUrl: './duplication-check-container.component.html', + styleUrls: ['./duplication-check-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationNameDuplicationCheckContainerComponent implements OnInit { + labelText = 'Application Name'; + message: string; + isValueValid: boolean; + placeholder$: Observable; + + private lengthGuide: string; + private MAX_CHAR = 24; + + constructor( + private changeDetectorRef: ChangeDetectorRef, + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + private applicationNameDuplicationCheckDataService: ApplicationNameDuplicationCheckDataService, + private applicationNameDuplicationCheckInteractionService: ApplicationNameDuplicationCheckInteractionService + ) {} + + ngOnInit() { + this.initPlaceholder(); + this.initLengthGuide(); + } + + private initPlaceholder(): void { + this.placeholder$ = this.translateService.get('CONFIGURATION.INSTALLATION.APPLICATION_NAME_PLACEHOLDER'); + } + + private initLengthGuide(): void { + this.translateService.get('CONFIGURATION.INSTALLATION.LENGTH_GUIDE').pipe( + map((lengthGuide: string) => { + return this.translateReplaceService.replace(lengthGuide, this.MAX_CHAR.toString()); + }) + ).subscribe((lengthGuide: string) => { + this.lengthGuide = lengthGuide; + }); + } + + onCheckValue(inputValue: string): void { + of(inputValue).pipe( + filter((value: string) => { + return this.isLengthValid(value.length) ? true : (this.onCheckFail(this.lengthGuide), false); + }), + switchMap((value) => { + return this.fetchResponse(value).pipe( + map((res: IApplicationAvailable) => { + return { value, res }; + }) + ); + }), + filter(({ res }) => { + return this.isValueAvailable(res.code) ? true : (this.onCheckFail(res.message), false); + }), + pluck('value') + ).subscribe((value: string) => { + this.onCheckSuccess(value, ''); + }, (error: IServerErrorFormat) => { + this.onCheckFail(error.exception.message); + }); + } + + private isLengthValid(length: number): boolean { + return !(length === 0 || length > this.MAX_CHAR); + } + + private fetchResponse(value: string): Observable { + return this.applicationNameDuplicationCheckDataService.getResponseWithParams(value); + } + + private isValueAvailable(code: number): boolean { + return code === 0; + } + + private onCheckFail(message: string): void { + this.message = message; + this.isValueValid = false; + this.changeDetectorRef.detectChanges(); + } + + private onCheckSuccess(value: string, message: string): void { + this.message = message; + this.isValueValid = true; + this.notifyCheckSuccess(value); + this.changeDetectorRef.detectChanges(); + } + + private notifyCheckSuccess(value: string): void { + this.applicationNameDuplicationCheckInteractionService.notifyCheckSuccess(value); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/application-name-duplication-check-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/duplication-check/application-name-duplication-check-data.service.ts new file mode 100644 index 000000000000..4018f4011971 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/application-name-duplication-check-data.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +export interface IApplicationAvailable { + code: number; + message: string; +} + +@Injectable() +export class ApplicationNameDuplicationCheckDataService { + private requestURL = 'isAvailableApplicationName.pinpoint'; + constructor(private http: HttpClient) {} + getResponseWithParams(value: string): Observable { + return this.http.get(this.requestURL, { + params: new HttpParams().set('applicationName', value) + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/application-name-duplication-check-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/duplication-check/application-name-duplication-check-interaction.service.ts new file mode 100644 index 000000000000..700216514b3b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/application-name-duplication-check-interaction.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; + +@Injectable() +export class ApplicationNameDuplicationCheckInteractionService { + private outCheckSuccess = new BehaviorSubject(''); + + onCheckSuccess$ = this.outCheckSuccess.asObservable(); + + constructor() {} + + notifyCheckSuccess(value: string): void { + this.outCheckSuccess.next(value); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check-container.component.css b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check-container.component.css new file mode 100644 index 000000000000..7f26ddcb5503 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check-container.component.css @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check-container.component.html b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check-container.component.html new file mode 100644 index 000000000000..0d7997f056c7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check-container.component.html @@ -0,0 +1,7 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check.component.css b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check.component.css new file mode 100644 index 000000000000..7e7a808b7d35 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check.component.css @@ -0,0 +1,86 @@ +:host { + display: block; + margin-bottom: 15px; +} +label { + font-size: 14px; + font-weight: 600; + width: 15%; + display: inline-block; + text-align: right; + margin-right: 10px; +} +.l-input-wrapper { + width: 70%; + display: inline-block; + position: relative; +} + +input { + border: 1px solid #ccc; + border-radius: 4px; + padding: 9px 14px; + font-size: 13px; + width: 100%; + display: inline-block; + outline: none; +} + +input:focus { + border-color: #4D90FE; + box-shadow: 0 0 2px #4D90FE; +} + +input.l-success-input { + border: 1px solid #3c763d; +} + +input.l-success-input:focus { + box-shadow: 0 0 2px #3c763d; +} + +input.l-fail-input { + border: 1px solid #a94442; +} + +input.l-fail-input:focus { + box-shadow: 0 0 2px #a94442; +} + +.l-check-status-icon { + position: absolute; + right: 10px; + top: 9px; + font-size: 20px; +} + +.fa-check { + color: #3c763d; +} + +.fa-times { + color: #a94442; +} + +.l-check-button { + border: 1px solid #ccc; + border-radius: 4px; + padding: 9px; + font-size: 13px; + width: 10%; + margin-left: 10px; +} + +.l-check-button:hover { + background-color: #e5e8f0; +} + +.l-check-button:focus { + outline: 0; +} + +.l-message { + text-align: center; + font-size: 14px; + margin-top: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check.component.html b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check.component.html new file mode 100644 index 000000000000..f8bf205ceaeb --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check.component.html @@ -0,0 +1,7 @@ + +
    + + +
    + +

    {{message}}

    diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check.component.ts b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check.component.ts new file mode 100644 index 000000000000..2d48770a137b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/duplication-check.component.ts @@ -0,0 +1,37 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-duplication-check', + templateUrl: './duplication-check.component.html', + styleUrls: ['./duplication-check.component.css'], +}) +export class DuplicationCheckComponent implements OnInit { + @Input() labelText: string; + @Input() placeholder: string; + @Input() message: string; + @Input() isValueValid: boolean; + @Output() outCheckValue = new EventEmitter(); + + id = Math.random().toString(36).substr(2, 5); + + constructor() {} + ngOnInit() {} + + emitValue(value: string): void { + this.outCheckValue.emit(value); + } + + getInputStyleClass(): object { + return { + 'l-success-input': this.isValueValid, + 'l-fail-input': this.isValueValid === false + }; + } + + getSpanStyleClass(): object { + return { + 'fa-check': this.isValueValid, + 'fa-times': this.isValueValid === false + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/duplication-check/index.ts b/web/src/main/webapp/v2/src/app/core/components/duplication-check/index.ts new file mode 100644 index 000000000000..0b72e1219e36 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/duplication-check/index.ts @@ -0,0 +1,32 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { AgentIdDuplicationCheckContainerComponent } from './agent-id-duplication-check-container.component'; +import { ApplicationNameDuplicationCheckContainerComponent } from './application-name-duplication-check-container.component'; +import { DuplicationCheckComponent } from './duplication-check.component'; +import { ApplicationNameDuplicationCheckInteractionService } from './application-name-duplication-check-interaction.service'; +import { AgentIdDuplicationCheckInteractionService } from './agent-id-duplication-check-interaction.service'; +import { ApplicationNameDuplicationCheckDataService } from './application-name-duplication-check-data.service'; +import { AgentIdDuplicationCheckDataService } from './agent-id-duplication-check-data.service'; + +@NgModule({ + declarations: [ + AgentIdDuplicationCheckContainerComponent, + ApplicationNameDuplicationCheckContainerComponent, + DuplicationCheckComponent + ], + imports: [ + SharedModule + ], + exports: [ + AgentIdDuplicationCheckContainerComponent, + ApplicationNameDuplicationCheckContainerComponent + ], + providers: [ + ApplicationNameDuplicationCheckInteractionService, + AgentIdDuplicationCheckInteractionService, + ApplicationNameDuplicationCheckDataService, + AgentIdDuplicationCheckDataService + ] +}) +export class DuplicationCheckModule {} diff --git a/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/empty-inspector-contents-container.component.css b/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/empty-inspector-contents-container.component.css new file mode 100644 index 000000000000..472e282fbe48 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/empty-inspector-contents-container.component.css @@ -0,0 +1,12 @@ +:host { + display: flex; + justify-content: center; + align-items: center; + height: 100%; +} +.guide-text-wrapper { + background-color: #fff; + padding: 50px; + border-radius: 30px; + border: 1px solid #e8e5f0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/empty-inspector-contents-container.component.html b/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/empty-inspector-contents-container.component.html new file mode 100644 index 000000000000..9f7305c734f5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/empty-inspector-contents-container.component.html @@ -0,0 +1,3 @@ +
    +

    {{guideText$ | async}}

    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/empty-inspector-contents-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/empty-inspector-contents-container.component.ts new file mode 100644 index 000000000000..d338c98c1e58 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/empty-inspector-contents-container.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + +import { Observable } from 'rxjs'; + +@Component({ + selector: 'pp-empty-inspector-contents-container', + templateUrl: './empty-inspector-contents-container.component.html', + styleUrls: ['./empty-inspector-contents-container.component.css'] +}) +export class EmptyInspectorContentsContainerComponent implements OnInit { + guideText$: Observable; + + constructor( + private translateService: TranslateService, + ) { } + + ngOnInit() { + this.guideText$ = this.translateService.get('MAIN.SELECT_YOUR_APP'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/index.ts b/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/index.ts new file mode 100644 index 000000000000..23dff1791517 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/empty-inspector-contents/index.ts @@ -0,0 +1,18 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { EmptyInspectorContentsContainerComponent } from './empty-inspector-contents-container.component'; + +@NgModule({ + declarations: [ + EmptyInspectorContentsContainerComponent + ], + imports: [ + SharedModule + ], + exports: [ + EmptyInspectorContentsContainerComponent + ], + providers: [] +}) +export class EmptyInspectorContentsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-information/filter-information-container.component.css b/web/src/main/webapp/v2/src/app/core/components/filter-information/filter-information-container.component.css new file mode 100644 index 000000000000..470dcf63dbff --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-information/filter-information-container.component.css @@ -0,0 +1,42 @@ +.l-filter-info { + padding: 16px 25px; + border-bottom: 1px solid #EAEEF4; + background-color: #F9FAFC; +} +.l-title { + font-size: 16px; + font-weight: 600; + margin-bottom: 23px; +} +.l-info-list { + width: 100%; + display: grid; + font-size: 14px; + grid-template-rows: auto; + grid-template-columns: 35% 65%; +} +.l-info-list div { + padding-top: 2px; + padding-bottom: 2px; +} +.l-info-list div:nth-child(odd) { + font-weight: 600; +} +.l-info-list div:nth-child(even) { + padding-left: 6px; + text-align: center; +} +.l-agent { + display: grid; + grid-template-rows: auto; + grid-template-columns: 45% 10% 45%; +} +.l-agent i { + padding-top: 3px; +} +.l-agent span { + display : block; + overflow : hidden; + white-space : nowrap; + text-overflow : ellipsis; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-information/filter-information-container.component.html b/web/src/main/webapp/v2/src/app/core/components/filter-information/filter-information-container.component.html new file mode 100644 index 000000000000..f459bd17669f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-information/filter-information-container.component.html @@ -0,0 +1,17 @@ +
    +

    Filter Information

    +
    +
    Agent
    +
    +
    + {{getAgentFrom()}} {{getAgentTo()}} +
    +
    +
    Url Pattern
    +
    {{getUrlPattern()}}
    +
    Response Time
    +
    {{getResponseTimeFrom() | number}}ms ~ {{getResponseTimeTo() | number}}ms
    +
    Transaction Result
    +
    {{getTransactionResult()}}
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-information/filter-information-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/filter-information/filter-information-container.component.ts new file mode 100644 index 000000000000..bc15c5d3f638 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-information/filter-information-container.component.ts @@ -0,0 +1,91 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { NewUrlStateNotificationService, StoreHelperService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { Filter } from 'app/core/models'; + +@Component({ + selector: 'pp-filter-information-container', + templateUrl: './filter-information-container.component.html', + styleUrls: ['./filter-information-container.component.css'] +}) +export class FilterInformationContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private serverMapData: any; + private selectedTarget: ISelectedTarget; + filterInfo: Filter[]; + filterIndexOfCurrentLink: number; + constructor( + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.FILTER); + }) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.filterInfo = Filter.instanceFromString(urlService.getPathValue(UrlPathId.FILTER)); + }); + this.connectStore(); + } + private connectStore(): void { + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: any) => { + this.serverMapData = serverMapData; + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.filterIndexOfCurrentLink = -1; + this.selectedTarget = target; + }); + } + showFilterInfo(): boolean { + if (this.selectedTarget) { + if (this.selectedTarget.isLink === true && this.selectedTarget.isMerged === false) { + const link = this.serverMapData.getLinkData(this.selectedTarget.link[0]); + if (this.isFilterLink(link)) { + return true; + } + } + } + return false; + } + isFilterLink(link: any): boolean { + for (let i = 0 ; i < this.filterInfo.length ; i++) { + const f = this.filterInfo[i]; + if ((f.fromApplication + '^' + f.fromServiceType) === link.from && (f.toApplication + '^' + f.toServiceType) === link.to) { + this.filterIndexOfCurrentLink = i; + return true; + } + } + return false; + } + getAgentFrom(): string { + return this.filterInfo[this.filterIndexOfCurrentLink].fromAgentName || 'All'; + } + getAgentTo(): string { + return this.filterInfo[this.filterIndexOfCurrentLink].toAgentName || 'All'; + } + getUrlPattern(): string { + return this.filterInfo[this.filterIndexOfCurrentLink].urlPattern || 'none'; + } + getResponseTimeFrom(): number { + return this.filterInfo[this.filterIndexOfCurrentLink].responseFrom || 0; + } + getResponseTimeTo(): number { + return this.filterInfo[this.filterIndexOfCurrentLink].responseTo || 30000; + } + getTransactionResult(): string { + return this.filterInfo[this.filterIndexOfCurrentLink].getTransactionResultStr(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-information/index.ts b/web/src/main/webapp/v2/src/app/core/components/filter-information/index.ts new file mode 100644 index 000000000000..c5f84d9e4e27 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-information/index.ts @@ -0,0 +1 @@ +export * from './filter-information-container.component'; diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component.css new file mode 100644 index 000000000000..3c6a97654ec4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component.css @@ -0,0 +1,18 @@ +:host { + display: block; + background-color: transparent; + width: 100%; + height: 100%; +} + +:host::before { + content: ''; + display: block; + height: 100%; + width: 100%; + background: #000; + opacity: 0.6; + position: absolute; + left: 0; + top: 0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component.html new file mode 100644 index 000000000000..eaeab1e2474b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component.html @@ -0,0 +1,7 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component.ts new file mode 100644 index 000000000000..926ffae8861b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component.ts @@ -0,0 +1,96 @@ +import { Component, OnInit, Input, Output, EventEmitter, AfterViewInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; + +import { + WindowRefService, + WebAppSettingDataService, + UrlRouteManagerService, + NewUrlStateNotificationService, + DynamicPopup +} from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { Filter } from 'app/core/models'; + +@Component({ + selector: 'pp-filter-transaction-wizard-popup-container', + templateUrl: './filter-transaction-wizard-popup-container.component.html', + styleUrls: ['./filter-transaction-wizard-popup-container.component.css'] +}) +export class FilterTransactionWizardPopupContainerComponent implements OnInit, AfterViewInit, DynamicPopup { + @Input() data: any; + @Output() outCreated = new EventEmitter(); + @Output() outClose = new EventEmitter(); + + filterInfo$: Observable; + funcImagePath: Function; + + constructor( + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private windowRefService: WindowRefService, + ) {} + + ngOnInit() { + this.funcImagePath = this.webAppSettingDataService.getIconPathMakeFunc(); + this.filterInfo$ = this.newUrlStateNotificationService.onUrlStateChange$.pipe( + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.FILTER); + }), + map((urlService) => { + const filterInfo = Filter.instanceFromString(urlService.getPathValue(UrlPathId.FILTER)); + const { from, to } = this.data; + + return filterInfo.find((f: Filter) => { + return (`${f.fromApplication}^${f.fromServiceType}` === from) && (`${f.toApplication}^${f.toServiceType}` === to); + }); + }), + filter((f: Filter) => !!f) + ); + } + + ngAfterViewInit() { + this.outCreated.emit({ coordX: 0, coordY: 0 }); + } + + openFilterMapPage(param: any): void { + const f = new Filter( + param.from.applicationName, + param.from.serviceType, + param.to.applicationName, + param.to.serviceType, + param.transactionResult + ); + f.setResponseFrom(param.responseFrom); + f.setResponseTo(param.responseTo); + if (param.urlPattern) { + f.setUrlPattern(this.windowRefService.nativeWindow.btoa(param.urlPattern)); + } + if (param.from.agent) { + f.setFromAgentName(param.from.agent); + } + if (param.to.agent) { + f.setToAgentName(param.to.agent); + } + const isBothWas = param.from.isWas && param.to.isWas; + this.urlRouteManagerService.openPage( + this.urlRouteManagerService.makeFilterMapUrl({ + applicationName: param.from.applicationName, + serviceType: param.from.serviceType, + periodStr: this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithAddedWords(), + timeStr: this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + filterStr: this.newUrlStateNotificationService.hasValue(UrlPathId.FILTER) ? this.newUrlStateNotificationService.getPathValue(UrlPathId.FILTER) : '', + hintStr: this.newUrlStateNotificationService.hasValue(UrlPathId.HINT) ? this.newUrlStateNotificationService.getPathValue(UrlPathId.HINT) : '', + addedFilter: f, + addedHint: (isBothWas ? { + [param.to.applicationName]: param.filterTargetRpcList + } : null) + }) + ); + } + + onClosePopup(): void { + this.outClose.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup.component.css new file mode 100644 index 000000000000..1121370c7b6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup.component.css @@ -0,0 +1,241 @@ +:host { + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + width: 752px; + max-width: 1000px; + height: 730px; + background-color: #fff; + border: 1px solid #e5e8f0; + box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.75); +} +.l-title-group { + padding: 17px 18px; + height: auto; + background-color: #FFF; + border-bottom: 1px solid #E5E8F0; + position: relative; + font-size: 13px; + font-weight: 600; + color: #333; + display: flex; + align-items: center; + justify-content: space-between; +} +.l-title-group dt { + font-weight: normal; + font-size: 20px; + color: #4A8FD2; +} +.l-popup-close { + font-size: 30px; +} +.l-contents-group { + padding: 17px 18px 0px 18px; +} +.l-table { + width: 100%; + display: grid; + position: relative; + font-size: 13px; + grid-template-columns: 140px 286px 286px; + grid-template-rows: 46px 140px 21px 195px 106px 64px; +} +.l-table > div { + display: flex; + padding: 10px 15px; + border-bottom: 1px solid #E5E8F0; + border-right: 1px solid #E5E8F0; +} +.l-table .first-row { + border-top: 1px solid #E5E8F0; +} +.l-table .first-row img { + margin-right: 8px; +} +.l-table .first-row span { + float: left; + margin-left: -25px; + margin-right: 10px; + font-size: 18px; + color: #4B99E3; +} +.l-table .col1 { + padding: 0; + border-left: 1px solid #E5E8F0; +} +.row-col-1-1 { + grid-column: 1 / 2; + /* autoprefixer: off */ + grid-row: 1 / 2; +} +.row-col-1-2 { + align-items: center; + grid-column: 2 / 3; + grid-row: 1 / 2; +} +.row-col-1-3 { + align-items: center; + grid-column: 3 / 4; + grid-row: 1 / 2; +} +.row-col-2-1 { + grid-column: 1; + grid-row: 2; +} +.row-col-2-2 { + overflow-y: auto; + padding: 0 !important; + grid-column: 2; + grid-row: 2; +} +.row-col-2-3 { + overflow-y: auto; + padding: 0 !important; + grid-column: 3; + grid-row: 2; +} +.row-col-3 { + grid-column: 1 / 4; + grid-row: 3; +} +.row-col-4-1 { + grid-column: 1; + grid-row: 4; +} +.row-col-4-2 { + flex-flow: row wrap; + grid-column: 2 / 4; + grid-row: 4; +} +.row-col-5-1 { + grid-column: 1; + grid-row: 5; +} +.row-col-5-2 { + grid-column: 2 / 4; + grid-row: 5; +} +.row-col-6-1 { + grid-column: 1; + grid-row: 6; +} +.row-col-6-2 { + grid-column: 2 / 4; + grid-row: 6; +} +.col1 { + justify-content: center; + align-items: center; + font-size: 13px; + background-color: #f6f8fb; +} +.ellipsis { + display : block; + overflow : hidden; + white-space : nowrap; + text-overflow : ellipsis; +} +.l-application-list { + width: 100%; + cursor: pointer; + margin: 0; + padding: 0; + list-style: none; +} +.l-application-list li { + padding: 7px 15px; + font-size: 13px; +} +.l-application-list li.active { + color: #fff; + font-weight: 600; + background-color: #4B99E3; +} +.l-application-list li:hover { + color: #000; + background-color: #e4f3eb; +} +.l-widget-group { + padding: 0; + width: 100%; +} +.l-widget-group input { + border: 1px solid #469ae4; + font-size: 13px; + color: #b3b3b4; + padding: 6px 11px; + width: 100%; +} +.l-pattern-guide { + margin-top: 6px; + border: 1px solid #e6e8ec; + background-color: #F6F8FB; +} +.l-pattern-guide tr td:first-child { + padding:4px; + font-size: 11px; + text-align: center; +} +.l-pattern-guide tr td:last-child { + padding:4px; + font-size: 11px; +} +.l-pattern-guide td { + border: none; +} +.l-pattern-guide tr:last-child { + border-top: 1px solid #e6e8ec; +} +.l-response-time { + display: block !important; + padding: 30px 30px 10px 30px !important; + font-size: 11px !important; +} +.l-response-time div.noUi-tooltip { + color: #4B99E3; +} +.l-response-time div.noUi-connect { + background-color: #3dcfa8 !important; +} +.l-range-info { + text-align: center !important; +} +.l-range-info span:first-child { + float: left; +} +.l-range-info .l-range-text { + color: #4B99E3; +} +.l-range-info span:last-child { + float: right; + margin-right: -26px; +} +.l-transaction-result { + width: 100%; +} +.l-transaction-result button { + float: left; + width: 33.3%; + border: 1px solid #E6E8EC; + padding: 12px; + font-size: 13px; + font-weight: 600; +} +.l-transaction-result button.active { + color: #fff; + background: #4a8fd2; + border-color: transparent; +} + +.l-buttons { + text-align: right; + padding-top: 14px; +} +.l-buttons button { + margin-right: 15px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup.component.html new file mode 100644 index 000000000000..35d3fd338f34 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup.component.html @@ -0,0 +1,95 @@ +
    +
    Filter Wizard
    + +
    +
    +
    +
    Path
    +
    + +
    {{link?.sourceInfo.applicationName}}
    +
    +
    + + +
    {{link?.targetInfo.applicationName}}
    +
    +
    Agent
    +
    +
      +
    • ALL
    • +
    • {{agent}}
    • +
    +
    +
    +
      +
    • ALL
    • +
    • {{agent}}
    • +
    +
    +
    +
    URL Pattern
    +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    *Matchers zero or more characters
    ?Matchers exactly one characters
    **Matchers zero or more directories
    Example +
    /pinpoint/**/*.html
    +
    /pinpoint/??.html
    +
    /pinpoint/**/??.html
    +
    +
    +
    +
    Response Time
    +
    + +
    + {{responseTimeMin.toLocaleString()}} ms + Range {{(responseTimeRange[1] - responseTimeRange[0]).toLocaleString()}} ms + {{responseTimeMax.toLocaleString()}}+ ms +
    +
    +
    Transaction Result
    +
    +
    + +
    +
    +
    +
    +
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup.component.ts new file mode 100644 index 000000000000..3bcde01806d8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup.component.ts @@ -0,0 +1,120 @@ +import { Component, OnInit, Input, Output, EventEmitter, HostBinding } from '@angular/core'; +import { NouiFormatter } from 'ng2-nouislider'; + +import { Filter } from 'app/core/models/'; + +export class TimeFormatter implements NouiFormatter { + to(value: number): string { + return value.toLocaleString() + (value === 30000 ? '+' : '') + ' ms'; + } + + from(value: string): number { + return parseInt(value.replace(/(.) ms/, '$1').replace(/,/, ''), 10); + } +} +enum RESULT_TYPE { + SUCCESS_AND_FAIL, + SUCCESS_ONLY, + FAIL_ONLY +} +const AGENT_ALL = 'All'; + +@Component({ + selector: 'pp-filter-transaction-wizard-popup', + templateUrl: './filter-transaction-wizard-popup.component.html', + styleUrls: ['./filter-transaction-wizard-popup.component.css'] +}) +export class FilterTransactionWizardPopupComponent implements OnInit { + @Input() filterInfo: Filter; + @Input() link: ILinkInfo; + @Input() funcImagePath: Function; + @Output() outRequestFilterOpen = new EventEmitter(); + @Output() outClosePopup = new EventEmitter(); + @HostBinding('class.font-opensans') fontFamily = true; + + resultType: string[] = ['Success + Failed', 'Success Only', 'Failed Only']; + selectedResultType: RESULT_TYPE = RESULT_TYPE.SUCCESS_AND_FAIL; + selectedFromAgent = AGENT_ALL; + selectedToAgent = AGENT_ALL; + urlPattern = ''; + responseTimeMin = 0; + responseTimeMax = 30000; + responseTimeRange = [0, 30000]; + + constructor() {} + ngOnInit() { + this.resetValue(); + } + resetValue() { + if (this.filterInfo) { + this.selectedFromAgent = this.filterInfo.fromAgentName || AGENT_ALL; + this.selectedToAgent = this.filterInfo.toAgentName || AGENT_ALL; + this.responseTimeRange = [this.filterInfo.responseFrom, this.filterInfo.responseTo]; + this.urlPattern = this.filterInfo.urlPattern || ''; + if (this.filterInfo.transactionResult === true) { + this.selectedResultType = RESULT_TYPE.SUCCESS_ONLY; + } else if (this.filterInfo.transactionResult === false) { + this.selectedResultType = RESULT_TYPE.FAIL_ONLY; + } else { + this.selectedResultType = RESULT_TYPE.SUCCESS_AND_FAIL; + } + } + } + onClickFilter(): void { + this.outRequestFilterOpen.emit({ + filterApplicationName: this.link.filterApplicationName, + filterApplicationServiceTypeName: this.link.filterApplicationServiceTypeName, + from: { + applicationName: this.link.sourceInfo.applicationName, + serviceType: this.link.sourceInfo.serviceType, + agent: this.selectedFromAgent === AGENT_ALL ? null : this.selectedFromAgent, + isWas: this.link.sourceInfo.isWas + }, + to: { + applicationName: this.link.targetInfo.applicationName, + serviceType: this.link.targetInfo.serviceType, + agent: this.selectedToAgent === AGENT_ALL ? null : this.selectedToAgent, + isWas: this.link.targetInfo.isWas + }, + urlPattern: this.urlPattern, + responseFrom: this.responseTimeRange[0], + responseTo: this.responseTimeRange[1], + transactionResult: this.selectedResultType === 0 ? null : this.selectedResultType === 1 ? true : false, + filterTargetRpcList : this.link.sourceInfo.isWas && this.link.targetInfo.isWas ? this.link.filterTargetRpcList : [] + }); + this.onClickClose(); + } + onClickClose(): void { + // this.selectedResultType = RESULT_TYPE.SUCCESS_AND_FAIL; + // this.selectedFromAgent = AGENT_ALL; + // this.selectedToAgent = AGENT_ALL; + // this.responseTimeRange = [this.responseTimeMin, this.responseTimeMax]; + // this.urlPattern = ''; + + this.outClosePopup.emit(); + } + onSelectResultType(type: number): void { + this.selectedResultType = type; + } + onSelectFromAgent(agent: string): void { + this.selectedFromAgent = agent; + } + onSelectToAgent(agent: string): void { + this.selectedToAgent = agent; + } + getIconFullPath(applicationName: string): string { + return this.funcImagePath(applicationName); + } + isSelectedResultType(type: number): boolean { + return this.selectedResultType === type; + } + isSelectedFromAgent(agent: string): boolean { + return this.selectedFromAgent === agent; + } + isSelectedToAgent(agent: string): boolean { + return this.selectedToAgent === agent; + } + getTimeFormatter(): NouiFormatter { + return new TimeFormatter(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/index.ts b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/index.ts new file mode 100644 index 000000000000..5c87f10ca34a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filter-transaction-wizard-popup/index.ts @@ -0,0 +1,24 @@ + +import { NgModule } from '@angular/core'; +import { NouisliderModule } from 'ng2-nouislider'; + +import { SharedModule } from 'app/shared'; +import { FilterTransactionWizardPopupComponent } from './filter-transaction-wizard-popup.component'; +import { FilterTransactionWizardPopupContainerComponent } from './filter-transaction-wizard-popup-container.component'; + +@NgModule({ + declarations: [ + FilterTransactionWizardPopupComponent, + FilterTransactionWizardPopupContainerComponent + ], + imports: [ + NouisliderModule, + SharedModule + ], + exports: [], + entryComponents: [ + FilterTransactionWizardPopupContainerComponent + ], + providers: [] +}) +export class FilterTransactionWizardPopupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/filtered-map-contents-container.component.css b/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/filtered-map-contents-container.component.css new file mode 100644 index 000000000000..f47e448eed3b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/filtered-map-contents-container.component.css @@ -0,0 +1,17 @@ +.l-main-contents-top { + display: flex; + flex-flow: row wrap; + margin: 11px 0 0 25px; + align-items: center; + top: 0; + right: 0; + z-index: 8; + padding:0 10px; + font-size:13px; + justify-content: flex-end; + position:absolute; +} +.fas { + color:#a8acb5; + font-size:18px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/filtered-map-contents-container.component.html b/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/filtered-map-contents-container.component.html new file mode 100644 index 000000000000..4824dcf6a569 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/filtered-map-contents-container.component.html @@ -0,0 +1,6 @@ +
    + + + +
    + diff --git a/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/filtered-map-contents-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/filtered-map-contents-container.component.ts new file mode 100644 index 000000000000..75a1b8d7061e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/filtered-map-contents-container.component.ts @@ -0,0 +1,30 @@ +import { Component, OnInit } from '@angular/core'; + +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; + +@Component({ + selector: 'pp-filtered-map-contents-container', + templateUrl: './filtered-map-contents-container.component.html', + styleUrls: ['./filtered-map-contents-container.component.css'] +}) +export class FilteredMapContentsContainerComponent implements OnInit { + constructor( + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() {} + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.SERVER_MAP); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.SERVER_MAP, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/index.ts b/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/index.ts new file mode 100644 index 000000000000..48de3ba8a360 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/filtered-map-contents/index.ts @@ -0,0 +1,27 @@ + +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { FixedPeriodMoverModule } from 'app/core/components/fixed-period-mover'; +import { ServerMapSearchResultViewerModule } from 'app/core/components/server-map-search-result-viewer'; +import { ServerMapModule } from 'app/core/components/server-map'; +import { FilteredMapContentsContainerComponent } from './filtered-map-contents-container.component'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + FilteredMapContentsContainerComponent + ], + imports: [ + SharedModule, + FixedPeriodMoverModule, + ServerMapSearchResultViewerModule, + ServerMapModule, + HelpViewerPopupModule + ], + exports: [ + FilteredMapContentsContainerComponent + ], + providers: [] +}) +export class FilteredMapContentsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover-container.component.css b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover-container.component.html b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover-container.component.html new file mode 100644 index 000000000000..bf42be50dcab --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover-container.component.html @@ -0,0 +1,8 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover-container.component.ts new file mode 100644 index 000000000000..53066e20914f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover-container.component.ts @@ -0,0 +1,69 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { + StoreHelperService, + NewUrlStateNotificationService, + UrlRouteManagerService, + AnalyticsService, + TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { Period, EndTime } from 'app/core/models'; + +@Component({ + selector: 'pp-fixed-period-mover-container', + templateUrl: './fixed-period-mover-container.component.html', + styleUrls: ['./fixed-period-mover-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FixedPeriodMoverContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + hiddenComponent = true; + period: Period; + endTime: EndTime; + timezone$: Observable; + dateFormat$: Observable; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private analyticsService: AnalyticsService, + private storeHelperService: StoreHelperService + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.PERIOD, UrlPathId.END_TIME)) { + this.period = urlService.getPathValue(UrlPathId.PERIOD); + this.endTime = urlService.getPathValue(UrlPathId.END_TIME); + this.hiddenComponent = false; + } else { + this.hiddenComponent = true; + } + this.changeDetectorRef.markForCheck(); + }); + this.connectStore(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(); + this.dateFormat$ = this.storeHelperService.getDateFormat(this.unsubscribe, 1); + } + onMovePeriod(moveTime: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_FIXED_PERIOD_MOVE_BUTTON); + this.urlRouteManagerService.moveOnPage({ + url: [ + this.newUrlStateNotificationService.getStartPath(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.period.getValueWithTime(), + moveTime + ] + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover.component.css b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover.component.css new file mode 100644 index 000000000000..efb6182ac04d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover.component.css @@ -0,0 +1,17 @@ +.l-time-select { + color:#8a939e; + background-color:rgba(255, 255, 255, 0.6); + padding:7px; + margin-right: 15px; +} +.l-time-select span { + font-size:13px; + font-weight:600; + margin-right: 10px; +} +.l-time-select .fab { + font-size:15px; +} +.l-time-select button:first-child { + margin-right: 4px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover.component.html b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover.component.html new file mode 100644 index 000000000000..a938aed7d3b2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover.component.html @@ -0,0 +1,5 @@ +
    + {{getStartTime()}} ~ {{getEndTime()}} + + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover.component.ts b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover.component.ts new file mode 100644 index 000000000000..c47d14187e79 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/fixed-period-mover.component.ts @@ -0,0 +1,42 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import * as moment from 'moment-timezone'; +import { Period } from 'app/core/models/period'; +import { EndTime } from 'app/core/models/end-time'; + +@Component({ + selector: 'pp-fixed-period-mover', + templateUrl: './fixed-period-mover.component.html', + styleUrls: ['./fixed-period-mover.component.css'] +}) +export class FixedPeriodMoverComponent implements OnInit { + + @Input() hiddenComponent: boolean; + @Input() period: Period; + @Input() endTime: EndTime; + @Input() timezone: string; + @Input() dateFormat: string; + @Output() outMove: EventEmitter = new EventEmitter(); + constructor() { } + + ngOnInit() { } + getStartTime(): string { + if (this.endTime) { + return moment(this.endTime.calcuStartTime(this.period.getValue()).getMilliSecond()).tz(this.timezone).format(this.dateFormat); + } else { + return ''; + } + } + getEndTime(): string { + if (this.endTime) { + return moment(this.endTime.getMilliSecond()).tz(this.timezone).format(this.dateFormat); + } else { + return ''; + } + } + onMovePrev(): void { + this.outMove.emit(this.endTime.calcuStartTime(this.period.getValue()).getEndTime()); + } + onMoveNext(): void { + this.outMove.emit(this.endTime.calcuNextTime(this.period.getValue()).getEndTime()); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/index.ts b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/index.ts new file mode 100644 index 000000000000..4a0e7f45d5f5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/fixed-period-mover/index.ts @@ -0,0 +1,20 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { FixedPeriodMoverComponent } from './fixed-period-mover.component'; +import { FixedPeriodMoverContainerComponent } from './fixed-period-mover-container.component'; + +@NgModule({ + declarations: [ + FixedPeriodMoverComponent, + FixedPeriodMoverContainerComponent + ], + imports: [ + SharedModule + ], + exports: [ + FixedPeriodMoverContainerComponent + ], + providers: [] +}) +export class FixedPeriodMoverModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-container.component.css b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-container.component.css new file mode 100644 index 000000000000..be0f52ba2341 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-container.component.css @@ -0,0 +1,52 @@ +:host { + position: relative; +} +.l-group-member-wrapper { + color: #333; + border: 1px solid #e5e8f0; + height: 100%; + display: grid; + position: relative; + font-size: 13px; + font-family: 'Open Sans', sans-serif; + font-weight: 600; + grid-template-columns: auto; + grid-template-rows: 48px 469px; +} +.l-group-member-title { + display: flex; + padding: 0px 15px; + align-items: center; + justify-content: space-between; + background-color: #f6f8fb; + border-bottom: 1px solid #e5e8f0; +} +.l-group-member-title button:last-child { + margin-left: 12px; +} +.l-group-member-sort-exchange { + color: #b3b6bf; + transform: rotate(90deg); +} +.l-group-member-list { + overflow-y: auto; +} +.l-message { + width: 100%; + height: 100%; + z-index: 15; + display: flex; + position: absolute; + align-items: center; + justify-content: center; + background-color: rgba(226, 226, 226, 0.8); +} +.l-message span { + color: #ff8c00; + text-align: center; +} +.l-message button { + top: 0px; + right: 0px; + position: absolute; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-container.component.html b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-container.component.html new file mode 100644 index 000000000000..b2fc7a3d050d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-container.component.html @@ -0,0 +1,21 @@ +
    +
    + Group Member ({{groupMemberList.length}}) +
    + + +
    +
    +
    + +
    +
    + + {{message}} +
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-container.component.ts new file mode 100644 index 000000000000..05703ae3146c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-container.component.ts @@ -0,0 +1,162 @@ +import { Component, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { UserGroupInteractionService } from 'app/core/components/user-group/user-group-interaction.service'; +import { PinpointUserInteractionService } from 'app/core/components/pinpoint-user/pinpoint-user-interaction.service'; +import { GroupMemberInteractionService } from './group-member-interaction.service'; +import { GroupMemberDataService, IGroupMember, IGroupMemberResponse } from './group-member-data.service'; + +@Component({ + selector: 'pp-group-member-container', + templateUrl: './group-member-container.component.html', + styleUrls: ['./group-member-container.component.css'] +}) +export class GroupMemberContainerComponent implements OnInit { + private unsubscribe: Subject = new Subject(); + private ascendSort = true; + currentUserGroupId: string; + groupMemberList: IGroupMember[] = []; + useDisable = false; + showLoading = false; + message = ''; + constructor( + private groupMemberDataService: GroupMemberDataService, + private groupMemberInteractionService: GroupMemberInteractionService, + private userGroupInteractionService: UserGroupInteractionService, + private pinpointUserInteracionService: PinpointUserInteractionService + ) {} + ngOnInit() { + this.userGroupInteractionService.onSelect$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((id: string) => { + this.currentUserGroupId = id; + if (this.isValidUserGroupId()) { + this.getGroupMemberList(); + } else { + this.groupMemberList = []; + this.groupMemberInteractionService.setChangeGroupMember([]); + } + }); + this.pinpointUserInteracionService.onAdd$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((userId: string) => { + this.addGroupMember(userId); + }); + this.pinpointUserInteracionService.onUpdate$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((memberInfo: any) => { + let memberIndex = -1; + let editMemberInfo; + for (let i = 0 ; i < this.groupMemberList.length ; i++) { + if (this.groupMemberList[i].memberId === memberInfo.userId) { + memberIndex = i; + editMemberInfo = { + name: memberInfo.name, + department: memberInfo.department, + number: this.groupMemberList[i].number, + memberId: this.groupMemberList[i].memberId, + userGroupId: this.groupMemberList[i].userGroupId + }; + break; + } + } + this.groupMemberList.splice(memberIndex, 1, editMemberInfo); + }); + } + private isValidUserGroupId(): boolean { + return this.currentUserGroupId !== ''; + } + private getGroupMemberList(): void { + this.showProcessing(); + this.groupMemberDataService.retrieve(this.currentUserGroupId).subscribe((groupMemberData: IGroupMember[] | IServerErrorShortFormat) => { + if ((groupMemberData as IServerErrorShortFormat).errorCode) { + this.groupMemberInteractionService.setChangeGroupMember(this.getMemberIdList()); + this.message = (groupMemberData as IServerErrorShortFormat).errorMessage; + } else { + this.groupMemberList = groupMemberData as IGroupMember[]; + this.sortGroupMemberList(); + this.groupMemberInteractionService.setChangeGroupMember(this.getMemberIdList()); + } + this.hideProcessing(); + }, (error: IServerErrorFormat) => { + this.groupMemberInteractionService.setChangeGroupMember(this.getMemberIdList()); + this.hideProcessing(); + this.message = error.exception.message; + }); + } + private addGroupMember(userId: string): void { + this.groupMemberDataService.create(userId, this.currentUserGroupId).subscribe((response: IGroupMemberResponse | IServerErrorShortFormat) => { + if ((response as IServerErrorShortFormat).errorCode) { + this.message = (response as IServerErrorShortFormat).errorMessage; + this.hideProcessing(); + } else { + this.doAfterAddAndRemoveAction(response as IGroupMemberResponse); + } + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + }); + } + private getMemberIdList(): string[] { + return this.groupMemberList.map((groupMember: IGroupMember): string => { + return groupMember.memberId; + }); + } + private doAfterAddAndRemoveAction(response: IGroupMemberResponse): void { + if (response.result === 'SUCCESS') { + this.getGroupMemberList(); + } else { + this.hideProcessing(); + } + } + private sortAscend(): void { + this.groupMemberList.sort((a: IGroupMember, b: IGroupMember): number => { + return a.name > b.name ? 1 : -1; + }); + } + private sortDescend(): void { + this.groupMemberList.sort((a: IGroupMember, b: IGroupMember): number => { + return a.name < b.name ? 1 : -1; + }); + } + private sortGroupMemberList() { + if (this.ascendSort === true) { + this.sortAscend(); + } else { + this.sortDescend(); + } + } + onRemoveGroupMember(id: string): void { + this.showProcessing(); + this.groupMemberDataService.remove(id, this.currentUserGroupId).subscribe((response: IGroupMemberResponse) => { + this.doAfterAddAndRemoveAction(response); + }, (error: string) => { + this.hideProcessing(); + this.message = error; + }); + } + onCloseMessage(): void { + this.message = ''; + this.groupMemberInteractionService.setChangeGroupMember(this.getMemberIdList()); + } + onSort(): void { + if (this.isValidUserGroupId()) { + this.ascendSort = !this.ascendSort; + this.sortGroupMemberList(); + } + } + onReload(): void { + this.getGroupMemberList(); + } + hasMessage(): boolean { + return this.message !== ''; + } + private showProcessing(): void { + this.useDisable = true; + this.showLoading = true; + } + private hideProcessing(): void { + this.useDisable = false; + this.showLoading = false; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-data.service.ts new file mode 100644 index 000000000000..9c9ee7b361dd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-data.service.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + +export interface IGroupMember { + department: string; + memberId: string; + name: string; + number: string; + userGroupId: string; +} +export interface IGroupMemberResponse { + result: string; +} + +@Injectable() +export class GroupMemberDataService { + private url = 'userGroup/member.pinpoint'; + constructor(private http: HttpClient) { } + retrieve(userGroupId: string): Observable { + return this.http.get(this.url, { params: new HttpParams().set('userGroupId', userGroupId) }).pipe( + retry(3) + ); + } + create(memberId: string, userGroupId: string): Observable { + return this.http.post(this.url, { + memberId, + userGroupId + }).pipe( + retry(3) + ); + } + remove(memberId: string, userGroupId: string): Observable { + return this.http.request('delete', this.url, { + body: { + memberId, + userGroupId + } + }).pipe( + retry(3) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-interaction.service.ts new file mode 100644 index 000000000000..422f43e6ddc6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member-interaction.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; + +@Injectable() +export class GroupMemberInteractionService { + private outChangeGroupMember = new Subject(); + onChangeGroupMember$: Observable; + + constructor() { + this.onChangeGroupMember$ = this.outChangeGroupMember.asObservable(); + } + setChangeGroupMember(groupMemberList: string[]): void { + this.outChangeGroupMember.next(groupMemberList); + } +} + diff --git a/web/src/main/webapp/v2/src/app/core/components/group-member/group-member.component.css b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member.component.css new file mode 100644 index 000000000000..ebe69e85053f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member.component.css @@ -0,0 +1,31 @@ +li { + color: #333; + height: 28px; + margin: 0; + cursor: pointer; + padding: 6px 15px 0px 15px; + font-size: 13px; +} +li:hover { + background:#fff0f0; +} +li.selected { + background:#fff0f0; +} +.item-wrapper { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.item-wrapper > div { + float: right; +} +.item-wrapper .fa-trash-alt { + color: #b3b6bf; + font-size: 14px; +} +.item-wrapper .fa-check { + color: #F00; + margin-left: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/group-member/group-member.component.html b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member.component.html new file mode 100644 index 000000000000..17b96394fcf7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member.component.html @@ -0,0 +1,12 @@ +
      +
    • +
      +
      + + + +
      + ({{group.department}}) {{group.name}} +
      +
    • +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/group-member/group-member.component.ts b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member.component.ts new file mode 100644 index 000000000000..a177acb2826a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/group-member/group-member.component.ts @@ -0,0 +1,28 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { IGroupMember } from './group-member-data.service'; + +@Component({ + selector: 'pp-group-member', + templateUrl: './group-member.component.html', + styleUrls: ['./group-member.component.css'] +}) +export class GroupMemberComponent implements OnInit { + @Input() groupMemberList: IGroupMember[]; + @Output() outRemove: EventEmitter = new EventEmitter(); + private removeConformId = ''; + constructor() {} + ngOnInit() {} + onRemove(id: string): void { + this.removeConformId = id; + } + onCancelRemove(): void { + this.removeConformId = ''; + } + onConfirmRemove(): void { + this.outRemove.emit(this.removeConformId); + this.removeConformId = ''; + } + isRemoveTarget(id: string): boolean { + return this.removeConformId === id; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/group-member/index.ts b/web/src/main/webapp/v2/src/app/core/components/group-member/index.ts new file mode 100644 index 000000000000..d73d292844e5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/group-member/index.ts @@ -0,0 +1,29 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { GroupMemberComponent } from './group-member.component'; +import { GroupMemberContainerComponent } from './group-member-container.component'; +import { GroupMemberInteractionService } from './group-member-interaction.service'; +import { GroupMemberDataService } from './group-member-data.service'; + +@NgModule({ + declarations: [ + GroupMemberComponent, + GroupMemberContainerComponent + ], + imports: [ + SharedModule + ], + exports: [ + GroupMemberContainerComponent + ], + entryComponents: [ + GroupMemberComponent, + GroupMemberContainerComponent + ], + providers: [ + GroupMemberInteractionService, + GroupMemberDataService + ] +}) +export class GroupMemberModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup-container.component.css new file mode 100644 index 000000000000..c8c6286b3461 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup-container.component.css @@ -0,0 +1,86 @@ +:host { + display: block; + border: 1px solid transparent; +} + +:host(.navbar), +:host(.server_map) { + width: 500px; +} + +:host(.response_summary), +:host(.load), +:host(.agent_response_time), +:host(.application_response_time) { + width: 340px; +} + +:host(.call_tree) { + width: 540px; +} + +:host(.scatter) { + width: 580px; +} + +:host(.real_time) { + width: 650px; +} + +:host(.agent_list), +:host(.agent_data_source), +:host(.application_data_source) { + width: 300px; +} + +:host(.agent_heap), +:host(.application_heap), +:host(.agent_non_heap), +:host(.application_non_heap) { + width: 530px; +} + +:host(.agent_active_thread), +:host(.application_active_thread), +:host(.agent_tps), +:host(.application_tps), +:host(.agent_open_file_descriptor), +:host(.application_open_file_descriptor), +:host(.application_direct_buffer_count), +:host(.application_direct_buffer_memory), +:host(.application_mapped_buffer_count) { + width: 405px; +} + +:host(.application_mapped_buffer_memory) { + width: 420px; +} + +:host(.agent_cpu_usage) { + width: 470px; +} + +:host(.application_jvm_cpu_usage), +:host(.application_system_cpu_usage) { + width: 520px; +} + +:host(.agent_direct_buffer_count), +:host(.agent_mapped_buffer_count) { + width: 270px; +} + +:host(.agent_direct_buffer_memory) { + width: 310px; +} + +:host(.agent_mapped_buffer_memory) { + width: 320px; +} + +.tooltip-triangle { + width: 0; + height: 0; + display: inline-block; + position: fixed; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup-container.component.html new file mode 100644 index 000000000000..3cc858bfd818 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup-container.component.html @@ -0,0 +1,8 @@ + + + +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup-container.component.ts new file mode 100644 index 000000000000..78363a94e95a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup-container.component.ts @@ -0,0 +1,212 @@ +import { Component, OnInit, ElementRef, Input, Output, EventEmitter, AfterViewInit, HostBinding } from '@angular/core'; +import { Observable } from 'rxjs'; +import { TranslateService } from '@ngx-translate/core'; + +import { WindowRefService, DynamicPopup } from 'app/shared/services'; + +export enum HELP_VIEWER_LIST { + NAVBAR = 'HELP_VIEWER.NAVBAR', + RESPONSE_SUMMARY = 'HELP_VIEWER.RESPONSE_SUMMARY', + LOAD = 'HELP_VIEWER.LOAD', + SERVER_MAP = 'HELP_VIEWER.SERVER_MAP', + REAL_TIME = 'HELP_VIEWER.REAL_TIME', + CALL_TREE = 'HELP_VIEWER.CALL_TREE', + SCATTER = 'HELP_VIEWER.SCATTER', + AGENT_LIST = 'HELP_VIEWER.INSPECTOR.AGENT_LIST', + AGENT_HEAP = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.HEAP', + AGENT_NON_HEAP = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.NON_HEAP', + AGENT_CPU_USAGE = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.CPU_USAGE', + AGENT_TPS = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.TPS', + AGENT_ACTIVE_THREAD = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.ACTIVE_THREAD', + AGENT_RESPONSE_TIME = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.RESPONSE_TIME', + AGENT_DATA_SOURCE = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.DATA_SOURCE', + AGENT_OPEN_FILE_DESCRIPTOR = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.OPEN_FILE_DESCRIPTOR', + AGENT_DIRECT_BUFFER_COUNT = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.DIRECT_BUFFER_COUNT', + AGENT_DIRECT_BUFFER_MEMORY = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.DIRECT_BUFFER_MEMORY', + AGENT_MAPPED_BUFFER_COUNT = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.MAPPED_BUFFER_COUNT', + AGENT_MAPPED_BUFFER_MEMORY = 'HELP_VIEWER.INSPECTOR.AGENT_CHART.MAPPED_BUFFER_MEMORY', + APPLICATION_HEAP = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.HEAP', + APPLICATION_NON_HEAP = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.NON_HEAP', + APPLICATION_JVM_CPU_USAGE = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.JVM_CPU_USAGE', + APPLICATION_SYSTEM_CPU_USAGE = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.SYSTEM_CPU_USAGE', + APPLICATION_TPS = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.TPS', + APPLICATION_ACTIVE_THREAD = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.ACTIVE_THREAD', + APPLICATION_RESPONSE_TIME = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.RESPONSE_TIME', + APPLICATION_DATA_SOURCE = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.DATA_SOURCE', + APPLICATION_OPEN_FILE_DESCRIPTOR = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.OPEN_FILE_DESCRIPTOR', + APPLICATION_DIRECT_BUFFER_COUNT = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.DIRECT_BUFFER_COUNT', + APPLICATION_DIRECT_BUFFER_MEMORY = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.DIRECT_BUFFER_MEMORY', + APPLICATION_MAPPED_BUFFER_COUNT = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.MAPPED_BUFFER_COUNT', + APPLICATION_MAPPED_BUFFER_MEMORY = 'HELP_VIEWER.INSPECTOR.APPLICATION_CHART.MAPPED_BUFFER_MEMORY', +} + +const enum HELP_VIEWER_WIDTH_STATE { + OK, + LEFT_OVERFLOW, + RIGHT_OVERFLOW +} + +const enum HELP_VIEWER_HEIGHT_STATE { + OK, + DOWN_OVERFLOW +} + +const enum TOOLTIP_CONSTANT { + START_POINT = 28, // 툴팁 시작을 모서리에서 살짝 밀어주는 길이 + DISTANCE_FROM_BUTTON = 9, // 클릭한 버튼에서 살짝 떨어뜨려줄 길이 + HEIGHT = 7, // 툴팁 삼각형 높이 + WIDTH = 14 // 툴팁 삼각형 넓이 +} + +@Component({ + selector: 'pp-help-viewer-popup-container', + templateUrl: './help-viewer-popup-container.component.html', + styleUrls: ['./help-viewer-popup-container.component.css'], +}) +export class HelpViewerPopupContainerComponent implements OnInit, AfterViewInit, DynamicPopup { + @Input() data: HELP_VIEWER_LIST; + @Input() coord: ICoordinate; + @Output() outCreated = new EventEmitter(); + @Output() outClose = new EventEmitter(); + @Output() outReInit = new EventEmitter<{[key: string]: any}>(); + @HostBinding('class') styleClass: string; + + data$: Observable<{[key: string]: any}[]>; + tooltipTriangleStyle: {[key: string]: any} = { + 'border-bottom': `${TOOLTIP_CONSTANT.HEIGHT}px solid #fff`, + 'border-right': `${TOOLTIP_CONSTANT.HEIGHT}px solid transparent`, + 'border-left': `${TOOLTIP_CONSTANT.HEIGHT}px solid transparent`, + 'transform-origin': `50% -${TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON}px`, + }; + + constructor( + private elementRef: ElementRef, + private translateService: TranslateService, + private windowRefService: WindowRefService, + ) {} + + ngOnInit() { + this.setStyleClass(this.data); + this.data$ = this.getHelpViewerText(this.data); + } + + ngAfterViewInit() { + this.outCreated.emit(this.getPosition(this.coord)); + } + + onInputChange({data, coord}: {data: HELP_VIEWER_LIST, coord: ICoordinate}): void { + if (this.coord) { + const { coordX: x1, coordY: y1 } = this.coord; + const { coordX: x2, coordY: y2 } = coord; + + x1 === x2 && y1 === y2 ? this.outClose.emit() : this.outReInit.emit({ data, coord }); + } + } + + private setStyleClass(data: HELP_VIEWER_LIST): void { + const className = Object.keys(HELP_VIEWER_LIST).find((cur: keyof typeof HELP_VIEWER_LIST) => { + return HELP_VIEWER_LIST[cur] === data; + }).toLowerCase(); + + this.styleClass = `popup ${className}`; + } + + private setPosition(coordY: number, coordX: number): ICoordinate { + return { coordX, coordY }; + } + + private getPosition({coordX, coordY}: ICoordinate): ICoordinate { + /** + * HelpViewer위치 띄워주는 기준 + * Width기준: event.clientX - TOOLTIP_CONSTANT.INDENT_WIDTH(왼쪽으로 살짝 밀어줄 너비) + width 의 overflow여부 + * Height기준: event.clientY + TOOLTIP_CONSTANT.TRIANGLE_HEIGHT(말풍선 삼각형 높이) + height 의 overflow여부 + * 1. Width: OK, Height: OK => 클릭한 버튼 기준 밑에 위치 + * 2. Width: OK, Height: Overflow => 클릭한 버튼 기준 위에 위치 + * 3. Width: Left Overflow, Height: OK => 클릭한 버튼 기준 오른쪽, 밑방향으로 위치 + * 4. Width: Right Overflow, Height: OK => 클릭한 버튼 기준 왼쪽, 밑방향으로 위치 + * 5. Width: Left Overflow, Height: Overflow => 클릭한 기준 오른쪽, 윗방향으로 위치 + * 6. Width: Right Overflow, Height: Overflow => 클릭한 기준 왼쪽, 윗방향으로 위치 + */ + const width = this.elementRef.nativeElement.offsetWidth; + const height = this.elementRef.nativeElement.offsetHeight; + const widthState = this.checkWidth(width); + const heightState = this.checkHeight(height); + let pos: ICoordinate; + + switch (widthState) { + case HELP_VIEWER_WIDTH_STATE.OK: + switch (heightState) { + case HELP_VIEWER_HEIGHT_STATE.OK: + this.setTooltipTriangleStyle(coordY + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON, coordX - TOOLTIP_CONSTANT.WIDTH / 2, ''); + pos = this.setPosition(coordY + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON + TOOLTIP_CONSTANT.HEIGHT, coordX - TOOLTIP_CONSTANT.START_POINT); + break; + case HELP_VIEWER_HEIGHT_STATE.DOWN_OVERFLOW: + this.setTooltipTriangleStyle(coordY + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON, coordX - TOOLTIP_CONSTANT.WIDTH / 2, 'rotate(-180deg)'); + pos = this.setPosition(coordY - height - TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON - TOOLTIP_CONSTANT.HEIGHT, coordX - TOOLTIP_CONSTANT.START_POINT); + break; + } + break; + case HELP_VIEWER_WIDTH_STATE.LEFT_OVERFLOW: + switch (heightState) { + case HELP_VIEWER_HEIGHT_STATE.OK: + this.setTooltipTriangleStyle(coordY + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON, coordX - TOOLTIP_CONSTANT.WIDTH / 2, 'rotate(-90deg)'); + pos = this.setPosition(coordY - TOOLTIP_CONSTANT.START_POINT, coordX + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON + TOOLTIP_CONSTANT.HEIGHT); + break; + case HELP_VIEWER_HEIGHT_STATE.DOWN_OVERFLOW: + this.setTooltipTriangleStyle(coordY + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON, coordX - TOOLTIP_CONSTANT.WIDTH / 2, 'rotate(-90deg)'); + pos = this.setPosition(coordY - height + TOOLTIP_CONSTANT.START_POINT, coordX + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON + TOOLTIP_CONSTANT.HEIGHT); + break; + } + break; + case HELP_VIEWER_WIDTH_STATE.RIGHT_OVERFLOW: + switch (heightState) { + case HELP_VIEWER_HEIGHT_STATE.OK: + this.setTooltipTriangleStyle(coordY + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON, coordX - TOOLTIP_CONSTANT.WIDTH / 2, 'rotate(90deg)'); + pos = this.setPosition(coordY - TOOLTIP_CONSTANT.START_POINT, coordX - width - TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON - TOOLTIP_CONSTANT.HEIGHT); + break; + case HELP_VIEWER_HEIGHT_STATE.DOWN_OVERFLOW: + this.setTooltipTriangleStyle(coordY + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON, coordX - TOOLTIP_CONSTANT.WIDTH / 2, 'rotate(90deg)'); + pos = this.setPosition(coordY - height + TOOLTIP_CONSTANT.START_POINT, coordX - width - TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON - TOOLTIP_CONSTANT.HEIGHT); + break; + } + break; + } + + return pos; + } + + private checkWidth(width: number): HELP_VIEWER_WIDTH_STATE { + const value = this.coord.coordX - TOOLTIP_CONSTANT.START_POINT; + const windowWidth = this.windowRefService.nativeWindow.innerWidth; + + return (value >= 0 && value + width <= windowWidth) ? HELP_VIEWER_WIDTH_STATE.OK + : value < 0 ? HELP_VIEWER_WIDTH_STATE.LEFT_OVERFLOW + : HELP_VIEWER_WIDTH_STATE.RIGHT_OVERFLOW; + } + + private checkHeight(height: number): HELP_VIEWER_HEIGHT_STATE { + const value = this.coord.coordY + TOOLTIP_CONSTANT.DISTANCE_FROM_BUTTON + height; + const windowHeight = this.windowRefService.nativeWindow.innerHeight; + + return value <= windowHeight ? HELP_VIEWER_HEIGHT_STATE.OK : HELP_VIEWER_HEIGHT_STATE.DOWN_OVERFLOW; + } + + private setTooltipTriangleStyle(top: number, left: number, transform: string): void { + this.tooltipTriangleStyle = { + ...this.tooltipTriangleStyle, + ...{ + left: left < 0 ? 0 : `${left}px`, + top: top < 0 ? 0 : `${top}px`, + transform + } + }; + } + + private getHelpViewerText(viewerType: HELP_VIEWER_LIST): Observable<{[key: string]: any}[]> { + return this.translateService.get(viewerType); + } + + onClickOutside(): void { + this.outClose.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup.component.css new file mode 100644 index 000000000000..eb07fe175338 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup.component.css @@ -0,0 +1,72 @@ +:host { + display: block; + width: 100%; +} + +.main-dl:not(:first-of-type) { + border-top: 1px solid #e5e8f0; +} + +.title-group { + display: block; + padding: 14px 18px; + height: auto; + border-bottom: 1px solid #e5e8f0; + font-size: 13px; + font-weight: 600; + color: #333; +} + +.title-group > dt { + font-size: 16px; + font-weight: 600; + color: #4a8fd2; +} + +.title-group > dd { + font-size: 12px; + color: #777879; + margin-top: 8px; +} + +.contents-group .category-title { + font-size: 13px; + font-weight: 600; + color: #333; + margin-bottom: 12px; + padding-left: 26px; +} + +.contents-group .category-item-list { + display: flex; + padding: 5px 0; + line-height: 20px; +} + +.category-list { + padding: 14px 8px; +} + +.category-list:not(:last-of-type) { + border-bottom: 1px solid #e5e8f0; +} + +.category-item-list > dt { + font-size: 12px; + font-weight: 600; + color: #666; + width: 80px; + display: flex; + align-items: center; + justify-content: center; + margin-right: 5px; + text-align: center; +} + +.category-item-list > dd { + font-size: 12px; + color: #999; + flex: 1; + display: flex; + align-items: center; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup.component.html new file mode 100644 index 000000000000..bcdf7f4d483e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup.component.html @@ -0,0 +1,17 @@ +
    +
    +
    {{helpViewerText.TITLE}}
    +
    {{helpViewerText.DESC}}
    +
    +
    +
    +
    {{category.TITLE}}
    +
    +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup.component.ts new file mode 100644 index 000000000000..3a18ec7b326a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/help-viewer-popup.component.ts @@ -0,0 +1,13 @@ +import { Component, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'pp-help-viewer-popup', + templateUrl: './help-viewer-popup.component.html', + styleUrls: ['./help-viewer-popup.component.css'] +}) +export class HelpViewerPopupComponent implements OnInit { + @Input() data: {[key: string]: any}[]; + + constructor() {} + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/index.ts b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/index.ts new file mode 100644 index 000000000000..e73f2d8344a4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/help-viewer-popup/index.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { HelpViewerPopupContainerComponent } from './help-viewer-popup-container.component'; +import { HelpViewerPopupComponent } from './help-viewer-popup.component'; + +@NgModule({ + declarations: [ + HelpViewerPopupContainerComponent, + HelpViewerPopupComponent + ], + imports: [ + SharedModule + ], + exports: [], + entryComponents: [ + HelpViewerPopupContainerComponent + ], + providers: [] +}) +export class HelpViewerPopupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-container.component.css new file mode 100644 index 000000000000..bc32c5675c9f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-container.component.css @@ -0,0 +1,4 @@ +:host { + display: block; + margin-right: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-container.component.html new file mode 100644 index 000000000000..bc115f1dac0e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-container.component.html @@ -0,0 +1,8 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-container.component.ts new file mode 100644 index 000000000000..339c70b0c71f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-container.component.ts @@ -0,0 +1,75 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, tap, map } from 'rxjs/operators'; + +import { UrlQuery, UrlPathId } from 'app/shared/models'; +import { WebAppSettingDataService, NewUrlStateNotificationService, UrlRouteManagerService } from 'app/shared/services'; + +@Component({ + selector: 'pp-inbound-outbound-range-selector-container', + templateUrl: './inbound-outbound-range-selector-container.component.html', + styleUrls: ['./inbound-outbound-range-selector-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class InboundOutboundRangeSelectorContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + + hiddenComponent: boolean; + inboundList: string[]; + outboundList: string[]; + selectedInbound: string; + selectedOutbound: string; + + constructor( + private changeDetectorRef: ChangeDetectorRef, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + ) {} + + ngOnInit() { + this.inboundList = this.webAppSettingDataService.getInboundList(); + this.outboundList = this.webAppSettingDataService.getOutboundList(); + + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + tap((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.APPLICATION, UrlPathId.PERIOD, UrlPathId.END_TIME)) { + this.hiddenComponent = false; + } else { + this.hiddenComponent = true; + } + }), + map((urlService: NewUrlStateNotificationService) => { + return { + inbound: urlService.hasValue(UrlQuery.INBOUND) ? urlService.getQueryValue(UrlQuery.INBOUND) : this.webAppSettingDataService.getUserDefaultInbound(), + outbound: urlService.hasValue(UrlQuery.OUTBOUND) ? urlService.getQueryValue(UrlQuery.OUTBOUND) : this.webAppSettingDataService.getUserDefaultOutbound() + }; + }) + ).subscribe(({inbound, outbound}: {inbound: string, outbound: string}) => { + this.selectedInbound = inbound; + this.selectedOutbound = outbound; + this.changeDetectorRef.detectChanges(); + }); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + onChangeBound(bound: string[]): void { + this.urlRouteManagerService.moveOnPage({ + url: [ + this.newUrlStateNotificationService.getStartPath(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ], + queryParam: { + [UrlQuery.INBOUND]: bound[0], + [UrlQuery.OUTBOUND]: bound[1] + } + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-for-configuration-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-for-configuration-popup-container.component.css new file mode 100644 index 000000000000..e8922768b7b9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-for-configuration-popup-container.component.css @@ -0,0 +1,4 @@ +:host { + display: inline-block; + margin-left: 15px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-for-configuration-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-for-configuration-popup-container.component.html new file mode 100644 index 000000000000..a0eb52b8d002 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-for-configuration-popup-container.component.html @@ -0,0 +1,7 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-for-configuration-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-for-configuration-popup-container.component.ts new file mode 100644 index 000000000000..61bd403a4c89 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector-for-configuration-popup-container.component.ts @@ -0,0 +1,33 @@ +import { Component, OnInit } from '@angular/core'; + +import { WebAppSettingDataService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; + +@Component({ + selector: 'pp-inbound-outbound-range-selector-for-configuration-popup-container', + templateUrl: './inbound-outbound-range-selector-for-configuration-popup-container.component.html', + styleUrls: ['./inbound-outbound-range-selector-for-configuration-popup-container.component.css'] +}) +export class InboundOutboundRangeSelectorForConfigurationPopupContainerComponent implements OnInit { + inboundList: string[]; + outboundList: string[]; + selectedInbound: string; + selectedOutbound: string; + + constructor( + private webAppSettingDataService: WebAppSettingDataService, + private analyticsService: AnalyticsService + ) {} + + ngOnInit() { + this.inboundList = this.webAppSettingDataService.getInboundList(); + this.outboundList = this.webAppSettingDataService.getOutboundList(); + this.selectedInbound = this.webAppSettingDataService.getUserDefaultInbound(); + this.selectedOutbound = this.webAppSettingDataService.getUserDefaultOutbound(); + } + + onChangeBound(bound: string[]): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SET_BOUND_IN_CONFIGURATION, `Inbound: ${bound[0]}, Outbound: ${bound[1]}`); + this.webAppSettingDataService.setUserDefaultInbound(bound[0]); + this.webAppSettingDataService.setUserDefaultOutbound(bound[1]); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector.component.css b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector.component.css new file mode 100644 index 000000000000..cbbe302a3d9f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector.component.css @@ -0,0 +1,108 @@ +:host { + display: block; + position: relative; + width: 115px; +} +.fa-sign-in-alt, .fa-sign-out-alt { + color: #33b692; +} +button { + outline: none; +} +.l-wrapper { + border: 1px solid #4488CB; +} +.l-dropdown-button { + text-align: left; + width: 100%; + background-color: #fff; + font-size: 13px; + padding: 7px 0 6px 0; + outline: 0; +} +.l-dropdown-button > .fa-angle-down { + font-size: 15px; + display: inline-block; + margin-left: 9px; + color: #33b692; +} + +.l-bound-text { + display: inline-block; + font-size: 14px; + margin-left: 15px; + color: #333; +} + +.l-dropdown-menu-wrapper { + position: absolute; + top: 100%; + left: 0; + z-index: 9999; + display: flex; + flex-wrap: wrap; + border: 1px solid #e5e8f0; + border-radius: 2px; + margin-top: 2px; + background-color: #fff; + width: 180px; +} + +.l-inbound-list { + border-right: 1px solid #e5e8f0; +} + +.l-inbound-list, .l-outbound-list { + width: 50%; + text-align: center; +} + +.l-bound-list-item { + font-weight: 400; + color: #333; + font-size: 13px; + padding: 5px 10px; + cursor: pointer; +} + +.l-bound-title { + padding: 5px 10px; + color: #333; + background-color: #edf2f8; + font-weight: 600 !important; + font-size: 13px; + border-bottom: 1px solid #e5e8f0; +} + +.l-bound-list-item:hover { + background-color: #eee; +} + +.l-bound-list-item.active { + color: #4b99e3; + background-color: #edf2f8; +} + +.l-button-group-wrapper { + width: 100%; + border-top: 1px solid #e5e8f0; + padding: 1px; + text-align: right; +} + +.l-apply-button { + background-color: #4a8fd2; + border: 1px solid #4a8fd2; + border-radius: 0px; + padding: 5px 11px; + color: #fff; + margin: 2px; +} + +.l-cancel-button { + border: 1px solid #e5e8f0; + border-radius: 0px; + padding: 5px 7px; + color: #333; + margin: 2px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector.component.html b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector.component.html new file mode 100644 index 000000000000..cfb72cc7c5d2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector.component.html @@ -0,0 +1,21 @@ +
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector.component.ts b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector.component.ts new file mode 100644 index 000000000000..b89f93730fd0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/inbound-outbound-range-selector.component.ts @@ -0,0 +1,63 @@ +import { Component, EventEmitter, Input, Output, OnInit, OnChanges, SimpleChanges } from '@angular/core'; + +@Component({ + selector: 'pp-inbound-outbound-range-selector', + templateUrl: './inbound-outbound-range-selector.component.html', + styleUrls: ['./inbound-outbound-range-selector.component.css'] +}) +export class InboundOutboundRangeSelectorComponent implements OnInit, OnChanges { + hideList = true; + prevSelectedInbound: string; + prevSelectedOutbound: string; + @Input() selectedInbound: string; + @Input() selectedOutbound: string; + @Input() inboundList: string[]; + @Input() outboundList: string[]; + @Output() outSelected: EventEmitter = new EventEmitter(); + + constructor() {} + + ngOnChanges(changes: SimpleChanges) { + if (changes['selectedInbound']) { + this.prevSelectedInbound = this.selectedInbound = changes['selectedInbound'].currentValue; + } + if (changes['selectedOutbound']) { + this.prevSelectedOutbound = this.selectedOutbound = changes['selectedOutbound'].currentValue; + } + } + + ngOnInit() { } + onSelectInbound(inbound: string): void { + this.selectedInbound = inbound; + } + + onSelectOutbound(outbound: string): void { + this.selectedOutbound = outbound; + } + + onApply(): void { + if (!(this.selectedInbound === this.prevSelectedInbound && this.selectedOutbound === this.prevSelectedOutbound)) { + this.outSelected.emit([this.selectedInbound, this.selectedOutbound]); + } + this.close(); + } + + onCancel(): void { + this.selectedInbound = this.prevSelectedInbound; + this.selectedOutbound = this.prevSelectedOutbound; + this.close(); + } + + toggleList(): void { + this.hideList = !this.hideList; + } + + onClose(): void { + this.onCancel(); + this.close(); + } + + private close(): void { + this.hideList = true; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/index.ts b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/index.ts new file mode 100644 index 000000000000..9935d7cf140a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inbound-outbound-range-selector/index.ts @@ -0,0 +1,23 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { InboundOutboundRangeSelectorComponent } from './inbound-outbound-range-selector.component'; +import { InboundOutboundRangeSelectorContainerComponent } from './inbound-outbound-range-selector-container.component'; +import { InboundOutboundRangeSelectorForConfigurationPopupContainerComponent } from './inbound-outbound-range-selector-for-configuration-popup-container.component'; + +@NgModule({ + declarations: [ + InboundOutboundRangeSelectorComponent, + InboundOutboundRangeSelectorContainerComponent, + InboundOutboundRangeSelectorForConfigurationPopupContainerComponent + ], + imports: [ + SharedModule + ], + exports: [ + InboundOutboundRangeSelectorContainerComponent, + InboundOutboundRangeSelectorForConfigurationPopupContainerComponent + ], + providers: [] +}) +export class InboundOutboundRangeSelectorModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/info-per-server/index.ts b/web/src/main/webapp/v2/src/app/core/components/info-per-server/index.ts new file mode 100644 index 000000000000..9069a20360f9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/info-per-server/index.ts @@ -0,0 +1,33 @@ + +import { NgModule } from '@angular/core'; +import { MatTooltipModule } from '@angular/material'; +import { SharedModule } from 'app/shared'; +import { ScatterChartModule } from 'app/core/components/scatter-chart'; +import { ResponseSummaryChartModule } from 'app/core/components/response-summary-chart'; +import { LoadChartModule } from 'app/core/components/load-chart'; +import { ServerListModule } from 'app/core/components/server-list'; +import { InfoPerServerContainerComponent } from './info-per-server-container.component'; +import { InfoPerServerForFilteredMapContainerComponent } from './info-per-server-for-filtered-map-container.component'; +import { ServerErrorPopupModule } from 'app/core/components/server-error-popup'; + +@NgModule({ + declarations: [ + InfoPerServerContainerComponent, + InfoPerServerForFilteredMapContainerComponent + ], + imports: [ + SharedModule, + MatTooltipModule, + ScatterChartModule, + ResponseSummaryChartModule, + LoadChartModule, + ServerListModule, + ServerErrorPopupModule + ], + exports: [ + InfoPerServerContainerComponent, + InfoPerServerForFilteredMapContainerComponent + ], + providers: [] +}) +export class InfoPerServerModule {} diff --git a/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-container.component.css b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-container.component.css new file mode 100644 index 000000000000..555c38936fff --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-container.component.css @@ -0,0 +1,116 @@ +:host { + z-index: 9; +} +.l-sidemenu2 { + position: absolute; + top: 0px; + left: 0px; + width: 461px; + border-left: 1px solid #e5e8f0; + border-right: 1px solid #e5e8f0; + background: #fff; + height: 100%; + overflow-y: auto; + overflow-x: hidden; +} +.l-title-group2 { + display: flex; + flex-flow: row wrap; + color: #666; + justify-content: space-between; + align-items: center; + padding: 0 25px; + background: none; + border: none; + height: 50px; +} +.l-selected-agent { + color: #666; + font-size: 13px; + display: block; + overflow : hidden; + white-space : nowrap; + text-overflow : ellipsis; +} +.l-selected-agent label { + color: #fff; + font-size: 11px; + font-weight: 600; + display: inline-block; + background: #4b99e3; + margin: 0 12px 0 0; + padding: 6px 11px; + line-height: 1em; + position: relative; +} +.l-selected-agent label:after { + content:''; + position:absolute; + width:0; + height:0; + border-top:4px solid transparent; + border-bottom:4px solid transparent; + border-left:3px solid #4b99e3; + right:-3px; + top:50%; + transform:translateY(-50%); +} +.l-contents-group { + padding: 51px 0px 16px; + overflow-y: auto; + overflow-x: hidden; +} +.l-chart-group-list { + flex: 1; +} + +.l-sidemenu3 { + top: 0px; + left: 0px; + width: 348px; + background: #f8f9fb; + border: none; + position: absolute; + height: 100%; + overflow-y: auto; + overflow-x: hidden; +} +.l-title-group3 { + display: flex; + flex-flow: row wrap; + align-items: center; + height: 64px; + padding: 0 25px; + position: relative; +} +.l-title-group3 .fas { + font-size: 14px; + width: 33px; + height: 33px; + border-radius: 50%; + background: #4a8fd2; + color: #fff; + align-items: center; + display: flex; + justify-content: center; + margin: 0 7px 0 0; +} +.l-title-group3 .l-title { + font-size: 24px; + font-weight: 600; + color: #666; +} + + +.sidemenu { + top: 0px; + left: -461px; +} +.title-group2 { + background-color: #f9fafc; + border-bottom: 1px solid #eaeef4; +} +hr { + height: 1px; + border-top: 1px solid #EAEEF4; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-container.component.html b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-container.component.html new file mode 100644 index 000000000000..772421c5db8a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-container.component.html @@ -0,0 +1,29 @@ +
    +
    +
    + + {{ selectedAgent }} +
    +
    +
    +
    + +
    + +
    + +
    +
    +
    +
    +
    + + Servers List +
    +
    + +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-container.component.ts new file mode 100644 index 000000000000..a460b377fa75 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-container.component.ts @@ -0,0 +1,150 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { trigger, state, style, animate, transition } from '@angular/animations'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { + StoreHelperService, + NewUrlStateNotificationService, + UrlRouteManagerService, + AgentHistogramDataService, + DynamicPopupService, + AnalyticsService, + TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ServerMapData } from 'app/core/components/server-map/class/server-map-data.class'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; + +@Component({ + selector: 'pp-info-per-server-container', + templateUrl: './info-per-server-container.component.html', + styleUrls: ['./info-per-server-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush, + animations: [ + trigger('listAnimationTrigger', [ + state('start', style({ + left: '0px' + })), + state('end', style({ + left: '-809px' + })), + transition('* => *', [ + animate('0.2s 0.5s ease-out') + ]) + ]), + trigger('chartAnimationTrigger', [ + state('start', style({ + left: '0px' + })), + state('end', style({ + left: '-461px' + })), + transition('* => *', [ + animate('0.2s 0s ease-out') + ]) + ]), + ] +}) +export class InfoPerServerContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + selectedTarget: ISelectedTarget; + serverMapData: ServerMapData; + agentHistogramData: any; + selectedAgent = ''; + listAnimationTrigger = 'start'; + chartAnimationTrigger = 'start'; + constructor( + private storeHelperService: StoreHelperService, + private changeDetector: ChangeDetectorRef, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private agentHistogramDataService: AgentHistogramDataService, + private dynamicPopupService: DynamicPopupService, + private analyticsService: AnalyticsService, + ) {} + ngOnInit() { + this.connectStore(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.hide(); + this.changeDetector.detectChanges(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).subscribe((target: ISelectedTarget) => { + this.selectedTarget = target; + }); + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: ServerMapData) => { + this.serverMapData = serverMapData; + }); + this.storeHelperService.getInfoPerServerState(this.unsubscribe).subscribe((visibleState: boolean) => { + if (this.selectedTarget && this.selectedTarget.isNode) { + const node = this.serverMapData.getNodeData(this.selectedTarget.node[0]); + if (visibleState === true) { + this.agentHistogramDataService.getData(node.key, node.applicationName, node.serviceTypeCode, this.serverMapData).subscribe((histogramData: any) => { + this.show(); + this.agentHistogramData = histogramData || {}; + this.agentHistogramData.isWas = node.isWas; + this.changeDetector.detectChanges(); + this.storeHelperService.dispatch(new Actions.UpdateServerList(this.agentHistogramData)); + this.onSelectAgent(this.getFirstAgent()); + this.storeHelperService.dispatch(new Actions.ChangeInfoPerServerVisibleState(true)); + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent + }); + this.storeHelperService.dispatch(new Actions.ChangeServerMapDisableState(false)); + this.storeHelperService.dispatch(new Actions.ChangeInfoPerServerVisibleState(false)); + }); + } else { + this.hide(); + this.changeDetector.detectChanges(); + this.storeHelperService.dispatch(new Actions.ChangeInfoPerServerVisibleState(false)); + } + } + }); + } + private hide(): void { + this.listAnimationTrigger = 'start'; + this.chartAnimationTrigger = 'start'; + } + private show(): void { + this.listAnimationTrigger = 'end'; + this.chartAnimationTrigger = 'end'; + } + getFirstAgent(): string { + const firstKey = Object.keys(this.agentHistogramData['serverList']).sort()[0]; + return Object.keys(this.agentHistogramData['serverList'][firstKey]['instanceList']).sort()[0]; + } + onSelectAgent(agentName: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_AGENT); + this.storeHelperService.dispatch(new Actions.ChangeAgentForServerList({ + agent: agentName, + responseSummary: this.agentHistogramData['agentHistogram'][agentName], + load: this.agentHistogramData['agentTimeSeriesHistogram'][agentName] + })); + this.selectedAgent = agentName; + this.changeDetector.detectChanges(); + } + onOpenInspector(agentName: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_INSPECTOR_WITH_AGENT); + this.urlRouteManagerService.openPage([ + UrlPath.INSPECTOR, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + agentName + ]); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-for-filtered-map-container.component.css b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-for-filtered-map-container.component.css new file mode 100644 index 000000000000..510be65bcd4c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-for-filtered-map-container.component.css @@ -0,0 +1,113 @@ +:host { + z-index: 9; +} +.l-sidemenu2 { + position: absolute; + top: 0px; + left: 0px; + width: 461px; + border-left: 1px solid #e5e8f0; + border-right: 1px solid #e5e8f0; + background: #fff; + height: 100%; + overflow-y: auto; + overflow-x: hidden; +} +.l-title-group2 { + display: flex; + flex-flow: row wrap; + color: #666; + justify-content: space-between; + align-items: center; + padding: 0 25px; + background: none; + border: none; + height: 50px; +} +.l-selected-agent { + color: #666; + font-size: 13px; +} +.l-selected-agent button { + color: #fff; + font-size: 11px; + font-weight: 600; + display: inline-block; + background: #4b99e3; + margin: 0 12px 0 0; + padding: 6px 11px; + line-height: 1em; + position: relative; +} +.l-selected-agent button:after { + content:''; + position:absolute; + width:0; + height:0; + border-top:4px solid transparent; + border-bottom:4px solid transparent; + border-left:3px solid #4b99e3; + right:-3px; + top:50%; + transform:translateY(-50%); +} +.l-contents-group { + padding-bottom: 16px; + overflow-y: auto; + overflow-x: hidden; + margin-top: 51px; +} +.l-chart-group-list { + flex: 1; +} + +.l-sidemenu3 { + top: 0px; + left: 0px; + width: 348px; + background: #f8f9fb; + border: none; + position: absolute; + height: 100%; + overflow-y: auto; + overflow-x: hidden; +} +.l-title-group3 { + display: flex; + flex-flow: row wrap; + align-items: center; + height: 64px; + padding: 0 25px; + position: relative; +} +.l-title-group3 .fas { + font-size: 14px; + width: 33px; + height: 33px; + border-radius: 50%; + background: #4a8fd2; + color: #fff; + align-items: center; + display: flex; + justify-content: center; + margin: 0 7px 0 0; +} +.l-title-group3 .l-title { + font-size: 24px; + font-weight: 600; + color: #666; +} + + +.sidemenu { + top: 0px; + left: -461px; +} +.title-group2 { + background-color: #f9fafc; + border-bottom: 1px solid #eaeef4; +} +hr { + height: 1px; + border-top: 1px solid #EAEEF4; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-for-filtered-map-container.component.html b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-for-filtered-map-container.component.html new file mode 100644 index 000000000000..16b0da2780e9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-for-filtered-map-container.component.html @@ -0,0 +1,29 @@ +
    +
    +

    + + {{ selectedAgent }} +

    +
    +
    +
    + +
    + +
    + +
    +
    +
    +
    +
    + + Servers List +
    +
    + +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-for-filtered-map-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-for-filtered-map-container.component.ts new file mode 100644 index 000000000000..c60bb3062f24 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/info-per-server/info-per-server-for-filtered-map-container.component.ts @@ -0,0 +1,133 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { trigger, state, style, animate, transition } from '@angular/animations'; +import { Subject } from 'rxjs'; + +import { + StoreHelperService, + NewUrlStateNotificationService, + UrlRouteManagerService, + AnalyticsService, + TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ServerMapData } from 'app/core/components/server-map/class/server-map-data.class'; + +@Component({ + selector: 'pp-info-per-server-for-filtered-map-container', + templateUrl: './info-per-server-for-filtered-map-container.component.html', + styleUrls: ['./info-per-server-for-filtered-map-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush, + animations: [ + trigger('listAnimationTrigger', [ + state('start', style({ + left: '0px' + })), + state('end', style({ + left: '-809px' + })), + transition('* => *', [ + animate('0.2s 0.5s ease-out') + ]) + ]), + trigger('chartAnimationTrigger', [ + state('start', style({ + left: '0px' + })), + state('end', style({ + left: '-461px' + })), + transition('* => *', [ + animate('0.2s 0s ease-out') + ]) + ]), + ] +}) +export class InfoPerServerForFilteredMapContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + selectedTarget: ISelectedTarget; + serverMapData: ServerMapData; + agentHistogramData: any; + selectedAgent = ''; + listAnimationTrigger = 'start'; + chartAnimationTrigger = 'start'; + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private analyticsService: AnalyticsService, + ) {} + ngOnInit() { + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).subscribe((target: ISelectedTarget) => { + this.selectedTarget = target; + }); + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: ServerMapData) => { + this.serverMapData = serverMapData; + }); + this.storeHelperService.getInfoPerServerState(this.unsubscribe).subscribe((visibleState: boolean) => { + if (this.selectedTarget && this.selectedTarget.isNode) { + if (visibleState === true) { + const node = this.serverMapData.getNodeData(this.selectedTarget.node[0]); + this.show(); + this.agentHistogramData = { + serverList: node.serverList, + agentHistogram: node.agentHistogram, + agentTimeSeriesHistogram: node.agentTimeSeriesHistogram, + isWas: node.isWas + }; + this.changeDetector.detectChanges(); + this.storeHelperService.dispatch(new Actions.UpdateServerList(this.agentHistogramData)); + this.onSelectAgent(this.getFirstAgent()); + this.storeHelperService.dispatch(new Actions.ChangeInfoPerServerVisibleState(true)); + } else { + this.hide(); + this.changeDetector.detectChanges(); + this.storeHelperService.dispatch(new Actions.ChangeInfoPerServerVisibleState(false)); + } + } + }); + } + private hide(): void { + this.listAnimationTrigger = 'start'; + this.chartAnimationTrigger = 'start'; + } + private show(): void { + this.listAnimationTrigger = 'end'; + this.chartAnimationTrigger = 'end'; + } + isWAS(): boolean { + return this.selectedTarget.isWAS; + } + getFirstAgent(): string { + const firstKey = Object.keys(this.agentHistogramData['serverList']).sort()[0]; + return Object.keys(this.agentHistogramData['serverList'][firstKey]['instanceList']).sort()[0]; + } + onSelectAgent(agentName: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_AGENT); + this.storeHelperService.dispatch(new Actions.ChangeAgentForServerList({ + agent: agentName, + responseSummary: this.agentHistogramData['agentHistogram'][agentName], + load: this.agentHistogramData['agentTimeSeriesHistogram'][agentName] + })); + this.selectedAgent = agentName; + this.changeDetector.detectChanges(); + } + onOpenInspector(agentName: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_INSPECTOR_WITH_AGENT); + this.urlRouteManagerService.openPage([ + UrlPath.INSPECTOR, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + agentName + ]); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-container.component.html new file mode 100644 index 000000000000..15084f4f991a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Active Thread
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-container.component.ts new file mode 100644 index 000000000000..e15e4241f8f2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-container.component.ts @@ -0,0 +1,250 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { + WebAppSettingDataService, + NewUrlStateNotificationService, + AjaxExceptionCheckerService, + AnalyticsService, + StoreHelperService, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { AgentActiveThreadChartDataService } from './agent-active-thread-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-active-thread-chart-container', + templateUrl: './agent-active-thread-chart-container.component.html', + styleUrls: ['./agent-active-thread-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentActiveThreadChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentActiveThreadChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 10, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected parseData(data: number): number | null { + return data === -1 ? null : Number(data.toFixed(2)); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const fastArr = []; + const normalArr = []; + const slowArr = []; + const verySlowArr = []; + + const xData = chartData.charts.x; + const atFast = chartData.charts.y['ACTIVE_TRACE_FAST']; + const atNormal = chartData.charts.y['ACTIVE_TRACE_NORMAL']; + const atSlow = chartData.charts.y['ACTIVE_TRACE_SLOW']; + const atVerySlow = chartData.charts.y['ACTIVE_TRACE_VERY_SLOW']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if ( atFast.length === 0 ) { + continue; + } + fastArr.push(this.parseData(atFast[i][2])); + normalArr.push(this.parseData(atNormal[i][2])); + slowArr.push(this.parseData(atSlow[i][2])); + verySlowArr.push(this.parseData(atVerySlow[i][2])); + } + return { + x: xArr, + fast: fastArr, + normal: normalArr, + slow: slowArr, + verySlow: verySlowArr + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Fast', + data: data.fast, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(44, 160, 44)', + backgroundColor: 'rgba(44, 160, 44, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Normal', + data: data.normal, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(60, 129, 250)', + backgroundColor: 'rgba(60, 129, 250, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Slow', + data: data.slow, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(248, 199, 49)', + backgroundColor: 'rgba(248, 199, 49, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Very Slow', + data: data.verySlow, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(246, 145, 36)', + backgroundColor: 'rgba(246, 145, 36, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Active Thread' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Active Thread (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_ACTIVE_THREAD); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-data.service.ts new file mode 100644 index 000000000000..406a4aa90244 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-active-thread-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class AgentActiveThreadChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/activeTrace/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-container.component.html new file mode 100644 index 000000000000..deec38222b39 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    JVM/System CPU Usage
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-container.component.ts new file mode 100644 index 000000000000..fb08ac8c7f65 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-container.component.ts @@ -0,0 +1,213 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { + WebAppSettingDataService, + NewUrlStateNotificationService, + AjaxExceptionCheckerService, + AnalyticsService, + StoreHelperService, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { AgentCPUChartDataService } from './agent-cpu-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-cpu-chart-container', + templateUrl: './agent-cpu-chart-container.component.html', + styleUrls: ['./agent-cpu-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentCPUChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentCPUChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected parseData(data: number): number | null { + return data === -1 ? null : Number(data.toFixed(2)); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const jvmArr = []; + const systemArr = []; + const maxArr = []; + + const xData = chartData.charts.x; + const cpuJVM = chartData.charts.y['CPU_LOAD_JVM']; + const cpuSystem = chartData.charts.y['CPU_LOAD_SYSTEM']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + maxArr.push(100); + if ( cpuJVM.length === 0 ) { + continue; + } + jvmArr.push(this.parseData(cpuJVM[i][1])); + systemArr.push(this.parseData(cpuSystem[i][1])); + } + return { + x: xArr, + jvm: jvmArr, + system: systemArr + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'JVM', + data: data.jvm, + fill: false, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180)', + backgroundColor: 'rgba(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'System', + data: data.system, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(174, 199, 232)', + backgroundColor: 'rgba(174, 199, 232, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'JVM/System CPU Usage' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : value.yLabel}%`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'CPU Usage (%)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return `${label}%`; + }, + min: 0, + max: this.defaultYMax, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_CPU_USAGE); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-data.service.ts new file mode 100644 index 000000000000..17c0078012b8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-cpu-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class AgentCPUChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/cpuLoad/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.css new file mode 100644 index 000000000000..8488ec0b669d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.css @@ -0,0 +1,29 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; + position: relative; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-text { + flex-basis: 70%; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.html new file mode 100644 index 000000000000..6458cf60f67c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.html @@ -0,0 +1,26 @@ +
    +
    +

    Data Source

    + + + + + +
    + + + + + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.ts new file mode 100644 index 000000000000..76c6f2c1b5ee --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.ts @@ -0,0 +1,275 @@ +import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { InspectorChartComponent } from './inspector-chart.component'; +import { TranslateService } from '@ngx-translate/core'; +import { filter, skip, tap } from 'rxjs/operators'; +import * as moment from 'moment-timezone'; + +import { + WebAppSettingDataService, + NewUrlStateNotificationService, + AjaxExceptionCheckerService, + AnalyticsService, + StoreHelperService, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { AgentDataSourceChartDataService, IAgentDataSourceChart } from './agent-data-source-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; + +@Component({ + selector: 'pp-agent-data-source-chart-container', + templateUrl: './agent-data-source-chart-container.component.html', + styleUrls: ['./agent-data-source-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentDataSourceChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + @ViewChild(InspectorChartComponent) inspectorChartComponent: InspectorChartComponent; + private checkedSourceDataArr: {[key: string]: any}[]; + + sourceDataArr: {[key: string]: any}[]; + infoTableObj: {[key: string]: any}; + + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentDataSourceChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 10, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initInfoTableObj(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + private initInfoTableObj(): void { + this.infoTableObj = { + activeAvg: '-', + activeMax: '-', + totalMax: '-', + id: '-', + serviceType: '-', + databaseName: '-', + jdbcUrl: '-', + }; + } + + protected initHoveredInfo(): void { + this.hoveredInfo$ = this.storeHelperService.getHoverInfo(this.unsubscribe).pipe( + skip(1), + filter(() => { + return !(!this.chartConfig || this.chartConfig.isDataEmpty); + }), + tap((hoverInfo: IHoveredInfo) => this.updateInfoTable(hoverInfo)), + ); + } + + private updateInfoTable(hoverInfo: IHoveredInfo): void { + if (hoverInfo.index !== -1) { + const activeIndex = hoverInfo.index; // x축 기준 index + const activeElements = this.inspectorChartComponent.getActiveTooltipElements(activeIndex); + const eventCord = {x1: hoverInfo.offsetX, y1: hoverInfo.offsetY}; + const distanceArr = activeElements.map((element) => this.getDistanceBetweenPoints(eventCord, {x2: element._view.x, y2: element._view.y})); + const minDistance = Math.min(...distanceArr); + const elementIndex = distanceArr.indexOf(minDistance); // element들 중 event point에 가장 가까운 element의 index + if (elementIndex !== -1) { + this.infoTableObj = { + activeAvg: this.checkedSourceDataArr[elementIndex].activeAvg[activeIndex], + activeMax: this.checkedSourceDataArr[elementIndex].activeMax[activeIndex], + totalMax: this.checkedSourceDataArr[elementIndex].totalMax[activeIndex], + id: this.checkedSourceDataArr[elementIndex].id, + serviceType: this.checkedSourceDataArr[elementIndex].serviceType, + databaseName: this.checkedSourceDataArr[elementIndex].databaseName, + jdbcUrl: this.checkedSourceDataArr[elementIndex].jdbcUrl, + }; + } + } + } + + private getDistanceBetweenPoints({x1, y1}: {x1: number, y1: number}, {x2, y2}: {x2: number, y2: number}): number { + return Math.hypot(x1 - x2, y1 - y2); + } + + protected getChartData(range: number[]): void { + this.chartDataService.getData(range) + .subscribe( + (data: IAgentDataSourceChart[] | AjaxException) => { + if (this.ajaxExceptionCheckerService.isAjaxException(data)) { + this.setErrObj(data); + } else { + this.chartData = data; + this.sourceDataArr = this.makeChartData(data); + this.setChartConfig(this.sourceDataArr); + } + }, + (err) => { + this.setErrObj(); + } + ); + } + + onCheckedIdChange(checkedIdSet: Set): void { + this.setChartConfig(this.getCheckedSourceDataArr(checkedIdSet)); + } + + private getCheckedSourceDataArr(checkedIdSet: Set): {[key: string]: any}[] { + this.checkedSourceDataArr = this.sourceDataArr.filter((sourceData) => checkedIdSet.has(sourceData.id)); + return this.checkedSourceDataArr; + } + + protected makeChartData(chartDataArr: IAgentDataSourceChart[]): {[key: string]: any}[] { + return chartDataArr.map((chartData: IAgentDataSourceChart) => { + return { + x: chartData.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + activeAvg: chartData.charts.y['ACTIVE_CONNECTION_SIZE'].map((arr: number[]) => this.parseData(arr[2])), + activeMax: chartData.charts.y['ACTIVE_CONNECTION_SIZE'].map((arr: number[]) => this.parseData(arr[1])), + totalMax: chartData.charts.y['MAX_CONNECTION_SIZE'].map((arr: number[]) => this.parseData(arr[1])), + databaseName: chartData.databaseName, + id: chartData.id, + jdbcUrl: chartData.jdbcUrl, + serviceType: chartData.serviceType, + }; + }); + } + + protected makeDataOption(data: {[key: string]: any}[]): {[key: string]: any} { + const colorMap = [ + '#850901', '#969755', '#421416', '#c8814b', '#aa8735', '#cd7af4', '#f6546a', '#1c1a1f', '#127999', '#b7ebd9', + '#f6546a', '#bea87f', '#d1b4b0', '#e0d4ba', '#0795d9', '#43aa83', '#09d05b', '#c26e67', '#ed7575', '#96686a' + ]; + const labels = this.sourceDataArr[0].x; + + return { + labels, + datasets: data.map((obj, i) => { + return { + label: 'ActiveAvg', + data: obj.activeAvg, + fill: false, + borderWidth: 0.5, + borderColor: colorMap[i], + pointRadius: 0, + pointHoverRadius: 3 + }; + }) + }; + } + + protected makeNormalOption(data: {[key: string]: any}[]): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Data Source' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return ''; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Connection (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + max: this.defaultYMax, + padding: 5 + } + }] + }, + legend: { + display: false, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_DATA_SOURCE); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-data.service.ts new file mode 100644 index 000000000000..d4f2faf570ad --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-data.service.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +export interface IAgentDataSourceChart extends IChartDataFromServer { + databaseName: string; + id: number; + jdbcUrl: string; + serviceType: string; +} + +@Injectable() +export class AgentDataSourceChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/dataSource/chartList.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-infotable.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-infotable.component.css new file mode 100644 index 000000000000..fd4125fa0dd1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-infotable.component.css @@ -0,0 +1,24 @@ +.l-source-info-wrapper { + background-color: #fff; + font-size: 12px; + padding: 10px; +} +.l-source-info-title { + background-color: #f6f8fb; + border-top: 1px solid #ddd; + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + padding: 10px; +} +.l-source-info-table { + border: 1px solid #ddd; + width: 100%; +} +.l-source-info-table th, td { + border: 1px solid #ddd; + padding: 4px; + text-align: center; +} +.l-source-info-table th { + width: 20%; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-infotable.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-infotable.component.html new file mode 100644 index 000000000000..b9d9c7c5a61a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-infotable.component.html @@ -0,0 +1,35 @@ +
    +

    Data Source Info

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Active Avg{{infoTableObj.activeAvg}}
    Active Max{{infoTableObj.activeMax}}
    Total Max{{infoTableObj.totalMax}}
    ID{{infoTableObj.id}}
    Type{{infoTableObj.serviceType}}
    Database Name{{infoTableObj.databaseName}}
    Jdbc URL{{infoTableObj.jdbcUrl}}
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-infotable.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-infotable.component.ts new file mode 100644 index 000000000000..637927d7ff00 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-infotable.component.ts @@ -0,0 +1,14 @@ +import { Component, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'pp-agent-data-source-chart-infotable', + templateUrl: './agent-data-source-chart-infotable.component.html', + styleUrls: ['./agent-data-source-chart-infotable.component.css'] +}) +export class AgentDataSourceChartInfotableComponent implements OnInit { + @Input() isDataEmpty: boolean; + @Input() infoTableObj: { [key: string]: any }; + + constructor() {} + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-select-source.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-select-source.component.css new file mode 100644 index 000000000000..3890e741da8d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-select-source.component.css @@ -0,0 +1,40 @@ +.l-source-select-text { + cursor: pointer; + text-align: center; + font-weight: 400; +} +.l-source-select-text > .far { + font-size: 15px; + margin-left: 3px; +} +.l-source-select-modal { + position: absolute; + top: 34px; + right: 0px; + border: 1px solid black; + width: 100%; + z-index: 1000; + padding: 15px; + background-color: #fff; + font-weight: 400; +} +.l-select-all-button { + width: 80px; + border: 1px solid #ccc; + border-radius: 3px; + padding: 5px; +} +.l-source-data-list { + margin-top: 10px; + border-top: 1px solid #ddd; + padding: 10px 0; +} +.l-source-data-list-item { + display: inline-block; +} +.l-list-item-label { + margin-right: 20px; +} +.l-list-item-input { + margin-right: 5px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-select-source.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-select-source.component.html new file mode 100644 index 000000000000..6aec8779aa3c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-select-source.component.html @@ -0,0 +1,12 @@ +

    Select Source

    +
    + +
      +
    • + +
    • +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-select-source.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-select-source.component.ts new file mode 100644 index 000000000000..d2239bf9d736 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-data-source-chart-select-source.component.ts @@ -0,0 +1,49 @@ +import { Component, OnInit, OnChanges, Input, Output, EventEmitter, SimpleChanges } from '@angular/core'; + +@Component({ + selector: 'pp-agent-data-source-chart-select-source', + templateUrl: './agent-data-source-chart-select-source.component.html', + styleUrls: ['./agent-data-source-chart-select-source.component.css'] +}) +export class AgentDataSourceChartSelectSourceComponent implements OnInit, OnChanges { + @Input() isDataEmpty: boolean; + @Input() sourceDataArr: { [key: string]: any }[]; + @Output() outCheckedIdChange: EventEmitter> = new EventEmitter(); + + showSourceSelectModal = false; + checkedIdSet = new Set(); + + constructor() {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + Object.keys(changes).map((propName: string) => { + switch (propName) { + case 'sourceDataArr': + this.initCheckedIdSet(); + break; + } + }); + } + + onSourceSelectClick(): void { + this.showSourceSelectModal = !this.showSourceSelectModal; + } + + onCheckAllBtnClick(): void { + this.initCheckedIdSet(); + } + + onSourceCheckboxChange(id: number): void { + this.toggleCheckedId(id); + } + + private initCheckedIdSet(): void { + this.sourceDataArr.map((data) => this.checkedIdSet.add(data.id)); + this.outCheckedIdChange.emit(this.checkedIdSet); + } + + private toggleCheckedId(id: number): void { + this.checkedIdSet.has(id) ? this.checkedIdSet.delete(id) : this.checkedIdSet.add(id); + this.outCheckedIdChange.emit(this.checkedIdSet); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-chart-data.service.ts new file mode 100644 index 000000000000..941ce135078a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class AgentDirectBufferChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/directBuffer/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component.html new file mode 100644 index 000000000000..3c458cdafe47 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Direct Buffer Count
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component.ts new file mode 100644 index 000000000000..d95c82603910 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component.ts @@ -0,0 +1,178 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { + WebAppSettingDataService, + NewUrlStateNotificationService, + AjaxExceptionCheckerService, + AnalyticsService, + StoreHelperService, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { AgentDirectBufferChartDataService } from './agent-direct-buffer-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-direct-buffer-count-chart-container', + templateUrl: './agent-direct-buffer-count-chart-container.component.html', + styleUrls: ['./agent-direct-buffer-count-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentDirectBufferCountChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentDirectBufferChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + directCount: data.charts.y['DIRECT_COUNT'].map((arr: number[]) => this.parseData(arr[2])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + type: 'line', + label: 'Direct Buffer Count', + data: data.directCount, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180, 0.4)', + backgroundColor: 'rgb(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Direct Buffer Count' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : value.yLabel}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Buffer (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_DIRECT_BUFFER_COUNT); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component.html new file mode 100644 index 000000000000..fa23ce97c70c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Direct Buffer Memory
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component.ts new file mode 100644 index 000000000000..784c8bcf52e0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component.ts @@ -0,0 +1,190 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { AgentDirectBufferChartDataService } from 'app/core/components/inspector-chart/agent-direct-buffer-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-direct-buffer-memory-chart-container', + templateUrl: './agent-direct-buffer-memory-chart-container.component.html', + styleUrls: ['./agent-direct-buffer-memory-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentDirectBufferMemoryChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentDirectBufferChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + directMemoryUsed: data.charts.y['DIRECT_MEMORY_USED'].map((arr: number[]) => this.parseData(arr[2])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + type: 'line', + label: 'Direct Buffer Memory', + data: data.directMemoryUsed, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180, 0.4)', + backgroundColor: 'rgb(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Direct Buffer Memory' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + const hoverInfo: IHoveredInfo = { + index: event.type === 'mouseout' ? -1 : elements[0]._index + }; + if (hoverInfo.index !== -1) { + hoverInfo.offsetX = event.offsetX; + hoverInfo.offsetY = event.offsetY; + } + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts(hoverInfo)); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_DIRECT_BUFFER_MEMORY); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-heap-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-heap-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-heap-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-heap-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-heap-chart-container.component.html new file mode 100644 index 000000000000..211d0ea16cd6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-heap-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Heap Usage
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-heap-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-heap-chart-container.component.ts new file mode 100644 index 000000000000..7bd2ad3f0149 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-heap-chart-container.component.ts @@ -0,0 +1,282 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { AgentMemoryChartDataService } from './agent-memory-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-jvm-heap-chart-container', + templateUrl: './agent-jvm-heap-chart-container.component.html', + styleUrls: ['./agent-jvm-heap-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentJVMHeapChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentMemoryChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected setChartConfig(data: {[key: string]: any}): void { + this.chartConfig = { + type: 'bar', + dataConfig: this.makeDataOption(data), + elseConfig: this.makeNormalOption(data), + isDataEmpty: this.isDataEmpty(data) + }; + this.changeDetector.detectChanges(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const usedArr = []; + const fgcTimeArr = []; + const fgcCountArr = []; + + const xData = chartData.charts.x; + const gcOldTime = chartData.charts.y['JVM_GC_OLD_TIME']; + const gcOldCount = chartData.charts.y['JVM_GC_OLD_COUNT']; + const memoryUsed = chartData.charts.y['JVM_MEMORY_HEAP_USED']; + const memoryMax = chartData.charts.y['JVM_MEMORY_HEAP_MAX']; + const dataCount = xData.length; + + let totalSumGCTime = 0; + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if ( memoryMax.length === 0 ) { + continue; + } + maxArr.push(this.parseData(memoryMax[i][1])); + usedArr.push(this.parseData(memoryUsed[i][1])); + + const gcOldCountSumValue = gcOldCount[i][3]; + const gcOldTimeSumValue = gcOldTime[i][3]; + + if ( gcOldTimeSumValue > 0 ) { + totalSumGCTime += gcOldTimeSumValue; + } + if ( gcOldCountSumValue > 0 ) { + fgcTimeArr.push(totalSumGCTime); + fgcCountArr.push(gcOldCountSumValue); + totalSumGCTime = 0; + } else { + fgcTimeArr.push(0); + fgcCountArr.push(0); + } + } + return { + x: xArr, + max: maxArr, + used: usedArr, + fgcTime: fgcTimeArr, + fgcCount: fgcCountArr + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + type: 'line', + label: 'Max', + data: data.max, + fill: false, + borderWidth: 0.5, + borderColor: 'rgb(174, 199, 232)', + backgroundColor: 'rgb(174, 199, 232)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + type: 'line', + label: 'Used', + data: data.used, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180)', + backgroundColor: 'rgba(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + type: 'bar', + label: 'Major GC', + data: data.fgcTime, + borderWidth: 1, + borderColor: 'rgb(255, 42, 0)', + backgroundColor: 'rgba(255, 42, 0, 0.3)', + // pointRadius: 0, + // pointHoverRadius: 3, + yAxisID: 'y-axis-2' + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Heap Usage' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + id: 'y-axis-1', + display: true, + position: 'left', + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }, + { + id: 'y-axis-2', + display: true, + position: 'right', + scaleLabel: { + display: true, + labelString: 'Full GC (ms)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_HEAP); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-non-heap-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-non-heap-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-non-heap-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-non-heap-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-non-heap-chart-container.component.html new file mode 100644 index 000000000000..e908e6f83fb3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-non-heap-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Non Heap Usage
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-non-heap-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-non-heap-chart-container.component.ts new file mode 100644 index 000000000000..6349ebeb54cd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-jvm-non-heap-chart-container.component.ts @@ -0,0 +1,282 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { AgentMemoryChartDataService } from './agent-memory-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-jvm-non-heap-chart-container', + templateUrl: './agent-jvm-non-heap-chart-container.component.html', + styleUrls: ['./agent-jvm-non-heap-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentJVMNonHeapChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentMemoryChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected setChartConfig(data: {[key: string]: any}): void { + this.chartConfig = { + type: 'bar', + dataConfig: this.makeDataOption(data), + elseConfig: this.makeNormalOption(data), + isDataEmpty: this.isDataEmpty(data) + }; + this.changeDetector.detectChanges(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const usedArr = []; + const fgcTimeArr = []; + const fgcCountArr = []; + + const xData = chartData.charts.x; + const gcOldTime = chartData.charts.y['JVM_GC_OLD_TIME']; + const gcOldCount = chartData.charts.y['JVM_GC_OLD_COUNT']; + const memoryUsed = chartData.charts.y['JVM_MEMORY_NON_HEAP_USED']; + const memoryMax = chartData.charts.y['JVM_MEMORY_NON_HEAP_MAX']; + const dataCount = xData.length; + + let totalSumGCTime = 0; + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if ( memoryMax.length === 0 ) { + continue; + } + maxArr.push(this.parseData(memoryMax[i][1])); + usedArr.push(this.parseData(memoryUsed[i][1])); + + const gcOldCountSumValue = gcOldCount[i][3]; + const gcOldTimeSumValue = gcOldTime[i][3]; + + if ( gcOldTimeSumValue > 0 ) { + totalSumGCTime += gcOldTimeSumValue; + } + if ( gcOldCountSumValue > 0 ) { + fgcTimeArr.push(totalSumGCTime); + fgcCountArr.push(gcOldCountSumValue); + totalSumGCTime = 0; + } else { + fgcTimeArr.push(0); + fgcCountArr.push(0); + } + } + return { + x: xArr, + max: maxArr, + used: usedArr, + fgcTime: fgcTimeArr, + fgcCount: fgcCountArr + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + type: 'line', + label: 'Max', + data: data.max, + fill: false, + borderWidth: 0.5, + borderColor: 'rgb(174, 199, 232)', + backgroundColor: 'rgb(174, 199, 232)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + type: 'line', + label: 'Used', + data: data.used, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180)', + backgroundColor: 'rgba(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + type: 'bar', + label: 'Major GC', + data: data.fgcTime, + borderWidth: 1, + borderColor: 'rgb(255, 42, 0)', + backgroundColor: 'rgba(255, 42, 0, 0.3)', + // pointRadius: 0, + // pointHoverRadius: 3, + yAxisID: 'y-axis-2' + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Heap Usage' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: any[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + id: 'y-axis-1', + display: true, + position: 'left', + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }, + { + id: 'y-axis-2', + display: true, + position: 'right', + scaleLabel: { + display: true, + labelString: 'Full GC (ms)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_NON_HEAP); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component.html new file mode 100644 index 000000000000..08c6f6f0da5d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Mapped Buffer Count
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component.ts new file mode 100644 index 000000000000..ee07f7dcc86d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component.ts @@ -0,0 +1,171 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { AgentDirectBufferChartDataService } from './agent-direct-buffer-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-mapped-buffer-count-chart-container', + templateUrl: './agent-mapped-buffer-count-chart-container.component.html', + styleUrls: ['./agent-mapped-buffer-count-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentMappedBufferCountChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentDirectBufferChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + mappedCount: data.charts.y['MAPPED_COUNT'].map((arr: number[]) => this.parseData(arr[2])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + type: 'line', + label: 'Mapped Buffer Count', + data: data.mappedCount, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180, 0.4)', + backgroundColor: 'rgb(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Mapped Buffer Count' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : value.yLabel}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Buffer (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_MAPPED_BUFFER_COUNT); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component.html new file mode 100644 index 000000000000..59a32928a273 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Mapped Buffer Memory
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component.ts new file mode 100644 index 000000000000..8cb754a9ad1e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component.ts @@ -0,0 +1,187 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { AgentDirectBufferChartDataService } from './agent-direct-buffer-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-mapped-buffer-memory-chart-container', + templateUrl: './agent-mapped-buffer-memory-chart-container.component.html', + styleUrls: ['./agent-mapped-buffer-memory-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentMappedBufferMemoryChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentDirectBufferChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + mappedMemoryUsed: data.charts.y['MAPPED_MEMORY_USED'].map((arr: number[]) => this.parseData(arr[2])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + type: 'line', + label: 'Mapped Buffer Memory', + data: data.mappedMemoryUsed, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180, 0.4)', + backgroundColor: 'rgb(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Mapped Buffer Memory' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_MAPPED_BUFFER_MEMORY); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-memory-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-memory-chart-data.service.ts new file mode 100644 index 000000000000..a28da256264d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-memory-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class AgentMemoryChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/jvmGc/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component.html new file mode 100644 index 000000000000..b62d6fb4a1a2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Open File Descriptor
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component.ts new file mode 100644 index 000000000000..7b5730252ac0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component.ts @@ -0,0 +1,171 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { AgentOpenFileDescriptorChartDataService } from './agent-open-file-descriptor-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-open-file-descriptor-chart-container', + templateUrl: './agent-open-file-descriptor-chart-container.component.html', + styleUrls: ['./agent-open-file-descriptor-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentOpenFileDescriptorChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentOpenFileDescriptorChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + openFileDescriptorCount: data.charts.y['OPEN_FILE_DESCRIPTOR_COUNT'].map((arr: number[]) => this.parseData(arr[2])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + type: 'line', + label: 'Open File Descriptor', + data: data.openFileDescriptorCount, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180, 0.4)', + backgroundColor: 'rgb(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Open File Descriptor' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : value.yLabel}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'File Descriptor (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_OPEN_FILE_DESCRIPTOR); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-data.service.ts new file mode 100644 index 000000000000..b3de4039e22e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-open-file-descriptor-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class AgentOpenFileDescriptorChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/fileDescriptor/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-container.component.html new file mode 100644 index 000000000000..971df60336df --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Response Time
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-container.component.ts new file mode 100644 index 000000000000..2f2df851c60c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-container.component.ts @@ -0,0 +1,214 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { AgentResponseTimeChartDataService } from './agent-response-time-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-response-time-chart-container', + templateUrl: './agent-response-time-chart-container.component.html', + styleUrls: ['./agent-response-time-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentResponseTimeChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentResponseTimeChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const avgArr = []; + const maxArr = []; + + const xData = chartData.charts.x; + const responseAVG = chartData.charts.y['AVG']; + const responseMAX = chartData.charts.y['MAX']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if ( responseAVG.length === 0 ) { + continue; + } + avgArr.push(this.parseData(responseAVG[i][2])); + maxArr.push(this.parseData(responseMAX[i][1])); + } + return { + x: xArr, + avg: avgArr, + max: maxArr, + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Avg', + data: data.avg, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(44, 160, 44)', + backgroundColor: 'rgba(44, 160, 44, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.max, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(246, 145, 36)', + backgroundColor: 'rgba(246, 145, 36, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + } + ] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Response Time' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Response Time (ms)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + private convertWithUnit(value: number): string { + const unit = ['ms', 'sec', 'min']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_RESPONSE_TIME); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-data.service.ts new file mode 100644 index 000000000000..6b54b84b4003 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-response-time-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class AgentResponseTimeChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/responseTime/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-container.component.html new file mode 100644 index 000000000000..6252a5c933ff --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Transactions Per Second
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-container.component.ts new file mode 100644 index 000000000000..a0c4af7a8c64 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-container.component.ts @@ -0,0 +1,251 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { AgentTPSChartDataService } from './agent-tps-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-agent-tps-chart-container', + templateUrl: './agent-tps-chart-container.component.html', + styleUrls: ['./agent-tps-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentTPSChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: AgentTPSChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 10, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected parseData(data: number): number | null { + return data < 0 ? null : Number(data.toFixed(2)); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const tpsSCArr = []; + const tpsSNArr = []; + const tpsUCArr = []; + const tpsUNArr = []; + const tpsTArr = []; + + const xData = chartData.charts.x; + const tpsSC = chartData.charts.y['TPS_SAMPLED_CONTINUATION']; + const tpsSN = chartData.charts.y['TPS_SAMPLED_NEW']; + const tpsUC = chartData.charts.y['TPS_UNSAMPLED_CONTINUATION']; + const tpsUN = chartData.charts.y['TPS_UNSAMPLED_NEW']; + const tpsT = chartData.charts.y['TPS_TOTAL']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if ( tpsSC.length === 0 ) { + continue; + } + tpsSCArr.push(this.parseData(tpsSC[i][2])); + tpsSNArr.push(this.parseData(tpsSN[i][2])); + tpsUCArr.push(this.parseData(tpsUC[i][2])); + tpsUNArr.push(this.parseData(tpsUN[i][2])); + if ( tpsT ) { + tpsTArr.push(this.parseData(tpsT[i][2])); + } else { + tpsTArr.push(this.parseData((tpsSC[i][2] + tpsSN[i][2] + tpsUC[i][2] + tpsUN[i][2]))); + } + } + return { + x: xArr, + tpsSC: tpsSCArr, + tpsSN: tpsSNArr, + tpsUC: tpsUCArr, + tpsUN: tpsUNArr, + tpsT: tpsTArr + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'S.C', + data: data.tpsSC, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(214, 141, 8)', + backgroundColor: 'rgba(214, 141, 8, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'S.N', + data: data.tpsSN, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(252, 178, 65)', + backgroundColor: 'rgba(252, 178, 65, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'U.C', + data: data.tpsUC, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(90, 103, 166)', + backgroundColor: 'rgba(90, 103, 166, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'U.N', + data: data.tpsUN, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(160, 153, 255)', + backgroundColor: 'rgba(160, 153, 255, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Total', + data: data.tpsT, + fill: false, + borderWidth: 0.5, + // borderColor: 'rgb(31, 119, 180)', + // backgroundColor: 'rgba(31, 119, 180, 0.4)', + borderColor: 'rgba(31, 119, 180, 0)', + backgroundColor: 'rgba(255, 255, 255, 0)', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'TPS' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : value.yLabel.toFixed(1)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + stacked: true, + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + stacked: true, + display: true, + scaleLabel: { + display: true, + labelString: 'Transaction (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (value: number): number => { + const label = Number.isInteger(value) ? value : Number(value.toFixed(1)); + return label; + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.AGENT_TPS); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-data.service.ts new file mode 100644 index 000000000000..cf9ab9c7a108 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/agent-tps-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class AgentTPSChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/transaction/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-container.component.html new file mode 100644 index 000000000000..15084f4f991a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Active Thread
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-container.component.ts new file mode 100644 index 000000000000..518db2213b87 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-container.component.ts @@ -0,0 +1,237 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationActiveThreadChartDataService } from './application-active-thread-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-active-thread-chart-container', + templateUrl: './application-active-thread-chart-container.component.html', + styleUrls: ['./application-active-thread-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationActiveThreadChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationActiveThreadChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 10, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const minArr = []; + const avgArr = []; + const maxAgentIdArr = []; + const minAgentIdArr = []; + + const xData = chartData.charts.x; + const activeTraceCount = chartData.charts.y['ACTIVE_TRACE_COUNT']; + const dataCount = xData.length; + + for (let i = 0; i < dataCount; i++) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if (activeTraceCount[i]) { + minArr.push(this.parseData(activeTraceCount[i][0])); + minAgentIdArr.push(activeTraceCount[i][1]); + maxArr.push(this.parseData(activeTraceCount[i][2])); + maxAgentIdArr.push(activeTraceCount[i][3]); + avgArr.push(this.parseData(activeTraceCount[i][4])); + } + } + return { + x: xArr, + maxArr, + minArr, + avgArr, + minAgentIdArr, + maxAgentIdArr, + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]) => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel) + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Active Thread (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_ACTIVE_THREAD); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-data.service.ts new file mode 100644 index 000000000000..6d62567d73dc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-active-thread-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForApplicationChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class ApplicationActiveThreadChartDataService implements IChartDataService { + private requestURL = 'getApplicationStat/activeTrace/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForApplicationChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-cpu-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-cpu-chart-data.service.ts new file mode 100644 index 000000000000..8ba0b3875e25 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-cpu-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForApplicationChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class ApplicationCPUChartDataService implements IChartDataService { + private requestURL = 'getApplicationStat/cpuLoad/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForApplicationChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-container.component.html new file mode 100644 index 000000000000..3bd19ce8b449 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-container.component.html @@ -0,0 +1,20 @@ +
    +
    +

    Data Source

    + +
    + + + + + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-container.component.ts new file mode 100644 index 000000000000..d458283ff423 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-container.component.ts @@ -0,0 +1,227 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationDataSourceChartDataService, IApplicationDataSourceChart } from './application-data-source-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; + +@Component({ + selector: 'pp-application-data-source-chart-container', + templateUrl: './application-data-source-chart-container.component.html', + styleUrls: ['./application-data-source-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationDataSourceChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + sourceDataArr: {[key: string]: any}[]; + + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationDataSourceChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 10, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected getChartData(range: number[]): void { + this.chartDataService.getData(range) + .subscribe( + (data: IApplicationDataSourceChart[] | AjaxException) => { + if (this.ajaxExceptionCheckerService.isAjaxException(data)) { + this.setErrObj(data); + } else { + this.chartData = data; + this.sourceDataArr = this.makeChartData(data); + this.setChartConfig(this.sourceDataArr[0]); + } + }, + (err) => { + this.setErrObj(); + } + ); + } + + onSourceDataSelected(index: number): void { + this.setChartConfig(this.sourceDataArr[index]); + } + + protected makeChartData(chartDataArr: IApplicationDataSourceChart[]): {[key: string]: any}[] { + return chartDataArr.map((chartData: IApplicationDataSourceChart) => { + return { + x: chartData.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + minArr: chartData.charts.y['ACTIVE_CONNECTION_SIZE'].map((arr: any[]) => this.parseData(arr[0])), + minAgentIdArr: chartData.charts.y['ACTIVE_CONNECTION_SIZE'].map((arr: any[]) => arr[1]), + maxArr: chartData.charts.y['ACTIVE_CONNECTION_SIZE'].map((arr: any[]) => this.parseData(arr[2])), + maxAgentIdArr: chartData.charts.y['ACTIVE_CONNECTION_SIZE'].map((arr: any[]) => arr[3]), + avgArr: chartData.charts.y['ACTIVE_CONNECTION_SIZE'].map((arr: any[]) => this.parseData(arr[4])), + jdbcUrl: chartData.jdbcUrl, + serviceType: chartData.serviceType + }; + }); + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]) => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : value.yLabel + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Connection (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + max: this.defaultYMax, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_DATA_SOURCE); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-data.service.ts new file mode 100644 index 000000000000..02696dc879db --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-data.service.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForApplicationChartData } from 'app/core/utils/chart-data-param-maker'; + +export interface IApplicationDataSourceChart extends IChartDataFromServer { + jdbcUrl: string; + serviceType: string; +} + +@Injectable() +export class ApplicationDataSourceChartDataService implements IChartDataService { + private requestURL = 'getApplicationStat/dataSource/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForApplicationChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-soucelist.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-soucelist.component.css new file mode 100644 index 000000000000..6ef246b6f6fc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-soucelist.component.css @@ -0,0 +1,55 @@ +.l-sourcelist-wrapper { + background-color: #fff; + font-size: 12px; + padding: 10px; +} +.l-sourcelist-title { + background-color: #f6f8fb; + border-top: 1px solid #ddd; + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + padding: 10px; +} +.l-source-data-list { + border: 1px solid #ddd; +} +.l-source-data-list-item { + cursor: pointer; + color: #ddd; + display: flex; + align-items: center; +} +.l-source-data-list-item:hover { + background-color: #ddd; + color: #fff; +} +.l-selected-item { + color: #000; + font-weight: 600; +} +.l-selected-item:hover { + background-color: #fff; + color: #000; +} +.l-source-data-list-item .fas { + width: 7%; + text-align: center; +} +.l-source-data-wrapper { + display: flex; + justify-content: space-evenly; + align-items: center; + border-left: 1px solid #ddd; + padding: 7px 0 7px 7px; + width: 93%; +} +.l-service-type-wrapper { + display: inline-block; + width: 10%; + overflow-wrap: break-word; +} +.l-jdbc-url-wrapper { + display: inline-block; + width: 85%; + overflow-wrap: break-word; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-soucelist.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-soucelist.component.html new file mode 100644 index 000000000000..7cf145ba3eed --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-soucelist.component.html @@ -0,0 +1,14 @@ +
    +

    Data Source List

    +
      +
    • + +
      + {{sourceData.serviceType}} + {{sourceData.jdbcUrl}} +
      +
    • +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-soucelist.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-soucelist.component.ts new file mode 100644 index 000000000000..bbd9bb7849c5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-data-source-chart-soucelist.component.ts @@ -0,0 +1,45 @@ +import { Component, OnInit, OnChanges, Input, Output, EventEmitter, SimpleChanges } from '@angular/core'; + +@Component({ + selector: 'pp-application-data-source-chart-sourcelist', + templateUrl: './application-data-source-chart-soucelist.component.html', + styleUrls: ['./application-data-source-chart-soucelist.component.css'] +}) +export class ApplicationDataSourceChartSourcelistComponent implements OnInit, OnChanges { + @Input() isDataEmpty: boolean; + @Input() sourceDataArr: { [key: string]: any }[]; + @Output() outSourceDataSelected: EventEmitter = new EventEmitter(); + + private selectedIndex = 0; + + constructor() {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + Object.keys(changes).map((propName: string) => { + switch (propName) { + case 'sourceDataArr': + this.initSelectedIndex(); + break; + } + }); + } + + private initSelectedIndex(): void { + this.selectedIndex = 0; + } + + isItemSelected(index: number): boolean { + return index === this.selectedIndex; + } + + private selectSource(index: number): void { + this.selectedIndex = index; + this.outSourceDataSelected.emit(this.selectedIndex); + } + + onClickSourceList(index: number): void { + if (index !== this.selectedIndex) { + this.selectSource(index); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-chart-data.service.ts new file mode 100644 index 000000000000..39904b93c3bd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForApplicationChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class ApplicationDirectBufferChartDataService implements IChartDataService { + private requestURL = 'getApplicationStat/directBuffer/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForApplicationChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component.html new file mode 100644 index 000000000000..3f86665e24aa --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Direct Buffer Count
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component.ts new file mode 100644 index 000000000000..a0b27c55ca0c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component.ts @@ -0,0 +1,201 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationDirectBufferChartDataService } from './application-direct-buffer-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-direct-buffer-count-chart-container', + templateUrl: './application-direct-buffer-count-chart-container.component.html', + styleUrls: ['./application-direct-buffer-count-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationDirectBufferCountChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationDirectBufferChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + minArr: data.charts.y['DIRECT_COUNT'].map((arr: any[]) => this.parseData(arr[0])), + minAgentIdArr: data.charts.y['DIRECT_COUNT'].map((arr: any[]) => arr[1]), + maxArr: data.charts.y['DIRECT_COUNT'].map((arr: any[]) => this.parseData(arr[2])), + maxAgentIdArr: data.charts.y['DIRECT_COUNT'].map((arr: any[]) => arr[3]), + avgArr: data.charts.y['DIRECT_COUNT'].map((arr: any[]) => this.parseData(arr[4])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Direct Buffer Count' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : value.yLabel + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Buffer (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_DIRECT_BUFFER_COUNT); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component.html new file mode 100644 index 000000000000..67cc6afb6bc1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Direct Buffer Memory
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component.ts new file mode 100644 index 000000000000..354ea3fc18ac --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component.ts @@ -0,0 +1,217 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationDirectBufferChartDataService } from './application-direct-buffer-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-direct-buffer-memory-chart-container', + templateUrl: './application-direct-buffer-memory-chart-container.component.html', + styleUrls: ['./application-direct-buffer-memory-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationDirectBufferMemoryChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationDirectBufferChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + minArr: data.charts.y['DIRECT_MEMORY_USED'].map((arr: any[]) => this.parseData(arr[0])), + minAgentIdArr: data.charts.y['DIRECT_MEMORY_USED'].map((arr: any[]) => arr[1]), + maxArr: data.charts.y['DIRECT_MEMORY_USED'].map((arr: any[]) => this.parseData(arr[2])), + maxAgentIdArr: data.charts.y['DIRECT_MEMORY_USED'].map((arr: any[]) => arr[3]), + avgArr: data.charts.y['DIRECT_MEMORY_USED'].map((arr: any[]) => this.parseData(arr[4])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Direct Buffer Memory' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel) + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_DIRECT_BUFFER_MEMORY); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-cpu-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-cpu-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-cpu-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-cpu-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-cpu-chart-container.component.html new file mode 100644 index 000000000000..d2b8171c754f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-cpu-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    JVM CPU Usage
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-cpu-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-cpu-chart-container.component.ts new file mode 100644 index 000000000000..3a974a0b35a9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-cpu-chart-container.component.ts @@ -0,0 +1,224 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationCPUChartDataService } from './application-cpu-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-jvm-cpu-chart-container', + templateUrl: './application-jvm-cpu-chart-container.component.html', + styleUrls: ['./application-jvm-cpu-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationJVMCPUChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationCPUChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const minArr = []; + const avgArr = []; + const maxAgentIdArr = []; + const minAgentIdArr = []; + + const xData = chartData.charts.x; + const cpuLoadJVM = chartData.charts.y['CPU_LOAD_JVM']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if (cpuLoadJVM[i]) { + minArr.push(this.parseData(cpuLoadJVM[i][0])); + minAgentIdArr.push(cpuLoadJVM[i][1]); + maxArr.push(this.parseData(cpuLoadJVM[i][2])); + maxAgentIdArr.push(cpuLoadJVM[i][3]); + avgArr.push(this.parseData(cpuLoadJVM[i][4])); + } + } + return { + x: xArr, + maxArr, + minArr, + avgArr, + minAgentIdArr, + maxAgentIdArr, + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]) => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : value.yLabel + `% ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'CPU Usage (%)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return `${label}%`; + }, + min: 0, + max: this.defaultYMax, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_JVM_CPU_USAGE); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-heap-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-heap-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-heap-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-heap-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-heap-chart-container.component.html new file mode 100644 index 000000000000..211d0ea16cd6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-heap-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Heap Usage
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-heap-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-heap-chart-container.component.ts new file mode 100644 index 000000000000..ff9f6a1d0efe --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-heap-chart-container.component.ts @@ -0,0 +1,239 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationMemoryChartDataService } from './application-memory-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-jvm-heap-chart-container', + templateUrl: './application-jvm-heap-chart-container.component.html', + styleUrls: ['./application-jvm-heap-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationJVMHeapChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationMemoryChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100000, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const minArr = []; + const avgArr = []; + const maxAgentIdArr = []; + const minAgentIdArr = []; + + const xData = chartData.charts.x; + const memoryHeap = chartData.charts.y['MEMORY_HEAP']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if (memoryHeap[i]) { + minArr.push(this.parseData(memoryHeap[i][0])); + minAgentIdArr.push(memoryHeap[i][1]); + maxArr.push(this.parseData(memoryHeap[i][2])); + maxAgentIdArr.push(memoryHeap[i][3]); + avgArr.push(this.parseData(memoryHeap[i][4])); + } + } + + return { + x: xArr, + maxArr, + minArr, + avgArr, + minAgentIdArr, + maxAgentIdArr, + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]) => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel) + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_HEAP); + } +} + diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-non-heap-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-non-heap-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-non-heap-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-non-heap-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-non-heap-chart-container.component.html new file mode 100644 index 000000000000..e908e6f83fb3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-non-heap-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Non Heap Usage
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-non-heap-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-non-heap-chart-container.component.ts new file mode 100644 index 000000000000..4c8e5625c745 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-jvm-non-heap-chart-container.component.ts @@ -0,0 +1,237 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationMemoryChartDataService } from './application-memory-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-jvm-non-heap-chart-container', + templateUrl: './application-jvm-non-heap-chart-container.component.html', + styleUrls: ['./application-jvm-non-heap-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationJVMNonHeapChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationMemoryChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100000, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const minArr = []; + const avgArr = []; + const maxAgentIdArr = []; + const minAgentIdArr = []; + + const xData = chartData.charts.x; + const memoryNonHeap = chartData.charts.y['MEMORY_NON_HEAP']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if (memoryNonHeap[i]) { + minArr.push(this.parseData(memoryNonHeap[i][0])); + minAgentIdArr.push(memoryNonHeap[i][1]); + maxArr.push(this.parseData(memoryNonHeap[i][2])); + maxAgentIdArr.push(memoryNonHeap[i][3]); + avgArr.push(this.parseData(memoryNonHeap[i][4])); + } + } + return { + x: xArr, + maxArr, + minArr, + avgArr, + minAgentIdArr, + maxAgentIdArr, + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]) => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel) + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_NON_HEAP); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component.html new file mode 100644 index 000000000000..879857bea4b6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Mapped Buffer Count
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component.ts new file mode 100644 index 000000000000..8538ca9bbdf9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component.ts @@ -0,0 +1,201 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationDirectBufferChartDataService } from './application-direct-buffer-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-mapped-buffer-count-chart-container', + templateUrl: './application-mapped-buffer-count-chart-container.component.html', + styleUrls: ['./application-mapped-buffer-count-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationMappedBufferCountChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationDirectBufferChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + minArr: data.charts.y['MAPPED_COUNT'].map((arr: any[]) => this.parseData(arr[0])), + minAgentIdArr: data.charts.y['MAPPED_COUNT'].map((arr: any[]) => arr[1]), + maxArr: data.charts.y['MAPPED_COUNT'].map((arr: any[]) => this.parseData(arr[2])), + maxAgentIdArr: data.charts.y['MAPPED_COUNT'].map((arr: any[]) => arr[3]), + avgArr: data.charts.y['MAPPED_COUNT'].map((arr: any[]) => this.parseData(arr[4])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Mapped Buffer Count' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : value.yLabel + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Buffer (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_MAPPED_BUFFER_COUNT); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component.html new file mode 100644 index 000000000000..afb8bb19c95f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Mapped Buffer Memory
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component.ts new file mode 100644 index 000000000000..1b77c92b5279 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component.ts @@ -0,0 +1,217 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationDirectBufferChartDataService } from './application-direct-buffer-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-mapped-buffer-memory-chart-container', + templateUrl: './application-mapped-buffer-memory-chart-container.component.html', + styleUrls: ['./application-mapped-buffer-memory-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationMappedBufferMemoryChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationDirectBufferChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + minArr: data.charts.y['MAPPED_MEMORY_USED'].map((arr: any[]) => this.parseData(arr[0])), + minAgentIdArr: data.charts.y['MAPPED_MEMORY_USED'].map((arr: any[]) => arr[1]), + maxArr: data.charts.y['MAPPED_MEMORY_USED'].map((arr: any[]) => this.parseData(arr[2])), + maxAgentIdArr: data.charts.y['MAPPED_MEMORY_USED'].map((arr: any[]) => arr[3]), + avgArr: data.charts.y['MAPPED_MEMORY_USED'].map((arr: any[]) => this.parseData(arr[4])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Mapped Buffer Memory' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel) + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_MAPPED_BUFFER_MEMORY); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-memory-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-memory-chart-data.service.ts new file mode 100644 index 000000000000..45aec21ffb32 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-memory-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForApplicationChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class ApplicationMemoryChartDataService implements IChartDataService { + private requestURL = 'getApplicationStat/memory/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForApplicationChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component.html new file mode 100644 index 000000000000..b62d6fb4a1a2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Open File Descriptor
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component.ts new file mode 100644 index 000000000000..f667613a5b7b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component.ts @@ -0,0 +1,201 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationOpenFileDescriptorChartDataService } from './application-open-file-descriptor-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-open-file-descriptor-chart-container', + templateUrl: './application-open-file-descriptor-chart-container.component.html', + styleUrls: ['./application-open-file-descriptor-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationOpenFileDescriptorChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationOpenFileDescriptorChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(data: IChartDataFromServer): {[key: string]: any} { + return { + x: data.charts.x.map((time: number) => moment(time).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(time).tz(this.timezone).format(this.dateFormat[1])), + minArr: data.charts.y['OPEN_FILE_DESCRIPTOR_COUNT'].map((arr: any[]) => this.parseData(arr[0])), + minAgentIdArr: data.charts.y['OPEN_FILE_DESCRIPTOR_COUNT'].map((arr: any[]) => arr[1]), + maxArr: data.charts.y['OPEN_FILE_DESCRIPTOR_COUNT'].map((arr: any[]) => this.parseData(arr[2])), + maxAgentIdArr: data.charts.y['OPEN_FILE_DESCRIPTOR_COUNT'].map((arr: any[]) => arr[3]), + avgArr: data.charts.y['OPEN_FILE_DESCRIPTOR_COUNT'].map((arr: any[]) => this.parseData(arr[4])), + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false, + text: 'Open File Descriptor' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : value.yLabel + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'File Descriptor (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_OPEN_FILE_DESCRIPTOR); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-data.service.ts new file mode 100644 index 000000000000..61fd5a42f510 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-open-file-descriptor-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForApplicationChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class ApplicationOpenFileDescriptorChartDataService implements IChartDataService { + private requestURL = 'getApplicationStat/fileDescriptor/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForApplicationChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-container.component.html new file mode 100644 index 000000000000..971df60336df --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Response Time
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-container.component.ts new file mode 100644 index 000000000000..60f92a3025d0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-container.component.ts @@ -0,0 +1,237 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationResponseTimeChartDataService } from './application-response-time-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-response-time-chart-container', + templateUrl: './application-response-time-chart-container.component.html', + styleUrls: ['./application-response-time-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationResponseTimeChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationResponseTimeChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const minArr = []; + const avgArr = []; + const maxAgentIdArr = []; + const minAgentIdArr = []; + + const xData = chartData.charts.x; + const responseTime = chartData.charts.y['RESPONSE_TIME']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if (responseTime[i]) { + minArr.push(this.parseData(responseTime[i][0])); + minAgentIdArr.push(responseTime[i][1]); + maxArr.push(this.parseData(responseTime[i][2])); + maxAgentIdArr.push(responseTime[i][3]); + avgArr.push(this.parseData(responseTime[i][4])); + } + } + return { + x: xArr, + maxArr: maxArr, + minArr: minArr, + avgArr: avgArr, + minAgentIdArr, + maxAgentIdArr, + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]) => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel) + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Response Time (ms)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + private convertWithUnit(value: number): string { + const unit = ['ms', 'sec', 'min']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_RESPONSE_TIME); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-data.service.ts new file mode 100644 index 000000000000..4d02852df4b2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-response-time-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForApplicationChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class ApplicationResponseTimeChartDataService implements IChartDataService { + private requestURL = 'getApplicationStat/responseTime/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForApplicationChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-system-cpu-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-system-cpu-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-system-cpu-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-system-cpu-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-system-cpu-chart-container.component.html new file mode 100644 index 000000000000..b778cd386178 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-system-cpu-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    System CPU Usage
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-system-cpu-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-system-cpu-chart-container.component.ts new file mode 100644 index 000000000000..9543c7ea8ea9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-system-cpu-chart-container.component.ts @@ -0,0 +1,224 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationCPUChartDataService } from './application-cpu-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-system-cpu-chart-container', + templateUrl: './application-system-cpu-chart-container.component.html', + styleUrls: ['./application-system-cpu-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationSystemCPUChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationCPUChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const minArr = []; + const avgArr = []; + const maxAgentIdArr = []; + const minAgentIdArr = []; + + const xData = chartData.charts.x; + const cpuLoadSystem = chartData.charts.y['CPU_LOAD_SYSTEM']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if (cpuLoadSystem[i]) { + minArr.push(this.parseData(cpuLoadSystem[i][0])); + minAgentIdArr.push(cpuLoadSystem[i][1]); + maxArr.push(this.parseData(cpuLoadSystem[i][2])); + maxAgentIdArr.push(cpuLoadSystem[i][3]); + avgArr.push(this.parseData(cpuLoadSystem[i][4])); + } + } + return { + x: xArr, + maxArr: maxArr, + minArr: minArr, + avgArr: avgArr, + minAgentIdArr, + maxAgentIdArr, + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]) => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : value.yLabel + `% ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'CPU Usage (%)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return `${label}%`; + }, + min: 0, + max: this.defaultYMax, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_SYSTEM_CPU_USAGE); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-container.component.css new file mode 100644 index 000000000000..7e076f488d6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-container.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + width: calc(50% - 20px); + margin: 10px; +} +.l-content-item { + width: 100%; + margin: 0px; +} +.l-title-group { + height:34px; + font-size:13px; + font-weight:600; + padding:0 20px; + color:#333; + display: flex; + align-items: center; + justify-content:space-between; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color:#a8acb5; + cursor:pointer; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-container.component.html new file mode 100644 index 000000000000..6252a5c933ff --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-container.component.html @@ -0,0 +1,10 @@ +
    +
    Transactions Per Second
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-container.component.ts new file mode 100644 index 000000000000..b78553df5255 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-container.component.ts @@ -0,0 +1,237 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { ApplicationTPSChartDataService } from './application-tps-chart-data.service'; +import { HELP_VIEWER_LIST } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { InspectorChartContainer } from 'app/core/components/inspector-chart/inspector-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-application-tps-chart-container', + templateUrl: './application-tps-chart-container.component.html', + styleUrls: ['./application-tps-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationTPSChartContainerComponent extends InspectorChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: ApplicationTPSChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + analyticsService: AnalyticsService, + dynamicPopupService: DynamicPopupService + ) { + super( + 10, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + analyticsService, + dynamicPopupService + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initTimezoneAndDateFormat(); + this.initChartData(); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const minArr = []; + const avgArr = []; + const maxAgentIdArr = []; + const minAgentIdArr = []; + + const xData = chartData.charts.x; + const transactionCount = chartData.charts.y['TRANSACTION_COUNT']; + const dataCount = xData.length; + + for (let i = 0; i < dataCount; i++) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if (transactionCount[i]) { + minArr.push(this.parseData(transactionCount[i][0])); + minAgentIdArr.push(transactionCount[i][1]); + maxArr.push(this.parseData(transactionCount[i][2])); + maxAgentIdArr.push(transactionCount[i][3]); + avgArr.push(this.parseData(transactionCount[i][4])); + } + } + return { + x: xArr, + maxArr: maxArr, + minArr: minArr, + avgArr: avgArr, + minAgentIdArr, + maxAgentIdArr, + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'Min', + data: data.minArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#66B2FF', + backgroundColor: '#66B2FF', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Avg', + data: data.avgArr, + fill: false, + borderWidth: 1.5, + borderColor: '#4C0099', + backgroundColor: '#4C0099', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'Max', + data: data.maxArr, + fill: false, + borderDash: [2, 2], + borderWidth: 1.5, + borderColor: '#0000CC', + backgroundColor: '#0000CC', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + title: { + display: false + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]) => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + const label = d.datasets[value.datasetIndex].label; + const index = value.index; + + return `${label}: ${isNaN(value.yLabel) ? `-` : value.yLabel.toFixed(1) + ` ` + this.getAgentId(data.minAgentIdArr, data.maxAgentIdArr, label, index)}`; + } + } + }, + hover: { + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (!this.isDataEmpty(data)) { + this.storeHelperService.dispatch(new Actions.ChangeHoverOnInspectorCharts({ + index: event.type === 'mouseout' ? -1 : elements[0]._index, + offsetX: event.offsetX, + offsetY: event.offsetY + })); + } + }, + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 4, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'Transaction (count)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 50, + padding: 10 + } + } + }; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(1)); + return result + unit[index]; + } + + private getAgentId(minAgentIdArr: string[], maxAgentIdArr: string[], label: string, index: number): string { + return label === 'Avg' ? '' : `(${label === 'Min' ? minAgentIdArr[index] : maxAgentIdArr[index]})`; + } + + onShowHelp($event: MouseEvent): void { + super.onShowHelp($event, HELP_VIEWER_LIST.APPLICATION_TPS); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-data.service.ts new file mode 100644 index 000000000000..9395254945b9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/application-tps-chart-data.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForApplicationChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class ApplicationTPSChartDataService implements IChartDataService { + private requestURL = 'getApplicationStat/transaction/chart.pinpoint'; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + return this.http.get(this.requestURL, + getParamForApplicationChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(), range) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/chart-data.service.ts new file mode 100644 index 000000000000..037c87659b71 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/chart-data.service.ts @@ -0,0 +1,17 @@ +import { Observable } from 'rxjs'; + +export interface IChartDataFromServer { + charts: { + schema: { + [key: string]: string[] | string; + }, + x: number[]; + y: { + [key: string]: number[][]; + } + }; +} + +export interface IChartDataService { + getData(range: number[]): Observable; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/index.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/index.ts new file mode 100644 index 000000000000..ca9686e45f75 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/index.ts @@ -0,0 +1,153 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { RetryComponent } from './retry.component'; +import { NoDataComponent } from './no-data.component'; +import { InspectorChartComponent } from './inspector-chart.component'; +import { AgentActiveThreadChartContainerComponent } from './agent-active-thread-chart-container.component'; +import { AgentCPUChartContainerComponent } from './agent-cpu-chart-container.component'; +import { AgentDataSourceChartContainerComponent } from './agent-data-source-chart-container.component'; +import { AgentJVMHeapChartContainerComponent } from './agent-jvm-heap-chart-container.component'; +import { AgentJVMNonHeapChartContainerComponent } from './agent-jvm-non-heap-chart-container.component'; +import { AgentResponseTimeChartContainerComponent } from './agent-response-time-chart-container.component'; +import { AgentTPSChartContainerComponent } from './agent-tps-chart-container.component'; +import { AgentDataSourceChartInfotableComponent } from './agent-data-source-chart-infotable.component'; +import { AgentDataSourceChartSelectSourceComponent } from './agent-data-source-chart-select-source.component'; +import { AgentOpenFileDescriptorChartContainerComponent } from 'app/core/components/inspector-chart/agent-open-file-descriptor-chart-container.component'; +import { AgentDirectBufferCountChartContainerComponent } from 'app/core/components/inspector-chart/agent-direct-buffer-count-chart-container.component'; +import { AgentDirectBufferMemoryChartContainerComponent } from 'app/core/components/inspector-chart/agent-direct-buffer-memory-chart-container.component'; +import { AgentMappedBufferCountChartContainerComponent } from 'app/core/components/inspector-chart/agent-mapped-buffer-count-chart-container.component'; +import { AgentMappedBufferMemoryChartContainerComponent } from 'app/core/components/inspector-chart/agent-mapped-buffer-memory-chart-container.component'; +import { ApplicationActiveThreadChartContainerComponent } from './application-active-thread-chart-container.component'; +import { ApplicationJVMCPUChartContainerComponent } from './application-jvm-cpu-chart-container.component'; +import { ApplicationJVMHeapChartContainerComponent } from './application-jvm-heap-chart-container.component'; +import { ApplicationJVMNonHeapChartContainerComponent } from './application-jvm-non-heap-chart-container.component'; +import { ApplicationResponseTimeChartContainerComponent } from './application-response-time-chart-container.component'; +import { ApplicationSystemCPUChartContainerComponent } from './application-system-cpu-chart-container.component'; +import { ApplicationDataSourceChartContainerComponent } from 'app/core/components/inspector-chart/application-data-source-chart-container.component'; +import { ApplicationTPSChartContainerComponent } from './application-tps-chart-container.component'; +import { ApplicationOpenFileDescriptorChartContainerComponent } from 'app/core/components/inspector-chart/application-open-file-descriptor-chart-container.component'; +import { ApplicationDataSourceChartSourcelistComponent } from './application-data-source-chart-soucelist.component'; +import { ApplicationDirectBufferCountChartContainerComponent } from 'app/core/components/inspector-chart/application-direct-buffer-count-chart-container.component'; +import { ApplicationDirectBufferMemoryChartContainerComponent } from 'app/core/components/inspector-chart/application-direct-buffer-memory-chart-container.component'; +import { ApplicationMappedBufferCountChartContainerComponent } from 'app/core/components/inspector-chart/application-mapped-buffer-count-chart-container.component'; +import { ApplicationMappedBufferMemoryChartContainerComponent } from 'app/core/components/inspector-chart/application-mapped-buffer-memory-chart-container.component'; +import { TransactionViewJVMHeapChartContainerComponent } from './transaction-view-jvm-heap-chart-container.component'; +import { TransactionViewJVMNonHeapChartContainerComponent } from './transaction-view-jvm-non-heap-chart-container.component'; +import { TransactionViewCPUChartContainerComponent } from './transaction-view-cpu-chart-container.component'; + +import { AgentActiveThreadChartDataService } from './agent-active-thread-chart-data.service'; +import { AgentCPUChartDataService } from './agent-cpu-chart-data.service'; +import { AgentDataSourceChartDataService } from './agent-data-source-chart-data.service'; +import { AgentMemoryChartDataService } from './agent-memory-chart-data.service'; +import { AgentTPSChartDataService } from './agent-tps-chart-data.service'; +import { ApplicationCPUChartDataService } from './application-cpu-chart-data.service'; +import { ApplicationActiveThreadChartDataService } from './application-active-thread-chart-data.service'; +import { ApplicationDataSourceChartDataService } from './application-data-source-chart-data.service'; +import { ApplicationMemoryChartDataService } from './application-memory-chart-data.service'; +import { ApplicationTPSChartDataService } from './application-tps-chart-data.service'; +import { ApplicationResponseTimeChartDataService } from './application-response-time-chart-data.service'; +import { AgentResponseTimeChartDataService } from './agent-response-time-chart-data.service'; +import { TransactionViewMemoryChartDataService } from './transaction-view-memory-chart-data.service'; +import { TransactionViewCPUChartDataService } from './transaction-view-cpu-chart-data.service'; +import { AgentOpenFileDescriptorChartDataService } from 'app/core/components/inspector-chart/agent-open-file-descriptor-chart-data.service'; +import { ApplicationOpenFileDescriptorChartDataService } from 'app/core/components/inspector-chart/application-open-file-descriptor-chart-data.service'; +import { AgentDirectBufferChartDataService } from 'app/core/components/inspector-chart/agent-direct-buffer-chart-data.service'; +import { ApplicationDirectBufferChartDataService } from 'app/core/components/inspector-chart/application-direct-buffer-chart-data.service'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + RetryComponent, + NoDataComponent, + InspectorChartComponent, + AgentActiveThreadChartContainerComponent, + AgentCPUChartContainerComponent, + AgentDataSourceChartContainerComponent, + AgentJVMHeapChartContainerComponent, + AgentJVMNonHeapChartContainerComponent, + AgentResponseTimeChartContainerComponent, + AgentTPSChartContainerComponent, + ApplicationActiveThreadChartContainerComponent, + ApplicationJVMCPUChartContainerComponent, + ApplicationJVMHeapChartContainerComponent, + ApplicationJVMNonHeapChartContainerComponent, + ApplicationResponseTimeChartContainerComponent, + ApplicationSystemCPUChartContainerComponent, + ApplicationTPSChartContainerComponent, + ApplicationDataSourceChartContainerComponent, + AgentDataSourceChartInfotableComponent, + AgentDataSourceChartSelectSourceComponent, + ApplicationDataSourceChartSourcelistComponent, + TransactionViewJVMHeapChartContainerComponent, + TransactionViewJVMNonHeapChartContainerComponent, + TransactionViewCPUChartContainerComponent, + AgentOpenFileDescriptorChartContainerComponent, + ApplicationOpenFileDescriptorChartContainerComponent, + AgentDirectBufferCountChartContainerComponent, + AgentDirectBufferMemoryChartContainerComponent, + AgentMappedBufferCountChartContainerComponent, + AgentMappedBufferMemoryChartContainerComponent, + ApplicationDirectBufferCountChartContainerComponent, + ApplicationDirectBufferMemoryChartContainerComponent, + ApplicationMappedBufferCountChartContainerComponent, + ApplicationMappedBufferMemoryChartContainerComponent + ], + imports: [ + SharedModule, + HelpViewerPopupModule + ], + exports: [ + AgentActiveThreadChartContainerComponent, + AgentCPUChartContainerComponent, + AgentDataSourceChartContainerComponent, + AgentJVMHeapChartContainerComponent, + AgentJVMNonHeapChartContainerComponent, + AgentResponseTimeChartContainerComponent, + AgentTPSChartContainerComponent, + ApplicationActiveThreadChartContainerComponent, + ApplicationJVMCPUChartContainerComponent, + ApplicationJVMHeapChartContainerComponent, + ApplicationJVMNonHeapChartContainerComponent, + ApplicationResponseTimeChartContainerComponent, + ApplicationSystemCPUChartContainerComponent, + ApplicationTPSChartContainerComponent, + ApplicationDataSourceChartContainerComponent, + AgentOpenFileDescriptorChartContainerComponent, + ApplicationOpenFileDescriptorChartContainerComponent, + AgentDirectBufferCountChartContainerComponent, + AgentDirectBufferMemoryChartContainerComponent, + AgentMappedBufferCountChartContainerComponent, + AgentMappedBufferMemoryChartContainerComponent, + ApplicationDirectBufferCountChartContainerComponent, + ApplicationDirectBufferMemoryChartContainerComponent, + ApplicationMappedBufferCountChartContainerComponent, + ApplicationMappedBufferMemoryChartContainerComponent + ], + entryComponents: [ + TransactionViewJVMHeapChartContainerComponent, + TransactionViewJVMNonHeapChartContainerComponent, + TransactionViewCPUChartContainerComponent + ], + providers: [ + AgentActiveThreadChartDataService, + AgentCPUChartDataService, + AgentDataSourceChartDataService, + AgentMemoryChartDataService, + AgentTPSChartDataService, + AgentResponseTimeChartDataService, + AgentOpenFileDescriptorChartDataService, + AgentDirectBufferChartDataService, + ApplicationCPUChartDataService, + ApplicationActiveThreadChartDataService, + ApplicationDataSourceChartDataService, + ApplicationMemoryChartDataService, + ApplicationTPSChartDataService, + ApplicationResponseTimeChartDataService, + ApplicationOpenFileDescriptorChartDataService, + ApplicationDirectBufferChartDataService, + TransactionViewMemoryChartDataService, + TransactionViewCPUChartDataService + ] +}) +export class InspectorChartModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart-container.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart-container.ts new file mode 100644 index 000000000000..a0091fff3e18 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart-container.ts @@ -0,0 +1,157 @@ +import { ChangeDetectorRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; +import { Subject, Observable, combineLatest } from 'rxjs'; +import { filter, map, skip, takeUntil } from 'rxjs/operators'; + +import { II18nText, IChartConfig, IErrObj } from 'app/core/components/inspector-chart/inspector-chart.component'; +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, AnalyticsService, TRACKED_EVENT_LIST, StoreHelperService, DynamicPopupService } from 'app/shared/services'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +export abstract class InspectorChartContainer { + private previousRange: number[]; + + protected chartData: IChartDataFromServer | IChartDataFromServer[]; + protected timezone: string; + protected dateFormat: string[]; + protected unsubscribe = new Subject(); + + i18nText$: Observable; + chartConfig: IChartConfig; + errObj: IErrObj; + hoveredInfo$: Observable; + + constructor( + protected defaultYMax: number, + protected storeHelperService: StoreHelperService, + protected changeDetector: ChangeDetectorRef, + protected webAppSettingDataService: WebAppSettingDataService, + protected newUrlStateNotificationService: NewUrlStateNotificationService, + protected chartDataService: IChartDataService, + protected translateService: TranslateService, + protected ajaxExceptionCheckerService: AjaxExceptionCheckerService, + protected analyticsService: AnalyticsService, + protected dynamicPopupService: DynamicPopupService + ) {} + + protected initI18nText(): void { + this.i18nText$ = combineLatest( + this.translateService.get('COMMON.FAILED_TO_FETCH_DATA'), + this.translateService.get('INSPECTOR.NO_DATA_COLLECTED'), + ).pipe( + map(([FAILED_TO_FETCH_DATA, NO_DATA_COLLECTED]: string[]) => { + return { FAILED_TO_FETCH_DATA, NO_DATA_COLLECTED }; + }) + ); + } + + protected initHoveredInfo(): void { + this.hoveredInfo$ = this.storeHelperService.getHoverInfo(this.unsubscribe).pipe( + skip(1), + filter(() => { + return !(!this.chartConfig || this.chartConfig.isDataEmpty); + }) + ); + } + + protected initTimezoneAndDateFormat(): void { + combineLatest( + this.storeHelperService.getTimezone(this.unsubscribe), + this.storeHelperService.getDateFormatArray(this.unsubscribe, 3, 4) + ).subscribe(([timezone, dateFormat]: [string, string[]]) => { + this.timezone = timezone; + this.dateFormat = dateFormat; + if (this.chartData) { + const xDataArr = Array.isArray(this.chartData) ? this.chartData[0].charts.x : this.chartData.charts.x; + + this.chartConfig = {...this.chartConfig}; + this.chartConfig.dataConfig.labels = this.getNewFormattedLabels(xDataArr); + this.changeDetector.detectChanges(); + } + }); + } + + private getNewFormattedLabels(xDataArr: number[]): string[] { + return xDataArr.map((xData: number) => { + return `${moment(xData).tz(this.timezone).format(this.dateFormat[0])}#${moment(xData).tz(this.timezone).format(this.dateFormat[1])}`; + }); + } + + protected initChartData(): void { + this.storeHelperService.getInspectorTimelineSelectionRange(this.unsubscribe).pipe( + filter((range: number[]) => { + if (this.previousRange) { + return !(this.previousRange[0] === range[0] && this.previousRange[1] === range[1]); + } + return true; + }) + ).subscribe((range: number[]) => { + this.previousRange = range; + this.getChartData(range); + }); + } + + onRetryGetChartData(): void { + this.getChartData(this.previousRange); + } + + protected getChartData(range: number[]): void { + this.chartDataService.getData(range).subscribe((data: IChartDataFromServer | IChartDataFromServer[] | AjaxException) => { + if (this.ajaxExceptionCheckerService.isAjaxException(data)) { + this.setErrObj(data); + } else { + this.chartData = data; + this.setChartConfig(this.makeChartData(data)); + } + }, () => { + this.setErrObj(); + }); + } + + protected setChartConfig(data: {[key: string]: any} | {[key: string]: any}[]): void { + this.chartConfig = { + type: 'line', + dataConfig: this.makeDataOption(data), + elseConfig: this.makeNormalOption(data), + isDataEmpty: this.isDataEmpty(data) + }; + this.changeDetector.detectChanges(); + } + + protected setErrObj(data?: AjaxException): void { + this.errObj = { + errType: data ? 'EXCEPTION' : 'ELSE', + errMessage: data ? data.exception.message : null + }; + this.changeDetector.detectChanges(); + } + + protected isDataEmpty(data: {[key: string]: any} | {[key: string]: any}[]): boolean { + const emptyCheckFunc = (d: {[key: string]: any}) => Object.getOwnPropertyNames(d).filter((prop) => prop !== 'x' && Array.isArray(d[prop])).map((yProp) => d[yProp].length).every((l) => l === 0); + + return Array.isArray(data) ? data.length === 0 || data.every((obj) => emptyCheckFunc(obj)) + : emptyCheckFunc(data); + } + + protected parseData(data: number): number | null { + return data === -1 ? null : data; + } + + protected abstract makeChartData(chartData: IChartDataFromServer | IChartDataFromServer[]): {[key: string]: any} | {[key: string]: any}[]; + protected abstract makeDataOption(data: {[key: string]: any} | {[key: string]: any}[]): {[key: string]: any}; + protected abstract makeNormalOption(data: {[key: string]: any} | {[key: string]: any}[]): {[key: string]: any}; + onShowHelp($event: MouseEvent, key: HELP_VIEWER_LIST): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, key); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: key, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart.component.css new file mode 100644 index 000000000000..ceda45587477 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart.component.css @@ -0,0 +1,25 @@ +:host { + width: 100%; + display: flex; + align-items: flex-end; +} +.l-chart-section { + background-color: #fff; + padding: 15px 20px; + position: relative; + width: 100%; +} +.show-chart { + visibility: visible; + opacity: 1; + transition: all 1s; +} +.shady-chart { + opacity: 0.5; + pointer-events: none; + transition: all 0.5s; +} +.hide-chart { + visibility: hidden; + opacity: 0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart.component.html new file mode 100644 index 000000000000..f2d26bcd9ce9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart.component.html @@ -0,0 +1,6 @@ +
    + + + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart.component.ts new file mode 100644 index 000000000000..d09994a184a7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/inspector-chart.component.ts @@ -0,0 +1,188 @@ +import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ViewChild, ElementRef, SimpleChanges, ChangeDetectorRef } from '@angular/core'; +import { Chart } from 'chart.js'; + +export interface IChartConfig { + type: string; + dataConfig: {[key: string]: any}; + elseConfig: {[key: string]: any}; + isDataEmpty: boolean; +} + +export interface II18nText { + FAILED_TO_FETCH_DATA: string; + NO_DATA_COLLECTED: string; +} + +export interface IErrObj { + errType: string; // EXCEPTION or ELSE + errMessage: string; // data.exception.message or null +} + +@Component({ + selector: 'pp-inspector-chart', + templateUrl: './inspector-chart.component.html', + styleUrls: ['./inspector-chart.component.css'] +}) +export class InspectorChartComponent implements OnInit, OnChanges { + @ViewChild('chartElement') el: ElementRef; + @Input() xRawData: number[]; + @Input() chartConfig: IChartConfig; + @Input() i18nText: II18nText; + @Input() errObj: IErrObj; + @Input() hoveredInfo: IHoveredInfo; + @Input() height: string; + @Output() outRetryGetChartData: EventEmitter = new EventEmitter(); + + retryMessage: string; + chartVisibility = {}; + chartSectionLayers = { + loading: true, + chart: false, + retry: false + }; + + private chartObj: any; + + constructor( + private changeDetector: ChangeDetectorRef, + ) {} + + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + Object.keys(changes) + .filter((propName: string) => { + return changes[propName].currentValue; + }) + .forEach((propName: string) => { + const changedProp = changes[propName]; + switch (propName) { + case 'chartConfig': + this.setChartSectionVisibility('loading'); + this.initChart(); + break; + case 'errObj': + this.setChartSectionVisibility('loading'); + this.setRetryMessage(changedProp.currentValue); + this.setChartSectionVisibility('retry'); + break; + case 'hoveredInfo': + this.syncHoverOnChart(changedProp.currentValue); + break; + } + }); + } + + getHeightConfig(): {[key: string]: any} { + return { + height: this.height, + setHeightAuto: this.chartSectionLayers.chart, + ratio: 1.92 + }; + } + + private syncHoverOnChart(hoverInfo: IHoveredInfo): void { + let activeElements; + if (hoverInfo.index === -1) { + if (hoverInfo.time) { + activeElements = this.getActiveTooltipElementsByTime(hoverInfo.time); + } else { + activeElements = []; + } + } else { + activeElements = this.getActiveTooltipElements(hoverInfo.index); + } + + this.chartObj.tooltip._active = activeElements; + this.chartObj.tooltip.update(true); + this.chartObj.draw(); + } + getActiveTooltipElementsByTime(time: number): any[] { + let index = -1; + const len = this.xRawData.length; + for (let i = 0 ; i < len ; i++) { + const t = this.xRawData[i]; + if (t === time) { + index = i; + break; + } else if (t > time) { + if (i + 1 === len) { + index = i; + } else { + if (this.xRawData[i] - time >= this.xRawData[i - 1] - time) { + index = i - 1; + } else { + index = i; + } + } + break; + } + } + return this.getActiveTooltipElements(index); + } + getActiveTooltipElements(index: number): any[] { + return this.chartObj.data.datasets.map((val: any, i: number) => this.chartObj.getDatasetMeta(i).data[index]); + } + + private initChart(): void { + if (this.chartObj) { + this.chartObj.data = this.chartConfig.dataConfig; + this.chartObj.options.tooltips.callbacks.label = this.chartConfig.elseConfig.tooltips.callbacks.label; + this.chartObj.options.scales.yAxes[0].ticks.max = this.chartConfig.elseConfig.scales.yAxes[0].ticks.max; + this.chartObj.update(); + } else { + this.chartObj = new Chart(this.el.nativeElement.getContext('2d'), { + type: this.chartConfig.type, + data: this.chartConfig.dataConfig, + options: this.chartConfig.elseConfig, + plugins: [{ + afterRender: (chart, options) => { + this.finishLoading(); + } + }], + }); + } + } + + private finishLoading(): void { + this.setChartSectionVisibility('chart'); + } + + private setRetryMessage(errObj: IErrObj): void { + this.retryMessage = errObj.errType === 'EXCEPTION' ? errObj.errMessage : this.i18nText['FAILED_TO_FETCH_DATA']; + } + + private setChartSectionVisibility(layer: string): void { + this.setChartSectionLayerAs(layer); + this.setChartVisibility(this.chartSectionLayers['chart'], this.chartObj); + this.notifyChanges(); + } + + private setChartSectionLayerAs(whichLayerToShow: string): void { + Object.keys(this.chartSectionLayers).forEach((layer) => { + this.chartSectionLayers[layer] = whichLayerToShow === layer; + }); + } + + private setChartVisibility(showChart: boolean, chartObj: Chart): void { + this.chartVisibility = { + 'show-chart': showChart, + 'shady-chart': !showChart && chartObj !== undefined, + 'hide-chart': !showChart && chartObj === undefined + }; + } + + retryGetChartData(): void { + this.setChartSectionVisibility('loading'); + this.outRetryGetChartData.emit(); + } + + showNoData(): boolean { + return this.chartSectionLayers.chart && this.chartConfig.isDataEmpty; + } + + private notifyChanges(): void { + if (!this.changeDetector['destroyed']) { + this.changeDetector.detectChanges(); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/no-data.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/no-data.component.css new file mode 100644 index 000000000000..3c65ae892265 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/no-data.component.css @@ -0,0 +1,16 @@ +:host { + display: block; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; +} + +.l-no-data-text { + position: absolute; + top: 42%; + left: 37%; + padding: 5px 10px; + background-color: #e3e5e8; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/no-data.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/no-data.component.html new file mode 100644 index 000000000000..1856dec2caeb --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/no-data.component.html @@ -0,0 +1 @@ +

    {{message}}

    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/no-data.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/no-data.component.ts new file mode 100644 index 000000000000..ecf627e87d6a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/no-data.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { style, animate, transition, trigger } from '@angular/animations'; + +@Component({ + selector: 'pp-no-data', + animations: [ + trigger('fadeIn', [ + transition(':enter', [ // is alias to 'void => *' + style({opacity: 0}), + animate(1000, style({opacity: 1})) + ]), + ]) + ], + templateUrl: './no-data.component.html', + styleUrls: ['./no-data.component.css'] +}) +export class NoDataComponent implements OnInit { + @Input() message: string; + @Input() showNoData: boolean; + constructor() { } + + ngOnInit() { + } + +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/retry.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/retry.component.css new file mode 100644 index 000000000000..acfb236b3df4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/retry.component.css @@ -0,0 +1,9 @@ +.l-retry { + width: 92%; + position: absolute; + top:40%; + text-align: center; +} +.l-retry-message { + margin-bottom: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/retry.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/retry.component.html new file mode 100644 index 000000000000..cd491543cc39 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/retry.component.html @@ -0,0 +1,4 @@ +
    +

    {{message}}

    + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/retry.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/retry.component.ts new file mode 100644 index 000000000000..e9547ca95813 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/retry.component.ts @@ -0,0 +1,30 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { style, animate, transition, trigger } from '@angular/animations'; + +@Component({ + selector: 'pp-retry', + animations: [ + trigger('fadeIn', [ + transition(':enter', [ // is alias to 'void => *' + style({opacity: 0}), + animate(2000, style({opacity: 1})) + ]), + ]) + ], + templateUrl: './retry.component.html', + styleUrls: ['./retry.component.css'] +}) +export class RetryComponent implements OnInit { + @Input() showRetry: boolean; + @Input() message: string; + @Output() outRetryGetChartData: EventEmitter = new EventEmitter(); + constructor() { } + + ngOnInit() { + } + + retryGetChartData(): void { + this.outRetryGetChartData.emit(); + } + +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-chart-container.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-chart-container.ts new file mode 100644 index 000000000000..f8d47d003650 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-chart-container.ts @@ -0,0 +1,148 @@ +import { ChangeDetectorRef, ElementRef } from '@angular/core'; +import { Subject, Observable, combineLatest } from 'rxjs'; +import { filter, map } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { II18nText, IChartConfig, IErrObj } from 'app/core/components/inspector-chart/inspector-chart.component'; +import { StoreHelperService, WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, GutterEventService } from 'app/shared/services'; +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { UrlPathId } from 'app/shared/models'; + +export abstract class TransactionViewChartContainer { + protected chartData: IChartDataFromServer; + protected timezone: string; + protected dateFormat: string[]; + protected unsubscribe = new Subject(); + + i18nText$: Observable; + height$: Observable; + chartConfig: IChartConfig; + errObj: IErrObj; + hoveredInfo$: Observable; + xRawData: number[]; + + constructor( + protected defaultYMax: number, + protected storeHelperService: StoreHelperService, + protected changeDetector: ChangeDetectorRef, + protected webAppSettingDataService: WebAppSettingDataService, + protected newUrlStateNotificationService: NewUrlStateNotificationService, + protected chartDataService: IChartDataService, + protected translateService: TranslateService, + protected ajaxExceptionCheckerService: AjaxExceptionCheckerService, + protected gutterEventService: GutterEventService, + protected el: ElementRef + ) {} + + protected initI18nText(): void { + this.i18nText$ = combineLatest( + this.translateService.get('COMMON.FAILED_TO_FETCH_DATA'), + this.translateService.get('INSPECTOR.NO_DATA_COLLECTED'), + ).pipe( + map(([FAILED_TO_FETCH_DATA, NO_DATA_COLLECTED]: string[]) => { + return { FAILED_TO_FETCH_DATA, NO_DATA_COLLECTED }; + }) + ); + } + protected initHoveredInfo(): void { + this.hoveredInfo$ = this.storeHelperService.getHoverInfo(this.unsubscribe).pipe( + filter(() => { + return !(!this.chartConfig || this.chartConfig.isDataEmpty); + }) + ); + } + protected initTimezoneAndDateFormat(): void { + combineLatest( + this.storeHelperService.getTimezone(this.unsubscribe), + this.storeHelperService.getDateFormatArray(this.unsubscribe, 3, 4) + ).subscribe((data: [string, string[]]) => { + this.timezone = data[0]; + this.dateFormat = data[1]; + if (this.chartData) { + const xDataArr = Array.isArray(this.chartData) ? this.chartData[0].charts.x : this.chartData.charts.x; + + this.chartConfig = {...this.chartConfig}; + this.chartConfig.dataConfig.labels = this.getNewFormattedLabels(xDataArr); + this.changeDetector.detectChanges(); + } + }); + } + + protected initHeight(): void { + // TODO: angular-split라이브러리에 minSize옵션 추가되면, filter오퍼레이터 제거. + this.height$ = this.gutterEventService.onGutterResized$.pipe( + map((ratioArr: number[]) => ratioArr[0]), + filter((ratio: number) => ratio >= 30 && ratio <= 55), // 30, 50: 차트가 포함되어 있는 split-area의 최소, 최대 사이즈(비율) + map(() => this.el.nativeElement.offsetHeight + 'px') + ); + } + + private getNewFormattedLabels(xDataArr: number[]): string[] { + return xDataArr.map((xData: number) => { + return `${moment(xData).tz(this.timezone).format(this.dateFormat[0])}#${moment(xData).tz(this.timezone).format(this.dateFormat[1])}`; + }); + } + + protected getTimeRange(): number[] { + const focusTime = Number(this.newUrlStateNotificationService.getPathValue(UrlPathId.FOCUS_TIMESTAMP)); + const range = 600000; + + return [focusTime - range, focusTime + range]; + } + + onRetryGetChartData(): void { + this.getChartData(this.getTimeRange()); + } + + protected getChartData(range: number[]): void { + this.chartDataService.getData(range) + .subscribe( + (data: IChartDataFromServer | AjaxException) => { + if (this.ajaxExceptionCheckerService.isAjaxException(data)) { + this.setErrObj(data); + } else { + this.xRawData = data.charts.x; + this.chartData = data; + this.setChartConfig(this.makeChartData(data)); + } + }, + (err) => { + this.setErrObj(); + } + ); + } + + protected setChartConfig(data: {[key: string]: any} | {[key: string]: any}[]): void { + this.chartConfig = { + type: 'line', + dataConfig: this.makeDataOption(data), + elseConfig: this.makeNormalOption(data), + isDataEmpty: this.isDataEmpty(data) + }; + this.changeDetector.detectChanges(); + } + + protected setErrObj(data?: AjaxException): void { + this.errObj = { + errType: data ? 'EXCEPTION' : 'ELSE', + errMessage: data ? data.exception.message : null + }; + this.changeDetector.detectChanges(); + } + + protected isDataEmpty(data: {[key: string]: any} | {[key: string]: any}[]): boolean { + const emptyCheckFunc = (d: {[key: string]: any}) => Object.getOwnPropertyNames(d).filter((prop) => prop !== 'x' && Array.isArray(d[prop])).map((yProp) => d[yProp].length).every((l) => l === 0); + + return Array.isArray(data) ? data.length === 0 || data.every((obj) => emptyCheckFunc(obj)) + : emptyCheckFunc(data); + } + + protected parseData(data: number): number | null { + return data === -1 ? null : data; + } + + protected abstract makeChartData(chartData: IChartDataFromServer): {[key: string]: any} | {[key: string]: any}[]; + protected abstract makeDataOption(data: {[key: string]: any} | {[key: string]: any}[]): {[key: string]: any}; + protected abstract makeNormalOption(data: {[key: string]: any} | {[key: string]: any}[]): {[key: string]: any}; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-container.component.css new file mode 100644 index 000000000000..8bc6555c724d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-container.component.css @@ -0,0 +1,8 @@ +:host { + display: block; + height: calc(100% - 45px); +} +.l-content-item { + width: 100%; + margin: 0px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-container.component.html new file mode 100644 index 000000000000..ba6a1c2f48a4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-container.component.html @@ -0,0 +1,11 @@ +
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-container.component.ts new file mode 100644 index 000000000000..378d205da533 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-container.component.ts @@ -0,0 +1,189 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, ElementRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, GutterEventService, StoreHelperService } from 'app/shared/services'; +import { TransactionViewCPUChartDataService } from './transaction-view-cpu-chart-data.service'; +import { TransactionViewChartContainer } from 'app/core/components/inspector-chart/transaction-view-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-transaction-view-cpu-chart-container', + templateUrl: './transaction-view-cpu-chart-container.component.html', + styleUrls: ['./transaction-view-cpu-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TransactionViewCPUChartContainerComponent extends TransactionViewChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: TransactionViewCPUChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + gutterEventService: GutterEventService, + el: ElementRef + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + gutterEventService, + el + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initHeight(); + this.initTimezoneAndDateFormat(); + this.getChartData(this.getTimeRange()); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected parseData(data: number): number | null { + return data === -1 ? null : Number(data.toFixed(2)); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const jvmArr = []; + const systemArr = []; + const maxArr = []; + + const xData = chartData.charts.x; + const cpuJVM = chartData.charts.y['CPU_LOAD_JVM']; + const cpuSystem = chartData.charts.y['CPU_LOAD_SYSTEM']; + const dataCount = xData.length; + + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + maxArr.push(100); + if ( cpuJVM.length === 0 ) { + continue; + } + jvmArr.push(this.parseData(cpuJVM[i][1])); + systemArr.push(this.parseData(cpuSystem[i][1])); + } + return { + x: xArr, + jvm: jvmArr, + system: systemArr + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + label: 'JVM', + data: data.jvm, + fill: false, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180)', + backgroundColor: 'rgba(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + label: 'System', + data: data.system, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(174, 199, 232)', + backgroundColor: 'rgba(174, 199, 232, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + maintainAspectRatio: false, + title: { + display: false, + text: 'JVM/System CPU Usage' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : value.yLabel + `%`}`; + } + } + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 7, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + display: true, + scaleLabel: { + display: true, + labelString: 'CPU Usage (%)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return `${label}%`; + }, + min: 0, + max: this.defaultYMax, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-data.service.ts new file mode 100644 index 000000000000..f3b36a0e01cc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-cpu-chart-data.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { shareReplay } from 'rxjs/operators'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class TransactionViewCPUChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/cpuLoad/chart.pinpoint'; + private cache$: Observable; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + if (!this.cache$) { + const httpRequest$ = this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range)); + + this.cache$ = httpRequest$.pipe( + shareReplay(1) + ); + } + + return this.cache$; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component.css new file mode 100644 index 000000000000..c0f04e531812 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component.css @@ -0,0 +1,8 @@ +:host { + display: block; + height: calc(100% - 45px); +} +l-content-item { + width: 100%; + margin: 0px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component.html new file mode 100644 index 000000000000..ba6a1c2f48a4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component.html @@ -0,0 +1,11 @@ +
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component.ts new file mode 100644 index 000000000000..2e92f2f7f281 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component.ts @@ -0,0 +1,265 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, ElementRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, GutterEventService, StoreHelperService } from 'app/shared/services'; +import { TransactionViewMemoryChartDataService } from './transaction-view-memory-chart-data.service'; +import { TransactionViewChartContainer } from 'app/core/components/inspector-chart/transaction-view-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-trasaction-view-jvm-heap-chart-container', + templateUrl: './transaction-view-jvm-heap-chart-container.component.html', + styleUrls: ['./transaction-view-jvm-heap-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TransactionViewJVMHeapChartContainerComponent extends TransactionViewChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: TransactionViewMemoryChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + gutterEventService: GutterEventService, + el: ElementRef + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + gutterEventService, + el + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initHeight(); + this.initTimezoneAndDateFormat(); + this.getChartData(this.getTimeRange()); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected setChartConfig(data: {[key: string]: any}): void { + this.chartConfig = { + type: 'bar', + dataConfig: this.makeDataOption(data), + elseConfig: this.makeNormalOption(data), + isDataEmpty: this.isDataEmpty(data) + }; + this.changeDetector.detectChanges(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const usedArr = []; + const fgcTimeArr = []; + const fgcCountArr = []; + + const xData = chartData.charts.x; + const gcOldTime = chartData.charts.y['JVM_GC_OLD_TIME']; + const gcOldCount = chartData.charts.y['JVM_GC_OLD_COUNT']; + const memoryUsed = chartData.charts.y['JVM_MEMORY_HEAP_USED']; + const memoryMax = chartData.charts.y['JVM_MEMORY_HEAP_MAX']; + const dataCount = xData.length; + + let totalSumGCTime = 0; + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if ( memoryMax.length === 0 ) { + continue; + } + maxArr.push(this.parseData(memoryMax[i][1])); + usedArr.push(this.parseData(memoryUsed[i][1])); + + const gcOldCountSumValue = gcOldCount[i][3]; + const gcOldTimeSumValue = gcOldTime[i][3]; + + if ( gcOldTimeSumValue > 0 ) { + totalSumGCTime += gcOldTimeSumValue; + } + if ( gcOldCountSumValue > 0 ) { + fgcTimeArr.push(gcOldCountSumValue); + fgcCountArr.push(totalSumGCTime); + totalSumGCTime = 0; + } else { + fgcTimeArr.push(0); + fgcCountArr.push(0); + } + } + return { + x: xArr, + max: maxArr, + used: usedArr, + fgcTime: fgcTimeArr, + fgcCount: fgcCountArr + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + type: 'line', + label: 'Max', + data: data.max, + fill: false, + borderWidth: 0.5, + borderColor: 'rgb(174, 199, 232)', + backgroundColor: 'rgb(174, 199, 232)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + type: 'line', + label: 'Used', + data: data.used, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180)', + backgroundColor: 'rgba(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + type: 'bar', + label: 'Major GC', + data: data.fgcTime, + borderWidth: 1, + borderColor: 'rgb(255, 42, 0)', + backgroundColor: 'rgba(255, 42, 0, 0.3)', + // pointRadius: 0, + // pointHoverRadius: 3, + yAxisID: 'y-axis-2' + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + maintainAspectRatio: false, + title: { + display: false, + text: 'Heap Usage' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel)}`; + } + } + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 7, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + id: 'y-axis-1', + display: true, + position: 'left', + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }, + { + id: 'y-axis-2', + display: true, + position: 'right', + scaleLabel: { + display: true, + labelString: 'Full GC (ms)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component.css new file mode 100644 index 000000000000..734f4f3d0fa2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component.css @@ -0,0 +1,9 @@ +:host { + display: block; + height: calc(100% - 45px); +} +.l-content-item { + width: 100%; + height: 100%; + margin: 0px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component.html new file mode 100644 index 000000000000..ba6a1c2f48a4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component.html @@ -0,0 +1,11 @@ +
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component.ts new file mode 100644 index 000000000000..0c199a0309d4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component.ts @@ -0,0 +1,265 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, ElementRef } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import * as moment from 'moment-timezone'; + +import { WebAppSettingDataService, NewUrlStateNotificationService, AjaxExceptionCheckerService, GutterEventService, StoreHelperService } from 'app/shared/services'; +import { TransactionViewMemoryChartDataService } from './transaction-view-memory-chart-data.service'; +import { TransactionViewChartContainer } from 'app/core/components/inspector-chart/transaction-view-chart-container'; +import { IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; + +@Component({ + selector: 'pp-transaction-view-jvm-non-heap-chart-container', + templateUrl: './transaction-view-jvm-non-heap-chart-container.component.html', + styleUrls: ['./transaction-view-jvm-non-heap-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TransactionViewJVMNonHeapChartContainerComponent extends TransactionViewChartContainer implements OnInit, OnDestroy { + constructor( + storeHelperService: StoreHelperService, + changeDetector: ChangeDetectorRef, + webAppSettingDataService: WebAppSettingDataService, + newUrlStateNotificationService: NewUrlStateNotificationService, + chartDataService: TransactionViewMemoryChartDataService, + translateService: TranslateService, + ajaxExceptionCheckerService: AjaxExceptionCheckerService, + gutterEventService: GutterEventService, + el: ElementRef + ) { + super( + 100, + storeHelperService, + changeDetector, + webAppSettingDataService, + newUrlStateNotificationService, + chartDataService, + translateService, + ajaxExceptionCheckerService, + gutterEventService, + el + ); + } + + ngOnInit() { + this.initI18nText(); + this.initHoveredInfo(); + this.initHeight(); + this.initTimezoneAndDateFormat(); + this.getChartData(this.getTimeRange()); + } + + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + protected setChartConfig(data: {[key: string]: any}): void { + this.chartConfig = { + type: 'bar', + dataConfig: this.makeDataOption(data), + elseConfig: this.makeNormalOption(data), + isDataEmpty: this.isDataEmpty(data) + }; + this.changeDetector.detectChanges(); + } + + protected makeChartData(chartData: IChartDataFromServer): {[key: string]: any} { + const xArr = []; + const maxArr = []; + const usedArr = []; + const fgcTimeArr = []; + const fgcCountArr = []; + + const xData = chartData.charts.x; + const gcOldTime = chartData.charts.y['JVM_GC_OLD_TIME']; + const gcOldCount = chartData.charts.y['JVM_GC_OLD_COUNT']; + const memoryUsed = chartData.charts.y['JVM_MEMORY_NON_HEAP_USED']; + const memoryMax = chartData.charts.y['JVM_MEMORY_NON_HEAP_MAX']; + const dataCount = xData.length; + + let totalSumGCTime = 0; + for ( let i = 0 ; i < dataCount ; i++ ) { + xArr.push(moment(xData[i]).tz(this.timezone).format(this.dateFormat[0]) + '#' + moment(xData[i]).tz(this.timezone).format(this.dateFormat[1])); + if ( memoryMax.length === 0 ) { + continue; + } + maxArr.push(this.parseData(memoryMax[i][1])); + usedArr.push(this.parseData(memoryUsed[i][1])); + + const gcOldCountSumValue = gcOldCount[i][3]; + const gcOldTimeSumValue = gcOldTime[i][3]; + + if ( gcOldTimeSumValue > 0 ) { + totalSumGCTime += gcOldTimeSumValue; + } + if ( gcOldCountSumValue > 0 ) { + fgcTimeArr.push(gcOldCountSumValue); + fgcCountArr.push(totalSumGCTime); + totalSumGCTime = 0; + } else { + fgcTimeArr.push(0); + fgcCountArr.push(0); + } + } + return { + x: xArr, + max: maxArr, + used: usedArr, + fgcTime: fgcTimeArr, + fgcCount: fgcCountArr + }; + } + + protected makeDataOption(data: {[key: string]: any}): {[key: string]: any} { + return { + labels: data.x, + datasets: [{ + type: 'line', + label: 'Max', + data: data.max, + fill: false, + borderWidth: 0.5, + borderColor: 'rgb(174, 199, 232)', + backgroundColor: 'rgb(174, 199, 232)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + type: 'line', + label: 'Used', + data: data.used, + fill: true, + borderWidth: 0.5, + borderColor: 'rgb(31, 119, 180)', + backgroundColor: 'rgba(31, 119, 180, 0.4)', + pointRadius: 0, + pointHoverRadius: 3 + }, { + type: 'bar', + label: 'Major GC', + data: data.fgcTime, + borderWidth: 1, + borderColor: 'rgb(255, 42, 0)', + backgroundColor: 'rgba(255, 42, 0, 0.3)', + // pointRadius: 0, + // pointHoverRadius: 3, + yAxisID: 'y-axis-2' + }] + }; + } + + protected makeNormalOption(data: {[key: string]: any}): {[key: string]: any} { + return { + responsive: true, + maintainAspectRatio: false, + title: { + display: false, + text: 'Heap Usage' + }, + tooltips: { + mode: 'index', + intersect: false, + callbacks: { + title: (value: {[key: string]: any}[]): string => { + return value[0].xLabel.join(' '); + }, + label: (value: {[key: string]: any}, d: {[key: string]: any}): string => { + return `${d.datasets[value.datasetIndex].label}: ${isNaN(value.yLabel) ? `-` : this.convertWithUnit(value.yLabel)}`; + } + } + }, + scales: { + xAxes: [{ + display: true, + scaleLabel: { + display: false + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + maxTicksLimit: 7, + callback: (label: string): string[] => { + return label.split('#'); + }, + maxRotation: 0, + minRotation: 0, + fontSize: 11, + padding: 5 + } + }], + yAxes: [{ + id: 'y-axis-1', + display: true, + position: 'left', + scaleLabel: { + display: true, + labelString: 'Memory (bytes)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + callback: (label: number): string => { + return this.convertWithUnit(label); + }, + min: 0, + max: this.isDataEmpty(data) ? this.defaultYMax : undefined, + padding: 5 + } + }, + { + id: 'y-axis-2', + display: true, + position: 'right', + scaleLabel: { + display: true, + labelString: 'Full GC (ms)', + fontSize: 14, + fontStyle: 'bold' + }, + gridLines: { + color: 'rgb(0, 0, 0)', + lineWidth: 0.5, + drawBorder: true, + drawOnChartArea: false + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 5, + min: 0, + padding: 5 + } + }] + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + } + } + }; + } + + private convertWithUnit(value: number): string { + const unit = ['', 'K', 'M', 'G']; + let result = value; + let index = 0; + while ( result >= 1000 ) { + index++; + result /= 1000; + } + + result = Number.isInteger(result) ? result : Number(result.toFixed(2)); + return result + unit[index]; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-memory-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-memory-chart-data.service.ts new file mode 100644 index 000000000000..ba4034250382 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/inspector-chart/transaction-view-memory-chart-data.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { shareReplay } from 'rxjs/operators'; + +import { IChartDataService, IChartDataFromServer } from 'app/core/components/inspector-chart/chart-data.service'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { getParamForAgentChartData } from 'app/core/utils/chart-data-param-maker'; + +@Injectable() +export class TransactionViewMemoryChartDataService implements IChartDataService { + private requestURL = 'getAgentStat/jvmGc/chart.pinpoint'; + private cache$: Observable; + + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + + getData(range: number[]): Observable { + if (!this.cache$) { + const httpRequest$ = this.http.get(this.requestURL, + getParamForAgentChartData(this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), range)); + + this.cache$ = httpRequest$.pipe( + shareReplay(1) + ); + } + + return this.cache$; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/link-context-popup/index.ts b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/index.ts new file mode 100644 index 000000000000..89adf547f46d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/index.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { LinkContextPopupContainerComponent } from 'app/core/components/link-context-popup/link-context-popup-container.component'; +import { LinkContextPopupComponent } from 'app/core/components/link-context-popup/link-context-popup.component'; +import { FilterTransactionWizardPopupModule } from 'app/core/components/filter-transaction-wizard-popup'; + +@NgModule({ + declarations: [ + LinkContextPopupContainerComponent, + LinkContextPopupComponent + ], + imports: [ + SharedModule, + FilterTransactionWizardPopupModule + ], + exports: [], + entryComponents: [ + LinkContextPopupContainerComponent + ], + providers: [] +}) +export class LinkContextPopupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup-container.component.css new file mode 100644 index 000000000000..7f26ddcb5503 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup-container.component.css @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup-container.component.html new file mode 100644 index 000000000000..090c469aaea0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup-container.component.html @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup-container.component.ts new file mode 100644 index 000000000000..8c14682a6bbb --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup-container.component.ts @@ -0,0 +1,78 @@ +import { Component, OnInit, Input, Output, EventEmitter, AfterViewInit } from '@angular/core'; + +import { + UrlRouteManagerService, + NewUrlStateNotificationService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService, + DynamicPopup +} from 'app/shared/services'; +import { Filter } from 'app/core/models/filter'; +import { UrlPathId } from 'app/shared/models'; +import { FilterTransactionWizardPopupContainerComponent } from 'app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component'; + +@Component({ + selector: 'pp-link-context-popup-container', + templateUrl: './link-context-popup-container.component.html', + styleUrls: ['./link-context-popup-container.component.css'], +}) +export class LinkContextPopupContainerComponent implements OnInit, AfterViewInit, DynamicPopup { + @Input() data: any; + @Input() coord: ICoordinate; + @Output() outCreated = new EventEmitter(); + @Output() outClose = new EventEmitter(); + + constructor( + private urlRouteManagerService: UrlRouteManagerService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private dynamicPopupService: DynamicPopupService, + private analyticsService: AnalyticsService, + ) {} + + ngOnInit() {} + ngAfterViewInit() { + this.outCreated.emit(this.coord); + } + + onInputChange({coord}: {coord: ICoordinate}): void { + this.outCreated.emit(coord); + } + + onClickFilterTransaction(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_FILTER_TRANSACTION); + this.outClose.emit(); + const isBothWas = this.data.sourceInfo.isWas && this.data.targetInfo.isWas; + this.urlRouteManagerService.openPage( + this.urlRouteManagerService.makeFilterMapUrl({ + applicationName: this.data.filterApplicationName, + serviceType: this.data.filterApplicationServiceTypeName, + periodStr: this.newUrlStateNotificationService.hasValue(UrlPathId.PERIOD) ? this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime() : '', + timeStr: this.newUrlStateNotificationService.hasValue(UrlPathId.END_TIME) ? this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() : '', + filterStr: this.newUrlStateNotificationService.hasValue(UrlPathId.FILTER) ? this.newUrlStateNotificationService.getPathValue(UrlPathId.FILTER) : '', + hintStr: this.newUrlStateNotificationService.hasValue(UrlPathId.HINT) ? this.newUrlStateNotificationService.getPathValue(UrlPathId.HINT) : '', + addedFilter: new Filter( + this.data.sourceInfo.applicationName, + this.data.sourceInfo.serviceType, + this.data.targetInfo.applicationName, + this.data.targetInfo.serviceType + ), + addedHint: (isBothWas ? { + [this.data.targetInfo.applicationName]: this.data.filterTargetRpcList + } : null) + }) + ); + } + + onClickFilterTransactionWizard(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_FILTER_TRANSACTION_WIZARD); + this.dynamicPopupService.openPopup({ + data: this.data, + component: FilterTransactionWizardPopupContainerComponent + }); + } + + onClickOutside(): void { + this.outClose.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup.component.css new file mode 100644 index 000000000000..829090e403ac --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup.component.css @@ -0,0 +1,37 @@ +:host { + display: block; +} +.l-one-depth-list { + width: 100%; + margin: 0 0; + padding: 0 0; + list-style-type: none; +} +.l-one-depth-list > li { + border-bottom: 1px solid #E5E5E5; + padding: 10px; +} +.l-one-depth-list > li:last-of-type { + border-bottom: none; +} +li.l-selectable-command:first-of-type .fa-filter { + color:#4b99e3; +} +li.l-selectable-command:last-of-type .fa-filter { + color: #e95459; +} +li.l-selectable-command { + cursor: pointer; +} +li.l-selectable-command:hover { + background-color: #e4f3eb; +} +.l-two-depth-list { + padding-top: 10px; +} +.l-two-depth-list li { + padding: 4px; +} +.l-fas { + margin-right: 4px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup.component.html new file mode 100644 index 000000000000..2f88aa450360 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup.component.html @@ -0,0 +1,4 @@ +
      +
    • Filter Transaction
    • +
    • Filter Transaction Wizard
    • +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup.component.ts new file mode 100644 index 000000000000..c88fdb9d4079 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/link-context-popup/link-context-popup.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-link-context-popup', + templateUrl: './link-context-popup.component.html', + styleUrls: ['./link-context-popup.component.css'] +}) +export class LinkContextPopupComponent implements OnInit { + @Output() outClickFilterTransaction = new EventEmitter(); + @Output() outClickFilterTransactionWizard = new EventEmitter(); + + constructor() {} + ngOnInit() {} + onClickFilterTransaction(): void { + this.outClickFilterTransaction.emit(); + } + + onClickFilterTransactionWizard(): void { + this.outClickFilterTransactionWizard.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/index.ts b/web/src/main/webapp/v2/src/app/core/components/load-chart/index.ts new file mode 100644 index 000000000000..4bb052142f0f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/index.ts @@ -0,0 +1,29 @@ + +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { LoadChartComponent } from './load-chart.component'; +import { LoadChartForSideBarContainerComponent } from './load-chart-for-side-bar-container.component'; +import { LoadChartForInfoPerServerContainerComponent } from './load-chart-for-info-per-server-container.component'; +import { LoadChartForFilteredMapSideBarContainerComponent } from './load-chart-for-filtered-map-side-bar-container.component'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + LoadChartComponent, + LoadChartForSideBarContainerComponent, + LoadChartForFilteredMapSideBarContainerComponent, + LoadChartForInfoPerServerContainerComponent + ], + imports: [ + SharedModule, + HelpViewerPopupModule + ], + exports: [ + LoadChartForSideBarContainerComponent, + LoadChartForFilteredMapSideBarContainerComponent, + LoadChartForInfoPerServerContainerComponent + ], + providers: [] +}) +export class LoadChartModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-filtered-map-side-bar-container.component.css b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-filtered-map-side-bar-container.component.css new file mode 100644 index 000000000000..0919f4cddd72 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-filtered-map-side-bar-container.component.css @@ -0,0 +1,34 @@ +:host { + display: block; + position: relative; +} +.l-chart-item { + height: 253px; +} +.l-tool-box { + font-size: 14px; + color: #b3b5b9; + text-align: right; + position: relative; + padding: 16px 25px 0; +} +.l-tool-box .l-title { + float: left; + text-align: left; + font-size: 16px; + color: #333; + font-weight: 600; + margin: 0 0 23px; +} +.l-tool-box button { + font-size: 18px; + margin: 0; +} +.l-content-section { + padding: 0 25px 0; +} +.l-no-data { + padding-top: 60px; + text-align: center; + font-weight: 600; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-filtered-map-side-bar-container.component.html b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-filtered-map-side-bar-container.component.html new file mode 100644 index 000000000000..8f52d2296740 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-filtered-map-side-bar-container.component.html @@ -0,0 +1,20 @@ +
    +
    +

    Load

    + +
    +
    + + +
    + {{i18nText.NO_DATA}} +
    +
    +
    + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-filtered-map-side-bar-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-filtered-map-side-bar-container.component.ts new file mode 100644 index 000000000000..4d24f3fc80cc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-filtered-map-side-bar-container.component.ts @@ -0,0 +1,157 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, StoreHelperService, AgentHistogramDataService, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { ServerMapData } from 'app/core/components/server-map/class/server-map-data.class'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-load-chart-for-filtered-map-side-bar-container', + templateUrl: './load-chart-for-filtered-map-side-bar-container.component.html', + styleUrls: ['./load-chart-for-filtered-map-side-bar-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class LoadChartForFilteredMapSideBarContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private timezone: string; + private dateFormatMonth: string; + private dateFormatDay: string; + hiddenComponent = false; + hiddenChart = false; + yMax = -1; + selectedTarget: ISelectedTarget; + selectedAgent = ''; + serverMapData: ServerMapData; + useDisable = false; + showLoading = false; + i18nText = { + NO_DATA: '' + }; + chartData: IHistogram[]; + chartColors: string[]; + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private webAppSettingDataService: WebAppSettingDataService, + private agentHistogramDataService: AgentHistogramDataService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.chartColors = this.webAppSettingDataService.getColorByRequest(); + this.translateService.get('COMMON.NO_DATA').subscribe((txt: string) => { + this.i18nText.NO_DATA = txt; + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTimezone(this.unsubscribe).subscribe((timezone: string) => { + this.timezone = timezone; + if (this.chartData) { + this.loadLoadChartData(); + } + }); + this.storeHelperService.getDateFormatArray(this.unsubscribe, 5, 6).subscribe((dateFormat: string[]) => { + this.dateFormatMonth = dateFormat[0]; + this.dateFormatDay = dateFormat[1]; + if (this.chartData) { + this.loadLoadChartData(); + } + }); + this.storeHelperService.getAgentSelection(this.unsubscribe).subscribe((agent: string) => { + this.setDisable(true); + this.selectedAgent = agent; + if (this.selectedTarget) { + this.loadLoadChartData(); + } + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: ServerMapData) => { + this.serverMapData = serverMapData; + if (this.selectedTarget && this.selectedTarget.isMerged === false) { + this.yMax = -1; + this.loadLoadChartData(); + } + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.yMax = -1; + this.selectedTarget = target; + this.hiddenComponent = target.isMerged; + if (target.isMerged === false) { + this.loadLoadChartData(); + } + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getServerMapTargetSelectedByList(this.unsubscribe).subscribe((target: any) => { + this.yMax = -1; + this.hiddenComponent = false; + this.passDownChartData(this.agentHistogramDataService.makeChartDataForLoad(target.timeSeriesHistogram, this.timezone, [this.dateFormatMonth, this.dateFormatDay], this.getChartYMax())); + }); + } + private setDisable(disable: boolean): void { + this.useDisable = disable; + this.showLoading = disable; + } + private getChartYMax(): number { + return this.yMax === -1 ? null : this.yMax; + } + private loadLoadChartData(from?: number, to?: number): void { + const target = this.getTargetInfo(); + if (this.selectedAgent === '') { + this.passDownChartData(this.agentHistogramDataService.makeChartDataForLoad(target.timeSeriesHistogram, this.timezone, [this.dateFormatMonth, this.dateFormatDay], this.getChartYMax())); + } else { + this.passDownChartData(this.agentHistogramDataService.makeChartDataForLoad(target['agentTimeSeriesHistogram'][this.selectedAgent], this.timezone, [this.dateFormatMonth, this.dateFormatDay], this.getChartYMax())); + } + } + private passDownChartData(chartData: any): void { + if (chartData) { + this.hiddenChart = false; + this.chartData = chartData; + } else { + this.hiddenChart = true; + } + this.setDisable(false); + this.changeDetector.detectChanges(); + } + private getTargetInfo(): any { + if (this.selectedTarget.isNode) { + return this.serverMapData.getNodeData(this.selectedTarget.node[0]); + } else { + return this.serverMapData.getLinkData(this.selectedTarget.link[0]); + } + } + onNotifyMax(max: number) { + if (max > this.yMax) { + this.yMax = max; + this.storeHelperService.dispatch(new Actions.ChangeLoadChartYMax(max)); + } + } + onClickColumn($event: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_LOAD_GRAPH); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.LOAD); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.LOAD, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-info-per-server-container.component.css b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-info-per-server-container.component.css new file mode 100644 index 000000000000..28e7365d3a05 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-info-per-server-container.component.css @@ -0,0 +1,29 @@ +:host { + display: block; +} +.l-chart-item { + height: 253px; +} +.l-tool-box { + font-size: 14px; + color: #b3b5b9; + text-align: right; + position: relative; + padding: 16px 25px 0; +} +.l-tool-box .l-title { + float: left; + text-align: left; + font-size: 16px; + color: #333; + font-weight: 600; + margin: 0 0 23px; +} +.l-content-section { + padding: 0 25px 0; +} +.l-no-data { + padding-top: 60px; + text-align: center; + font-weight: 600; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-info-per-server-container.component.html b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-info-per-server-container.component.html new file mode 100644 index 000000000000..98c98ad1b784 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-info-per-server-container.component.html @@ -0,0 +1,19 @@ +
    +
    +

    Load

    + +
    +
    + + +
    +
    + {{i18nText.NO_DATA}} +
    +
    + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-info-per-server-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-info-per-server-container.component.ts new file mode 100644 index 000000000000..c222f01cc003 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-info-per-server-container.component.ts @@ -0,0 +1,102 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { WebAppSettingDataService, StoreHelperService, AgentHistogramDataService, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-load-chart-for-info-per-server-container', + templateUrl: './load-chart-for-info-per-server-container.component.html', + styleUrls: ['./load-chart-for-info-per-server-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class LoadChartForInfoPerServerContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private lastChartData: any = null; + private timezone: string; + private dateFormatMonth: string; + private dateFormatDay: string; + hiddenChart = false; + yMax: number; + chartData: IHistogram[]; + chartColors: string[]; + i18nText = { + NO_DATA: '' + }; + useDisable = false; + showLoading = false; + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private webAppSettingDataService: WebAppSettingDataService, + private agentHistogramDataService: AgentHistogramDataService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.chartColors = this.webAppSettingDataService.getColorByRequest(); + this.translateService.get('COMMON.NO_DATA').subscribe((txt: string) => { + this.i18nText.NO_DATA = txt; + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTimezone(this.unsubscribe).subscribe((timezone: string) => { + this.timezone = timezone; + if (this.lastChartData) { + this.makeChartData(); + } + }); + this.storeHelperService.getDateFormatArray(this.unsubscribe, 5, 6).subscribe((dateFormat: string[]) => { + this.dateFormatMonth = dateFormat[0]; + this.dateFormatDay = dateFormat[1]; + if (this.lastChartData) { + this.makeChartData(); + } + }); + this.storeHelperService.getLoadChartYMax(this.unsubscribe).subscribe((max: number) => { + this.yMax = max; + }); + this.storeHelperService.getAgentSelectionForServerList(this.unsubscribe).pipe( + filter((chartData: IAgentSelection) => { + return (chartData && chartData.agent) ? true : false; + }) + ).subscribe((chartData: IAgentSelection) => { + this.lastChartData = chartData; + this.makeChartData(); + }); + } + private makeChartData(): void { + if (this.lastChartData.load) { + this.hiddenChart = false; + this.chartData = this.agentHistogramDataService.makeChartDataForLoad(this.lastChartData.load, this.timezone, [this.dateFormatMonth, this.dateFormatDay], this.yMax); + } else { + this.hiddenChart = true; + } + this.changeDetector.detectChanges(); + } + onNotifyMax(max: number): void {} + onClickColumn($event: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_LOAD_GRAPH); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.LOAD); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.LOAD, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-side-bar-container.component.css b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-side-bar-container.component.css new file mode 100644 index 000000000000..0919f4cddd72 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-side-bar-container.component.css @@ -0,0 +1,34 @@ +:host { + display: block; + position: relative; +} +.l-chart-item { + height: 253px; +} +.l-tool-box { + font-size: 14px; + color: #b3b5b9; + text-align: right; + position: relative; + padding: 16px 25px 0; +} +.l-tool-box .l-title { + float: left; + text-align: left; + font-size: 16px; + color: #333; + font-weight: 600; + margin: 0 0 23px; +} +.l-tool-box button { + font-size: 18px; + margin: 0; +} +.l-content-section { + padding: 0 25px 0; +} +.l-no-data { + padding-top: 60px; + text-align: center; + font-weight: 600; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-side-bar-container.component.html b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-side-bar-container.component.html new file mode 100644 index 000000000000..f479492262b3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-side-bar-container.component.html @@ -0,0 +1,20 @@ +
    +
    +

    Load

    + +
    +
    + + +
    + {{getChartMessage()}} +
    +
    +
    + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-side-bar-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-side-bar-container.component.ts new file mode 100644 index 000000000000..15be21e638ee --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart-for-side-bar-container.component.ts @@ -0,0 +1,180 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject, combineLatest } from 'rxjs'; +import { filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, StoreHelperService, AgentHistogramDataService, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { ServerMapData } from 'app/core/components/server-map/class/server-map-data.class'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-load-chart-for-side-bar-container', + templateUrl: './load-chart-for-side-bar-container.component.html', + styleUrls: ['./load-chart-for-side-bar-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class LoadChartForSideBarContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private timezone: string; + private dateFormatMonth: string; + private dateFormatDay: string; + hasRequestError = false; + hiddenComponent = false; + hiddenChart = false; + yMax = -1; + selectedTarget: ISelectedTarget = null; + selectedAgent = ''; + serverMapData: ServerMapData; + useDisable = false; + showLoading = false; + i18nText = { + NO_DATA: '', + FAILED_TO_FETCH_DATA: '' + }; + chartData: IHistogram[]; + chartColors: string[]; + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private webAppSettingDataService: WebAppSettingDataService, + private agentHistogramDataService: AgentHistogramDataService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.chartColors = this.webAppSettingDataService.getColorByRequest(); + combineLatest( + this.translateService.get('COMMON.NO_DATA'), + this.translateService.get('COMMON.FAILED_TO_FETCH_DATA') + ).subscribe((text: string[]) => { + this.i18nText = { + NO_DATA: text[0], + FAILED_TO_FETCH_DATA: text[1] + }; + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTimezone(this.unsubscribe).subscribe((timezone: string) => { + this.timezone = timezone; + if (this.selectedTarget) { + this.loadLoadChartData(); + } + }); + this.storeHelperService.getDateFormatArray(this.unsubscribe, 5, 6).subscribe((dateFormat: string[]) => { + this.dateFormatMonth = dateFormat[0]; + this.dateFormatDay = dateFormat[1]; + if (this.selectedTarget) { + this.loadLoadChartData(); + } + }); + this.storeHelperService.getAgentSelection(this.unsubscribe).subscribe((agent: string) => { + this.setDisable(true); + this.selectedAgent = agent; + if (this.selectedTarget) { + this.loadLoadChartData(); + } + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getRealTimeScatterChartRange(this.unsubscribe).subscribe(({ from, to }: IScatterXRange) => { + this.yMax = -1; + this.loadLoadChartData(from, to); + }); + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: ServerMapData) => { + this.serverMapData = serverMapData; + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.yMax = -1; + this.selectedTarget = target; + this.hiddenComponent = target.isMerged; + if (target.isMerged === false) { + this.loadLoadChartData(); + } + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getServerMapTargetSelectedByList(this.unsubscribe).subscribe((target: any) => { + this.yMax = -1; + this.hiddenComponent = false; + this.passDownChartData(this.agentHistogramDataService.makeChartDataForLoad(target.timeSeriesHistogram, this.timezone, [this.dateFormatMonth, this.dateFormatDay], this.getChartYMax())); + }); + } + private setDisable(disable: boolean): void { + this.useDisable = disable; + this.showLoading = disable; + } + private getChartYMax(): number { + return this.yMax === -1 ? null : this.yMax; + } + private loadLoadChartData(from?: number, to?: number): void { + const target = this.getTargetInfo(); + if (this.isAllAgent() && arguments.length !== 2) { + this.passDownChartData(this.agentHistogramDataService.makeChartDataForLoad(target.timeSeriesHistogram, this.timezone, [this.dateFormatMonth, this.dateFormatDay], this.getChartYMax())); + } else { + this.agentHistogramDataService.getData(target.key, target.applicationName, target.serviceTypeCode, this.serverMapData, from, to).subscribe((chartData: any) => { + const chartDataForAgent = this.isAllAgent() ? chartData['timeSeriesHistogram'] : chartData['agentTimeSeriesHistogram'][this.selectedAgent]; + this.passDownChartData(this.agentHistogramDataService.makeChartDataForLoad(chartDataForAgent, this.timezone, [this.dateFormatMonth, this.dateFormatDay], this.getChartYMax())); + }, (error: IServerErrorFormat) => { + this.hasRequestError = true; + this.hiddenChart = true; + this.setDisable(false); + this.changeDetector.detectChanges(); + }); + } + } + private passDownChartData(chartData: any): void { + if (chartData) { + this.hiddenChart = false; + this.chartData = chartData; + } else { + this.hiddenChart = true; + } + this.hasRequestError = false; + this.setDisable(false); + this.changeDetector.detectChanges(); + } + private getTargetInfo(): any { + if (this.selectedTarget.isNode) { + return this.serverMapData.getNodeData(this.selectedTarget.node[0]); + } else { + return this.serverMapData.getLinkData(this.selectedTarget.link[0]); + } + } + private isAllAgent(): boolean { + return this.selectedAgent === ''; + } + getChartMessage(): string { + return this.hasRequestError ? this.i18nText.FAILED_TO_FETCH_DATA : this.i18nText.NO_DATA; + } + onNotifyMax(max: number) { + if (this.yMax === -1) { + this.yMax = max; + this.storeHelperService.dispatch(new Actions.ChangeLoadChartYMax(max)); + } + } + onClickColumn($event: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_LOAD_GRAPH); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.LOAD); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.LOAD, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart.component.css new file mode 100644 index 000000000000..ca3b73860ccd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart.component.css @@ -0,0 +1,6 @@ +:host { + width: 100%; + height: 200px; + display: block; + position: relative; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart.component.html new file mode 100644 index 000000000000..214e1a55d8a0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart.component.html @@ -0,0 +1 @@ + diff --git a/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart.component.ts new file mode 100644 index 000000000000..b6ee7cd817d6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/load-chart/load-chart.component.ts @@ -0,0 +1,138 @@ +import { Component, OnInit, OnChanges, ViewChild, ElementRef, SimpleChanges, Input, Output, EventEmitter } from '@angular/core'; +import { Chart } from 'chart.js'; + +// @TODO Loading 전 화면 처리 +@Component({ + selector: 'pp-load-chart', + templateUrl: './load-chart.component.html', + styleUrls: ['./load-chart.component.css'] +}) +export class LoadChartComponent implements OnInit, OnChanges { + @ViewChild('loadChart') el: ElementRef; + @Input() chartData: any; + @Input() chartColors: string[]; + @Output() outNotifyMax: EventEmitter = new EventEmitter(); + @Output() outClickColumn: EventEmitter = new EventEmitter(); + chartObj: any; + constructor() {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if (changes['chartData'] && changes['chartData']['firstChange'] === false) { + this.initChart(); + } + } + private initChart(): void { + if (this.chartObj) { + if (this.chartData.max) { + this.chartObj.config.options.scales.yAxes[0].ticks.max = this.chartData.max; + } + this.chartObj.data.labels = this.chartData.labels; + this.chartData.keyValues.forEach((keyValues: any, index: number) => { + this.chartObj.data.datasets[index].data = keyValues.values; + this.chartObj.data.datasets[index].label = keyValues.key; + }); + this.chartObj.update(); + } else { + this.chartObj = new Chart(this.el.nativeElement.getContext('2d'), { + type: 'bar', + data: this.makeDataOption(), + options: this.makeNormalOption() + }); + } + this.outNotifyMax.emit(this.chartObj.scales['y-axis-0'].max); + } + private makeDataOption(): any { + const dataOption = { + labels: this.chartData.labels, + borderWidth: 0, + datasets: [] + }; + + this.chartData.keyValues.forEach((keyValues: any, index: number) => { + dataOption.datasets.push({ + label: keyValues.key, + data: keyValues.values, + backgroundColor: this.chartColors[index], + borderColor: 'rgba(120, 119, 121, 0.8)', + borderWidth: 0 + }); + }); + return dataOption; + } + private makeNormalOption(): any { + return { + onClick: (event: any, aChartEl: any[]) => { + if ( aChartEl.length > 0 ) { + this.outClickColumn.emit(aChartEl[0]._view.label); + } + event.preventDefault(); + // AnalyticsService.send(AnalyticsService.CONST.MAIN, AnalyticsService.CONST.CLK_LOAD_GRAPH); + }, + maintainAspectRatio: false, + tooltips: { + mode: 'label', + bodySpacing: 6 + }, + scales: { + yAxes: [{ + gridLines: { + display: true, + drawBorder: false, + zeroLineWidth: 1.5, + zeroLineColor: 'rgb(0, 0, 0)' + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 4, + callback: (label: number) => { + return ' ' + (label >= 1000 ? `${label / 1000}k` : label) + ' '; + }, + fontColor: 'rgba(162, 162, 162, 1)', + fontSize: 11, + max: this.chartData.max + }, + stacked: true + }], + xAxes: [{ + gridLines: { + display: false, + drawBorder: false + }, + ticks: { + maxTicksLimit: 6, + callback: (label: string): string[] => { + return label.split('#'); + }, + autoSkip: true, + fontColor: 'rgba(162, 162, 162, 1)', + fontSize: 11, + max: this.chartData.max + }, + categoryPercentage: 1.0, + barPercentage: 1.0, + stacked: true, + display: true + }] + }, + animation: { + duration: 0 + }, + legend: { + display: true, + labels: { + boxWidth: 30, + padding: 10 + }, + position: 'bottom' + } + }; + } + getPreSpace(str: string) { + const space = ' '; // 7 is max space + if (str.length > space.length) { + return str; + } else { + return space.substr(0, space.length - str.length); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/main-contents/index.ts b/web/src/main/webapp/v2/src/app/core/components/main-contents/index.ts new file mode 100644 index 000000000000..670642d831b3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/main-contents/index.ts @@ -0,0 +1,27 @@ + +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { FixedPeriodMoverModule } from 'app/core/components/fixed-period-mover'; +import { ServerMapSearchResultViewerModule } from 'app/core/components/server-map-search-result-viewer'; +import { ServerMapModule } from 'app/core/components/server-map'; +import { MainContentsContainerComponent } from './main-contents-container.component'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + MainContentsContainerComponent + ], + imports: [ + SharedModule, + FixedPeriodMoverModule, + ServerMapSearchResultViewerModule, + ServerMapModule, + HelpViewerPopupModule + ], + exports: [ + MainContentsContainerComponent + ], + providers: [] +}) +export class MainContentsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/main-contents/main-contents-container.component.css b/web/src/main/webapp/v2/src/app/core/components/main-contents/main-contents-container.component.css new file mode 100644 index 000000000000..f47e448eed3b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/main-contents/main-contents-container.component.css @@ -0,0 +1,17 @@ +.l-main-contents-top { + display: flex; + flex-flow: row wrap; + margin: 11px 0 0 25px; + align-items: center; + top: 0; + right: 0; + z-index: 8; + padding:0 10px; + font-size:13px; + justify-content: flex-end; + position:absolute; +} +.fas { + color:#a8acb5; + font-size:18px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/main-contents/main-contents-container.component.html b/web/src/main/webapp/v2/src/app/core/components/main-contents/main-contents-container.component.html new file mode 100644 index 000000000000..a2e69aa3a065 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/main-contents/main-contents-container.component.html @@ -0,0 +1,6 @@ +
    + + + +
    + diff --git a/web/src/main/webapp/v2/src/app/core/components/main-contents/main-contents-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/main-contents/main-contents-container.component.ts new file mode 100644 index 000000000000..53b531b52b06 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/main-contents/main-contents-container.component.ts @@ -0,0 +1,28 @@ +import { Component, OnInit } from '@angular/core'; + +import { DynamicPopupService } from 'app/shared/services'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-main-contents-container', + templateUrl: './main-contents-container.component.html', + styleUrls: ['./main-contents-container.component.css'] +}) +export class MainContentsContainerComponent implements OnInit { + constructor( + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() {} + onShowHelp($event: MouseEvent): void { + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.SERVER_MAP, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/message-popup/index.ts b/web/src/main/webapp/v2/src/app/core/components/message-popup/index.ts new file mode 100644 index 000000000000..2f416d2241da --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/message-popup/index.ts @@ -0,0 +1,22 @@ + +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { MessagePopupContainerComponent } from './message-popup-container.component'; +import { MessagePopupComponent } from 'app/core/components/message-popup/message-popup.component'; + +@NgModule({ + declarations: [ + MessagePopupContainerComponent, + MessagePopupComponent + ], + imports: [ + SharedModule + ], + exports: [], + entryComponents: [ + MessagePopupContainerComponent + ], + providers: [] +}) +export class MessagePopupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup-container.component.css new file mode 100644 index 000000000000..3c6a97654ec4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup-container.component.css @@ -0,0 +1,18 @@ +:host { + display: block; + background-color: transparent; + width: 100%; + height: 100%; +} + +:host::before { + content: ''; + display: block; + height: 100%; + width: 100%; + background: #000; + opacity: 0.6; + position: absolute; + left: 0; + top: 0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup-container.component.html new file mode 100644 index 000000000000..5cb0e8c1493b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup-container.component.html @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup-container.component.ts new file mode 100644 index 000000000000..cf294dd730c3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup-container.component.ts @@ -0,0 +1,24 @@ +import { Component, OnInit, Input, Output, EventEmitter, AfterViewInit } from '@angular/core'; + +import { DynamicPopup } from 'app/shared/services'; + +@Component({ + selector: 'pp-message-popup-container', + templateUrl: './message-popup-container.component.html', + styleUrls: ['./message-popup-container.component.css'], +}) +export class MessagePopupContainerComponent implements OnInit, AfterViewInit, DynamicPopup { + @Input() data: ITransactionMessage; + @Output() outClose = new EventEmitter(); + @Output() outCreated = new EventEmitter(); + + constructor() {} + ngOnInit() {} + ngAfterViewInit() { + this.outCreated.emit({ coordX: 0, coordY: 0 }); + } + + onClosePopup() { + this.outClose.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup.component.css new file mode 100644 index 000000000000..60a9ec136756 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup.component.css @@ -0,0 +1,75 @@ +:host { + display: block; + position: absolute; + width: 100%; + min-width: 500px; + max-width: 1000px; + background-color: #fff; + border: 1px solid #e5e8f0; + box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.75); + text-align: left; + top: 50%; + transform: translateX(-50%) translateY(-50%); + left: 50%; +} +.l-title-group { + padding: 17px 18px; + height: auto; + background-color: #fff; + border-bottom: 1px solid #e5e8f0; + position: relative; + font-size: 13px; + font-weight: 600; + color: #333; + display: flex; + align-items: center; + justify-content: space-between; +} +.l-title-group dt { + font-size: 20px; + font-weight: 600; + color: #4a8fd2; +} +.l-title-group button { + position:absolute; + right:27px; + top:50%; + transform:translateY(-50%); + color:#4a8fd2; + font-size: 30px; + width:20px; + height:20px; + background:url(../../../../assets/img/icon-close.png) no-repeat 0 0; +} +.l-contents-group { + background: #f6f8fb; + padding: 17px 18px; + overflow: auto; +} +.l-list { + height: 400px; + margin: 30px 0 0 0; +} +.l-list:first-child { + margin: 0; +} +.l-list dt { + color: #333; + margin: 0 0 12px; + font-size: 13px; + font-weight: 600; +} +.l-list dd { + height: 100%; + border: 1px solid #cfd7e1; + display: block; + padding: 28px 28px; + font-size: 13px; + background: #fff; + word-break: break-all; + overflow-y: auto; + line-height: 2em; +} +.l-list a { + color: #4a8fd2; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup.component.html new file mode 100644 index 000000000000..a73f5ca2df9c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup.component.html @@ -0,0 +1,13 @@ +
    +
    +
    {{data.title}}
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup.component.ts new file mode 100644 index 000000000000..ce9e46c96d13 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/message-popup/message-popup.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit, Input, Output, EventEmitter, HostBinding } from '@angular/core'; + +@Component({ + selector: 'pp-message-popup', + templateUrl: './message-popup.component.html', + styleUrls: ['./message-popup.component.css'] +}) +export class MessagePopupComponent implements OnInit { + @Input() data: ITransactionMessage; + @Output() outClosePopup = new EventEmitter(); + @HostBinding('class.font-opensans') fontFamily = true; + + constructor() {} + ngOnInit() {} + onClose(): void { + this.outClosePopup.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/notice/index.ts b/web/src/main/webapp/v2/src/app/core/components/notice/index.ts new file mode 100644 index 000000000000..8f35a438ebda --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/notice/index.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { NoticeContainerComponent } from 'app/core/components/notice/notice-container.component'; + +@NgModule({ + imports: [ + SharedModule, + ], + exports: [ + NoticeContainerComponent + ], + declarations: [ + NoticeContainerComponent + ], + providers: [], +}) +export class NoticeModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/notice/notice-container.component.css b/web/src/main/webapp/v2/src/app/core/components/notice/notice-container.component.css new file mode 100644 index 000000000000..c8c63d1c4847 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/notice/notice-container.component.css @@ -0,0 +1,22 @@ +:host { + display: none; + position: relative; + padding: 8px 10px; + background-color: #f3e0df; + color: #c04e3f; +} + +.l-notice-message { + font-size: 13px; +} + +.l-notice-message > .fas { + margin-right: 4px; +} + +.l-close-notice-area-button { + position: absolute; + top: 7px; + right: 15px; + font-size: 15px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/notice/notice-container.component.html b/web/src/main/webapp/v2/src/app/core/components/notice/notice-container.component.html new file mode 100644 index 000000000000..035bfe2d826b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/notice/notice-container.component.html @@ -0,0 +1,4 @@ +

    + diff --git a/web/src/main/webapp/v2/src/app/core/components/notice/notice-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/notice/notice-container.component.ts new file mode 100644 index 000000000000..8576413273bf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/notice/notice-container.component.ts @@ -0,0 +1,41 @@ +import { Component, OnInit, ElementRef, Renderer2 } from '@angular/core'; +import { Observable } from 'rxjs'; +import { tap, filter } from 'rxjs/operators'; + +import { BrowserSupportCheckService } from 'app/shared/services'; + +@Component({ + selector: 'pp-notice-container', + templateUrl: './notice-container.component.html', + styleUrls: ['./notice-container.component.css'] +}) +export class NoticeContainerComponent implements OnInit { + noticeMessage$: Observable; + + constructor( + private elementRef: ElementRef, + private renderer: Renderer2, + private browserSupportCheckService: BrowserSupportCheckService + ) { } + + ngOnInit() { + this.noticeMessage$ = this.browserSupportCheckService.getMessage().pipe( + filter((message: string) => { + return message.length !== 0; + }), + tap(() => this.show()) + ); + } + + onClose(): void { + this.hide(); + } + + private hide(): void { + this.renderer.setStyle(this.elementRef.nativeElement, 'display', 'none'); + } + + private show(): void { + this.renderer.setStyle(this.elementRef.nativeElement, 'display', 'block'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/index.ts b/web/src/main/webapp/v2/src/app/core/components/period-selector/index.ts new file mode 100644 index 000000000000..dc631dae80bf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/index.ts @@ -0,0 +1,27 @@ + +import { NgModule } from '@angular/core'; +import { NguiDatetimePickerModule } from '@ngui/datetime-picker'; +import { SharedModule } from 'app/shared'; + +import { PeriodSelectorUsingReservedTimeComponent } from './period-selector-using-reserved-time.component'; +import { PeriodSelectorUsingCalendarComponent } from './period-selector-using-calendar.component'; +import { PeriodSelectorComponent } from './period-selector.component'; +import { PeriodSelectorContainerComponent } from './period-selector-container.component'; + +@NgModule({ + declarations: [ + PeriodSelectorUsingReservedTimeComponent, + PeriodSelectorUsingCalendarComponent, + PeriodSelectorComponent, + PeriodSelectorContainerComponent + ], + imports: [ + NguiDatetimePickerModule, + SharedModule + ], + exports: [ + PeriodSelectorContainerComponent + ], + providers: [] +}) +export class PeriodSelectorModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-container.component.css b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-container.component.html b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-container.component.html new file mode 100644 index 000000000000..ac3e6476d76c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-container.component.html @@ -0,0 +1,14 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-container.component.ts new file mode 100644 index 000000000000..4c642c1a288d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-container.component.ts @@ -0,0 +1,119 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject, Observable, combineLatest } from 'rxjs'; +import { takeUntil, tap } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { + TranslateReplaceService, + StoreHelperService, + WebAppSettingDataService, + UrlRouteManagerService, + NewUrlStateNotificationService, + AnalyticsService, + TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { Period } from 'app/core/models/period'; +import { EndTime } from 'app/core/models/end-time'; + +@Component({ + selector: 'pp-period-selector-container', + templateUrl: './period-selector-container.component.html', + styleUrls: ['./period-selector-container.component.css'] +}) +export class PeriodSelectorContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + i18nText = { + MAX_PERIOD: '', + }; + hiddenComponent: boolean; + selectedPeriod: Period; + selectedEndTime: EndTime; + periodList: Array; + maxPeriod: number; + isRealTimeMode: boolean; + showRealTimeButton: boolean; + timezone$: Observable; + dateFormat$: Observable; + constructor( + private webAppSettingDataService: WebAppSettingDataService, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + private analyticsService: AnalyticsService, + ) {} + ngOnInit() { + this.periodList = this.webAppSettingDataService.getPeriodList(this.newUrlStateNotificationService.getStartPath()); + this.maxPeriod = this.periodList[this.periodList.length - 1].getValue(); + this.getI18NText(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + tap((urlService: NewUrlStateNotificationService) => { + this.showRealTimeButton = urlService.showRealTimeButton(); + this.isRealTimeMode = urlService.isRealTimeMode(); + }) + ).subscribe((urlService: NewUrlStateNotificationService) => { + if ( this.showRealTimeButton && this.isRealTimeMode ) { + this.hiddenComponent = false; + this.selectedPeriod = this.webAppSettingDataService.getSystemDefaultPeriod(); + this.selectedEndTime = EndTime.newByNumber(urlService.getUrlServerTimeData()); + } else { + if (urlService.hasValue(UrlPathId.PERIOD, UrlPathId.END_TIME)) { + this.hiddenComponent = false; + this.selectedPeriod = urlService.getPathValue(UrlPathId.PERIOD); + this.selectedEndTime = urlService.getPathValue(UrlPathId.END_TIME); + } else { + this.hiddenComponent = true; + } + } + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + this.dateFormat$ = this.storeHelperService.getDateFormat(this.unsubscribe, 1); + } + private getI18NText(): void { + combineLatest( + this.translateService.get('COMMON.MAX_SEARCH_PERIOD') + ).subscribe((i18n: string[]) => { + this.i18nText.MAX_PERIOD = this.translateReplaceService.replace(i18n[0], this.maxPeriod / 24 / 60); + }); + } + onChangePeriodTime(selectedPeriod: string): void { + if (this.newUrlStateNotificationService.isRealTimeMode(selectedPeriod)) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SET_PERIOD_AS_REAL_TIME); + this.urlRouteManagerService.moveToRealTime(); + } else { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_PERIOD, selectedPeriod); + this.urlRouteManagerService.move({ + url: [ + this.newUrlStateNotificationService.getStartPath(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + selectedPeriod + ], + needServerTimeRequest: true, + nextUrl: this.newUrlStateNotificationService.hasValue(UrlPathId.AGENT_ID) ? [this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID)] : [] + }); + } + } + onChangeCalendarTime(oChangeTime: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_PERIOD, oChangeTime.period.getValueWithTime()); + this.urlRouteManagerService.move({ + url: [ + this.newUrlStateNotificationService.getStartPath(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + oChangeTime.period.getValueWithTime(), + oChangeTime.endTime.getEndTime() + ], + needServerTimeRequest: false, + nextUrl: this.newUrlStateNotificationService.hasValue(UrlPathId.AGENT_ID) ? [this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID)] : [] + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-calendar.component.css b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-calendar.component.css new file mode 100644 index 000000000000..649edca3d89f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-calendar.component.css @@ -0,0 +1,145 @@ +.l-calendar { + height: 100%; + position: relative; +} +.l-input-group { + display: flex; + flex-flow: row wrap; + align-items: center; + height: 100%; + justify-content: space-between; + background: #3e506b; + color: #fff; + width: 427px; +} +.l-input-group input { + font-size: 12px; + width: 180px; + font-weight: 600; + text-align: center; +} + +.l-input-wrap { + display: flex; + flex-flow: row wrap; + flex: 1 1 0; + justify-content: center; + height: 100%; + border-left:1px solid #4c5c75; + box-shadow: -1px 0px 0px #303f59; + align-items: center; +} +.l-input-wrap .l-sy { + display: inline-block; + margin: 0 6px; +} +.l-input-group .fa-search { + width: 35px; + height: 100%; + border-left: 1px solid #4c5c75; + box-shadow: -1px 0px 0px #303f59; +} + +.l-inner-calendar { + height: 260px; + border-bottom: 1px solid #DBDEE6; +} + +.l-calendar-group { + bottom: -439px; + position: absolute; + left: -36px; + background:#fff; + border: 1px solid #4477CB; + width: calc(100% + 37px); + z-index: 701; +} +.l-calendar-group .l-calendar-wrap { + display: flex; + flex-flow: row wrap; +} +.l-calendar-section { + flex:1; +} +.l-calendar-section:nth-last-child(2) { + border-right: 1px solid #dbdee6; +} +.l-calendar-section .l-set-group { + background: #f8f9fb; + color: #777879; + font-size: 12px; + padding: 15px 13px; +} +.l-calendar-section .l-set-group li { + margin: 6px 0 0 0; + padding: 0 0 0 10px; + background:url(../../../../assets/img/icon-calendar-arrow.png) no-repeat 0 center; + border-left: none; +} +.l-calendar-section .l-set-group li:first-child { + margin-top:0; +} +.l-calendar-section .l-set-group li span { + display: inline-block; + width: 52px; + border-right: 1px solid #e6e8ec; + margin: 0 10px 0 0; +} +.l-calendar-section .l-set-group li select { + border: 1px solid #d7dde4; + background:#fff; +} +.l-btn-group { + border: none; + height: 32px; +} +.l-btn-group .l-time-set { + display: flex; + flex-flow: row wrap; + height: 100%; + justify-content: space-between; +} +.l-btn-group .l-time-set li { + color:#777879; + font-size: 13px; + flex: 1; + text-align: center; + border-left:none; +} +.l-btn-group .l-time-set li.active button, .l-btn-group .l-time-set li button:hover, .l-btn-group .l-time-set li button:focus { + border: none; + background:#469ae4; + color:#fff; +} +.l-btn-group .l-time-set button { + background:none; + color:#777879; + border-left:none; + height: 34px; + font-size: 12px; + font-weight: 600; + padding: 0 8px; + border-radius: 0px; + border-bottom: 1px solid #dbdee6; + border-top: 1px solid #dbdee6; + width: 100%; +} + +.l-calendar-group .l-text { + padding: 15px 13px; + font-size: 13px; + color: #38c2a2; +} + +.ngui-datetime-picker { + font: normal 12px sans-serif !important; + border: none !important; +} +.ngui-datetime-picker > .days { + margin: 4px !important; + padding: 0 4px; +} +.ngui-datetime-picker > .days .day.selected { + background: #469ae4 !important; + color: #FFF !important; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-calendar.component.html b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-calendar.component.html new file mode 100644 index 000000000000..cd0904deed82 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-calendar.component.html @@ -0,0 +1,70 @@ +
    +
    +
    + + - + +
    + +
    +
    +
    +
    + + +
    +
      +
    • + Time{{getStartTime()}}
    • +
    • + Hour + +
    • +
    • + Minute + +
    • +
    +
    +
    +
    + + +
    +
      +
    • + Time{{getEndTime()}}
    • +
    • + Hour + +
    • +
    • + Minute + +
    • +
    +
    +
    +
    +
      +
    • + +
    • +
    +
    +
    {{i18nText.MAX_PERIOD}}
    +
    +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-calendar.component.ts b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-calendar.component.ts new file mode 100644 index 000000000000..cbebf580d0e0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-calendar.component.ts @@ -0,0 +1,122 @@ +import { Component, Input, Output, OnInit, OnChanges, SimpleChanges, EventEmitter, ViewEncapsulation } from '@angular/core'; +import * as moment from 'moment-timezone'; +import { Period } from 'app/core/models/period'; +import { EndTime } from 'app/core/models/end-time'; + +@Component({ + selector: 'pp-period-selector-using-calendar', + templateUrl: './period-selector-using-calendar.component.html', + styleUrls: ['./period-selector-using-calendar.component.css'], + encapsulation: ViewEncapsulation.None +}) +export class PeriodSelectorUsingCalendarComponent implements OnInit, OnChanges { + + @Input() isHidden: boolean; + @Input() i18nText: any; + @Input() maxPeriod: number; + @Input() periodList: Array; + @Input() initPeriod: Period; + @Input() initEndTime: EndTime; + @Input() timezone: string; + @Input() dateFormat: string; + @Output() outChangePeriod = new EventEmitter(); + + isPopupHidden = true; + startDate = moment(); + endDate = moment(); + minDate = new Date(1977, 0, 1); + maxDate = new Date(); + hours: Array = Array(24).fill('').map(function (v, i) { + return { + value: i, + display: ('0' + i).substr(-2) + }; + }); + minutes: Array = Array(60).fill('').map(function (v, i) { + return { + value: i, + display: ('0' + i).substr(-2) + }; + }); + wrongDate = false; + constructor() {} + ngOnChanges(changes: SimpleChanges) { + if ((changes['initEndTime'] && changes['initEndTime']['currentValue']) && (changes['initPeriod'] && changes['initPeriod']['currentValue'])) { + this.startDate = moment(this.initEndTime.calcuStartTime(this.initPeriod.getValue()).getDate()).tz(this.timezone); + this.endDate = moment(this.initEndTime.getDate()).tz(this.timezone); + } + } + ngOnInit() {} + getStartTime(): string { + return this.startDate.format('HH:mm Z'); + } + getEndTime(): string { + return this.endDate.format('HH:mm Z'); + } + getStartDate(): string { + return this.startDate.format(this.dateFormat); + } + getEndDate(): string { + return this.endDate.format(this.dateFormat); + } + checkTimeValid(): void { + if (this.endDate.isBefore(this.startDate) || this.endDate.diff(this.startDate, 'minute') > this.maxPeriod) { + this.wrongDate = true; + } else { + this.wrongDate = false; + } + } + onChangedStartDate(date: Date): void { + this.startDate.set({ + 'year': date.getFullYear(), + 'month': date.getMonth(), + 'date': date.getDate() + }); + this.checkTimeValid(); + } + onChangedEndDate(date: Date): void { + this.endDate.set({ + 'year': date.getFullYear(), + 'month': date.getMonth(), + 'date': date.getDate() + }); + this.checkTimeValid(); + } + onClosePopup(): void { + this.isPopupHidden = true; + } + onTogglePopup(): void { + this.isPopupHidden = !this.isPopupHidden; + } + onChangeStartHour(val: string): void { + this.startDate.hour(parseInt(val, 10)); + this.checkTimeValid(); + } + onChangeStartMinute(val: string): void { + this.startDate.minute(parseInt(val, 10)); + this.checkTimeValid(); + } + onChangeEndHour(val: string): void { + this.endDate.hour(parseInt(val, 10)); + this.checkTimeValid(); + } + onChangeEndMinute(val: string): void { + this.endDate.minute(parseInt(val, 10)); + this.checkTimeValid(); + } + onChangeToReservedPeriod($event: any): void { + if ($event.target.tagName.toUpperCase() === 'BUTTON') { + this.startDate = this.endDate.clone().subtract(Period.parseToMinute($event.target.getAttribute('data-period')), 'minute'); + this.checkTimeValid(); + } + } + onSelectPeriod(): void { + if (this.wrongDate === false) { + this.onClosePopup(); + this.outChangePeriod.emit({ + period: new Period(this.endDate.diff(this.startDate, 'minute')), + endTime: EndTime.newByNumber(this.endDate.valueOf()) + }); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-reserved-time.component.css b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-reserved-time.component.css new file mode 100644 index 000000000000..6d0aa99d576e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-reserved-time.component.css @@ -0,0 +1,28 @@ +.l-time-set { + display: flex; + flex-flow: row wrap; + height: 100%; +} +.l-time-set li { + border-left: 1px solid #364660; +} +.l-time-set button { + height: 100%; + font-size:12px; + font-weight:600; + color:#fff; + padding:0 8px; + background: #3e506b; + border-left:1px solid #4c5c75; + border-radius: 0px; +} +.l-time-set button.active { + background:#33b692; +} +.l-time-set button:focus { + background-color:#469ae4; + color:#fff; +} +.l-time-set button:hover, .l-time-set button:focus { + background:#33b692 +} diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-reserved-time.component.html b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-reserved-time.component.html new file mode 100644 index 000000000000..b92799a40c6e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-reserved-time.component.html @@ -0,0 +1,8 @@ +
      +
    • + +
    • +
    • + +
    • +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-reserved-time.component.ts b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-reserved-time.component.ts new file mode 100644 index 000000000000..865e3b45e7d9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector-using-reserved-time.component.ts @@ -0,0 +1,28 @@ +import { Component, EventEmitter, Input, Output, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { Period } from 'app/core/models/period'; + +@Component({ + selector: 'pp-period-selector-using-reserved-time', + templateUrl: './period-selector-using-reserved-time.component.html', + styleUrls: ['./period-selector-using-reserved-time.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class PeriodSelectorUsingReservedTimeComponent implements OnInit { + @Input() showRealTimeButton: boolean; + @Input() isRealTimeMode: boolean; + @Input() isHidden: boolean; + @Input() periodList: Array; + @Input() initPeriod: Period; + @Output() outChangePeriod = new EventEmitter(); + constructor() {} + ngOnInit() {} + onSelectPeriod($event: any): void { + if ($event.target.tagName.toUpperCase() === 'BUTTON') { + this.outChangePeriod.emit($event.target.getAttribute('data-period')); + } + } + isSelectedPeriod(period: Period): boolean { + return this.isRealTimeMode === false && period.equals(this.initPeriod); + } + +} diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector.component.css b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector.component.css new file mode 100644 index 000000000000..d14523ded466 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector.component.css @@ -0,0 +1,59 @@ +.l-wrapper { + display: flex; + flex-flow: row wrap; + margin-right: 10px; + border: 1px solid #364660; + border-radius: 0px; + line-height: 1em; + align-items:stretch; + height: 32px; +} +.fas { + font-size: 16px; +} +.l-type-select { + display: flex; + flex-flow: row wrap; + position: relative; +} +.l-type-select li { + position: relative; + border-left: none; +} +.l-type-select button { + height: 100%; + background: #3E506B; + padding: 0 5px; + width: 35px; + color:#38c2a2; +} +.l-type-select li.inactive { + border: 1px solid #364660; + border-radius: 0 0 2px 2px; + overflow: hidden; + bottom: -36px; + left: -1px; + position: absolute; +} +.l-type-select li:after { + content: ''; + width: 0; + height: 0; + border-right: 0 solid #33b692; + border-bottom: 8px solid #33b692; + border-left: 8px solid transparent; + position: absolute; + right: 0; + bottom: 0; +} +.l-type-select li.inactive:after { + display:none; +} +.l-type-select li.inactive button { + color:#7185a2; + height: 34px; + width: 34px; +} +.l-type-select li:first-child button { + border-left: none; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector.component.html b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector.component.html new file mode 100644 index 000000000000..d29b48c7d704 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector.component.html @@ -0,0 +1,27 @@ +
    +
      +
    • + +
    • +
    • + +
    • +
    + + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector.component.ts b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector.component.ts new file mode 100644 index 000000000000..44e45d9aa282 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/period-selector/period-selector.component.ts @@ -0,0 +1,72 @@ +import { Component, OnInit, OnChanges, OnDestroy, Input, Output, EventEmitter, SimpleChanges } from '@angular/core'; + +import { Period } from 'app/core/models/period'; +import { EndTime } from 'app/core/models/end-time'; +import { AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; + +enum PeriodSelectType { + RESERVED_PERIOD, + CALENDAR_PERIOD +} + +@Component({ + selector: 'pp-period-selector', + templateUrl: './period-selector.component.html', + styleUrls: ['./period-selector.component.css'] +}) +export class PeriodSelectorComponent implements OnInit, OnChanges, OnDestroy { + periodSelectType: PeriodSelectType = PeriodSelectType.RESERVED_PERIOD; + @Input() i18nText: any; + @Input() showRealTimeButton: boolean; + @Input() isRealTimeMode: boolean; + @Input() selectedPeriod: Period; + @Input() selectedEndTime: EndTime; + @Input() periodList: Array; + @Input() maxPeriod: number; + @Input() timezone: string; + @Input() dateFormat: string; + @Output() outChangePeriod: EventEmitter = new EventEmitter(); + @Output() outChangeCalendarTime: EventEmitter = new EventEmitter(); + constructor( + private analyticsService: AnalyticsService, + ) {} + ngOnChanges(changes: SimpleChanges) { + if (changes['selectedPeriod'] && changes['selectedEndTime'] || changes['isRealTimeMode']) { + this.checkPeriodType(); + } + } + ngOnInit() {} + ngOnDestroy() {} + onChangePeriodTime(selectedPeriod: string): void { + this.outChangePeriod.emit(selectedPeriod); + } + onChangeCalendarTime(oChangeTime: any): void { + if (this.selectedEndTime.equals(oChangeTime.endTime) === false || this.selectedPeriod.equals(oChangeTime.period) === false) { + this.outChangeCalendarTime.emit(oChangeTime); + } + } + private checkPeriodType(): void { + if (this.isRealTimeMode) { + this.periodSelectType = PeriodSelectType.RESERVED_PERIOD; + return; + } + for (let i = 0; i < this.periodList.length; i++) { + if (this.periodList[i].equals(this.selectedPeriod)) { + this.periodSelectType = PeriodSelectType.RESERVED_PERIOD; + return; + } + } + this.periodSelectType = PeriodSelectType.CALENDAR_PERIOD; + } + isReservedType(): boolean { + return this.periodSelectType === PeriodSelectType.RESERVED_PERIOD; + } + changeToReservedType(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_PERIOD_SELECT_TYPE, PeriodSelectType[PeriodSelectType.RESERVED_PERIOD]); + this.periodSelectType = PeriodSelectType.RESERVED_PERIOD; + } + changeToCalendarType(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_PERIOD_SELECT_TYPE, PeriodSelectType[PeriodSelectType.CALENDAR_PERIOD]); + this.periodSelectType = PeriodSelectType.CALENDAR_PERIOD; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/index.ts b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/index.ts new file mode 100644 index 000000000000..85c9294efea1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/index.ts @@ -0,0 +1,36 @@ + +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { ScrollingModule } from '@angular/cdk/scrolling'; +import { SharedModule } from 'app/shared'; +import { PinpointUserComponent } from './pinpoint-user.component'; +import { PinpointUserCreateAndUpdateComponent } from './pinpoint-user-create-and-update.component'; +import { PinpointUserContainerComponent } from './pinpoint-user-container.component'; +import { PinpointUserInteractionService } from './pinpoint-user-interaction.service'; +import { PinpointUserDataService } from './pinpoint-user-data.service'; + +@NgModule({ + declarations: [ + PinpointUserComponent, + PinpointUserCreateAndUpdateComponent, + PinpointUserContainerComponent + ], + imports: [ + FormsModule, + ReactiveFormsModule, + ScrollingModule, + SharedModule + ], + exports: [ + PinpointUserContainerComponent + ], + entryComponents: [ + PinpointUserComponent, + PinpointUserContainerComponent + ], + providers: [ + PinpointUserInteractionService, + PinpointUserDataService + ] +}) +export class PinpointUserModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-container.component.css b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-container.component.css new file mode 100644 index 000000000000..ab5a4696e26d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-container.component.css @@ -0,0 +1,59 @@ +:host { + position: relative; +} +.l-pinpoint-user-wrapper { + color: #333; + border: 1px solid #e5e8f0; + height: 100%; + display: grid; + position: relative; + font-size: 13px; + font-family: 'Open Sans', sans-serif; + font-weight: 600; + grid-template-columns: auto; + grid-template-rows: 48px 53px 416px; +} +.l-pinpoint-user-title { + display: flex; + padding: 0px 15px; + align-items: center; + justify-content: space-between; + background-color: #f6f8fb; + border-bottom: 1px solid #e5e8f0; +} +.l-pinpoint-user-title button:last-child { + margin-left: 2px; +} +.l-pinpoint-user-search { + padding: 10px 15px; + border-bottom: 1px solid #e5e8f0; +} +.l-pinpoint-user-list { + overflow-y: auto; +} +.l-message { + width: 100%; + height: 100%; + z-index: 15; + display: flex; + position: absolute; + align-items: center; + justify-content: center; + background-color: rgba(226, 226, 226, 0.8); +} +.l-message span { + color: #ff8c00; + text-align: center; +} +.l-message button { + top: 0px; + right: 0px; + position: absolute; +} +.l-search-input { + width: 100%; + color: #b3b3b4; + border: 1px solid #469ae4; + padding: 6px 11px; + font-size: 13px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-container.component.html b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-container.component.html new file mode 100644 index 000000000000..097e48370548 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-container.component.html @@ -0,0 +1,47 @@ +
    +
    + Pinpoint User ({{pinpointUserList.length}}) +
    + + +
    +
    + +
    + + + + +
    +
    + + {{message}} +
    + + + +
    + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-container.component.ts new file mode 100644 index 000000000000..ebeace5260e7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-container.component.ts @@ -0,0 +1,263 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject, combineLatest } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { TranslateReplaceService, WebAppSettingDataService } from 'app/shared/services'; +import { GroupMemberInteractionService } from 'app/core/components/group-member/group-member-interaction.service'; +import { UserGroupInteractionService } from 'app/core/components/user-group/user-group-interaction.service'; +import { PinpointUserInteractionService } from './pinpoint-user-interaction.service'; +import { PinpointUser } from './pinpoint-user-create-and-update.component'; +import { PinpointUserDataService, IPinpointUser, IPinpointUserResponse } from './pinpoint-user-data.service'; + +@Component({ + selector: 'pp-pinpoint-user-container', + templateUrl: './pinpoint-user-container.component.html', + styleUrls: ['./pinpoint-user-container.component.css'] +}) +export class PinpointUserContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private searchQuery = ''; + i18nLabel = { + USER_ID_LABEL: '', + NAME_LABEL: '', + DEPARTMENT_LABEL: '', + PHONE_LABEL: '', + EMAIL_LABEL: '', + }; + i18nGuide = { + USER_ID_MIN_LENGTH: '', + NAME_MIN_LENGTH: '', + USER_ID_REQUIRED: '', + NAME_REQUIRED: '', + PHONE_REQUIRED: '', + EMAIL_REQUIRED: '', + }; + i18nText = { + SEARCH_INPUT_GUIDE: '' + }; + minLength = { + userId: 3, + name: 3, + search: 2 + }; + allowedUserEdit = false; + searchUseEnter = false; + pinpointUserList: IPinpointUser[] = []; + filteredPinpointUserList: IPinpointUser[] = []; + groupMemberList: string[] = []; + editPinpointUserIndex: number; + editPinpointUser: PinpointUser; + isUserGroupSelected = false; + useDisable = true; + showLoading = true; + showCreate = false; + message = ''; + + displayPinpointUserList: IPinpointUser[] = []; + defaultScrollSize = 100; + currentSize: number; + constructor( + private webAppSettingDataService: WebAppSettingDataService, + private pinpointUserDataService: PinpointUserDataService, + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + private userGroupInteractionService: UserGroupInteractionService, + private groupMemberInteractionService: GroupMemberInteractionService, + private pinpointUserInteractionService: PinpointUserInteractionService + ) {} + ngOnInit() { + this.webAppSettingDataService.useUserEdit().subscribe((allowedUserEdit: boolean) => { + this.allowedUserEdit = allowedUserEdit; + }); + this.userGroupInteractionService.onSelect$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((userGroupId: string) => { + this.isUserGroupSelected = userGroupId === '' ? false : true; + }); + this.groupMemberInteractionService.onChangeGroupMember$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((memberList: string[]) => { + this.groupMemberList = memberList; + this.hideProcessing(); + }); + this.getI18NText(); + this.getPinpointUserList(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private getI18NText(): void { + combineLatest( + this.translateService.get('COMMON.MIN_LENGTH'), + this.translateService.get('COMMON.REQUIRED'), + this.translateService.get('CONFIGURATION.COMMON.USER_ID'), + this.translateService.get('CONFIGURATION.COMMON.NAME'), + this.translateService.get('CONFIGURATION.COMMON.DEPARTMENT'), + this.translateService.get('CONFIGURATION.COMMON.PHONE'), + this.translateService.get('CONFIGURATION.COMMON.EMAIL'), + this.translateService.get('CONFIGURATION.USER_GROUP.USER_GROUP_REQUIRED') + ).subscribe((i18n: string[]) => { + this.i18nGuide.USER_ID_MIN_LENGTH = this.translateReplaceService.replace(i18n[0], this.minLength.userId); + this.i18nGuide.NAME_MIN_LENGTH = this.translateReplaceService.replace(i18n[0], this.minLength.name); + this.i18nGuide.USER_ID_REQUIRED = this.translateReplaceService.replace(i18n[1], i18n[2]); + this.i18nGuide.NAME_REQUIRED = this.translateReplaceService.replace(i18n[1], i18n[3]); + this.i18nGuide.PHONE_REQUIRED = this.translateReplaceService.replace(i18n[1], i18n[5]); + this.i18nGuide.EMAIL_REQUIRED = this.translateReplaceService.replace(i18n[1], i18n[6]); + + this.i18nText.SEARCH_INPUT_GUIDE = this.translateReplaceService.replace(i18n[0], this.minLength.search); + + this.i18nLabel.USER_ID_LABEL = i18n[2]; + this.i18nLabel.NAME_LABEL = i18n[3]; + this.i18nLabel.DEPARTMENT_LABEL = i18n[4]; + this.i18nLabel.PHONE_LABEL = i18n[5]; + this.i18nLabel.EMAIL_LABEL = i18n[6]; + }); + } + private getPinpointUserList(): void { + this.showProcessing(); + this.webAppSettingDataService.getUserDepartment().subscribe((department: string) => { + this.pinpointUserDataService.retrieve(department).subscribe((pinpointUserData: IPinpointUser[] | IServerErrorShortFormat) => { + if ((pinpointUserData as IServerErrorShortFormat).errorCode) { + this.message = (pinpointUserData as IServerErrorShortFormat).errorMessage; + } else { + this.pinpointUserList = pinpointUserData as IPinpointUser[]; + this.filteringPinpointUserList(); + } + this.hideProcessing(); + }, (error: IServerErrorFormat) => { + this.message = error.exception.message; + this.hideProcessing(); + }); + }); + } + private filteringPinpointUserList(): void { + if (this.searchQuery === '') { + this.filteredPinpointUserList = this.pinpointUserList; + } else { + this.filteredPinpointUserList = this.pinpointUserList.filter((pinpointUser: IPinpointUser): boolean => { + return pinpointUser.name.indexOf(this.searchQuery) === -1 ? false : true; + }); + } + this.displayPinpointUserList = this.filteredPinpointUserList; + } + isEnable(): boolean { + return false; + } + isChecked(userId: string): boolean { + return this.groupMemberList.indexOf(userId) !== -1; + } + hasMessage(): boolean { + return this.message !== ''; + } + onAddUser(pinpointUserId: string): void { + this.showProcessing(); + this.pinpointUserInteractionService.setAddPinpointUser(pinpointUserId); + } + onCloseMessage(): void { + this.message = ''; + } + onSearch(query: string): void { + this.searchQuery = query; + this.filteringPinpointUserList(); + } + onReload(): void { + this.getPinpointUserList(); + } + onCloseCreateUserPopup(): void { + this.showCreate = false; + } + onShowCreateUserPopup(): void { + this.showCreate = true; + } + onCreatePinpointUser(pinpointUser: PinpointUser): void { + this.pinpointUserDataService.create({ + userId: pinpointUser.userId, + name: pinpointUser.name, + phoneNumber: pinpointUser.phoneNumber, + email: pinpointUser.email, + department: pinpointUser.department + } as IPinpointUser).subscribe((response: IPinpointUserResponse | IServerErrorShortFormat) => { + if ((response as IServerErrorShortFormat).errorCode) { + this.message = (response as IServerErrorShortFormat).errorMessage; + this.hideProcessing(); + } else { + this.getPinpointUserList(); + } + }, (error: string) => { + this.hideProcessing(); + this.message = error; + }); + } + onUpdatePinpointUser(pinpointUser: PinpointUser): void { + const editPinpointUser = this.pinpointUserList[this.editPinpointUserIndex]; + this.pinpointUserDataService.update({ + userId: pinpointUser.userId, + name: pinpointUser.name, + phoneNumber: pinpointUser.phoneNumber, + email: pinpointUser.email, + department: pinpointUser.department, + number: editPinpointUser.number + } as IPinpointUser).subscribe((response: IPinpointUserResponse | IServerErrorShortFormat) => { + if ((response as IServerErrorShortFormat).errorCode) { + this.message = (response as IServerErrorShortFormat).errorMessage; + this.hideProcessing(); + } else { + this.getPinpointUserList(); + this.pinpointUserInteractionService.setUserUpdated({ + userId: pinpointUser.userId, + department: pinpointUser.department, + name: pinpointUser.name + }); + } + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + }); + } + onRemovePinpointUser(userId: string): void { + this.showProcessing(); + this.pinpointUserDataService.remove(userId).subscribe((response: IPinpointUserResponse | IServerErrorShortFormat) => { + if ((response as IServerErrorShortFormat).errorCode) { + this.message = (response as IServerErrorShortFormat).errorMessage; + } else { + this.pinpointUserList.splice(this.getPinpointUserIndexByUserId(userId), 1); + } + this.hideProcessing(); + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + }); + } + onEditPinpointUser(userId: string): void { + this.editPinpointUserIndex = this.getPinpointUserIndexByUserId(userId); + const editPinpointUser = this.pinpointUserList[this.editPinpointUserIndex]; + this.editPinpointUser = new PinpointUser( + editPinpointUser.userId, + editPinpointUser.name, + editPinpointUser.phoneNumber, + editPinpointUser.email, + editPinpointUser.department + ); + this.onShowCreateUserPopup(); + } + private getPinpointUserIndexByUserId(userId: string): number { + let index = -1; + for (let i = 0 ; i < this.pinpointUserList.length ; i++) { + if (this.pinpointUserList[i].userId === userId) { + index = i; + break; + } + } + return index; + } + private showProcessing(): void { + this.useDisable = true; + this.showLoading = true; + } + private hideProcessing(): void { + this.useDisable = false; + this.showLoading = false; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-create-and-update.component.css b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-create-and-update.component.css new file mode 100644 index 000000000000..78db2a42dd5f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-create-and-update.component.css @@ -0,0 +1,50 @@ +.l-wrapper { + top: 0px; + left: 0px; + width: 100%; + height: 100%; + z-index: 15; + display: flex; + padding: 0px 20px; + position: absolute; + align-items: center; + flex-direction: column; + justify-content: center; + background-color: rgba(226, 226, 226, 0.9); +} +.l-wrapper h1 { + margin-bottom: 6px; +} +.l-wrapper input { + width: 100%; + border: 1px solid #469ae4; + padding: 6px 11px; + font-size: 13px; + margin-bottom: 2px; + background-color: #FFF; +} +.l-wrapper .l-create { + width: 100%; + margin-top: 6px; +} +.l-wrapper .l-close { + top: 0px; + right: 0px; + position: absolute; +} +.l-wrapper .l-alert { + color: #FFF; + padding: 4px; + margin-bottom: 4px; + background-color: #000; +} +.ng-valid[required], .ng-valid.required { + border-left: 5px solid #42A948 !important; +} + +.ng-invalid:not(form) { + border-left: 5px solid #a94442 !important; +} +input[disabled] { + border: 1px solid #DDD !important; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-create-and-update.component.html b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-create-and-update.component.html new file mode 100644 index 000000000000..0cdcf8e0d5b0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-create-and-update.component.html @@ -0,0 +1,41 @@ +
    + +

    {{title}}

    +
    +
    + + +
    +
    {{i18nGuide.USER_ID_REQUIRED}}
    +
    {{i18nGuide.USER_ID_MIN_LENGTH}}
    +
    +
    +
    + + +
    +
    {{i18nGuide.NAME_REQUIRED}}
    +
    {{i18nGuide.NAME_MIN_LENGTH}}
    +
    +
    +
    + + +
    +
    + + +
    +
    {{i18nGuide.PHONE_REQUIRED}}
    +
    +
    +
    + + +
    +
    {{i18nGuide.EMAIL_REQUIRED}}
    +
    +
    + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-create-and-update.component.ts b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-create-and-update.component.ts new file mode 100644 index 000000000000..02d3dc1bd53a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-create-and-update.component.ts @@ -0,0 +1,101 @@ +import { Component, OnInit, OnChanges, SimpleChanges, Input, Output, EventEmitter, AfterViewChecked, ViewChild, ElementRef } from '@angular/core'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; + +export class PinpointUser { + constructor( + public userId: string, + public name: string, + public phoneNumber: string, + public email: string, + public department?: string + ) {} +} + +@Component({ + selector: 'pp-pinpoint-user-create-and-update', + templateUrl: './pinpoint-user-create-and-update.component.html', + styleUrls: ['./pinpoint-user-create-and-update.component.css'] +}) +export class PinpointUserCreateAndUpdateComponent implements OnInit, OnChanges, AfterViewChecked { + @ViewChild('newUserGroupName') userGroupInput: ElementRef; + @Input() showCreate = false; + @Input() i18nLabel: any; + @Input() i18nGuide: any; + @Input() minLength: any; + @Input() editPinpointUser: PinpointUser = null; + @Output() outUpdatePinpointUser: EventEmitter = new EventEmitter(); + @Output() outCreatePinpointUser: EventEmitter = new EventEmitter(); + @Output() outClose: EventEmitter = new EventEmitter(); + newUserModel = new PinpointUser('', '', '', '', ''); + pinpointUserForm: FormGroup; + title = 'Pinpoint User'; + constructor() {} + ngOnInit() { + this.pinpointUserForm = new FormGroup({ + 'userId': new FormControl(this.newUserModel.userId, [ + Validators.required, + Validators.minLength(this.minLength.userId) + ]), + 'name': new FormControl(this.newUserModel.name, [ + Validators.required, + Validators.minLength(this.minLength.name) + ]), + 'phoneNumber': new FormControl(this.newUserModel.phoneNumber, [ + Validators.required, + Validators.pattern(/\d*/) + ]), + 'email': new FormControl(this.newUserModel.email, [ + Validators.required, + Validators.email + ]), + 'department': new FormControl(this.newUserModel.department, []) + }); + } + ngOnChanges(changes: SimpleChanges) { + if (changes['editPinpointUser'] && changes['editPinpointUser'].currentValue) { + this.pinpointUserForm.get('userId').setValue(this.editPinpointUser.userId); + this.pinpointUserForm.get('name').setValue(this.editPinpointUser.name); + this.pinpointUserForm.get('phoneNumber').setValue(this.editPinpointUser.phoneNumber); + this.pinpointUserForm.get('email').setValue(this.editPinpointUser.email); + this.pinpointUserForm.get('department').setValue(this.editPinpointUser.department); + this.pinpointUserForm.get('userId').disable(); + } + } + ngAfterViewChecked() {} + onCreateOrUpdate(): void { + const pinpointUser = new PinpointUser( + this.pinpointUserForm.get('userId').value, + this.pinpointUserForm.get('name').value, + this.pinpointUserForm.get('phoneNumber').value, + this.pinpointUserForm.get('email').value.toString(), + this.pinpointUserForm.get('department').value + ); + if (this.editPinpointUser) { + this.outUpdatePinpointUser.emit(pinpointUser); + } else { + this.outCreatePinpointUser.emit(pinpointUser); + } + this.onClose(); + } + onClose(): void { + this.editPinpointUser = null; + this.outClose.emit(); + this.pinpointUserForm.reset(); + this.pinpointUserForm.get('userId').enable(); + } + get userId() { + return this.pinpointUserForm.get('userId'); + } + get name() { + return this.pinpointUserForm.get('name'); + } + get department() { + return this.pinpointUserForm.get('department'); + } + get phoneNumber() { + return this.pinpointUserForm.get('phoneNumber'); + } + get email() { + return this.pinpointUserForm.get('email'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-data.service.ts new file mode 100644 index 000000000000..897cea098369 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-data.service.ts @@ -0,0 +1,49 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + +export interface IPinpointUser { + department?: string; + email: string; + name: string; + number: string; + phoneNumber: string; + userId: string; +} +export interface IPinpointUserResponse { + result: string; +} + +@Injectable() +export class PinpointUserDataService { + private url = 'user.pinpoint'; + constructor(private http: HttpClient) { } + retrieve(department?: string): Observable { + return this.http.get(this.url, this.makeRequestOptionsArgs(department)).pipe( + retry(3) + ); + } + create(params: IPinpointUser): Observable { + return this.http.post(this.url, params).pipe( + retry(3) + ); + } + update(params: IPinpointUser): Observable { + return this.http.put(this.url, params).pipe( + retry(3) + ); + } + remove(userId: string): Observable { + return this.http.request('delete', this.url, { + body: { userId } + }).pipe( + retry(3) + ); + } + private makeRequestOptionsArgs(department?: string): object { + return department ? { + params: new HttpParams().set('searchKey', department) + } : {}; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-interaction.service.ts new file mode 100644 index 000000000000..72f7ee0afe2f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user-interaction.service.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; + +@Injectable() +export class PinpointUserInteractionService { + private outAdd = new Subject(); + private outUpdate = new Subject(); + private outRemove = new Subject(); + + onAdd$: Observable; + onRemove$: Observable; + onUpdate$: Observable; + + constructor() { + this.onAdd$ = this.outAdd.asObservable(); + this.onRemove$ = this.outRemove.asObservable(); + this.onUpdate$ = this.outUpdate.asObservable(); + } + setAddPinpointUser(memberId: string): void { + this.outAdd.next(memberId); + } + setRemovePinpointUser(memberId: string): void { + this.outRemove.next(memberId); + } + setUserUpdated(memberInfo: any): void { + this.outUpdate.next(memberInfo); + } +} + diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user.component.css b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user.component.css new file mode 100644 index 000000000000..1ada1e8c3f54 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user.component.css @@ -0,0 +1,33 @@ +.l-item-wrapper { + height: 28px; + margin: 0; + color: #333; + padding: 6px 15px 0px 15px; + font-size: 13px; + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.l-item-wrapper:hover { + background:#fff0f0; +} +.l-item-wrapper.selected { + background:#fff0f0; +} + +.l-item-wrapper > div { + float: right; +} +.l-item-wrapper .fa-trash-alt { + color: #b3b6bf; + font-size: 14px; + margin-left: 4px; +} +.l-item-wrapper .fa-check { + color: #F00; + margin-left: 10px; +} +.l-disabled { + color:#DDD; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user.component.html b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user.component.html new file mode 100644 index 000000000000..bb6f0ab7932f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user.component.html @@ -0,0 +1,13 @@ +
    +
    + + + + +
    + ({{pinpointUser.department}}) {{pinpointUser.name}} +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user.component.ts b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user.component.ts new file mode 100644 index 000000000000..1f9e24d45e61 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/pinpoint-user/pinpoint-user.component.ts @@ -0,0 +1,49 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { IPinpointUser } from './pinpoint-user-data.service'; + +@Component({ + selector: 'pp-pinpoint-user', + templateUrl: './pinpoint-user.component.html', + styleUrls: ['./pinpoint-user.component.css'] +}) +export class PinpointUserComponent implements OnInit { + @Input() pinpointUser: IPinpointUser; + @Input() allowedUserEdit: boolean; + @Input() isChecked = false; + @Input() isEnabled = false; + @Output() outRemove: EventEmitter = new EventEmitter(); + @Output() outAddUser: EventEmitter = new EventEmitter(); + @Output() outEditUser: EventEmitter = new EventEmitter(); + private removeConformId = ''; + private selectedPinpointUser: string; + + constructor() {} + ngOnInit() {} + onRemove(): void { + this.removeConformId = this.pinpointUser.userId; + } + onEdit(): void { + this.outEditUser.emit(this.pinpointUser.userId); + } + onAddUser(): void { + if (this.isEnableUser()) { + this.outAddUser.emit(this.pinpointUser.userId); + } + } + onCancelRemove(): void { + this.removeConformId = ''; + } + onConfirmRemove(): void { + this.outRemove.emit(this.removeConformId); + this.removeConformId = ''; + } + isRemoveTarget(): boolean { + return this.removeConformId === this.pinpointUser.userId; + } + isSelected(): boolean { + return this.selectedPinpointUser === this.pinpointUser.userId; + } + isEnableUser(): boolean { + return this.isEnabled && !this.isChecked; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/index.ts b/web/src/main/webapp/v2/src/app/core/components/real-time-new/index.ts new file mode 100644 index 000000000000..ae7c90e99a11 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/index.ts @@ -0,0 +1,34 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; +import { NewResizeTopDirective } from 'app/core/components/real-time-new/new-resize-top.directive'; +import { NewRealTimeAgentChartComponent } from 'app/core/components/real-time-new/new-real-time-agent-chart.component'; +import { NewRealTimeChartComponent } from 'app/core/components/real-time-new/new-real-time-chart.component'; +import { NewRealTimeContainerComponent } from 'app/core/components/real-time-new/new-real-time-container.component'; +import { NewRealTimeTotalChartComponent } from 'app/core/components/real-time-new/new-real-time-total-chart.component'; +import { NewRealTimePagingContainerComponent } from 'app/core/components/real-time-new/new-real-time-paging-container.component'; +import { NewRealTimeWebSocketService } from 'app/core/components/real-time-new/new-real-time-websocket.service'; + +@NgModule({ + declarations: [ + NewResizeTopDirective, + NewRealTimeAgentChartComponent, + NewRealTimeChartComponent, + NewRealTimeContainerComponent, + NewRealTimeTotalChartComponent, + NewRealTimePagingContainerComponent + ], + imports: [ + SharedModule, + HelpViewerPopupModule + ], + exports: [ + NewRealTimeContainerComponent, + NewRealTimePagingContainerComponent + ], + providers: [ + NewRealTimeWebSocketService + ] +}) +export class NewRealTimeModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-agent-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-agent-chart.component.css new file mode 100644 index 000000000000..e077c05aa824 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-agent-chart.component.css @@ -0,0 +1,4 @@ +:host { + display: block; + width: 100%; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-agent-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-agent-chart.component.html new file mode 100644 index 000000000000..7f70217d90a8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-agent-chart.component.html @@ -0,0 +1,8 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-agent-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-agent-chart.component.ts new file mode 100644 index 000000000000..99f4b00475b8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-agent-chart.component.ts @@ -0,0 +1,59 @@ +import { Component, OnInit, Input, Output, EventEmitter, AfterViewInit } from '@angular/core'; + +import { IActiveThreadCounts } from 'app/core/components/real-time-new/new-real-time-websocket.service'; +import { ChartType } from './new-real-time-chart.component'; + +@Component({ + selector: 'pp-new-real-time-agent-chart', + templateUrl: './new-real-time-agent-chart.component.html', + styleUrls: ['./new-real-time-agent-chart.component.css'] +}) +export class NewRealTimeAgentChartComponent implements OnInit, AfterViewInit { + @Input() timeStamp: number; + @Input() activeThreadCounts: { [key: string]: IActiveThreadCounts }; + @Input() pagingSize: number; + @Input() currentPage = 1; + @Output() outOpenThreadDump = new EventEmitter(); + @Output() outRenderCompleted = new EventEmitter(true); + + chartOption = { + canvasLeftPadding: 0, + canvasTopPadding: 0, + canvasRightPadding: 0, + canvasBottomPadding: 0, + chartInnerPadding: 0, + containerWidth: 152, + containerHeight: 52, + chartWidth: 152, + chartHeight: 52, + titleHeight: 32, + gapBtnChart: 10, + chartColors: ['#33b692', '#51afdf', '#fea63e', '#e76f4b'], + chartLabels: ['1s', '3s', '5s', 'Slow'], + linkIconCode: '\uf35d', + marginRightForLinkIcon: 10, + ellipsis: '...', + drawHGridLine: false, + drawVGridLine: true, + showXAxis: false, + showXAxisLabel: false, + showYAxis: false, + showYAxisLabel: false, + yAxisLabelWidth: 0, + marginFromYAxis: 0, + tooltipEnabled: false, + titleFontSize: '11px', + errorFontSize: '13px', + duration: 4000, + chartType: ChartType.EACH + }; + + constructor() {} + ngOnInit() {} + ngAfterViewInit() { + this.outRenderCompleted.emit(); + } + onClick(key: string): void { + this.outOpenThreadDump.emit(key); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-chart.component.css new file mode 100644 index 000000000000..d764c9a2cc89 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-chart.component.css @@ -0,0 +1,53 @@ +:host { + display: block; + width: 100%; + height: 100%; + position: relative; +} + +.l-tooltip { + background-color: rgba(0, 0, 0, 0.8); + color: #fff; + border: 0px solid rgba(0, 0, 0, 0); + border-radius: 5px; + padding: 5px 7px; + position: absolute; + top: 110%; + width: 130px; +} + +.l-tooltip-caret { + width: 0; + height: 0; + position: absolute; + top: calc(110% - 6px); + border-bottom: 7px solid rgba(0, 0, 0, 0.8); + border-left: 7px solid transparent; + border-right: 7px solid transparent; +} + +.l-tooltip-title { + font-size: 12px; + font-weight: 600; + margin-bottom: 2px; +} + +.l-tooltip-body { + font-size: 12px; +} + +.l-tooltip-body > dl { + display: flex; +} + +.l-tooltip-body dt { + margin-right: 5px; +} + +.l-tooltip-label { + display: inline-block; + width: 10px; + height: 10px; + margin-right: 2px; + box-shadow: inset 0px 0px 0px 1px rgba(255, 255, 255, 0.4); +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-chart.component.html new file mode 100644 index 000000000000..698f2a6f6db9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-chart.component.html @@ -0,0 +1,18 @@ + + + +
    +
    {{tooltipDataObj.title}}
    +
    +
    +
    {{chartOption.chartLabels[i]}}:
    +
    {{value}}
    +
    +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-chart.component.ts new file mode 100644 index 000000000000..cdc0da797b79 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-chart.component.ts @@ -0,0 +1,736 @@ +import { Component, OnInit, ViewChild, ElementRef, Input, Output, AfterViewInit, OnDestroy, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; +import * as moment from 'moment-timezone'; + +import { IActiveThreadCounts, ResponseCode } from 'app/core/components/real-time/real-time-websocket.service'; + +export const enum ChartType { + SUM = 'sum', + EACH = 'each' +} + +@Component({ + selector: 'pp-new-real-time-chart', + templateUrl: './new-real-time-chart.component.html', + styleUrls: ['./new-real-time-chart.component.css'] +}) +export class NewRealTimeChartComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges { + @ViewChild('realTime') canvasRef: ElementRef; + @Input() activeThreadCounts: { [key: string]: IActiveThreadCounts }; + @Input() timezone: string; + @Input() dateFormat: string; + @Input() timeStamp: number; + @Input() applicationName: string; + @Input() pagingSize: number; + @Input() currentPage: number; + @Input() chartOption: { [key: string]: any }; + @Output() outClick = new EventEmitter(); + @Output() outSum = new EventEmitter(); + + private canvas: HTMLCanvasElement; + private ctx: CanvasRenderingContext2D; + private firstTimeStamp: { [key: string]: number } = {}; + private chartStart: { [key: string]: number } = {}; + private animationFrameId: number; + private timeStampList: { [key: string]: number[] } = {}; + private dataList: { [key: string]: number[][] } = {}; + private max: number; + private maxRatio = 3 / 4; // 차트의 높이에 대해 데이터의 최댓값을 위치시킬 비율 + private ratio: number; // maxRatio를 바탕으로 각 데이터에 적용되는 비율 + private startingXPos: { [key: string]: number } = {}; // 최초로 움직이기 시작하는 점의 x좌표 + private lastMousePosInCanvas: ICoordinate; + private chartNumPerRow: number; + private linkIconInfoList: { [key: string]: any }[] = []; // { leftX, rightX, topY, bottomY, agentKey } 를 담은 object의 배열 + private dataSumList: number[][] = []; + private removedKeys: string[] = []; + private addedKeys: string[] = []; + private mergedKeys: string[] = []; + + showTooltip = false; + tooltipDataObj = { + title: '', + values: [] as number[], + }; + _activeThreadCounts: { [key: string]: IActiveThreadCounts }; + + constructor( + private el: ElementRef + ) {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + const changesOnATC = changes['activeThreadCounts']; + const changesOnTimeStamp = changes['timeStamp']; + + if (changesOnATC && changesOnTimeStamp) { + const { previousValue: prevATC, currentValue: currATC, firstChange } = changesOnATC; + const { currentValue: timeStamp } = changesOnTimeStamp; + const { chartType } = this.chartOption; + const successDataList = this.getSuccessDataList(currATC); + const hasError = successDataList.length === 0; + const sum = this.getTotalResponseCount(successDataList); + + if (chartType === ChartType.EACH) { + const totalCount = Object.keys(currATC).length; + const firstChartIndex = (this.currentPage - 1) * this.pagingSize; + const indexLimit = this.currentPage * this.pagingSize - 1; + const lastChartIndex = totalCount - 1 <= indexLimit ? totalCount - 1 : indexLimit; + const prevATCKeys = firstChange ? [] : Object.keys(prevATC).slice(firstChartIndex, lastChartIndex + 1); + const currATCKeys = Object.keys(currATC).slice(firstChartIndex, lastChartIndex + 1); + + this._activeThreadCounts = currATCKeys.reduce((acc: { [key: string]: IActiveThreadCounts }, curr: string) => { + return { ...acc, [curr]: currATC[curr] }; + }, {}); + this.mergedKeys = [...new Set([...prevATCKeys, ...currATCKeys])]; + this.addedKeys = []; + this.removedKeys = []; + + this.mergedKeys.forEach((key: string) => { + if (!prevATCKeys.includes(key)) { + // 새로 추가된 agent + const { status } = currATC[key]; + const data = status ? status : []; + + this.initData(key, data, timeStamp); + if (!firstChange) { + this.addedKeys.push(key); + } + } else if (!currATCKeys.includes(key)) { + // 삭제된 agent + // 해당 key에 대한 dataList, timeStampList, firstStamp, startingXPos, chartStart 제거 + this.removeData(key); + this.removedKeys.push(key); + } else { + // 변동없는 agent + const { status } = currATC[key]; + const data = status ? status : []; + + this.addData(key, data, timeStamp); + } + }); + + if (this.canvas && (prevATCKeys.length !== currATCKeys.length)) { + this.setCanvasSize(); + } + } else if (chartType === ChartType.SUM) { + const key = this.applicationName; + + this.mergedKeys = [key]; + this._activeThreadCounts = { + [key]: { + code: hasError ? ResponseCode.ERROR_BLACK : ResponseCode.SUCCESS, + message: hasError ? currATC[Object.keys(currATC)[0]].message : 'OK', + status: hasError ? null : sum + } + }; + + const { status } = this._activeThreadCounts[key]; + const data = status ? status : []; + + firstChange ? this.initData(key, data, timeStamp) : this.addData(key, data, timeStamp); + this.outSum.emit(hasError ? [] : sum); + } + + this.dataSumList.push(sum); + } + } + + ngAfterViewInit() { + this.canvas = this.canvasRef.nativeElement; + this.ctx = this.canvas.getContext('2d'); + + this.setCanvasSize(); + + this.animationFrameId = requestAnimationFrame((t) => this.draw(t)); + this.addEventListener(); + } + + ngOnDestroy() { + cancelAnimationFrame(this.animationFrameId); + } + + private initData(key: string, data: number[], timeStamp: number): void { + this.dataList[key] = [data]; + this.timeStampList[key] = [timeStamp]; + this.firstTimeStamp[key] = timeStamp - 1000; + } + + private addData(key: string, data: number[], timeStamp: number): void { + this.dataList[key].push(data); + this.timeStampList[key].push(timeStamp); + } + + private removeData(key: string): void { + delete this.dataList[key]; + delete this.timeStampList[key]; + delete this.firstTimeStamp[key]; + delete this.startingXPos[key]; + delete this.chartStart[key]; + } + + private getSuccessDataList(obj: { [key: string]: IActiveThreadCounts }): number[][] { + return Object.keys(obj) + .filter((agentName: string) => obj[agentName].code === ResponseCode.SUCCESS) + .map((agentName: string) => obj[agentName].status); + } + + private getTotalResponseCount(dataList: number[][]): number[] { + return dataList.reduce((acc: number[], curr: number[]) => { + return acc.map((a: number, i: number) => a + curr[i]); + }, [0, 0, 0, 0]); + } + + private setCanvasSize(): void { + const { titleHeight, containerHeight, canvasBottomPadding } = this.chartOption; + const numOfChart = this.mergedKeys.length; + + this.canvas.width = this.el.nativeElement.offsetWidth; + this.setChartNumPerRow(); + this.canvas.height = this.getTopEdgeYPos(numOfChart - 1) + titleHeight + containerHeight + canvasBottomPadding; + } + + private setChartNumPerRow(): void { + const { canvasLeftPadding, canvasRightPadding, containerWidth, gapBtnChart } = this.chartOption; + + this.chartNumPerRow = Math.floor((this.canvas.width - canvasLeftPadding - canvasRightPadding) / (containerWidth + gapBtnChart)); + } + + private addEventListener(): void { + window.addEventListener('resize', (() => this.onResize())); + } + + private onResize(): void { + this.setCanvasSize(); + } + + private getLeftEdgeXPos(i: number): number { + // 차트 컨테이너 왼쪽 모서리 x좌표를 리턴 + const { canvasLeftPadding, containerWidth, gapBtnChart } = this.chartOption; + + return canvasLeftPadding + (containerWidth + gapBtnChart) * (i % this.chartNumPerRow); + } + + private getTopEdgeYPos(i: number): number { + // 차트 컨테이너 위쪽 모서리 y좌표를 리턴 + const { canvasTopPadding, containerHeight, titleHeight, gapBtnChart } = this.chartOption; + + return canvasTopPadding + (containerHeight + titleHeight + gapBtnChart) * Math.floor(i / this.chartNumPerRow); + } + + private getOriginXPos(chartIndex: number): number { + const { chartInnerPadding, yAxisLabelWidth, marginFromYAxis } = this.chartOption; + + return this.getLeftEdgeXPos(chartIndex) + chartInnerPadding + yAxisLabelWidth + marginFromYAxis; + } + + private getOriginYPos(chartIndex: number): number { + const { chartInnerPadding, titleHeight, chartHeight } = this.chartOption; + + return this.getTopEdgeYPos(chartIndex) + titleHeight + chartInnerPadding + chartHeight; + } + + private draw(timeStamp: number): void { + const { drawVGridLine, showXAxis, showYAxis, showYAxisLabel, tooltipEnabled, chartWidth } = this.chartOption; + + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.mergedKeys.forEach((key: string, i: number) => { + this.drawChartTitle(key, i); + this.drawChartContainerRect(i); + if (this.removedKeys.includes(key)) { + this.drawRemovedText(i); + return; + } + + if (showXAxis) { + this.drawXAxis(i); + } + + if (showYAxis) { + this.drawYAxis(i); + } + + if (this.timeStampList[key].length !== 0) { + this.setStartingXPos(timeStamp, key); + while (this.isChartOverflow(key)) { + this.timeStampList[key].shift(); + this.dataList[key].shift(); + if (this.dataSumList.length > this.dataList[key].length) { + this.dataSumList.shift(); + } + } + + this.setMaxValue(); + this.setRatio(); + if (showYAxisLabel && this.getXPosInChart(key, 0) < chartWidth) { + this.drawYAxisLabel(i); + } + + if (drawVGridLine) { + this.drawVGridLine(key, i); + } + + this.drawChart(key, i); + if (tooltipEnabled) { + this.setTooltip(key); + } + } + + this.drawErrorText(key, i); + }); + + this.animationFrameId = requestAnimationFrame((t) => this.draw(t)); + } + + private setMaxValue(): void { + this.max = Math.max(...this.dataSumList.map((data: number[]) => data.reduce((acc: number, curr: number) => acc + curr, 0))); + } + + private setRatio(): void { + if (this.max === 0) { + this.ratio = 1; + } else { + const { chartHeight } = this.chartOption; + const midValue = this.max / this.maxRatio / 2; + + if (!Number.isInteger(midValue)) { + this.maxRatio = this.max / (Math.round(midValue) * 2); + } + + this.ratio = chartHeight * this.maxRatio / this.max; + } + } + + private setStartingXPos(timeStamp: number, key: string): void { + const { chartWidth, duration } = this.chartOption; + + if (!this.chartStart[key]) { + this.chartStart[key] = timeStamp; + } + + this.startingXPos[key] = chartWidth - Math.floor(chartWidth / duration * (timeStamp - this.chartStart[key])); + } + + private drawRemovedText(i: number): void { + const { chartHeight, chartWidth } = this.chartOption; + const originXPos = this.getOriginXPos(i); + const originYPos = this.getOriginYPos(i); + const x = originXPos + chartWidth / 2; + const y = originYPos - chartHeight / 2; + + this.ctx.fillStyle = 'rgba(232, 229, 240, 0.9)'; + this.ctx.fillRect(originXPos, originYPos - chartHeight, chartWidth, chartHeight); + + this.ctx.font = `600 13px Nanum Gothic`; + this.ctx.textAlign = 'center'; + this.ctx.textBaseline = 'middle'; + this.ctx.fillStyle = '#c04e3f'; + this.ctx.fillText('Removed', x, y); + } + + private drawErrorText(key: string, i: number): void { + const { chartInnerPadding, errorFontSize, titleHeight, chartHeight, chartWidth } = this.chartOption; + + this.ctx.font = `600 ${errorFontSize} Nanum Gothic`; + this.ctx.textAlign = 'center'; + this.ctx.textBaseline = 'middle'; + + const { code, message } = this._activeThreadCounts[key]; + const isResponseSuccess = code === ResponseCode.SUCCESS; + + if (!isResponseSuccess) { + const originXPos = this.getOriginXPos(i); + const originYPos = this.getOriginYPos(i); + const x = originXPos + chartWidth / 2; + const isOverflow = (str: string) => this.ctx.measureText(str).width > chartWidth - 10; + + const words = message.split(' '); + const arrangedText: string[] = []; // 여기에 message를 루프돌면서 overflow하지않는 단위로 잘라서 넣어줄 예정. 그리고, 이걸로 마지막에 fillText() + let startIndex = 0; + let lastIndex = words.length - 1; + + while (message !== arrangedText.join(' ')) { + const substr = words.slice(startIndex, lastIndex + 1).join(' '); + + if (isOverflow(substr)) { + lastIndex--; + } else { + arrangedText.push(substr); + startIndex = lastIndex + 1; + lastIndex = words.length - 1; + } + } + + this.ctx.fillStyle = 'rgba(232, 229, 240, 0.9)'; + this.ctx.fillRect(originXPos, originYPos - chartHeight, chartWidth, chartHeight); + + const length = arrangedText.length; + + arrangedText.forEach((text: string, j: number) => { + const y = this.getTopEdgeYPos(i) + titleHeight + chartInnerPadding + (j + 1) * chartHeight / (length + 1); + + this.ctx.fillStyle = '#c04e3f'; + this.ctx.fillText(text, x, y); + }); + } + } + + private drawChartTitle(key: string, i: number): void { + const { containerWidth, titleHeight, titleFontSize, marginRightForLinkIcon, linkIconCode } = this.chartOption; + const isRemovedKey = this.removedKeys.includes(key); + const isAddedKey = this.addedKeys.includes(key); + + this.ctx.fillStyle = isAddedKey ? '#34b994' : isRemovedKey ? '#e95459' : '#74879a'; + this.ctx.fillRect(this.getLeftEdgeXPos(i), this.getTopEdgeYPos(i), containerWidth, titleHeight); + + this.ctx.font = `${titleFontSize} Nanum Gothic`; + this.ctx.fillStyle = '#fff'; + this.ctx.textAlign = 'center'; + this.ctx.textBaseline = 'middle'; + this.ctx.fillText(this.getChartTitleText(key), this.getLeftEdgeXPos(i) + containerWidth / 2, this.getTopEdgeYPos(i) + titleHeight / 2); + + if (linkIconCode) { + this.ctx.font = '600 9px "Font Awesome 5 Free"'; + this.ctx.textAlign = 'right'; + this.ctx.fillText(linkIconCode, this.getLeftEdgeXPos(i) + containerWidth - marginRightForLinkIcon, this.getTopEdgeYPos(i) + titleHeight / 2); + + const linkIconWidth = this.ctx.measureText(linkIconCode).width; + + this.linkIconInfoList.push({ + leftX: this.getLeftEdgeXPos(i) + containerWidth - marginRightForLinkIcon - linkIconWidth, + rightX: this.getLeftEdgeXPos(i) + containerWidth - marginRightForLinkIcon, + topY: this.getTopEdgeYPos(i) + titleHeight / 2 - linkIconWidth / 2, + bottomY: this.getTopEdgeYPos(i) + titleHeight / 2 + linkIconWidth / 2, + key + }); + } + } + + private getChartTitleText(text: string): string { + const { containerWidth, marginRightForLinkIcon, linkIconCode, ellipsis } = this.chartOption; + const linkIconWidth = linkIconCode ? this.ctx.measureText(linkIconCode).width : 0; + const ellipsisWidth = this.ctx.measureText(ellipsis).width; + const textWidth = this.ctx.measureText(text).width; + const maxWidth = linkIconCode ? containerWidth / 2 - linkIconWidth - marginRightForLinkIcon - 5 : containerWidth / 2; + const isOverflow = textWidth / 2 > maxWidth; + + if (isOverflow) { + let length = text.length; + let newText; + let newTextWidth; + + do { + newText = text.substring(0, length - 1); + newTextWidth = this.ctx.measureText(newText).width; + length--; + } while (newTextWidth / 2 + ellipsisWidth > maxWidth); + + return newText + ellipsis; + } else { + return text; + } + } + + private drawChartContainerRect(i: number): void { + const { containerWidth, containerHeight, titleHeight } = this.chartOption; + + this.ctx.fillStyle = '#fff'; + this.ctx.fillRect(this.getLeftEdgeXPos(i), this.getTopEdgeYPos(i) + titleHeight, containerWidth, containerHeight); + } + + // Horizontal Grid Line + private drawHGridLine(i: number): void { + const { chartHeight, chartWidth } = this.chartOption; + const originXPos = this.getOriginXPos(i); + const originYPos = this.getOriginYPos(i); + + // Horizontal grid line 1 (top) + this.ctx.beginPath(); + this.ctx.moveTo(originXPos, originYPos - chartHeight); + this.ctx.lineTo(originXPos + chartWidth, originYPos - chartHeight); + this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)'; + this.ctx.stroke(); + + // Horizontal grid line 2 (middle) + this.ctx.beginPath(); + this.ctx.moveTo(originXPos, originYPos - chartHeight / 2); + this.ctx.lineTo(originXPos + chartWidth, originYPos - chartHeight / 2); + this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)'; + this.ctx.stroke(); + } + + // Vertical Grid Line + private drawVGridLine(key: string, i: number): void { + const { chartWidth, chartHeight } = this.chartOption; + const originXPos = this.getOriginXPos(i); + const originYPos = this.getOriginYPos(i); + + this.timeStampList[key].forEach((t: number, j: number) => { + const x = this.getXPosInChart(key, j); + + if (!(x > 0 && x < chartWidth)) { + return; + } + + this.ctx.beginPath(); + this.ctx.moveTo(originXPos + x, originYPos - chartHeight); + this.ctx.lineTo(originXPos + x, originYPos); + this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)'; + this.ctx.stroke(); + }); + } + + private drawXAxis(i: number): void { + const { chartWidth } = this.chartOption; + const originXPos = this.getOriginXPos(i); + const originYPos = this.getOriginYPos(i); + + this.ctx.beginPath(); + this.ctx.moveTo(originXPos, originYPos); + this.ctx.lineTo(originXPos + chartWidth, originYPos); + this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.stroke(); + } + + private drawYAxis(i: number): void { + const { chartHeight } = this.chartOption; + const originXPos = this.getOriginXPos(i); + const originYPos = this.getOriginYPos(i); + + this.ctx.beginPath(); + this.ctx.moveTo(originXPos, originYPos); + this.ctx.lineTo(originXPos, originYPos - chartHeight); + this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)'; + this.ctx.stroke(); + } + + private drawYAxisLabel(i: number): void { + const { marginFromYAxis, chartHeight } = this.chartOption; + const xPos = this.getOriginXPos(i) - marginFromYAxis; + const originYPos = this.getOriginYPos(i); + const maxLabel = this.max === 0 ? null : this.max / this.maxRatio; + const midLabel = this.max === 0 ? null : maxLabel / 2; + + this.ctx.font = '9px Nanum Gothic'; + this.ctx.textBaseline = 'middle'; + this.ctx.textAlign = 'right'; + this.ctx.fillStyle = '#333'; + this.ctx.fillText(`0`, xPos, originYPos); + if (maxLabel) { + this.ctx.fillText(`${midLabel}`, xPos, originYPos - chartHeight / 2); + this.ctx.fillText(`${maxLabel}`, xPos, originYPos - chartHeight); + } + } + + private drawChart(key: string, i: number): void { + const { chartWidth, chartHeight, chartColors } = this.chartOption; + const dataList = this.dataList[key]; + const x0 = this.getXPosInChart(key, 0); + + if (x0 < chartWidth) { + const originXPos = this.getOriginXPos(i); + const originYPos = this.getOriginYPos(i); + const dataTypeLength = chartColors.length; + const dataLength = dataList.length; + + for (let j = dataTypeLength - 1; j >= 0; j--) { + this.ctx.fillStyle = chartColors[j]; + const data = dataList.map((d: number[]) => { + return d.length === 0 ? null : d.slice(0, j + 1).reduce((acc: number, curr: number) => acc + curr, 0); + }); // ex) [ null, 6, 2, null ] + + this.ctx.beginPath(); + + if (data[0] !== null) { + if (x0 < 0 && data[1] != null) { + // 앞 경계면 처리 + const x1 = this.getXPosInChart(key, 1); + + this.ctx.moveTo(originXPos, originYPos); // 시작 + this.ctx.lineTo(originXPos, originYPos - (data[0] * x1 - data[1] * x0) / (x1 - x0) * this.ratio); + } else if (x0 >= 0) { + this.ctx.moveTo(originXPos + x0, originYPos); // 시작 + this.ctx.lineTo(originXPos + x0, originYPos - (data[0] * this.ratio)); + } + } + + for (let k = 1; k < dataLength; k++) { + const xkm1 = this.getXPosInChart(key, k - 1); + const xk = this.getXPosInChart(key, k); + + if (data[k] === null || (data[k - 1] === null && xk > chartWidth)) { + continue; + } + + if (data[k - 1] === null) { + this.ctx.beginPath(); + this.ctx.moveTo(originXPos + xk, originYPos); + } + + if (xkm1 <= chartWidth && xk > chartWidth) { + this.ctx.lineTo(originXPos + chartWidth, originYPos - (data[k - 1] + (chartWidth - xkm1) * (data[k] - data[k - 1]) / (xk - xkm1)) * this.ratio); + this.ctx.lineTo(originXPos + chartWidth, originYPos); + this.ctx.fill(); + break; + } else { + this.ctx.lineTo(originXPos + xk, originYPos - (data[k] * this.ratio)); + if (data[k + 1] == null) { + this.ctx.lineTo(originXPos + xk, originYPos); + this.ctx.fill(); + if (data[k + 1] === undefined && xk <= chartWidth * 0.95) { + // When it's delayed + const x = originXPos + 5 / 6 * chartWidth; + const y = originYPos - 1 / 6 * chartHeight; + + this.ctx.font = '9px Nanum Gothic'; + this.ctx.fillStyle = '#c04e3f'; + this.ctx.textAlign = 'center'; + this.ctx.textBaseline = 'middle'; + this.ctx.fillText('Delayed', x, y); + } + } + } + } + } + } + } + + private getXPosInChart(key: string, i: number): number { + const { chartWidth, duration } = this.chartOption; + + return this.startingXPos[key] + Math.floor(chartWidth / duration * (this.timeStampList[key][i] - this.firstTimeStamp[key])); + } + + private isChartOverflow(key: string): boolean { + return this.timeStampList[key].length >= 2 && this.getXPosInChart(key, 1) < 0; + } + + calculateTooltipLeft(tooltip: HTMLElement): string { + const { coordX } = this.lastMousePosInCanvas; + const { chartWidth } = this.chartOption; + const originXPos = this.getOriginXPos(0); + const tooltipWidth = tooltip.offsetWidth; + const ratio = (coordX - originXPos) / chartWidth; + + return `${coordX - (tooltipWidth * ratio)}px`; + } + + calculateTooltipCaretLeft(tooltipCaret: HTMLElement): string { + const { coordX } = this.lastMousePosInCanvas; + + return `${coordX - (tooltipCaret.offsetWidth / 2)}px`; + } + + private drawTooltipPoint(key: string, i: number): void { + const { chartColors } = this.chartOption; + const originXPos = this.getOriginXPos(0); + const originYPos = this.getOriginYPos(0); + const data = this.dataList[key][i]; // [0, 1, 2, 3] + const length = data.length; + const x = originXPos + this.getXPosInChart(key, i); + const r = 3; + + if (x > originXPos) { + for (let j = 0; j < length; j++) { + if (data[j] === 0) { + continue; + } + + const d = data.slice(0, j + 1).reduce((acc: number, curr: number) => acc + curr, 0); + const y = originYPos - (d * this.ratio); + + this.ctx.beginPath(); + this.ctx.arc(x, y, r, 0, 2 * Math.PI); + this.ctx.fillStyle = chartColors[j]; + this.ctx.strokeStyle = 'rgb(0, 0, 0, 0.3)'; + this.ctx.stroke(); + this.ctx.fill(); + } + } + } + + private setTooltip(key: string): void { + if (this.isMouseInChartArea() && this.timeStampList[key].length >= 2) { + const originXPos = this.getOriginXPos(0); + const x = this.lastMousePosInCanvas.coordX; + const k = this.timeStampList[key].findIndex((timeStamp: number, i: number) => { + return originXPos + this.getXPosInChart(key, i) <= x && originXPos + this.getXPosInChart(key, i + 1) > x; + }); + const isDataEmpty = (i: number) => this.dataList[key][i].length === 0; + + if (!(k === -1 || isDataEmpty(k))) { + this.showTooltip = true; + this.setTooltipData(key, k); + this.drawTooltipPoint(key, k); + } + } else { + this.showTooltip = false; + } + } + + private setTooltipData(key: string, i: number): void { + this.tooltipDataObj = { + title: moment(this.timeStampList[key][i]).tz(this.timezone).format(this.dateFormat), + values: this.dataList[key][i] + }; + } + + private isMouseInChartArea(): boolean { + if (!this.lastMousePosInCanvas) { + return false; + } + + const { coordX, coordY } = this.lastMousePosInCanvas; + const { chartHeight, chartWidth } = this.chartOption; + const originXPos = this.getOriginXPos(0); + const originYPos = this.getOriginYPos(0); + const minX = originXPos + 10; + const maxX = originXPos + chartWidth - 10; + const minY = originYPos - chartHeight; + const maxY = originYPos; + + return minX < coordX && coordX < maxX && minY < coordY && coordY < maxY; + } + + onMouseMove(e: MouseEvent): void { + const { left, top } = this.canvas.getBoundingClientRect(); + const { clientX, clientY } = e; + const xPosOnCanvas = clientX - left; + const yPosOnCanvas = clientY - top; + + this.lastMousePosInCanvas = { + coordX: xPosOnCanvas, + coordY: yPosOnCanvas + }; + } + + onMouseOut(): void { + this.lastMousePosInCanvas = null; + this.showTooltip = false; + } + + onClick(): void { + const linkIconInfo = this.getLinkIconInfo(); + + if (linkIconInfo) { + this.outClick.emit(linkIconInfo.key); + } + } + + private getLinkIconInfo(): { [key: string]: any } { + const { linkIconCode } = this.chartOption; + + if (!(this.lastMousePosInCanvas && linkIconCode)) { + return null; + } + + const { coordX, coordY } = this.lastMousePosInCanvas; + + return this.linkIconInfoList.find((linkIcon: { [key: string]: any }) => { + const { leftX, rightX, topY, bottomY } = linkIcon; + + return coordX >= leftX && coordX <= rightX && coordY >= topY && coordY <= bottomY; + }); + } + + getCursorStyle(): string { + return this.getLinkIconInfo() ? 'pointer' : 'auto'; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-container.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-container.component.css new file mode 100644 index 000000000000..905f18e4e613 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-container.component.css @@ -0,0 +1,143 @@ +:host { + display: block; + z-index: 30; +} +.l-thread-chart-wrap { + background: #d3dbe6; + border-top: 1px solid #ccd5e0; + position: absolute; + bottom: 0; + left: 0; + width: 100%; +} +.l-title-group { + display: flex; + flex-flow: row wrap; + color: #566370; + font-size: 14px; + font-weight: 600; + height: 34px; + padding: 0 10px 0 25px; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #bdc7d5; + cursor: ns-resize; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color: #a8acb5; + cursor: pointer; +} +.l-title-group .l-title .fas { + margin: 0 9px 0 0; + +} +.l-title-group .l-tool-box { + color: #8F9CAF; +} +.l-tool-box button { + margin-left: 10px; +} +.l-pin-up { + color: #F00; +} +.l-chart-group-wrap { + display: flex; + flex-flow: row wrap; + padding: 20px 10px 20px 25px; + height: calc(100% - 34px); +} +.l-chart-group-wrap > .l-total-chart { + width: 277px; + height: 178px; + margin-right: 20px; +} +.l-agent-chart { + width: calc(100% - 297px); + max-height: 100%; + overflow-y: auto; + outline: none; +} +.l-message { + top: 0px; + left: 0px; + width: 100%; + height: 100%; + position: absolute; + text-align: center; + background-color: rgba(226, 226, 226, 0.5); + z-index: 9999; +} +.l-message h4 { + padding: 80px 0 10px 0; + font-weight: 100; +} +.l-message h4 span { + padding: 8px 40px 6px 40px; + background-color: #FFF; +} +.l-retry button span { + margin-right: 6px; +} +.l-message.l-no-data h4 span { + background-color: #000; + color: #FFF; +} +.l-paging { + width: 100%; + background-color: #74879a; + color: #FFF; + font-size: 15px; + margin: 0px 0px 5px 0px; + padding: 11px; + position: relative; +} +.l-paging .l-txt { + font-weight: lighter; +} +.l-paging .l-txt-bold { + font-weight: bolder; + font-size: 18px; + margin-right: 2px; +} +.fa-chart-area { + margin-right: 2px; +} + +.l-paging nav { + height: calc(100% - 22px); + display: inline-block; + position: absolute; + right: 10px; +} + +.l-pagination { + display: flex; + list-style: none; + height: 100%; +} + +.l-page-item { + display: block; + height: 100%; +} + +.l-page-item:first-child .l-page-link { + color: #000; + cursor: initial; + text-decoration: initial; + background-color: #FFF; +} + +.l-page-link { + padding: 0 6px; + cursor: pointer; + display: flex; + align-items: center; + height: 100%; +} + +.l-page-link:hover { + color: #4b99e3; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-container.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-container.component.html new file mode 100644 index 000000000000..104dd8c5f427 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-container.component.html @@ -0,0 +1,61 @@ +
    +
    +
    + Realtime Active Thread Chart +
    +
    + + +
    +
    +
    + +
    + + +
    +
    + +
    + Total Servers : + {{totalCount}} + [ {{firstChartIndex + 1}} ~ {{lastChartIndex + 1}} ] + +
    +
    + + +
    +
    + +
    +

    Waiting Connection...

    + +
    +
    +

    Closed connection

    + +
    +
    +

    This node is not WAS

    +
    + +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-container.component.ts new file mode 100644 index 000000000000..52e1574f81ca --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-container.component.ts @@ -0,0 +1,252 @@ +import { Component, OnInit, OnDestroy, AfterViewInit } from '@angular/core'; +import { Subject, Observable, fromEvent } from 'rxjs'; +import { takeUntil, filter, tap, delay } from 'rxjs/operators'; + +import { + StoreHelperService, + WebAppSettingDataService, + NewUrlStateNotificationService, + UrlRouteManagerService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { NewRealTimeWebSocketService, IWebSocketResponse, IWebSocketDataResult, IActiveThreadCounts } from 'app/core/components/real-time-new/new-real-time-websocket.service'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +// TODO: 나중에 공통으로 추출. +const enum MessageTemplate { + LOADING = 'LOADING', + RETRY = 'RETRY', + NO_DATA = 'NO_DATA', + NOTHING = 'NOTHING' +} + +@Component({ + selector: 'pp-new-real-time-container', + templateUrl: './new-real-time-container.component.html', + styleUrls: ['./new-real-time-container.component.css'] +}) +export class NewRealTimeContainerComponent implements OnInit, AfterViewInit, OnDestroy { + private unsubscribe = new Subject(); + private serviceType = ''; + pagingSize = 30; + totalCount: number; + firstChartIndex = 0; + lastChartIndex: number; + isPinUp = true; + lastHeight: number; + minHeight = 343; + maxHeightPadding = 50; // Header Height + timezone$: Observable; + dateFormat$: Observable; + timeStamp: number; + applicationName = ''; + activeThreadCounts: { [key: string]: IActiveThreadCounts }; + hiddenComponent = true; + messageTemplate = MessageTemplate.LOADING; + // messageTemplate: MessageTemplate; + constructor( + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private realTimeWebSocketService: NewRealTimeWebSocketService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.lastHeight = this.webAppSettingDataService.getLayerHeight() || this.minHeight; + this.lastChartIndex = this.pagingSize - 1; + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + ).subscribe(() => { + // this.hiddenComponent = true; + this.resetState(); + this.messageTemplate = MessageTemplate.LOADING; + }); + this.connectStore(); + + this.realTimeWebSocketService.onMessage$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((response: IWebSocketResponse) => { + switch (response.type) { + case 'open': + this.onOpen(); + break; + case 'close': + this.onClose(); + break; + case 'retry': + this.onRetry(); + break; + case 'message': + this.onMessage(response.message as IWebSocketDataResult); + break; + } + }); + } + ngAfterViewInit() { + this.addEventListener(); + } + ngOnDestroy() { + this.realTimeWebSocketService.close(); + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + this.dateFormat$ = this.storeHelperService.getDateFormat(this.unsubscribe, 0); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isMerged === true || target.isMerged === false) ? true : false; + }), + tap(() => this.hiddenComponent = false), + filter(() => { + return !(this.isPinUp && this.applicationName !== ''); + }) + ).subscribe((target: ISelectedTarget) => { + const [applicationName, serviceType] = target.node[0].split('^'); + + if (target.isWAS) { + if (!this.isSameWithCurrentTarget(applicationName, serviceType)) { + this.applicationName = applicationName; + this.serviceType = serviceType; + this.realTimeWebSocketService.isOpened() ? this.startDataRequest() : this.realTimeWebSocketService.connect(); + } + } else { + this.applicationName = applicationName; + this.serviceType = serviceType; + this.realTimeWebSocketService.close(); + this.stopDataRequest(); + this.hide(); + } + }); + } + private addEventListener(): void { + const visibility$ = fromEvent(document, 'visibilitychange').pipe(takeUntil(this.unsubscribe)); + + // visible + visibility$.pipe( + filter(() => { + return !document.hidden; + }), + filter(() => { + return !this.realTimeWebSocketService.isOpened(); + }) + ).subscribe(() => { + this.onRetry(); + }); + + // hidden + visibility$.pipe( + filter(() => { + return document.hidden; + }), + delay(60000), + filter(() => { + return document.hidden; + }), + ).subscribe(() => { + this.realTimeWebSocketService.close(); + }); + } + private resetState() { + this.applicationName = ''; + this.serviceType = ''; + this.activeThreadCounts = null; + this.isPinUp = true; + } + private hide() { + this.messageTemplate = MessageTemplate.NO_DATA; + } + private isSameWithCurrentTarget(applicationName: string, serviceType: string): boolean { + return (this.applicationName === applicationName && this.serviceType === serviceType); + } + private startDataRequest(): void { + this.realTimeWebSocketService.send(this.getRequestDataStr(this.applicationName)); + } + private stopDataRequest(): void { + this.realTimeWebSocketService.send(this.getRequestDataStr('')); + } + private getRequestDataStr(name: string): object { + return { + type: 'REQUEST', + command: 'activeThreadCount', + parameters: { + applicationName: name + } + }; + } + private onOpen(): void { + this.startDataRequest(); + } + private onClose(): void { + this.messageTemplate = MessageTemplate.RETRY; + this.activeThreadCounts = null; + } + private onRetry(): void { + this.retryConnection(); + } + private onMessage(data: IWebSocketDataResult): void { + // this.messageTemplate = MessageTemplate.NOTHING; + const { timeStamp, applicationName, activeThreadCounts } = data; + + if (applicationName && applicationName !== this.applicationName) { + return; + } + + this.totalCount = Object.keys(activeThreadCounts).length; + this.timeStamp = timeStamp; + this.activeThreadCounts = activeThreadCounts; + } + needPaging(): boolean { + return this.totalCount > this.pagingSize; + } + getTotalPage(): number[] { + const totalPage = Math.ceil(this.totalCount / this.pagingSize); + + return Array(totalPage).fill(0).map((v: number, i: number) => i + 1); + } + retryConnection(): void { + this.messageTemplate = MessageTemplate.LOADING; + this.realTimeWebSocketService.connect(); + } + onPinUp(): void { + this.analyticsService.trackEvent(this.isPinUp ? TRACKED_EVENT_LIST.PIN_UP_REAL_TIME_CHART : TRACKED_EVENT_LIST.REMOVE_PIN_ON_REAL_TIME_CHART); + this.isPinUp = !this.isPinUp; + } + openPage(page: number): void { + this.urlRouteManagerService.openPage([ + UrlPath.REAL_TIME, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + '' + page + ]); + } + onOpenThreadDump(agentId: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_THREAD_DUMP); + this.urlRouteManagerService.openPage([ + UrlPath.THREAD_DUMP, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + agentId, + '' + Date.now() + ]); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.REAL_TIME); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.REAL_TIME, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } + onRenderCompleted(): void { + this.messageTemplate = MessageTemplate.NOTHING; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-paging-container.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-paging-container.component.css new file mode 100644 index 000000000000..7039656dceaa --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-paging-container.component.css @@ -0,0 +1,57 @@ +:host { + display: block; + width: 100%; + height: 100%; +} +.l-thread-chart-wrap { + background:#d3dbe6; + width:100%; + height: 100%; +} +.l-agent-chart { + width: 100%; + max-height: 100%; + overflow-y: auto; + padding: 5px; +} +.l-message { + top: 0px; + left: 0px; + width: 100%; + height: 100%; + position: absolute; + text-align: center; + background-color: rgba(226, 226, 226, 0.5); + z-index: 9999; +} +.l-message h4 { + padding: 80px 0 10px 0; + font-weight: 100; +} +.l-message h4 span { + padding: 8px 40px 6px 40px; + background-color: #FFF; +} +.l-retry button span { + margin-right: 6px; +} +.l-message.l-no-data h4 span { + background-color: #000; + color: #FFF; +} +.l-paging { + width: 100%; + background-color: #74879a; + color: #FFF; + font-size: 15px; + margin-bottom: 5px; + padding: 11px; +} +.l-paging .l-txt { + font-weight: lighter; +} +.l-paging .l-txt-bold { + font-weight: bolder; + font-size: 18px; + margin-right: 2px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-paging-container.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-paging-container.component.html new file mode 100644 index 000000000000..bfbcb50b773a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-paging-container.component.html @@ -0,0 +1,35 @@ +
    +
    + +
    +
    + Total Servers : + {{totalCount}} + [ {{firstChartIndex + 1}} ~ {{lastChartIndex + 1}} ] +
    + + +
    +
    + +
    +

    Waiting Connection...

    + +
    +
    +

    Closed connection

    + +
    +
    +

    This node is not WAS

    +
    + +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-paging-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-paging-container.component.ts new file mode 100644 index 000000000000..71215213c134 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-paging-container.component.ts @@ -0,0 +1,166 @@ +import { Component, OnInit, OnDestroy, AfterViewInit } from '@angular/core'; +import { Subject, fromEvent } from 'rxjs'; +import { takeUntil, filter, delay } from 'rxjs/operators'; + +import { UrlPathId, UrlPath } from 'app/shared/models'; +import { NewUrlStateNotificationService, UrlRouteManagerService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; +import { NewRealTimeWebSocketService, IWebSocketResponse, IWebSocketDataResult, IActiveThreadCounts } from 'app/core/components/real-time-new/new-real-time-websocket.service'; + +// TODO: 나중에 공통으로 추출. +const enum MessageTemplate { + LOADING = 'LOADING', + RETRY = 'RETRY', + NO_DATA = 'NO_DATA', + NOTHING = 'NOTHING' +} + +@Component({ + selector: 'pp-new-real-time-paging-container', + templateUrl: './new-real-time-paging-container.component.html', + styleUrls: ['./new-real-time-paging-container.component.css'] +}) +export class NewRealTimePagingContainerComponent implements OnInit, AfterViewInit, OnDestroy { + private unsubscribe = new Subject(); + private applicationName = ''; + private serviceType = ''; + pagingSize = 30; + totalCount: number; + firstChartIndex: number; + lastChartIndex: number; + indexLimit: number; + currentPage: number; + timeStamp: number; + activeThreadCounts: { [key: string]: IActiveThreadCounts }; + messageTemplate = MessageTemplate.LOADING; + constructor( + private newUrlStateNotificationService: NewUrlStateNotificationService, + private realTimeWebSocketService: NewRealTimeWebSocketService, + private urlRouteManagerService: UrlRouteManagerService, + private analyticsService: AnalyticsService, + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + ).subscribe(() => { + this.resetState(); + this.messageTemplate = MessageTemplate.LOADING; + this.applicationName = this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(); + this.serviceType = this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getServiceType(); + this.currentPage = Number(this.newUrlStateNotificationService.getPathValue(UrlPathId.PAGE)); + this.firstChartIndex = (this.currentPage - 1) * this.pagingSize; + this.indexLimit = this.currentPage * this.pagingSize - 1; + this.realTimeWebSocketService.isOpened() ? this.startDataRequest() : this.realTimeWebSocketService.connect(); + }); + + this.realTimeWebSocketService.onMessage$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((response: IWebSocketResponse) => { + switch (response.type) { + case 'open': + this.onOpen(); + break; + case 'close': + this.onClose(); + break; + case 'retry': + this.onRetry(); + break; + case 'message': + this.onMessage(response.message as IWebSocketDataResult); + break; + } + }); + } + ngAfterViewInit() { + this.addEventListener(); + } + ngOnDestroy() { + this.realTimeWebSocketService.close(); + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private addEventListener(): void { + const visibility$ = fromEvent(document, 'visibilitychange').pipe(takeUntil(this.unsubscribe)); + + // visible + visibility$.pipe( + filter(() => { + return !document.hidden; + }), + filter(() => { + return !this.realTimeWebSocketService.isOpened(); + }) + ).subscribe(() => { + this.onRetry(); + }); + + // hidden + visibility$.pipe( + filter(() => { + return document.hidden; + }), + delay(60000), + filter(() => { + return document.hidden; + }), + ).subscribe(() => { + this.realTimeWebSocketService.close(); + }); + } + private resetState() { + this.applicationName = ''; + this.serviceType = ''; + this.activeThreadCounts = null; + } + private startDataRequest(): void { + this.realTimeWebSocketService.send(this.getRequestDataStr(this.applicationName)); + } + private getRequestDataStr(name: string): object { + return { + type: 'REQUEST', + command: 'activeThreadCount', + parameters: { + applicationName: name + } + }; + } + private onOpen(): void { + this.startDataRequest(); + } + private onClose(): void { + this.messageTemplate = MessageTemplate.RETRY; + this.activeThreadCounts = null; + } + private onRetry(): void { + this.retryConnection(); + } + private onMessage(data: IWebSocketDataResult): void { + // this.messageTemplate = MessageTemplate.NOTHING; + const { timeStamp, applicationName, activeThreadCounts } = data; + + if (applicationName && applicationName !== this.applicationName) { + return; + } + + this.totalCount = Object.keys(activeThreadCounts).length; + this.lastChartIndex = this.totalCount - 1 <= this.indexLimit ? this.totalCount - 1 : this.indexLimit; + this.timeStamp = timeStamp; + this.activeThreadCounts = activeThreadCounts; + } + retryConnection(): void { + this.messageTemplate = MessageTemplate.LOADING; + this.realTimeWebSocketService.connect(); + } + onOpenThreadDump(agentId: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_THREAD_DUMP); + this.urlRouteManagerService.openPage([ + UrlPath.THREAD_DUMP, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + agentId, + '' + Date.now() + ]); + } + onRenderCompleted(): void { + this.messageTemplate = MessageTemplate.NOTHING; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-total-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-total-chart.component.css new file mode 100644 index 000000000000..457b28dc2124 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-total-chart.component.css @@ -0,0 +1,56 @@ +:host { + display: block; + position: relative; + width: 100%; + height: 100%; +} +.l-legend { + position: absolute; + list-style: none; + font-size: 11px; + width: 65px; + /* height: 110px; */ +} +.l-legend li { + margin: 8px 0 0; + color: #666; +} +.l-legend li:first-child { + margin: 0; + color: #010101; + font-weight: 600; +} +.l-legend li span { + display: inline-block; + vertical-align: middle; +} +.l-legend li .l-text { + width: 30px; + text-align: right; + margin: 0 10px 0 0; +} +.l-legend li .l-circle { + width: 21px; + height: 11px; + line-height: 11px; + color: #fff; + border-radius: 10px; + text-align: center; + overflow: hidden; + text-overflow: ellipsis; +} +.l-legend li:nth-child(1) .l-circle { + background:#a8acb5 +} +.l-legend li:nth-child(2) .l-circle { + background:#e76f4b +} +.l-legend li:nth-child(3) .l-circle { + background:#fea63e +} +.l-legend li:nth-child(4) .l-circle { + background:#51afdf +} +.l-legend li:nth-child(5) .l-circle { + background:#33b692 +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-total-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-total-chart.component.html new file mode 100644 index 000000000000..a9151a98579f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-total-chart.component.html @@ -0,0 +1,31 @@ + + +
      +
    • + Total + {{totalCount}} +
    • +
    • + Slow + {{data[3]}} +
    • +
    • + 5s + {{data[2]}} +
    • +
    • + 3s + {{data[1]}} +
    • +
    • + 1s + {{data[0]}} +
    • +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-total-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-total-chart.component.ts new file mode 100644 index 000000000000..85b04f98db88 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-total-chart.component.ts @@ -0,0 +1,67 @@ +import { Component, OnInit, Input } from '@angular/core'; + +import { IActiveThreadCounts } from 'app/core/components/real-time-new/new-real-time-websocket.service'; +import { ChartType } from './new-real-time-chart.component'; + +@Component({ + selector: 'pp-new-real-time-total-chart', + templateUrl: './new-real-time-total-chart.component.html', + styleUrls: ['./new-real-time-total-chart.component.css'] +}) +export class NewRealTimeTotalChartComponent implements OnInit { + @Input() timeStamp: number; + @Input() timezone: string; + @Input() dateFormat: string; + @Input() applicationName: string; + @Input() activeThreadCounts: { [key: string]: IActiveThreadCounts }; + + data: number[]; + totalCount: number; + chartOption = { + canvasLeftPadding: 0, + canvasTopPadding: 0, + canvasRightPadding: 0, + canvasBottomPadding: 0, + chartInnerPadding: 15, + containerWidth: 277, + containerHeight: 132, + chartWidth: 159, + chartHeight: 102, + titleHeight: 46, + gapBtnChart: 0, + chartColors: ['#33b692', '#51afdf', '#fea63e', '#e76f4b'], + chartLabels: ['1s', '3s', '5s', 'Slow'], + ellipsis: '...', + drawHGridLine: false, + drawVGridLine: true, + showXAxis: true, + showXAxisLabel: false, + showYAxis: true, + showYAxisLabel: true, + yAxisLabelWidth: 8, + marginFromYAxis: 5, // Space between y axis and y labels + marginFromLegend: 10, + tooltipEnabled: true, + titleFontSize: '15px', + errorFontSize: '15px', + duration: 4000, + chartType: ChartType.SUM + }; + + constructor() {} + ngOnInit() {} + getLegendStyle(legend: HTMLElement): { [key: string]: string } { + const { containerWidth, chartInnerPadding, titleHeight } = this.chartOption; + const legendWidth = legend.offsetWidth; + + return { + left: `${containerWidth - chartInnerPadding - legendWidth}px`, + top: `${titleHeight + chartInnerPadding - 12}px` + }; + } + + onSum(sum: number[]): void { + this.data = sum; + this.totalCount = sum.length === 0 ? null : sum.reduce((acc: number, curr: number) => acc + curr, 0); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-websocket.service.ts b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-websocket.service.ts new file mode 100644 index 000000000000..781a9827d128 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-real-time-websocket.service.ts @@ -0,0 +1,165 @@ +import { Injectable } from '@angular/core'; +import { Subject, Observable, of, throwError } from 'rxjs'; +import { WebSocketSubject, WebSocketSubjectConfig } from 'rxjs/webSocket'; +import { timeout, catchError, map, filter } from 'rxjs/operators'; + +import { WindowRefService } from 'app/shared/services'; + +interface IWebSocketData { + type: ResponseType; + command: string; + result: IWebSocketDataResult; +} + +export interface IWebSocketDataResult { + timeStamp: number; + applicationName: string; + activeThreadCounts: { [key: string]: IActiveThreadCounts }; +} + +export interface IActiveThreadCounts { + code: number; + message: string; + status?: number[]; +} + +export interface IWebSocketResponse { + type: string; + message: string | IWebSocketDataResult; +} + +export const enum ResponseType { + PING = 'PING', + RESPONSE = 'RESPONSE' +} + +export const enum ResponseCode { + SUCCESS = 0, + TIMEOUT = 211, + ERROR_BLACK = 111, + OVER_DELAY = 9999 +} + +@Injectable() +export class NewRealTimeWebSocketService { + private url = 'agent/activeThread.pinpointws'; + private delayLimit = 5000; // 서버로부터의 응답을 기다리는 최대시간(ms) + private retryTimeout = 3000; + private retryCount = 0; + private maxRetryCount = 1; + private connectTime: number; + private isOpen = false; + private socket$: WebSocketSubject = null; + private outMessage: Subject = new Subject(); + + onMessage$: Observable; + + constructor( + private windowRefService: WindowRefService + ) { + this.onMessage$ = this.outMessage.asObservable(); + } + connect(): void { + if (this.isOpen === false) { + this.openWebSocket(); + } + } + isOpened(): boolean { + return this.isOpen; + } + close(): void { + if (this.isOpen) { + this.socket$.complete(); + } else { + this.outMessage.next({ + type: 'close', + message: '' + }); + } + } + send(message: object): void { + if (this.isOpen) { + this.socket$.next(message); + } + } + private openWebSocket(): void { + const location = this.windowRefService.nativeWindow.location; + const protocol = location.protocol.indexOf('https') === -1 ? 'ws' : 'wss'; + const url = `${protocol}://${location.host}/${this.url}`; + + this.socket$ = new WebSocketSubject({ + url: url, + openObserver: { + next: () => { + this.isOpen = true; + this.connectTime = Date.now(); + this.outMessage.next({ + type: 'open', + message: event.toString() + }); + } + }, + closeObserver: { + next: () => { + this.onCloseEvents(); + } + } + } as WebSocketSubjectConfig); + + this.socket$.pipe( + filter((message: IWebSocketData) => { + return message.type === ResponseType.PING ? (this.send({ type: 'PONG' }), false) : true; + }), + map(({result}: {result: IWebSocketDataResult}) => result), + timeout(this.delayLimit), + catchError((err: any) => err.name === 'TimeoutError' ? this.onTimeout() : throwError(err)), + filter((message: IWebSocketDataResult | null) => { + return !!message; + }), + ).subscribe((message: IWebSocketDataResult) => { + this.outMessage.next({ + type: 'message', + message + }); + }, (err: any) => { + console.log(err); + this.closed(); + }, () => { + console.log('Complete'); + this.closed(); + }); + } + + // TODO: No Response 메시지 띄워주기 + private onTimeout(): Observable { + this.close(); + + return of(null); + } + + private closed(): void { + this.isOpen = false; + this.socket$ = null; + this.outMessage.next({ + type: 'close', + message: '' + }); + } + + private onCloseEvents(): void { + if (Date.now() - this.connectTime < this.retryTimeout) { + if (this.retryCount < this.maxRetryCount) { + this.retryCount++; + this.outMessage.next({ + type: 'retry', + message: '' + }); + } else { + this.outMessage.next({ + type: 'close', + message: '' + }); + } + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-resize-top.directive.ts b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-resize-top.directive.ts new file mode 100644 index 000000000000..245c2d281a71 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time-new/new-resize-top.directive.ts @@ -0,0 +1,61 @@ +import { Directive, ElementRef, OnInit, OnDestroy, Renderer2, Input, HostListener } from '@angular/core'; + +import { WindowRefService, WebAppSettingDataService } from 'app/shared/services'; + +@Directive({ + selector: '[ppResizeTop]' +}) +export class NewResizeTopDirective implements OnInit, OnDestroy { + @Input() minHeight: number; + @Input() maxHeightPadding: number; + private resizeElement: HTMLElement; + private maxHeight: number; + private dragging = false; + constructor( + private elementRef: ElementRef, + private renderer: Renderer2, + private webAppSettingDataService: WebAppSettingDataService, + private windowRefService: WindowRefService + ) { + this.resizeElement = this.elementRef.nativeElement.parentElement; + this.maxHeight = this.windowRefService.nativeWindow.innerHeight; + this.windowRefService.nativeWindow.addEventListener('mouseup', this.onWindowMouseUp.bind(this)); + this.windowRefService.nativeWindow.addEventListener('mousemove', this.onWindowMouseMove.bind(this)); + } + ngOnInit() { + this.maxHeight = this.windowRefService.nativeWindow.innerHeight - this.maxHeightPadding; + } + ngOnDestroy() { + this.windowRefService.nativeWindow.removeEventListener('mouseup', this.onWindowMouseUp); + this.windowRefService.nativeWindow.removeEventListener('mousemove', this.onWindowMouseMove); + } + onWindowMouseUp($event: MouseEvent): void { + this.dragging = false; + } + onWindowMouseMove($event: MouseEvent): void { + if (this.dragging) { + this.resizeOn(-$event.movementY); + } + } + @HostListener('mousedown', ['$event']) onMouseDown($event) { + this.dragging = true; + } + @HostListener('mousemove', ['$event']) onMouseMove($event: MouseEvent) { + if (this.dragging) { + this.resizeOn(-$event.movementY); + } + } + @HostListener('mouseup') onMouseUp() { + this.dragging = false; + } + resizeOn(y: number): void { + if (y !== 0) { + const nextHeight = (Number.parseInt(this.resizeElement.style.height, 10) || this.minHeight) + y; + if (nextHeight >= this.minHeight && nextHeight <= this.maxHeight) { + this.webAppSettingDataService.setLayerHeight(nextHeight); + this.renderer.setStyle(this.resizeElement, 'height', nextHeight + 'px'); + + } + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/index.ts b/web/src/main/webapp/v2/src/app/core/components/real-time/index.ts new file mode 100644 index 000000000000..8341a6856f5e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/index.ts @@ -0,0 +1,38 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { RealTimeChartComponent } from './real-time-chart.component'; +import { RealTimeContainerComponent } from './real-time-container.component'; +import { RealTimePagingContainerComponent } from './real-time-paging-container.component'; +import { RealTimeTotalChartComponent } from './real-time-total-chart.component'; +import { RealTimeAgentChartComponent } from './real-time-agent-chart.component'; +import { RealTimeWebSocketService } from './real-time-websocket.service'; +import { ResizeTopDirective } from './resize-top.directive'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + ResizeTopDirective, + RealTimeChartComponent, + RealTimeAgentChartComponent, + RealTimeTotalChartComponent, + RealTimeContainerComponent, + RealTimePagingContainerComponent, + ], + imports: [ + SharedModule, + HelpViewerPopupModule + ], + exports: [ + RealTimeContainerComponent, + RealTimePagingContainerComponent, + ], + entryComponents: [ + RealTimeTotalChartComponent, + RealTimeAgentChartComponent, + ], + providers: [ + RealTimeWebSocketService + ] +}) +export class RealTimeModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-agent-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-agent-chart.component.css new file mode 100644 index 000000000000..e813513515b1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-agent-chart.component.css @@ -0,0 +1,53 @@ +:host { + display: block; + width: 152px; + height: 84px; + margin: 0 15px 10px 0px; +} +dt { + color: #fff; + padding: 10px 20px 10px 2px; + display: block; + overflow: hidden; + font-size: 11px; + text-align: center; + line-height: 1em; + white-space: nowrap; + text-overflow: ellipsis; + border-bottom: 1px solid #687b8e; + background-color: #74879a; +} +i { + float: right; + cursor: pointer; + margin-right: -16px; +} +dd { + display: flex; + flex-flow: row wrap; + background: #fff; + justify-content: space-around; + align-items: center; +} +.l-chart-section { + background: #fff; + border-top: 1px solid #e5e8f0; + height: 54px; + width: 100%; + position: relative; +} +.l-error-template { + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + justify-content: center; + align-items: center; + z-index: 2; +} +.l-error-text { + font-size: 14px; + font-weight: 600; + color: #c04e3f; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-agent-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-agent-chart.component.html new file mode 100644 index 000000000000..95dbe8181257 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-agent-chart.component.html @@ -0,0 +1,15 @@ +
    +
    {{agentName}}
    +
    +
    + + +
    +

    {{errorMessage}}

    +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-agent-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-agent-chart.component.ts new file mode 100644 index 000000000000..568d129f62f2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-agent-chart.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { IRealTimeChartData } from './real-time-chart.component'; + +@Component({ + selector: 'pp-real-time-agent-chart', + templateUrl: './real-time-agent-chart.component.html', + styleUrls: ['./real-time-agent-chart.component.css'] +}) +export class RealTimeAgentChartComponent implements OnInit { + @Input() agentName: string; + @Input() hasError: boolean; + @Input() errorMessage: string; + @Input() chartData: IRealTimeChartData; + @Output() outOpenThreadDump: EventEmitter = new EventEmitter(); + + showAxis = false; + + constructor() {} + ngOnInit() {} + onOpen(): void { + this.outOpenThreadDump.emit(this.agentName); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-chart.component.css new file mode 100644 index 000000000000..31b579f87ed9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-chart.component.css @@ -0,0 +1,52 @@ +:host { + display: block; + width: 100%; + height: 100%; + position: relative; +} + +.l-tooltip { + background-color: rgba(0, 0, 0, 0.8); + color: #fff; + border: 0px solid rgba(0, 0, 0, 0); + border-radius: 5px; + padding: 5px 7px; + position: absolute; + top: 110%; +} + +.l-tooltip-caret { + width: 0; + height: 0; + position: absolute; + top: calc(110% - 7px); + border-bottom: 7px solid rgba(0, 0, 0, 0.8); + border-left: 7px solid transparent; + border-right: 7px solid transparent; +} + +.l-tooltip-title { + font-size: 12px; + font-weight: 600; + margin-bottom: 2px; +} + +.l-tooltip-body { + font-size: 12px; +} + +.l-tooltip-body > dl { + display: flex; +} + +.l-tooltip-body dt { + margin-right: 5px; +} + +.l-tooltip-label { + display: inline-block; + width: 10px; + height: 10px; + margin-right: 2px; + box-shadow: inset 0px 0px 0px 1px rgba(255, 255, 255, 0.4); +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-chart.component.html new file mode 100644 index 000000000000..5f556d032afd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-chart.component.html @@ -0,0 +1,13 @@ + + +
    +
    {{tooltipDataObj.title}}
    +
    +
    +
    {{chartLabels[i]}}:
    +
    {{value}}
    +
    +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-chart.component.ts new file mode 100644 index 000000000000..57758147a3b7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-chart.component.ts @@ -0,0 +1,204 @@ +import { Component, OnInit, ViewChild, ElementRef, Input, OnChanges, SimpleChanges, Renderer2 } from '@angular/core'; +import { Chart, ChartPoint, ChartDataSets } from 'chart.js'; +import 'chartjs-plugin-streaming'; +import * as moment from 'moment-timezone'; + +export interface IRealTimeChartData { + timeStamp: number; + responseCount: number[]; +} + +@Component({ + selector: 'pp-real-time-chart', + templateUrl: './real-time-chart.component.html', + styleUrls: ['./real-time-chart.component.css'] +}) +export class RealTimeChartComponent implements OnInit, OnChanges { + @ViewChild('real') chartElement: ElementRef; + @ViewChild('tooltip') tooltip: ElementRef; + @ViewChild('tooltipCaret') tooltipCaret: ElementRef; + @Input() showAxis: boolean; + @Input() namespace: string; + @Input() timezone: string; + @Input() dateFormat: string; + @Input() chartData: IRealTimeChartData; + + private chartObj: Chart; + private defaultYMax = 5; + + chartColors = ['#33b692', '#51afdf', '#fea63e', '#e76f4b']; + chartLabels = ['1s', '3s', '5s', 'Slow']; + showTooltip: boolean; + tooltipDataObj = { + title: '', + values: [] as number[], + }; + // private yMaxHolder: number[] = []; + + constructor( + private renderer: Renderer2, + private el: ElementRef + ) {} + ngOnChanges(changes: SimpleChanges) { + Object.keys(changes) + .filter(() => this.chartObj !== undefined) + .filter((propName: string) => { + return changes[propName].currentValue; + }) + .forEach((propName: string) => { + const changedProp = changes[propName]; + + switch (propName) { + case 'chartData': + this.updateChartData(changedProp.currentValue); + break; + } + + this.chartObj.update({ + duration: 0 + }); + }); + } + ngOnInit() { + this.chartObj = new Chart(this.chartElement.nativeElement.getContext('2d'), { + type: 'line', + data: { + labels: [], + datasets: this.chartColors.map((color: string, i: number) => { + return { + label: this.chartLabels[i], + backgroundColor: color, + borderColor: color, + borderWidth: 0.5, + fill: true, + pointRadius: 0, + pointHoverRadius: 3, + data: [] + }; + }) + }, + options: { + animation: { + duration: 0 + }, + elements: { + line: { + tension: 0 + } + }, + responsive: true, + maintainAspectRatio: false, + legend: { + display: false + }, + events: this.showAxis ? ['mousemove', 'mouseout', 'click'] : [], + hover: { + animationDuration: 0, + mode: 'index', + intersect: false, + onHover: (event: MouseEvent, elements: {[key: string]: any}[]): void => { + if (event.type !== 'mouseout' && event.offsetX >= 25 && event.offsetX <= 167) { + this.showTooltip = true; + this.setTooltipData(elements); + this.setTooltipPosition(event); + } else { + // * event.type === 'mouseout' + this.showTooltip = false; + } + } + }, + responsiveAnimationDuration: 0, + tooltips: { + enabled: false, + }, + scales: { + xAxes: [{ + type: 'realtime', + gridLines: { + display: !this.showAxis, + drawBorder: false, + tickMarkLength: 0 + }, + ticks: { + display: false + } + }], + yAxes: [{ + gridLines: { + display: this.showAxis, + drawBorder: false, + tickMarkLength: 0 + }, + ticks: { + display: this.showAxis, + beginAtZero: true, + min: 0, + max: this.defaultYMax, + padding: 5 + }, + + }] + }, + plugins: { + streaming: { + duration: 12000, // data in the past 12000 ms will be displayed + // refresh: 1000, // onRefresh callback will be called every 1000 ms + delay: 2000, // delay of 2000 ms, so upcoming values are known before plotting a line + frameRate: 30, // chart is drawn 30 times every second + // pause: false, + } + } + } + }); + } + + private setTooltipData(elements: {[key: string]: any}[]): void { + const datasets = this.chartObj.config.data.datasets; + + this.tooltipDataObj = { + title: moment((datasets[0].data[elements[0]._index] as ChartPoint).x).tz(this.timezone).format(this.dateFormat), + values: elements.map((element: {[key: string]: any}, i: number) => (datasets[i].data[element._index] as ChartPoint).y as number) + }; + } + + private setTooltipPosition(event: MouseEvent): void { + if (this.tooltip) { + const tooltipCaret = this.tooltipCaret.nativeElement; + const tooltip = this.tooltip.nativeElement; + const ratio = event.offsetX / this.el.nativeElement.offsetWidth; + + this.renderer.setStyle(tooltipCaret, 'left', event.offsetX - (tooltipCaret.offsetWidth / 2) + 'px'); + this.renderer.setStyle(tooltip, 'left', event.offsetX - (tooltip.offsetWidth * ratio) + 'px'); + } + } + + private updateChartData({timeStamp, responseCount}: {timeStamp: number, responseCount: number[]}): void { + if (responseCount.length === 0) { + this.chartObj.config.options.plugins.streaming.pause = true; + } else { + this.chartObj.config.data.datasets.forEach(function(dataset, i) { + (dataset.data as ChartPoint[]).push({ + x: timeStamp, + y: responseCount[i] + }); + }); + /** + * 1. 데이터 들어올때 마다 최댓값을 yMaxHolder에 넣음. + * 2. 11초(duration time이랑 비슷한 시간) 지날때마다 맨앞의 element 제거. + * 3. yMaxHolder의 최댓값을 yMax로 세팅. + */ + // this.yMaxHolder.push(Math.max(...responseCount)); + // setTimeout(() => { + // this.yMaxHolder.shift(); + // }, 11000); + // this.chartObj.config.options.scales.yAxes[0].ticks.max = Math.max(this.defaultYMax, Math.round(Math.max(...this.yMaxHolder) * 2)); + this.chartObj.config.options.scales.yAxes[0].ticks.max = + Math.max(...this.chartObj.data.datasets.map(function(dataset: ChartDataSets) { + return Math.max(...(dataset.data as ChartPoint[]).map(function(value) { + return value.y as number; + })); + })) >= this.defaultYMax ? undefined : this.defaultYMax; + this.chartObj.config.options.plugins.streaming.pause = false; + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-container.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-container.component.css new file mode 100644 index 000000000000..b84c1343d3e0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-container.component.css @@ -0,0 +1,118 @@ +:host { + z-index: 30; +} +.l-thread-chart-wrap { + background: #d3dbe6; + border-top: 1px solid #ccd5e0; + position: absolute; + bottom: 0; + left: 0; + width: 100%; +} +.l-title-group { + display: flex; + flex-flow: row wrap; + color: #566370; + font-size: 14px; + font-weight: 600; + height: 34px; + padding: 0 10px 0 25px; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #bdc7d5; + cursor: ns-resize; + background: #f6f8fb; +} +.l-title-group .fas { + font-size: 18px; + color: #a8acb5; + cursor: pointer; +} +.l-title-group .l-title .fas { + margin: 0 9px 0 0; + +} +.l-title-group .l-tool-box { + color: #8F9CAF; +} +.l-tool-box button { + margin-left: 10px; +} +.l-pin-up { + color: #F00; +} +.l-chart-group-wrap { + display: flex; + flex-flow: row wrap; + padding: 20px 10px 20px 25px; + max-height: calc(100% - 34px); +} +.l-chart-group-wrap > .l-chart-item { + width: 277px; + height: 178px; + margin-right: 20px; +} +.l-chart-group-wrap .l-chart-group-list { + display: flex; + flex-flow: row wrap; + flex: 1; + overflow-y: auto; + justify-content: space-between; +} +.l-message { + top: 0px; + left: 0px; + width: 100%; + height: 100%; + position: absolute; + text-align: center; + background-color: rgba(226, 226, 226, 0.5); + z-index: 9999; +} +.l-message h4 { + padding: 80px 0 10px 0; + font-weight: 100; +} +.l-message h4 span { + padding: 8px 40px 6px 40px; + background-color: #FFF; +} +.l-retry button span { + margin-right: 6px; +} +.l-message.l-no-data h4 span { + background-color: #000; + color: #FFF; +} +.l-paging { + width: 100%; + background-color: #74879a; + color: #FFF; + font-size: 15px; + margin: 5px 5px 4px 5px; + padding: 11px; +} +.l-paging .l-txt { + font-weight: lighter; +} +.l-paging .l-txt-bold { + font-weight: bolder; + font-size: 18px; +} +.l-paging .l-page { + float: right; + cursor: pointer; + padding: 0px 6px; +} +.l-paging .l-page:hover { + color: #4b99e3; +} +.l-paging .l-page:last-child { + color: #000; + cursor: initial; + text-decoration: initial; + background-color: #FFF; +} +.fa-chart-area { + margin-right: 2px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-container.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-container.component.html new file mode 100644 index 000000000000..2b3afd680206 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-container.component.html @@ -0,0 +1,40 @@ +
    +
    +
    + Realtime Active Thread Chart +
    +
    + + +
    +
    +
    +
    + +
    +
    +
    + Total Servers : + {{totalCount}} + [ 1 ~ {{pagingSize}} ] + {{page}} + 1 +
    + +
    + +
    +

    Waiting Connection...

    + +
    +
    +

    Closed connection

    + +
    +
    +

    This node is not WAS

    +
    + +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-container.component.ts new file mode 100644 index 000000000000..11a3a4401a6b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-container.component.ts @@ -0,0 +1,329 @@ +import { Component, OnInit, OnDestroy, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { + StoreHelperService, + WebAppSettingDataService, + NewUrlStateNotificationService, + UrlRouteManagerService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { RealTimeWebSocketService, IWebSocketResponse, IWebSocketDataResult, ResponseCode, IActiveThreadCounts } from './real-time-websocket.service'; +import { RealTimeTotalChartComponent } from './real-time-total-chart.component'; +import { RealTimeAgentChartComponent } from './real-time-agent-chart.component'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +// TODO: 나중에 공통으로 추출. +const enum MessageTemplate { + LOADING = 'LOADING', + RETRY = 'RETRY', + NO_DATA = 'NO_DATA', + NOTHING = 'NOTHING' +} + +@Component({ + selector: 'pp-real-time-container', + templateUrl: './real-time-container.component.html', + styleUrls: ['./real-time-container.component.css'] +}) +export class RealTimeContainerComponent implements OnInit, OnDestroy { + @ViewChild('totalChartPlaceHolder', { read: ViewContainerRef} ) totalChartViewContainerRef: ViewContainerRef; + @ViewChild('agentChartPlaceHolder', { read: ViewContainerRef} ) agentChartViewContainerRef: ViewContainerRef; + + private unsubscribe = new Subject(); + private applicationName = ''; + private serviceType = ''; + private totalComponentRef: any = null; + private componentRefMap: any = {}; + totalCount = 0; + pinUp = true; + lastHeight: number; + minHeight = 343; + maxHeightPadding = 50; // Header Height + timezone: string; + dateFormat: string; + hiddenComponent = true; + messageTemplate = MessageTemplate.LOADING; + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private realTimeWebSocketService: RealTimeWebSocketService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.lastHeight = this.webAppSettingDataService.getLayerHeight() || this.minHeight; + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter(() => { + return this.newUrlStateNotificationService.hasValue(UrlPathId.APPLICATION); + }) + ).subscribe(() => { + this.hiddenComponent = true; + this.resetState(); + this.resetAgentComponentRef(); + }); + this.connectStore(); + + this.realTimeWebSocketService.onMessage$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((response: IWebSocketResponse) => { + switch (response.type) { + case 'open': + this.onOpen(); + break; + case 'close': + this.onClose(); + break; + case 'retry': + this.onRetry(); + break; + case 'message': + this.onMessage(response.message as IWebSocketDataResult); + break; + } + }); + } + ngOnDestroy() { + this.realTimeWebSocketService.close(); + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTimezone(this.unsubscribe).subscribe((timezone: string) => { + this.timezone = timezone; + }); + this.storeHelperService.getDateFormat(this.unsubscribe, 0).subscribe((dateFormat: string) => { + this.dateFormat = dateFormat; + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isMerged === true || target.isMerged === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.webAppSettingDataService.useActiveThreadChart().subscribe((use: boolean) => { + this.hiddenComponent = false; + const application = target.node[0].split('^'); + if (use === false) { + // this.resetState(); + // this.resetAgentComponentRef(); + this.hide(); + return; + } + if (this.pinUp === true) { + if (this.applicationName !== '') { + return; + } + } + if (target.isWAS) { + if (this.isSameWithCurrentTarget(application[0], application[1]) === false) { + // this.resetState(); + // this.resetAgentComponentRef(); + // this.hide(); + // } else { + this.applicationName = application[0]; + this.serviceType = application[1]; + if (this.realTimeWebSocketService.isOpened()) { + this.resetAgentComponentRef(); + this.startDataRequest(); + } else { + this.realTimeWebSocketService.connect(); + } + } + } else { + this.applicationName = application[0]; + this.serviceType = application[1]; + this.realTimeWebSocketService.close(); + this.stopDataRequest(); + this.resetAgentComponentRef(); + this.hide(); + } + }); + }); + } + private resetAgentComponentRef(): void { + this.totalChartViewContainerRef.clear(); + this.agentChartViewContainerRef.clear(); + this.totalComponentRef = null; + this.componentRefMap = {}; + } + private resetState() { + this.applicationName = ''; + this.serviceType = ''; + this.pinUp = true; + } + private hide() { + this.messageTemplate = MessageTemplate.NO_DATA; + } + private isSameWithCurrentTarget(applicationName: string, serviceType: string): boolean { + return (this.applicationName === applicationName && this.serviceType === serviceType); + } + private startDataRequest(): void { + this.realTimeWebSocketService.send(this.getRequestDataStr(this.applicationName)); + } + private stopDataRequest(): void { + this.realTimeWebSocketService.send(this.getRequestDataStr('')); + } + private getRequestDataStr(name: string): object { + return { + type: 'REQUEST', + command: 'activeThreadCount', + parameters: { + applicationName: name + } + }; + } + private onOpen(): void { + this.startDataRequest(); + } + private onClose(): void { + this.messageTemplate = MessageTemplate.RETRY; + } + private onRetry(): void { + this.retryConnection(); + } + private onMessage(data: IWebSocketDataResult): void { + this.messageTemplate = MessageTemplate.NOTHING; + if (data.applicationName && data.applicationName !== this.applicationName) { + return; + } + this.totalCount = Object.keys(data.activeThreadCounts).length; + this.publishData(data); + } + private setAgentChart({timeStamp, activeThreadCounts}: {timeStamp?: number, activeThreadCounts: { [key: string]: IActiveThreadCounts }}): void { + /** + * 0. MERGE (componentRefMap Key, 넘어온 데이터 Key) as Set + * 1. Set 루핑 + * 2. 넘어온 데이터 object에 대해서 hasOwnProperty(key) + * 2-1. true && componentRefMap에 없음 => init + update + * 2-2. true && componentRefMap에 존재 => update + * 2-3. false => componentRefMap에서 delete, viewContainer에서 지움(.remove(index)) + */ + const mergedKeySet = new Set([...Object.keys(this.componentRefMap), ...Object.keys(activeThreadCounts)]); + + mergedKeySet.forEach((agentName: string) => { + if (activeThreadCounts.hasOwnProperty(agentName)) { + if (typeof this.componentRefMap[agentName] === 'undefined') { + this.initAgentComponent(agentName); + } + const componentInstance = this.componentRefMap[agentName].componentRef.instance; + const isResponseSuccess = activeThreadCounts[agentName].code === ResponseCode.SUCCESS; + + componentInstance.agentName = agentName; + componentInstance.hasError = isResponseSuccess ? false : true; + componentInstance.errorMessage = isResponseSuccess ? '' : activeThreadCounts[agentName].message; + componentInstance.chartData = { + timeStamp, + responseCount: isResponseSuccess ? activeThreadCounts[agentName].status : [] + }; + } else { + this.componentRefMap[agentName].unsubscription.unsubscribe(); + this.agentChartViewContainerRef.remove(this.componentRefMap[agentName].index); + delete this.componentRefMap[agentName]; + } + }); + } + private setTotalChart({timeStamp, applicationName, activeThreadCounts}: {timeStamp?: number, applicationName?: string, activeThreadCounts: { [key: string]: IActiveThreadCounts }}): void { + if (this.totalComponentRef === null) { + this.initTotalComponent(); + } + const componentInstance = this.totalComponentRef.instance; + const successData = this.getSuccessData(activeThreadCounts); + + componentInstance.applicationName = applicationName ? applicationName : this.applicationName; + componentInstance.hasError = successData.length === 0 ? true : false; + componentInstance.errorMessage = successData.length === 0 ? activeThreadCounts[Object.keys(activeThreadCounts)[0]].message : ''; + componentInstance.timezone = this.timezone; + componentInstance.dateFormat = this.dateFormat; + componentInstance.chartData = { + timeStamp, + responseCount: successData.length === 0 ? [] : this.getTotalResponseCount(successData) + }; + } + private getSuccessData(obj: { [key: string]: IActiveThreadCounts }): IActiveThreadCounts[] { + return Object.keys(obj) + .filter((agentName: string) => obj[agentName].code === ResponseCode.SUCCESS) + .map((agentName: string) => obj[agentName]); + } + private getTotalResponseCount(data: IActiveThreadCounts[]): number[] { + return data.reduce((prev: number[], curr: IActiveThreadCounts) => { + return prev.map((a: number, i: number) => a + curr.status[i]); + }, [0, 0, 0, 0]); + } + private publishData(data: IWebSocketDataResult): void { + this.setTotalChart(data); + this.setAgentChart(data); + } + private initTotalComponent(): void { + const componentFactory = this.componentFactoryResolver.resolveComponentFactory(RealTimeTotalChartComponent); + this.totalComponentRef = this.totalChartViewContainerRef.createComponent(componentFactory); + } + private initAgentComponent(namespace: string) { + const componentFactory = this.componentFactoryResolver.resolveComponentFactory(RealTimeAgentChartComponent); + const componentRef = this.agentChartViewContainerRef.createComponent(componentFactory); + const unsubscription = componentRef.instance.outOpenThreadDump.subscribe((agentId: string) => { + this.openThreadDump(agentId); + }); + + this.componentRefMap[namespace] = { + componentRef: componentRef, + index: this.agentChartViewContainerRef.length - 1, + unsubscription: unsubscription + }; + } + needPaging(): boolean { + return this.totalCount > this.realTimeWebSocketService.getPagingSize(); + } + getTotalPage(): number[] { + const totalPage = Math.ceil(this.totalCount / this.realTimeWebSocketService.getPagingSize()); + const pages = []; + for (let i = totalPage ; i > 1 ; i-- ) { + pages.push(i); + } + return pages; + } + retryConnection(): void { + this.messageTemplate = MessageTemplate.LOADING; + this.realTimeWebSocketService.connect(); + } + onPinUp(): void { + this.analyticsService.trackEvent(this.pinUp ? TRACKED_EVENT_LIST.PIN_UP_REAL_TIME_CHART : TRACKED_EVENT_LIST.REMOVE_PIN_ON_REAL_TIME_CHART); + this.pinUp = !this.pinUp; + } + openPage(page: number): void { + this.urlRouteManagerService.openPage([ + UrlPath.REAL_TIME, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + '' + page + ]); + } + openThreadDump(agentId: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_THREAD_DUMP); + this.urlRouteManagerService.openPage([ + UrlPath.THREAD_DUMP, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + agentId, + '' + Date.now() + ]); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.REAL_TIME); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.REAL_TIME, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-paging-container.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-paging-container.component.css new file mode 100644 index 000000000000..ce04f966de8a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-paging-container.component.css @@ -0,0 +1,77 @@ +:host { + z-index: 30; +} +.l-thread-chart-wrap { + display: flex; + flex-flow: row wrap; + background:#d3dbe6; + border-top:1px solid #ccd5e0; + position: absolute; + bottom: 0; + left: 0; + width:100%; + height: 100%; +} +.l-chart-group-wrap { + display: flex; + flex-flow: row wrap; +} +.l-chart-group-list { + display: flex; + flex-flow: row wrap; + width: 100%; +} +.l-message { + top: 0px; + left: 0px; + width: 100%; + height: 100%; + position: absolute; + text-align: center; + background-color: rgba(226, 226, 226, 0.5); + z-index: 9999; +} +.l-message h4 { + padding: 80px 0 10px 0; + font-weight: 100; +} +.l-message h4 span { + padding: 8px 40px 6px 40px; + background-color: #FFF; +} +.l-retry button span { + margin-right: 6px; +} +.l-message.l-no-data h4 span { + background-color: #000; + color: #FFF; +} +.l-paging { + width: 100%; + background-color: #74879a; + color: #FFF; + font-size: 15px; + margin: 5px 5px 4px 5px; + padding: 11px; +} +.l-paging .l-txt { + font-weight: lighter; +} +.l-paging .l-txt-bold { + font-weight: bolder; + font-size: 18px; +} +.l-paging .l-page { + float: right; + cursor: pointer; + padding: 0px 6px; +} +.l-paging .l-page:hover { + color: #4b99e3; +} +.l-paging .l-page:last-child { + color: #000; + cursor: initial; + text-decoration: initial; + background-color:#FFF; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-paging-container.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-paging-container.component.html new file mode 100644 index 000000000000..8f87ef7629de --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-paging-container.component.html @@ -0,0 +1,26 @@ +
    +
    +
    +
    + Total Servers : + {{totalCount}} + [ {{startCount + 1}} ~ {{endCount}} ] +
    + +
    + +
    +

    Waiting Connection...

    + +
    +
    +

    Closed connection

    + +
    +
    +

    This node is not WAS

    +
    + +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-paging-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-paging-container.component.ts new file mode 100644 index 000000000000..6164774659ee --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-paging-container.component.ts @@ -0,0 +1,182 @@ +import { Component, OnInit, OnDestroy, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { WebAppSettingDataService, NewUrlStateNotificationService } from 'app/shared/services'; +import { RealTimeWebSocketService, IWebSocketResponse, IWebSocketDataResult, ResponseCode, IActiveThreadCounts } from './real-time-websocket.service'; +import { RealTimeAgentChartComponent } from './real-time-agent-chart.component'; + +// TODO: 나중에 공통으로 추출. +const enum MessageTemplate { + LOADING = 'LOADING', + RETRY = 'RETRY', + NO_DATA = 'NO_DATA', + NOTHING = 'NOTHING' +} + +@Component({ + selector: 'pp-real-time-paging-container', + templateUrl: './real-time-paging-container.component.html', + styleUrls: ['./real-time-paging-container.component.css'] +}) +export class RealTimePagingContainerComponent implements OnInit, OnDestroy { + @ViewChild('agentChartPlaceHolder', { read: ViewContainerRef} ) agentChartViewContainerRef: ViewContainerRef; + + private unsubscribe = new Subject(); + private applicationName = ''; + private serviceType = ''; + private componentRefMap: any = {}; + totalCount = 0; + startCount: number; + endCount: number; + currentPage: number; + messageTemplate = MessageTemplate.LOADING; + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private webAppSettingDataService: WebAppSettingDataService, + private realTimeWebSocketService: RealTimeWebSocketService + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter(() => { + return this.newUrlStateNotificationService.hasValue(UrlPathId.APPLICATION); + }) + ).subscribe(() => { + this.applicationName = this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName(); + this.serviceType = this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getServiceType(); + this.currentPage = Number(this.newUrlStateNotificationService.getPathValue(UrlPathId.PAGE)); + this.startCount = this.currentPage * (this.realTimeWebSocketService.getPagingSize() - 1); + this.endCount = this.startCount + this.realTimeWebSocketService.getPagingSize(); + + this.webAppSettingDataService.useActiveThreadChart().subscribe((use: boolean) => { + if (use === false) { + this.resetState(); + this.resetAgentComponentRef(); + this.hide(); + return; + } + if (this.realTimeWebSocketService.isOpened()) { + this.resetAgentComponentRef(); + this.startDataRequest(); + } else { + this.realTimeWebSocketService.connect(); + } + }); + }); + this.realTimeWebSocketService.onMessage$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((response: IWebSocketResponse) => { + switch (response.type) { + case 'open': + this.onOpen(); + break; + case 'close': + this.onClose(); + break; + case 'retry': + this.onRetry(); + break; + case 'message': + this.onMessage(response.message as IWebSocketDataResult); + break; + } + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private resetAgentComponentRef(): void { + this.agentChartViewContainerRef.clear(); + this.componentRefMap = {}; + } + private resetState() { + this.applicationName = ''; + this.serviceType = ''; + } + private hide() { + this.messageTemplate = MessageTemplate.NO_DATA; + } + private startDataRequest(): void { + this.realTimeWebSocketService.send(this.getRequestDataStr(this.applicationName)); + } + private getRequestDataStr(name: string): object { + return { + type: 'REQUEST', + command: 'activeThreadCount', + parameters: { + applicationName: name + } + }; + } + private onOpen(): void { + this.startDataRequest(); + } + private onClose(): void { + this.messageTemplate = MessageTemplate.RETRY; + } + private onRetry(): void { + this.retryConnection(); + } + private onMessage(data: IWebSocketDataResult): void { + this.messageTemplate = MessageTemplate.NOTHING; + if (data.applicationName && data.applicationName !== this.applicationName) { + return; + } + this.totalCount = Object.keys(data.activeThreadCounts).length; + this.publishData(data); + } + private setAgentChart({timeStamp, activeThreadCounts}: {timeStamp?: number, activeThreadCounts: { [key: string]: IActiveThreadCounts }}): void { + const mergedKeySet = new Set([...Object.keys(this.componentRefMap), ...Object.keys(activeThreadCounts)]); + + mergedKeySet.forEach((agentName: string) => { + if (activeThreadCounts.hasOwnProperty(agentName)) { + if (typeof this.componentRefMap[agentName] === 'undefined') { + this.initAgentComponent(agentName); + } + const componentInstance = this.componentRefMap[agentName].componentRef.instance; + const isResponseSuccess = activeThreadCounts[agentName].code === ResponseCode.SUCCESS; + + componentInstance.agentName = agentName; + componentInstance.hasError = isResponseSuccess ? false : true; + componentInstance.errorMessage = isResponseSuccess ? '' : activeThreadCounts[agentName].message; + componentInstance.chartData = { + timeStamp, + responseCount: isResponseSuccess ? activeThreadCounts[agentName].status : [] + }; + } else { + this.agentChartViewContainerRef.remove(this.componentRefMap[agentName].index); + delete this.componentRefMap[agentName]; + } + }); + } + private publishData(data: IWebSocketDataResult): void { + this.setAgentChart(data); + } + private initAgentComponent(namespace: string) { + const componentFactory = this.componentFactoryResolver.resolveComponentFactory(RealTimeAgentChartComponent); + const componentRef = this.agentChartViewContainerRef.createComponent(componentFactory); + this.componentRefMap[namespace] = { + componentRef: componentRef, + index: this.agentChartViewContainerRef.length - 1 + }; + } + needPaging(): boolean { + return this.totalCount > this.realTimeWebSocketService.getPagingSize(); + } + getTotalPage(): number[] { + const totalPage = Math.ceil(this.totalCount / this.realTimeWebSocketService.getPagingSize()); + const pages = []; + for (let i = totalPage ; i > 1 ; i-- ) { + pages.push(i); + } + return pages; + } + retryConnection(): void { + this.messageTemplate = MessageTemplate.LOADING; + this.realTimeWebSocketService.connect(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-total-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-total-chart.component.css new file mode 100644 index 000000000000..1ae408e5b373 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-total-chart.component.css @@ -0,0 +1,93 @@ +:host { + display: block; +} +.l-wrapper dt { + color:#fff; + padding: 15px 4px; + display: block; + overflow: hidden; + font-size: 15px; + text-align:center; + line-height: 1em; + white-space: nowrap; + text-overflow: ellipsis; + border-bottom: 1px solid #687b8e; + background-color: #74879a; +} +.l-wrapper dd { + display: flex; + flex-flow: row wrap; + background:#fff; + justify-content:space-around; + align-items:center; + height: 135px; +} +.l-chart-section { + width: 180px; + height: 110px; + border-top: none; + padding: unset; + position: relative; +} +.l-error-template { + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + justify-content: center; + align-items: center; + z-index: 2; +} +.l-error-text { + font-size: 14px; + font-weight: 600; + color: #c04e3f; +} +.l-legend { + font-size:11px; + width: 70px; + height: 110px; +} +.l-legend li { + margin:7px 0 0; + color:#666; +} +.l-legend li:first-child { + margin:0; + color:#010101; + font-weight:600; +} +.l-legend li span { + display:inline-block; +} +.l-legend li .l-text { + width:30px; + text-align:right; + margin:0 10px 0 0; +} +.l-legend li .l-circle { + width:21px; + height:11px; + color:#fff; + border-radius:10px; + text-align:center; + overflow: hidden; + text-overflow: ellipsis; + line-height: 1em; +} +.l-legend li:nth-child(1) .l-circle { + background:#a8acb5 +} +.l-legend li:nth-child(2) .l-circle { + background:#e76f4b +} +.l-legend li:nth-child(3) .l-circle { + background:#fea63e +} +.l-legend li:nth-child(4) .l-circle { + background:#51afdf +} +.l-legend li:nth-child(5) .l-circle { + background:#33b692 +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-total-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-total-chart.component.html new file mode 100644 index 000000000000..88a4c1f25ef7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-total-chart.component.html @@ -0,0 +1,39 @@ +
    +
    {{applicationName}}
    +
    +
    + + +
    +

    {{errorMessage}}

    +
    +
    +
      +
    • + Total + {{getTotalCount()}} +
    • +
    • + Slow + {{chartData.responseCount[3]}} +
    • +
    • + 5s + {{chartData.responseCount[2]}} +
    • +
    • + 3s + {{chartData.responseCount[1]}} +
    • +
    • + 1s + {{chartData.responseCount[0]}} +
    • +
    +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-total-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-total-chart.component.ts new file mode 100644 index 000000000000..2d17ddcc156d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-total-chart.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { IRealTimeChartData } from './real-time-chart.component'; + +@Component({ + selector: 'pp-real-time-total-chart', + templateUrl: './real-time-total-chart.component.html', + styleUrls: ['./real-time-total-chart.component.css'] +}) +export class RealTimeTotalChartComponent implements OnInit { + @Input() applicationName: string; + @Input() hasError: boolean; + @Input() errorMessage: string; + @Input() timezone: string; + @Input() dateFormat: string; + @Input() chartData: IRealTimeChartData; + + showAxis = true; + constructor() {} + ngOnInit() {} + getTotalCount(): number { + return this.chartData.responseCount.reduce((prev: number, curr: number) => prev + curr, 0); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-websocket.service.ts b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-websocket.service.ts new file mode 100644 index 000000000000..bf867197c398 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/real-time-websocket.service.ts @@ -0,0 +1,242 @@ +import { Injectable } from '@angular/core'; +import { Subject, Observable, of, throwError } from 'rxjs'; +import { WebSocketSubject, WebSocketSubjectConfig } from 'rxjs/webSocket'; +import { timeout, catchError, map, filter } from 'rxjs/operators'; + +import { WindowRefService } from 'app/shared/services'; + +interface IWebSocketData { + type: ResponseType; + command: string; + result: IWebSocketDataResult; +} + +export interface IWebSocketDataResult { + timeStamp?: number; + applicationName?: string; + activeThreadCounts: { [key: string]: IActiveThreadCounts }; +} + +export interface IActiveThreadCounts { + code: number; + message: string; + status?: number[]; +} + +export interface IWebSocketResponse { + type: string; + message: string | IWebSocketDataResult; +} + +export const enum ResponseType { + PING = 'PING', + RESPONSE = 'RESPONSE' +} + +export const enum ResponseCode { + SUCCESS = 0, + TIMEOUT = 211, + ERROR_BLACK = 111, + OVER_DELAY = 9999 +} + +@Injectable() +export class RealTimeWebSocketService { + private url = 'agent/activeThread.pinpointws'; + private timeoutLimit = 10; // 서버로부터의 timeout response를 무시하는 최대횟수 + private timeoutCount: { [key: string]: number } = {}; // 각 agent별 timeout된 횟수 + private delayLimit = 10000; // 서버로부터의 응답을 기다리는 최대시간(ms) + private prevData: { [key: string]: IActiveThreadCounts } = {}; // Success일때의 데이터({ code, message, status })를 킵 + + private retryTimeout = 3000; + private retryCount = 0; + private maxRetryCount = 1; + private connectTime: number; + private isOpen = false; + private pagingSize = 30; + + private socket$: WebSocketSubject = null; + + private outMessage: Subject = new Subject(); + onMessage$: Observable; + + constructor( + private windowRefService: WindowRefService + ) { + this.onMessage$ = this.outMessage.asObservable(); + } + connect(): void { + if (this.isOpen === false) { + this.openWebSocket(); + } + } + isOpened(): boolean { + return this.isOpen; + } + close(): void { + if (this.isOpen) { + this.socket$.complete(); + } else { + this.outMessage.next({ + type: 'close', + message: '' + }); + } + } + send(message: object): void { + if (this.isOpen) { + this.socket$.next(message); + } + } + getPagingSize(): number { + return this.pagingSize; + } + private openWebSocket(): void { + const location = this.windowRefService.nativeWindow.location; + const protocol = location.protocol.indexOf('https') === -1 ? 'ws' : 'wss'; + const url = `${protocol}://${location.host}/${this.url}`; + + this.socket$ = new WebSocketSubject({ + url: url, + openObserver: { + next: () => { + this.isOpen = true; + this.connectTime = Date.now(); + this.outMessage.next({ + type: 'open', + message: event.toString() + }); + } + }, + closeObserver: { + next: () => { + this.onCloseEvents(); + } + } + } as WebSocketSubjectConfig); + + this.socket$.pipe( + filter((message: IWebSocketData) => { + return message.type === ResponseType.PING ? (this.send({ type: 'PONG' }), false) : true; + }), + map(({result}: {result: IWebSocketDataResult}) => { + return this.parseResult(result); + }), + // map(({timeStamp, applicationName}) => { + // const activeThreadCounts = {}; + // for (let i = 0; i < 30; i++) { + // activeThreadCounts[i] = { + // code: 0, + // message: 'OK', + // status: [ + // Math.floor(2 * Math.random()), + // Math.floor(3 * Math.random()), + // Math.floor(1 * Math.random()), + // Math.floor(4 * Math.random()) + // ] + // }; + // } + // return { + // timeStamp, + // applicationName, + // activeThreadCounts + // }; + // }), + timeout(this.delayLimit), + catchError((err: any) => err.name === 'TimeoutError' ? this.onTimeout() : throwError(err)), + filter((message: IWebSocketDataResult | null) => { + return !!message; + }), + ).subscribe((message: IWebSocketDataResult) => { + this.outMessage.next({ + type: 'message', + message: message + }); + }, (err: any) => { + console.log(err); + this.closed(); + }, () => { + console.log('Complete'); + this.closed(); + }); + } + + private parseResult(result: IWebSocketDataResult): IWebSocketDataResult { + const activeThreadCounts = Object.keys(result.activeThreadCounts).reduce((prev: IWebSocketDataResult, curr: string) => { + const responseCode = result.activeThreadCounts[curr].code; + let agentData: IActiveThreadCounts; + + switch (responseCode) { + case ResponseCode.SUCCESS: + this.timeoutCount[curr] = 0; + this.prevData[curr] = result.activeThreadCounts[curr]; + agentData = result.activeThreadCounts[curr]; + break; + case ResponseCode.TIMEOUT: + this.timeoutCount[curr] = this.timeoutCount[curr] ? this.timeoutCount[curr] + 1 : 1; + agentData = this.prevData[curr] && this.timeoutCount[curr] < this.timeoutLimit ? this.prevData[curr] : result.activeThreadCounts[curr]; + break; + default: + agentData = result.activeThreadCounts[curr]; + break; + } + return { + ...prev, + ...{ [curr]: agentData } + }; + }, {}); + + return { ...result, ...{ activeThreadCounts } }; + } + + private onTimeout(): Observable { + this.close(); + return this.getDelayMessage(); + } + + private getDelayMessage(): Observable { + const delayObj = { + code: ResponseCode.OVER_DELAY, + message: 'No Response' + }; + + if (Object.keys(this.prevData).length !== 0) { + return of({ + activeThreadCounts: Object.keys(this.prevData).reduce((prev: IWebSocketDataResult, curr: string) => { + return { + ...prev, + ...{ [curr]: delayObj } + }; + }, {}) + }); + } else { + return of(null); + } + } + + private closed(): void { + this.isOpen = false; + this.socket$ = null; + this.outMessage.next({ + type: 'close', + message: '' + }); + } + + private onCloseEvents(): void { + if (Date.now() - this.connectTime < this.retryTimeout) { + if (this.retryCount < this.maxRetryCount) { + this.retryCount++; + this.outMessage.next({ + type: 'retry', + message: '' + }); + } else { + this.outMessage.next({ + type: 'close', + message: '' + }); + } + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/real-time/resize-top.directive.ts b/web/src/main/webapp/v2/src/app/core/components/real-time/resize-top.directive.ts new file mode 100644 index 000000000000..28923164c511 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/real-time/resize-top.directive.ts @@ -0,0 +1,61 @@ +import { Directive, ElementRef, OnInit, OnDestroy, Renderer2, Input, HostListener } from '@angular/core'; + +import { WindowRefService, WebAppSettingDataService } from 'app/shared/services'; + +@Directive({ + selector: '[ppResizeTop]' +}) +export class ResizeTopDirective implements OnInit, OnDestroy { + @Input() minHeight: number; + @Input() maxHeightPadding: number; + private resizeElement: HTMLElement; + private maxHeight: number; + private dragging = false; + constructor( + private elementRef: ElementRef, + private renderer: Renderer2, + private webAppSettingDataService: WebAppSettingDataService, + private windowRefService: WindowRefService + ) { + this.resizeElement = this.elementRef.nativeElement.parentElement; + this.maxHeight = this.windowRefService.nativeWindow.innerHeight; + this.windowRefService.nativeWindow.addEventListener('mouseup', this.onWindowMouseUp.bind(this)); + this.windowRefService.nativeWindow.addEventListener('mousemove', this.onWindowMouseMove.bind(this)); + } + ngOnInit() { + this.maxHeight = this.windowRefService.nativeWindow.innerHeight - this.maxHeightPadding; + } + ngOnDestroy() { + this.windowRefService.nativeWindow.removeEventListener('mouseup', this.onWindowMouseUp); + this.windowRefService.nativeWindow.removeEventListener('mousemove', this.onWindowMouseMove); + } + onWindowMouseUp($event: MouseEvent): void { + this.dragging = false; + } + onWindowMouseMove($event: MouseEvent): void { + if (this.dragging) { + this.resizeOn(-$event.movementY); + } + } + @HostListener('mousedown', ['$event']) onMouseDown($event) { + this.dragging = true; + } + @HostListener('mousemove', ['$event']) onMouseMove($event: MouseEvent) { + if (this.dragging) { + this.resizeOn(-$event.movementY); + } + } + @HostListener('mouseup') onMouseUp() { + this.dragging = false; + } + resizeOn(y: number): void { + if (y !== 0) { + const nextHeight = (Number.parseInt(this.resizeElement.style.height, 10) || this.minHeight) + y; + if (nextHeight >= this.minHeight && nextHeight <= this.maxHeight) { + this.webAppSettingDataService.setLayerHeight(nextHeight); + this.renderer.setStyle(this.resizeElement, 'height', nextHeight + 'px'); + + } + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/index.ts b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/index.ts new file mode 100644 index 000000000000..8ddabcfaa461 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/index.ts @@ -0,0 +1,28 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { ResponseSummaryChartComponent } from './response-summary-chart.component'; +import { ResponseSummaryChartForSideBarContainerComponent } from './response-summary-chart-for-side-bar-container.component'; +import { ResponseSummaryChartForInfoPerServerContainerComponent } from './response-summary-chart-for-info-per-server-container.component'; +import { ResponseSummaryChartForFilteredMapSideBarContainerComponent } from './response-summary-chart-for-filtered-map-side-bar-container.component'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + ResponseSummaryChartComponent, + ResponseSummaryChartForSideBarContainerComponent, + ResponseSummaryChartForFilteredMapSideBarContainerComponent, + ResponseSummaryChartForInfoPerServerContainerComponent + ], + imports: [ + SharedModule, + HelpViewerPopupModule + ], + exports: [ + ResponseSummaryChartForSideBarContainerComponent, + ResponseSummaryChartForFilteredMapSideBarContainerComponent, + ResponseSummaryChartForInfoPerServerContainerComponent + ], + providers: [] +}) +export class ResponseSummaryChartModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-filtered-map-side-bar-container.component.css b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-filtered-map-side-bar-container.component.css new file mode 100644 index 000000000000..099907bb7fd6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-filtered-map-side-bar-container.component.css @@ -0,0 +1,34 @@ +:host { + display: block; + position: relative; +} +.l-chart-item { + height: 202px; +} +.l-tool-box { + font-size: 14px; + color: #b3b5b9; + text-align: right; + position: relative; + padding: 16px 25px 0; +} +.l-tool-box .l-title { + float: left; + text-align: left; + font-size: 16px; + color: #333; + font-weight: 600; + margin: 0 0 23px; +} +.l-tool-box button { + font-size: 18px; + margin: 0; +} +.l-content-section { + padding: 0 25px 0; +} +.l-no-data { + padding-top: 60px; + text-align: center; + font-weight: 600; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-filtered-map-side-bar-container.component.html b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-filtered-map-side-bar-container.component.html new file mode 100644 index 000000000000..45c22260aebd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-filtered-map-side-bar-container.component.html @@ -0,0 +1,20 @@ +
    +
    +

    Response Summary

    + +
    +
    + + +
    + {{i18nText.NO_DATA}} +
    +
    +
    + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-filtered-map-side-bar-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-filtered-map-side-bar-container.component.ts new file mode 100644 index 000000000000..202756083517 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-filtered-map-side-bar-container.component.ts @@ -0,0 +1,156 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { Actions } from 'app/shared/store'; +import { StoreHelperService, WebAppSettingDataService, AgentHistogramDataService, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { ServerMapData } from 'app/core/components/server-map/class/server-map-data.class'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-response-summary-chart-for-filtered-map-side-bar-container', + templateUrl: './response-summary-chart-for-filtered-map-side-bar-container.component.html', + styleUrls: ['./response-summary-chart-for-filtered-map-side-bar-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ResponseSummaryChartForFilteredMapSideBarContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + yMax = -1; + selectedTarget: ISelectedTarget; + selectedAgent = ''; + serverMapData: ServerMapData; + hiddenComponent = false; + hiddenChart = false; + useDisable = false; + showLoading = false; + i18nText = { + NO_DATA: '' + }; + chartData: IResponseTime | IResponseMilliSecondTime; + chartColors: string[]; + constructor( + private changeDetector: ChangeDetectorRef, + private translateService: TranslateService, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private agentHistogramDataService: AgentHistogramDataService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.chartColors = this.webAppSettingDataService.getColorByRequest(); + this.translateService.get('COMMON.NO_DATA').subscribe((txt: string) => { + this.i18nText.NO_DATA = txt; + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getAgentSelection(this.unsubscribe).subscribe((agent: string) => { + this.setDisable(true); + this.selectedAgent = agent; + if (this.selectedTarget) { + this.loadResponseSummaryChartData(); + } + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: ServerMapData) => { + this.serverMapData = serverMapData; + if (this.selectedTarget && this.selectedTarget.isMerged === false) { + this.yMax = -1; + this.loadResponseSummaryChartData(); + } + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.yMax = -1; + this.selectedTarget = target; + this.hiddenComponent = target.isMerged; + if (target.isMerged === false) { + this.loadResponseSummaryChartData(); + } + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getServerMapTargetSelectedByList(this.unsubscribe).subscribe((target: any) => { + this.yMax = -1; + this.hiddenComponent = false; + this.passDownChartData(this.agentHistogramDataService.makeChartDataForResponseSummary(target.histogram, this.getChartYMax())); + }); + } + private getChartYMax(): number { + return this.yMax === -1 ? null : this.yMax; + } + private setDisable(disable: boolean): void { + this.useDisable = disable; + this.showLoading = disable; + } + private loadResponseSummaryChartData(from?: number, to?: number): void { + const target = this.getTargetInfo(); + if (this.selectedAgent === '') { + this.passDownChartData(this.agentHistogramDataService.makeChartDataForResponseSummary(target.histogram, this.getChartYMax())); + } else { + this.passDownChartData(this.agentHistogramDataService.makeChartDataForResponseSummary(target['agentHistogram'][this.selectedAgent], this.getChartYMax())); + } + } + private passDownChartData(chartData: any): void { + if (chartData) { + this.hiddenChart = false; + this.chartData = chartData; + } else { + this.hiddenChart = true; + } + this.setDisable(false); + this.changeDetector.detectChanges(); + } + private getTargetInfo(): any { + if (this.selectedTarget.isNode) { + return this.serverMapData.getNodeData(this.selectedTarget.node[0]); + } else { + // return this.serverMapData.getNodeData(this.serverMapData.getLinkData(this.selectedTarget.link[0]).to); + return this.serverMapData.getLinkData(this.selectedTarget.link[0]); + } + } + onNotifyMax(max: number): void { + if (max > this.yMax) { + this.yMax = max; + this.storeHelperService.dispatch(new Actions.ChangeResponseSummaryChartYMax(max)); + } + } + onClickColumn(columnName: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_RESPONSE_GRAPH); + console.log('clicked Column Name :', columnName ); + if (columnName === 'Error') { + // scope.$emit('responseTimeSummaryChartDirective.showErrorTransactionList', type); + // @TODO Scatter Chart의 에러 부분만 Drag 하도록 하는 액션 + } + // @TODO FilteredMap transaction에서 만 처리되는 이벤트 + // if (useFilterTransaction) { + // scope.$emit('responseTimeSummaryChartDirective.itemClicked.' + scope.namespace, { + // "responseTime": type, + // "count": aTarget[0]._chart.config.data.datasets[0].data[aTarget[0]._index] + // }); + // } + + } + + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.RESPONSE_SUMMARY); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.RESPONSE_SUMMARY, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-info-per-server-container.component.css b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-info-per-server-container.component.css new file mode 100644 index 000000000000..fce05d97d0ac --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-info-per-server-container.component.css @@ -0,0 +1,33 @@ +:host { + display: block; +} +.l-chart-item { + height: 202px; +} +.l-tool-box { + font-size: 14px; + color: #b3b5b9; + text-align: right; + position: relative; + padding: 16px 25px 0; +} +.l-tool-box .l-title { + float: left; + text-align: left; + font-size: 16px; + color: #333; + font-weight: 600; + margin: 0 0 23px; +} +.l-tool-box button { + font-size: 18px; + margin: 0; +} +.l-content-section { + padding: 0 25px 0; +} +.l-no-data { + padding-top: 60px; + text-align: center; + font-weight: 600; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-info-per-server-container.component.html b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-info-per-server-container.component.html new file mode 100644 index 000000000000..4e1c8ee16a9e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-info-per-server-container.component.html @@ -0,0 +1,20 @@ +
    +
    +

    Response Summary

    + +
    +
    + + +
    + {{i18nText.NO_DATA}} +
    +
    +
    + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-info-per-server-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-info-per-server-container.component.ts new file mode 100644 index 000000000000..5f463539f588 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-info-per-server-container.component.ts @@ -0,0 +1,93 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { WebAppSettingDataService, StoreHelperService, AgentHistogramDataService, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-response-summary-chart-for-info-per-server-container', + templateUrl: './response-summary-chart-for-info-per-server-container.component.html', + styleUrls: ['./response-summary-chart-for-info-per-server-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ResponseSummaryChartForInfoPerServerContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + hiddenChart = false; + yMax: number; + chartData: IResponseTime | IResponseMilliSecondTime; + chartColors: string[]; + useDisable = false; + showLoading = false; + i18nText = { + NO_DATA: '' + }; + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private webAppSettingDataService: WebAppSettingDataService, + private agentHistogramDataService: AgentHistogramDataService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.chartColors = this.webAppSettingDataService.getColorByRequest(); + this.translateService.get('COMMON.NO_DATA').subscribe((txt: string) => { + this.i18nText.NO_DATA = txt; + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getResponseSummaryChartYMax(this.unsubscribe).subscribe((max: number) => { + this.yMax = max; + }); + this.storeHelperService.getAgentSelectionForServerList(this.unsubscribe).pipe( + filter((chartData: IAgentSelection) => { + return (chartData && chartData.agent) ? true : false; + }) + ).subscribe((chartData: IAgentSelection) => { + if (chartData.responseSummary) { + this.hiddenChart = false; + this.chartData = this.agentHistogramDataService.makeChartDataForResponseSummary(chartData.responseSummary, this.yMax); + } else { + this.hiddenChart = true; + } + this.changeDetector.detectChanges(); + }); + } + onNotifyMax(max: number): void {} + onClickColumn(columnName: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_RESPONSE_GRAPH); + if (columnName === 'Error') { + // scope.$emit('responseTimeSummaryChartDirective.showErrorTransactionList', type); + // @TODO Scatter Chart의 에러 부분만 Drag 하도록 하는 액션 + } + // @TODO FilteredMap transaction에서 만 처리되는 이벤트 + // if (useFilterTransaction) { + // scope.$emit('responseTimeSummaryChartDirective.itemClicked.' + scope.namespace, { + // "responseTime": type, + // "count": aTarget[0]._chart.config.data.datasets[0].data[aTarget[0]._index] + // }); + // } + + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.RESPONSE_SUMMARY); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.RESPONSE_SUMMARY, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-side-bar-container.component.css b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-side-bar-container.component.css new file mode 100644 index 000000000000..f54bc58bff5e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-side-bar-container.component.css @@ -0,0 +1,30 @@ +.l-chart-item { + height: 202px; +} +.l-tool-box { + font-size: 14px; + color: #b3b5b9; + text-align: right; + position: relative; + padding: 16px 25px 0; +} +.l-tool-box .l-title { + float: left; + text-align: left; + font-size: 16px; + color: #333; + font-weight: 600; + margin: 0 0 23px; +} +.l-tool-box button { + font-size: 18px; + margin: 0; +} +.l-content-section { + padding: 0 25px 0; +} +.l-no-data { + padding-top: 60px; + text-align: center; + font-weight: 600; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-side-bar-container.component.html b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-side-bar-container.component.html new file mode 100644 index 000000000000..02f11e3dd873 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-side-bar-container.component.html @@ -0,0 +1,20 @@ +
    +
    +

    Response Summary

    + +
    +
    + + +
    + {{getChartMessage()}} +
    +
    +
    + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-side-bar-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-side-bar-container.component.ts new file mode 100644 index 000000000000..209251241c6c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart-for-side-bar-container.component.ts @@ -0,0 +1,177 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject, combineLatest } from 'rxjs'; +import { filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { Actions } from 'app/shared/store'; +import { ServerMapData } from 'app/core/components/server-map/class/server-map-data.class'; +import { StoreHelperService, WebAppSettingDataService, AgentHistogramDataService, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-response-summary-chart-for-side-bar-container', + templateUrl: './response-summary-chart-for-side-bar-container.component.html', + styleUrls: ['./response-summary-chart-for-side-bar-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ResponseSummaryChartForSideBarContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + hasRequestError = false; + selectedTarget: ISelectedTarget; + selectedAgent = ''; + serverMapData: ServerMapData; + hiddenComponent = false; + hiddenChart = false; + yMax = -1; + useDisable = false; + showLoading = false; + i18nText = { + NO_DATA: '', + FAILED_TO_FETCH_DATA: '' + }; + chartData: IResponseTime | IResponseMilliSecondTime; + chartColors: string[]; + constructor( + private changeDetector: ChangeDetectorRef, + private translateService: TranslateService, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private agentHistogramDataService: AgentHistogramDataService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.chartColors = this.webAppSettingDataService.getColorByRequest(); + combineLatest( + this.translateService.get('COMMON.NO_DATA'), + this.translateService.get('COMMON.FAILED_TO_FETCH_DATA') + ).subscribe((text: string[]) => { + this.i18nText = { + NO_DATA: text[0], + FAILED_TO_FETCH_DATA: text[1] + }; + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getAgentSelection(this.unsubscribe).subscribe((agent: string) => { + this.setDisable(true); + this.selectedAgent = agent; + if (this.selectedTarget) { + this.loadResponseSummaryChartData(); + } + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: ServerMapData) => { + this.serverMapData = serverMapData; + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.yMax = -1; + this.selectedTarget = target; + this.hiddenComponent = target.isMerged; + if (target.isMerged === false) { + this.loadResponseSummaryChartData(); + } + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getRealTimeScatterChartRange(this.unsubscribe).subscribe((range: IScatterXRange) => { + this.yMax = -1; + this.loadResponseSummaryChartData(range.from, range.to); + }); + this.storeHelperService.getServerMapTargetSelectedByList(this.unsubscribe).subscribe((target: any) => { + this.yMax = -1; + this.hiddenComponent = false; + this.passDownChartData(this.agentHistogramDataService.makeChartDataForResponseSummary(target.histogram, this.getChartYMax())); + }); + } + private getChartYMax(): number { + return this.yMax === -1 ? null : this.yMax; + } + private setDisable(disable: boolean): void { + this.useDisable = disable; + this.showLoading = disable; + } + private loadResponseSummaryChartData(from?: number, to?: number): void { + const target = this.getTargetInfo(); + if (this.isAllAgent() && arguments.length !== 2) { + this.passDownChartData(this.agentHistogramDataService.makeChartDataForResponseSummary(target.histogram, this.getChartYMax())); + } else { + this.agentHistogramDataService.getData(target.key, target.applicationName, target.serviceTypeCode, this.serverMapData, from, to).subscribe((chartData: any) => { + const chartDataForAgent = this.isAllAgent() ? chartData['histogram'] : chartData['agentHistogram'][this.selectedAgent]; + this.passDownChartData(this.agentHistogramDataService.makeChartDataForResponseSummary(chartDataForAgent, this.getChartYMax())); + }, (error: IServerErrorFormat) => { + this.hasRequestError = true; + this.hiddenChart = true; + this.setDisable(false); + this.changeDetector.detectChanges(); + }); + } + } + private passDownChartData(chartData: any): void { + if (chartData) { + this.hiddenChart = false; + this.chartData = chartData; + } else { + this.hiddenChart = true; + } + this.hasRequestError = false; + this.setDisable(false); + this.changeDetector.detectChanges(); + } + private getTargetInfo(): any { + if (this.selectedTarget.isNode) { + return this.serverMapData.getNodeData(this.selectedTarget.node[0]); + } else { + return this.serverMapData.getLinkData(this.selectedTarget.link[0]); + } + } + private isAllAgent(): boolean { + return this.selectedAgent === ''; + } + getChartMessage(): string { + return this.hasRequestError ? this.i18nText.FAILED_TO_FETCH_DATA : this.i18nText.NO_DATA; + } + onNotifyMax(max: number): void { + if (this.yMax === -1) { + this.yMax = max; + this.storeHelperService.dispatch(new Actions.ChangeResponseSummaryChartYMax(max)); + } + } + onClickColumn(columnName: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_RESPONSE_GRAPH); + console.log('clicked Column Name :', columnName ); + if (columnName === 'Error') { + // scope.$emit('responseTimeSummaryChartDirective.showErrorTransactionList', type); + // @TODO Scatter Chart의 에러 부분만 Drag 하도록 하는 액션 + } + // @TODO FilteredMap transaction에서 만 처리되는 이벤트 + // if (useFilterTransaction) { + // scope.$emit('responseTimeSummaryChartDirective.itemClicked.' + scope.namespace, { + // "responseTime": type, + // "count": aTarget[0]._chart.config.data.datasets[0].data[aTarget[0]._index] + // }); + // } + + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.RESPONSE_SUMMARY); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.RESPONSE_SUMMARY, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart.component.css new file mode 100644 index 000000000000..116a2a1d8688 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart.component.css @@ -0,0 +1,6 @@ +:host { + width: 100%; + height: 121px; + display: block; + position: relative; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart.component.html new file mode 100644 index 000000000000..82928869e15f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart.component.html @@ -0,0 +1 @@ + diff --git a/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart.component.ts new file mode 100644 index 000000000000..8cb1a3a82ba5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/response-summary-chart/response-summary-chart.component.ts @@ -0,0 +1,135 @@ +import { Component, ViewChild, ElementRef, OnInit, OnChanges, SimpleChanges, Input, Output, EventEmitter } from '@angular/core'; +import { Chart } from 'chart.js'; + +@Component({ + selector: 'pp-response-summary-chart', + templateUrl: './response-summary-chart.component.html', + styleUrls: ['./response-summary-chart.component.css'] +}) +export class ResponseSummaryChartComponent implements OnInit, OnChanges { + @ViewChild('responseSummaryChart') el: ElementRef; + @Input() instanceKey: string; + @Input() chartData: any; + @Input() chartColors: string[]; + @Output() outNotifyMax: EventEmitter = new EventEmitter(); + @Output() outClickColumn: EventEmitter = new EventEmitter(); + chartObj: any; + constructor() {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if ( changes['chartData'] && changes['chartData']['firstChange'] === false ) { + this.initChart(); + } + } + private initChart(): void { + if (this.chartObj) { + if (this.chartData.max) { + this.chartObj.config.options.scales.yAxes[0].ticks.max = this.chartData.max; + } + this.chartObj.data.labels = this.chartData.keys; + this.chartObj.data.datasets[0].data = this.chartData.values; + this.chartObj.update(); + } else { + this.chartObj = new Chart(this.el.nativeElement.getContext('2d'), { + type: 'bar', + data: this.makeDataOption(), + options: this.makeNormalOption() + }); + } + this.outNotifyMax.emit(this.chartObj.scales['y-axis-0'].max); + } + private makeDataOption(): any { + return { + labels: this.chartData['keys'], + datasets: [{ + data: this.chartData['values'], + backgroundColor: this.chartColors, + borderColor: [ + 'rgba(120, 119, 121, 0)', + 'rgba(120, 119, 121, 0)', + 'rgba(120, 119, 121, 0)', + 'rgba(120, 119, 121, 0)', + 'rgba(120, 119, 121, 0)' + ], + borderWidth: 0.5 + }] + }; + } + private makeNormalOption(): any { + return { + onClick: (event, aChartEl: any[]) => { + if ( aChartEl.length > 0 ) { + this.outClickColumn.emit(aChartEl[0]._view.label); + } + event.preventDefault(); + }, + layout: { + padding: { + top: 20 + } + }, + maintainAspectRatio: false, + legend: { + display: false + }, + title: { + display: false + }, + scales: { + yAxes: [{ + gridLines: { + display: true, + drawBorder: false, + zeroLineWidth: 1.5, + zeroLineColor: 'rgb(0, 0, 0)' + }, + ticks: { + beginAtZero: true, + maxTicksLimit: 3, + callback: (label: number) => { + return ' ' + (label >= 1000 ? `${label / 1000}k` : label) + ' '; + }, + fontColor: 'rgba(162, 162, 162, 1)', + fontSize: 11, + max: this.chartData.max + } + }], + xAxes: [{ + gridLines: { + display: false, + drawBorder: false + }, + ticks: { + fontColor: 'rgba(162, 162, 162, 1)', + fontSize: 11 + } + }] + }, + animation: { + duration: 0, + onComplete: (chartElement: any) => { + const ctx = chartElement.chart.ctx; + // ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily); + ctx.fillStyle = chartElement.chart.config.options.defaultFontColor; + ctx.textAlign = 'center'; + ctx.textBaseline = 'bottom'; + chartElement.chart.data.datasets.forEach((dataset) => { + for (let i = 0 ; i < dataset.data.length ; i++) { + const model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model; + ctx.fillText(this.addComma(dataset.data[i] + ''), model.x, model.y - 5); + } + }); + } + }, + hover: { + animationDuration: 0 + }, + tooltips: { + enabled: false + } + }; + } + addComma(str: string): string { + return str.replace(/(\d)(?=(?:\d{3})+(?!\d))/g, '$1,'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-axis-renderer.class.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-axis-renderer.class.ts new file mode 100644 index 000000000000..5fcda5bdb662 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-axis-renderer.class.ts @@ -0,0 +1,250 @@ +import { interval, of, animationFrameScheduler } from 'rxjs'; +import { map, takeWhile, concat } from 'rxjs/operators'; +import * as moment from 'moment-timezone'; +import { IOptions } from './scatter-chart.class'; +import { ScatterChartSizeCoordinateManager } from './scatter-chart-size-coordinate-manager.class'; + +export class ScatterChartAxisRenderer { + private ticksX: number; + private ticksY: number; + + private elementAxisCanvas: HTMLCanvasElement; + private ctxAxisCanvas: CanvasRenderingContext2D; + private elementAxisContainer: HTMLElement; + private elementsAxisX: HTMLElement[] = []; + private elementsAxisY: HTMLElement[] = []; + private elementAxisXUnit: HTMLElement; + private elementAxisYUnit: HTMLElement; + constructor( + private options: IOptions, + private coordinateManager: ScatterChartSizeCoordinateManager, + private elementContainer: HTMLElement + ) { + this.ticksX = this.options.ticks.x - 1; + this.ticksY = this.options.ticks.y - 1; + + this.makeAxisCanvas(); + this.drawAxisLine(); + this.drawAxisValue(); + this.updateAxisValue(); + } + private makeAxisCanvas(): void { + this.elementAxisCanvas = document.createElement('canvas'); + this.elementAxisCanvas.setAttribute('width', this.coordinateManager.getWidth() + 'px'); + this.elementAxisCanvas.setAttribute('height', this.coordinateManager.getHeight() + 'px'); + this.elementAxisCanvas.setAttribute('style', 'top: 0px; z-index: 10; position: absolute'); + + this.elementContainer.appendChild(this.elementAxisCanvas); + this.ctxAxisCanvas = this.elementAxisCanvas.getContext('2d'); + } + private drawAxisLine(): void { + const width = this.coordinateManager.getWidth(); + const height = this.coordinateManager.getHeight(); + const oPadding = this.coordinateManager.getPadding(); + const bubbleHalfSize = this.coordinateManager.getBubbleHalfSize(); + const lineColor = this.options.lineColor; + const gridAxisStyle = this.options.gridAxisStyle; + const tickX = this.coordinateManager.getWidthOfChartSpace() / this.ticksX; + const tickY = this.coordinateManager.getHeightOfChartSpace() / this.ticksY; + const xTickLength = this.options.tickLength.x; + const yTickLength = this.options.tickLength.y; + + this.ctxAxisCanvas.lineWidth = gridAxisStyle.lineWidth; + this.ctxAxisCanvas.globalAlpha = 1; + this.ctxAxisCanvas.lineCap = 'round'; + this.ctxAxisCanvas.strokeStyle = lineColor; + + this.ctxAxisCanvas.beginPath(); + this.moveTo(this.ctxAxisCanvas, oPadding.left, oPadding.top); + this.lineTo(this.ctxAxisCanvas, oPadding.left, height - oPadding.bottom); + this.lineTo(this.ctxAxisCanvas, width - oPadding.right, height - oPadding.bottom); + this.ctxAxisCanvas.stroke(); + + for (let i = 0 ; i <= this.ticksX ; i++) { + const mov = oPadding.left + bubbleHalfSize + tickX * i; + this.ctxAxisCanvas.beginPath(); + this.moveTo(this.ctxAxisCanvas, mov, height - oPadding.bottom); + this.lineTo(this.ctxAxisCanvas, mov, height - oPadding.bottom + xTickLength); + this.ctxAxisCanvas.stroke(); + } + + for (let i = 0 ; i <= this.ticksY ; i++) { + const mov = height - (oPadding.bottom + bubbleHalfSize + tickY * i); + this.ctxAxisCanvas.beginPath(); + this.moveTo(this.ctxAxisCanvas, oPadding.left, mov); + this.lineTo(this.ctxAxisCanvas, oPadding.left - yTickLength, mov); + this.ctxAxisCanvas.stroke(); + } + } + private moveTo(ctx: any, x: number, y: number): void { + if (x % 1 === 0) { + x += 0.5; + } + if (y % 1 === 0) { + y += 0.5; + } + ctx.moveTo(x, y); + } + private lineTo(ctx: any, x: number, y: number): void { + if (x % 1 === 0) { + x += 0.5; + } + if (y % 1 === 0) { + y += 0.5; + } + ctx.lineTo(x, y); + } + private drawAxisValue() { + const widthTickX = this.coordinateManager.getWidthOfChartSpace() / this.ticksX; + const widthTickY = this.coordinateManager.getHeightOfChartSpace() / this.ticksY; + const width = this.coordinateManager.getWidth(); + const height = this.coordinateManager.getHeight(); + const padding = this.coordinateManager.getPadding(); + const bubbleHalfSize = this.coordinateManager.getBubbleHalfSize(); + const axisColor = this.options.axisColor; + + this.elementAxisContainer = document.createElement('div'); + const elementDivStyle = `top: 0px; width:${width}px ; height:${height}px ;cursor: corsshair; z-index: 10; position: absolute; background-color: rgba(0,0,0,0)`; + this.elementAxisContainer.setAttribute('style', elementDivStyle); + this.elementContainer.appendChild(this.elementAxisContainer); + + // x axis + for (let i = 0 ; i <= this.ticksX ; i++) { + const tempAxisDiv = document.createElement('div'); + const style = ` + top: ${height - padding.bottom + 10}px; + left: ${padding.left - (widthTickX / 2) + (i * widthTickX)}px; + width: ${widthTickX}px; + color: ${axisColor}; + position: absolute; + text-align: center; + `; + tempAxisDiv.setAttribute('style', style + this.options.axisLabelStyle); + tempAxisDiv.textContent = ' '; + this.elementsAxisX.push(tempAxisDiv); + this.elementAxisContainer.appendChild(tempAxisDiv); + } + // y axis + for (let i = 0 ; i <= this.ticksY ; i++) { + const tempAxisDiv = document.createElement('div'); + const style = ` + top: ${bubbleHalfSize + (i * widthTickY) + padding.top - 10}px; + left: 0px; + width: ${padding.left - 10}px; + color: ${axisColor}; + position: absolute; + text-align: center; + vertical-align: middle; + `; + tempAxisDiv.setAttribute('style', style + this.options.axisLabelStyle); + tempAxisDiv.textContent = ' '; + this.elementsAxisY.push(tempAxisDiv); + this.elementAxisContainer.appendChild(tempAxisDiv); + } + + // x axis unit + const xUnit = this.options.axisUnit.x; + if (xUnit !== '') { + this.elementAxisXUnit = document.createElement('div'); + const style = ` + top: ${height - padding.bottom + 10}px; + right: 80px; + color: ${axisColor}; + position: absolute; + text-align: right; + `; + this.elementAxisXUnit.setAttribute('style', style + this.options.axisLabelStyle); + this.elementAxisXUnit.textContent = xUnit; + this.elementAxisContainer.appendChild(this.elementAxisXUnit); + } + // y axis unit + const yUnit = this.options.axisUnit.y; + if (yUnit !== '') { + this.elementAxisYUnit = document.createElement('div'); + const style = ` + top: 0px; + left: 10px; + color: ${axisColor}; + width: ${padding.left - 15}; + position: absolute; + text-align: right; + vertical-align: middle; + `; + this.elementAxisYUnit.setAttribute('style', style + this.options.axisLabelStyle); + this.elementAxisYUnit.textContent = yUnit; + this.elementAxisContainer.appendChild(this.elementAxisYUnit); + } + } + updateAxisValue(animation?: boolean, duration?: number): void { + const xRange = this.coordinateManager.getX(); + const tickX = (this.coordinateManager.getGapX()) / this.ticksX; + this.elementsAxisX.forEach((element: Element, index: number) => { + const xMoment = moment(tickX * index + xRange.from).tz(this.options.timezone); + element.innerHTML = xMoment.format(this.options.dateFormat[0]) + '
    ' + xMoment.format(this.options.dateFormat[1]); + }); + + const yRange = this.coordinateManager.getY(); + const tickY = (this.coordinateManager.getGapY()) / this.ticksY; + this.elementsAxisY.forEach((element: Element, index: number) => { + element.innerHTML = ((yRange.to + yRange.from) - ((tickY * index) + yRange.from)).toLocaleString(); + }); + if (animation === true) { + this.animateBackground(this.elementsAxisX[this.elementsAxisX.length - 1], duration); + } + } + private animateBackground(element: HTMLElement, duration: number): void { + const start = animationFrameScheduler.now(); + interval(1, animationFrameScheduler).pipe( + map(() => { + return (animationFrameScheduler.now() - start) / duration; + }), + takeWhile((opacity: number) => { + return opacity <= 1; + }), + concat(of(1)) + ).subscribe((opacity: number) => { + element.style.backgroundColor = `rgba(254, 255, 210, ${1 - opacity}`; + }); + + } + drawToCanvas(ctxDownload: CanvasRenderingContext2D, topPadding: number): CanvasRenderingContext2D { + let xLastLabelLeftPosition = 0; + ctxDownload.drawImage(this.elementAxisCanvas, 0, topPadding); + // x axis + ctxDownload.textAlign = 'center'; + this.elementsAxisX.forEach((element: HTMLElement) => { + ctxDownload.font = element.style.font; + ctxDownload.fillStyle = element.style.color; + const axisX = element.innerHTML.replace(/
    /gi, ' ').split(' '); + axisX.forEach((txt: string, index: number) => { + ctxDownload.fillText(txt, parseInt(element.style.left, 10) + element.getBoundingClientRect().width / 2, parseInt(element.style.top, 10) + (15 * (index + 1)) + topPadding); + }); + xLastLabelLeftPosition = Math.max(xLastLabelLeftPosition, parseInt(element.style.left, 10)); + }); + // y axis + ctxDownload.textAlign = 'right'; + this.elementsAxisY.forEach((element: HTMLElement) => { + ctxDownload.font = element.style.font; + ctxDownload.fillStyle = element.style.color; + ctxDownload.fillText(element.textContent, element.getBoundingClientRect().width - 10, parseInt(element.style.top, 10) + 15 + + topPadding); + }); + // x label + if (this.options.axisUnit.x !== '' && this.elementAxisXUnit) { + ctxDownload.textAlign = 'right'; + ctxDownload.font = this.elementAxisXUnit.style.fontFamily; + ctxDownload.fillStyle = this.elementAxisXUnit.style.color; + ctxDownload.fillText(this.elementAxisXUnit.textContent, xLastLabelLeftPosition + this.elementAxisXUnit.getBoundingClientRect().width, parseInt(this.elementAxisXUnit.style.top, 10) + 30 + topPadding); + } + // y label + if (this.options.axisUnit.y !== '' && this.elementAxisYUnit) { + ctxDownload.textAlign = 'right'; + ctxDownload.font = this.elementAxisYUnit.style.fontFamily; + ctxDownload.fillStyle = this.elementAxisYUnit.style.color; + ctxDownload.fillText(this.elementAxisYUnit.textContent, parseInt(this.elementAxisYUnit.style.left, 10) + this.elementAxisYUnit.getBoundingClientRect().width, 10 + topPadding); + } + return ctxDownload; + } + reset(): void { + this.updateAxisValue(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-data-block.class.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-data-block.class.ts new file mode 100644 index 000000000000..1d909cebffa9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-data-block.class.ts @@ -0,0 +1,183 @@ +import { ITypeInfo } from './scatter-chart.class'; +import { ScatterChartTransactionTypeManager } from './scatter-chart-transaction-type-manager.class'; + +export enum DataIndex { + X, + Y, + META, + TRANSACTION_ID, + TYPE, + GROUP_COUNT +} +export enum MetadataIndex { + AGENT_NAME, TRANSACTION_PREFIX_1, TRANSACTION_PREFIX_2 +} + +export class ScatterChartDataBlock { + private from: number; + private to: number; + private resultFrom: number; + private resultTo: number; + + private agentMetadata: { [key: string]: any[] }; + private transactionData: number[][]; + + private agentList: string[] = []; + private transactionDataByAgent: {[key: string]: any} = {}; + private countByType: {[key: string]: {[key: string]: number}} = {}; + + private fromX: number; + private toX: number; + /* + oPropertyIndex : { + x: 0, + y: 1, + meta: 2, + transactionId: 3, + type: 4, + groupCount: 5 + } + */ + constructor(private originalData: IScatterData, private typeManager: ScatterChartTransactionTypeManager) { + this.initVariable(); + this.initInnerDataStructure(); + this.classifyDataByAgent(); + } + private initVariable() { + this.from = this.originalData.from; + this.to = this.originalData.to; + if (this.originalData.complete) { + this.fromX = this.resultFrom = this.originalData.from; + this.toX = this.resultTo = this.originalData.to; + } else { + this.fromX = this.resultFrom = this.originalData.resultFrom; + this.toX = this.resultTo = this.originalData.resultTo; + } + this.agentMetadata = this.originalData.scatter.metadata; + this.transactionData = []; + } + private initInnerDataStructure(): void { + Object.keys(this.agentMetadata).forEach((key: string) => { + const metaInfo = this.agentMetadata[key]; + const agentName = metaInfo[MetadataIndex.AGENT_NAME]; + this.transactionDataByAgent[agentName] = []; + + this.countByType[agentName] = {}; + this.typeManager.getTypeNameList().forEach((typeName: string) => { + this.countByType[agentName][typeName] = 0; + }); + if (this.agentList.indexOf(agentName) === -1) { + this.agentList.push(agentName); + } + }); + this.agentList.sort(); + } + private classifyDataByAgent(): void { + this.originalData.scatter.dotList.forEach((tData: number[]) => { + const agentName = this.getAgentName(tData); + const typeName = this.typeManager.getNameByIndex(tData[DataIndex.TYPE]); + const tNewData = tData.concat(); + + tNewData[DataIndex.X] += this.from; + this.transactionData.push(tNewData); + this.transactionDataByAgent[agentName].push(tNewData); + this.countByType[agentName][typeName]++; + }); + } + getAgentName(data: number[] | string): string { + if (typeof data === 'string') { + return this.agentMetadata[data][MetadataIndex.AGENT_NAME]; + } else { + return this.agentMetadata[data[DataIndex.META]][MetadataIndex.AGENT_NAME]; + } + } + getDataByAgentAndIndex(agent: string, index: number): number[] { + return this.transactionDataByAgent[agent][index]; + } + getGroupCount(data: number[]): number { + return data[DataIndex.GROUP_COUNT]; + } + getDataByIndex(index: number): number[] { + return this.transactionData[index]; + } + getTotalCount(): number { + return this.transactionData.length; + } + countByAgent(agent: string): number { + if (this.transactionDataByAgent[agent]) { + return this.transactionDataByAgent[agent].length; + } else { + return 0; + } + } + getCount(agentName: string, type: string, fromX?: number, toX?: number): number { + if ( fromX && toX ) { + return this.getCountOfRange(agentName, type, fromX, toX); + } else { + if (agentName === '') { + let sumType = 0; + Object.keys(this.countByType).forEach((innerAgentName: string) => { + sumType += this.countByType[innerAgentName][type]; + }); + return sumType; + } else { + if (this.countByType[agentName]) { + return this.countByType[agentName][type]; + } else { + return 0; + } + } + } + } + private getCountOfRange(agentName: string, type: string, fromX: number, toX: number): number { + // @TODO: agentName : ALL 인 경우 처리 + let sum = 0; + const length = this.transactionDataByAgent[agentName].length; + if (this.from >= toX || this.to <= fromX || length === 0 || (agentName in this.countByType) === false) { + return sum; + } + if (this.from >= fromX && this.to <= toX) { + return this.getCount(agentName, type); + } + for (let i = 0 ; i < length ; i++) { + const data = this.transactionDataByAgent[agentName][i]; + if (data[DataIndex.X] < fromX) { + break; + } + // if (agentName === this.getAgentName(data)) { + if (type === this.typeManager.getNameByIndex(data[DataIndex.TYPE])) { + if (data[DataIndex.X] <= toX) { + sum++; + } + } + // } + } + return sum; + } + getTransactionID(data: number[]): string { + const oMeta = this.agentMetadata[data[DataIndex.META]]; + return `${oMeta[MetadataIndex.TRANSACTION_PREFIX_1]}^${oMeta[MetadataIndex.TRANSACTION_PREFIX_2]}^${data[DataIndex.TRANSACTION_ID]}`; + } + getX(data: number[]): number { + return data[DataIndex.X]; + } + getY(data: number[]): number { + return data[DataIndex.Y]; + } + getTypeIndex(data: number[]): number { + return data[DataIndex.TYPE]; + } + getXRange(): {from: number, to: number} { + return { + 'from': this.fromX, + 'to': this.toX + }; + } + isEmpty(): boolean { + return this.transactionData.length === 0; + } + getAgentList(): string[] { + return this.agentList; + } + +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-data-load-manager.class.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-data-load-manager.class.ts new file mode 100644 index 000000000000..f1677e1f66e5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-data-load-manager.class.ts @@ -0,0 +1,142 @@ +export class ScatterChartDataLoadManager { + constructor(application, filter, option, cbLoaded) { + // this._filter = filter; + // this._option = option; + // this._application = application; + // this._cbLoaded = cbLoaded; + // this._initVar(); + } + // _initVar() { + // this._callCount = 0; + // this._bLoadCompleted = false; + // this._lastLoadTime = -1; + // }; + // option(k) { + // return this._option[k]; + // } + // loadData(cbComplete, cbSuccess, cbFail, widthOfPixel, heightOfPixel) { + // var self = this; + // var oFromTo = this._oSCManager.getX(); + + // this._oAjax = $.ajax({ + // 'url': this.getUrl(), + // 'data': { + // 'to': this._callCount === 0 ? oFromTo.max : this._lastLoadTime - 1, + // 'from': oFromTo.min, + // 'limit': this.option('fetchLimit'), + // 'filter': this._filter || '', + // 'application': this._application, + // 'xGroupUnit': widthOfPixel, + // 'yGroupUnit': heightOfPixel + // }, + // 'headers': { 'accept': 'application/json' }, + // 'dataType': 'json' + // }).done(function (oResultData) { + // if (oResultData.exception) { + // cbFail(); + // } else { + // self._callCount += 1; + // self._bLoadCompleted = oResultData.complete; + // self._lastLoadTime = oResultData.resultFrom; + // cbSuccess(oResultData, !self._bLoadCompleted, self._getIntervalTime()); + // } + // }).always(function () { + // cbComplete(); + // }); + // } + // loadRealtimeData(callbackRealtimeSuccess, callbackRealtimeFail, widthOfPixel, heightOfPixel) { + // var self = this; + // var oFromTo = this._oSCManager.getX(); + + // var beforeRequest = Date.now(); + // var currentFrom = this._nextFrom || oFromTo.max; + // var currentTo = this._nextTo || oFromTo.max + this.option('realtimeInterval'); + + // this._oRealtimeAjax = $.ajax({ + // 'url': this.getUrl(), + // 'data': { + // 'to': currentTo, + // 'from': currentFrom, + // 'limit': this.option('fetchLimit'), + // 'filter': '', + // 'application': this._application, + // 'xGroupUnit': widthOfPixel, + // 'yGroupUnit': heightOfPixel, + // 'backwardDirection': false + // }, + // 'headers': { 'accept': 'application/json' }, + // 'dataType': 'json' + // }).done(function (oResultData) { + // if (oResultData.exception) { + // callbackRealtimeFail(); + // } else { + + // self._nextFrom = oResultData.complete ? oResultData.to : oResultData.resultTo; + // self._nextTo = self._nextFrom + self.option('realtimeInterval'); + + // callbackRealtimeSuccess(oResultData, self._calcuRealtimeIntervalTime(oResultData.currentServerTime, Date.now() - beforeRequest), self._isResetRealtime(oResultData.currentServerTime), oResultData.currentServerTime); + // self._cbLoaded(self._oSCManager.getX(), self._nextFrom, self._nextTo); + // } + // }).fail(function () { + // setTimeout(function () { + // self.loadRealtimeData(callbackRealtimeSuccess, callbackRealtimeFail, widthOfPixel, heightOfPixel); + // }, (self.option('realtimeInterval') / 2)); + // }); + // } + // _isResetRealtime(currentServerTime) { + // return (currentServerTime - this._nextTo) >= this.option('realtimeResetTimeGap'); + // } + // _calcuRealtimeIntervalTime(currentServerTime, requestGap) { + // var interval = parseInt(this.option('realtimeInterval'), 0); + // if (requestGap > interval) { + // return 0; + // } else { + // var gapTime = (currentServerTime - this._nextTo) - this.option('realtimeDefaultTimeGap'); + // if (gapTime < 0) { + // return Math.max(interval - requestGap - gapTime, interval); + // } else { + // return Math.max(interval - requestGap - gapTime, 0); + // } + // } + // } + // setRealtimeFrom(from) { + // this._nextFrom = from; + // this._nextTo = from + this.option('realtimeInteraval'); + // } + // _getIntervalTime() { + // if (this.option('useIntervalForFetching')) { + // return this.option('fetchingInterval'); + // } + // return 0; + // } + // getRealtimeInterval() { + // return this.option('realtimeDefaultTimeGap'); + // } + // getUrl() { + // return this.option('url'); + // } + // initCallCount() { + // this._callCount = 0; + // } + // isFirstRequest() { + // return this._callCount === 0; + // } + // isCompleted() { + // return this._bLoadCompleted; + // } + // abort() { + // if (this._oAjax) { + // this._oAjax.abort(); + // } + // if (this._oRealtimeAjax) { + // this._oRealtimeAjax.abort(); + // } + // } + // setTimeManager(oSCManager) { + // this._oSCManager = oSCManager; + // } + // reset = function () { + // this._bLoadCompleted = false; + // this.initCallCount(); + // } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-grid-renderer.class.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-grid-renderer.class.ts new file mode 100644 index 000000000000..d88d7ebffca7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-grid-renderer.class.ts @@ -0,0 +1,96 @@ +import { IOptions } from './scatter-chart.class'; +import { ScatterChartSizeCoordinateManager } from './scatter-chart-size-coordinate-manager.class'; + +export class ScatterChartGridRenderer { + private ticksX: number; + private ticksY: number; + private elementGridCanvas: HTMLCanvasElement; + private ctxGridCanvas: CanvasRenderingContext2D; + constructor(private options: IOptions, private coordinateManager: ScatterChartSizeCoordinateManager, private elementContainer: HTMLElement) { + this.ticksX = this.options.ticks.x - 1; + this.ticksY = this.options.ticks.y - 1; + + this.makeGridCanvas(); + this.drawGridLine(); + } + private makeGridCanvas(): void { + this.elementGridCanvas = document.createElement('canvas'); + this.elementGridCanvas.setAttribute('width', this.coordinateManager.getWidth() + 'px'); + this.elementGridCanvas.setAttribute('height', this.coordinateManager.getHeight() + 'px'); + this.elementGridCanvas.setAttribute('style', 'top: 0px; z-index: 0; position: absolute'); + + this.elementContainer.appendChild(this.elementGridCanvas); + this.ctxGridCanvas = this.elementGridCanvas.getContext('2d'); + } + private drawGridLine(): void { + this.setStyle(this.ctxGridCanvas, this.options.gridAxisStyle); + this.drawXGridLine(); + this.drawYGridLine(); + } + private drawXGridLine(): void { + const height = this.coordinateManager.getHeight(); + const padding = this.coordinateManager.getPadding(); + const bubbleHalfSize = this.coordinateManager.getBubbleHalfSize(); + const tickX = this.coordinateManager.getWidthOfChartSpace() / this.ticksX; + + const xStart = padding.left + bubbleHalfSize; + const yStart = padding.top; + const yEnd = height - padding.bottom; + for (let i = 0 ; i <= this.ticksX ; i++) { + const x = xStart + (tickX * i); + this.drawLine(this.ctxGridCanvas, x, yStart, x, yEnd); + } + } + private drawYGridLine(): void { + const width = this.coordinateManager.getWidth(); + const height = this.coordinateManager.getHeight(); + const padding = this.coordinateManager.getPadding(); + const bubbleHalfSize = this.coordinateManager.getBubbleHalfSize(); + const tickY = this.coordinateManager.getHeightOfChartSpace() / this.ticksY; + + const xStart = padding.left; + const xEnd = width - padding.right; + const yZero = padding.bottom + bubbleHalfSize; + for (let i = 0 ; i <= this.ticksY ; i++) { + const y = height - (yZero + tickY * i); + this.drawLine(this.ctxGridCanvas, xStart, y, xEnd, y); + } + } + private drawLine(context: CanvasRenderingContext2D, xStart: number, yStart: number, xEnd: number, yEnd: number): void { + context.beginPath(); + this.moveTo(context, xStart, yStart); + this.lineTo(context, xEnd, yEnd); + context.stroke(); + } + private setStyle(ctx: any, styles: any): void { + Object.keys(styles).forEach((key: string) => { + if (key === 'lineDash') { + ctx.setLineDash(styles[key]); + } else { + ctx[key] = styles[key]; + } + }); + } + private moveTo(ctx: any, x: number, y: number): void { + if (x % 1 === 0) { + x += 0.5; + } + if (y % 1 === 0) { + y += 0.5; + } + ctx.moveTo(x, y); + } + private lineTo(ctx: any, x: number, y: number): void { + if (x % 1 === 0) { + x += 0.5; + } + if (y % 1 === 0) { + y += 0.5; + } + ctx.lineTo(x, y); + } + drawToCanvas(ctxDownload: CanvasRenderingContext2D, topPadding: number): CanvasRenderingContext2D { + ctxDownload.drawImage(this.elementGridCanvas, 0, topPadding); + return ctxDownload; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-mouse-manager.class.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-mouse-manager.class.ts new file mode 100644 index 000000000000..3c421257c3af --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-mouse-manager.class.ts @@ -0,0 +1,332 @@ +import * as moment from 'moment-timezone'; +import { Observable, Subject } from 'rxjs'; +import { IOptions } from './scatter-chart.class'; +import { ScatterChartSizeCoordinateManager } from './scatter-chart-size-coordinate-manager.class'; + +export class ScatterChartMouseManager { + elementAxisWrapper: HTMLElement; + elementXAxisLabelWrapper: HTMLElement; + elementXAxisLabel: HTMLElement; + elementYAxisLabelWrapper: HTMLElement; + elementYAxisLabel: HTMLElement; + elementDragWrapper: HTMLElement; + elementDragArea: HTMLElement; + private outDragArea: Subject; + onDragArea$: Observable; + constructor( + private options: IOptions, + private coordinateManager: ScatterChartSizeCoordinateManager, + private elementContainer: HTMLElement + ) { + this.outDragArea = new Subject(); + this.onDragArea$ = this.outDragArea.asObservable(); + + const padding = this.coordinateManager.getPadding(); + const areaWidth = this.coordinateManager.getWidth() - padding.left - padding.right; + const areaHeight = this.coordinateManager.getHeight() - padding.top - padding.bottom; + const redLineWidth = 10; + + this.initWrapperElement(areaWidth, areaHeight); + this.initXLabelElement(areaHeight, redLineWidth); + this.initYLabelElement(padding.left, redLineWidth); + this.initDragElement(); + this.initEvent(); + } + private initWrapperElement(areaWidth: number, areaHeight: number): void { + this.elementAxisWrapper = document.createElement('div'); + this.elementAxisWrapper.setAttribute('style', ` + top: ${this.coordinateManager.getTopPadding()}px; + left: ${this.coordinateManager.getLeftPadding()}px; + width: ${areaWidth}px; + height: ${areaHeight}px; + cursor: crosshair; + z-index: 600; + position: absolute; + background-color: rgba(0,0,0,0); + `); + this.elementAxisWrapper.setAttribute('class', 'overlay'); + this.elementContainer.appendChild(this.elementAxisWrapper); + } + private initXLabelElement(areaHeight: number, redLineWidth: number): void { + this.elementXAxisLabelWrapper = document.createElement('div'); + this.elementXAxisLabelWrapper.draggable = false; + this.elementXAxisLabelWrapper.setAttribute('style', ` + top: ${areaHeight + redLineWidth}px; + left: 0px; + color: #FFF; + width: 80px; + display: none; + position: absolute; + text-align: center; + background: #000; + font-family: monospace; + margin-left: ${-(56 / 2)}px; + ` + this.options.axisLabelStyle); + this.elementXAxisLabel = document.createElement('span'); + const elementXLine = document.createElement('div'); + elementXLine.setAttribute('style', ` + top: ${-redLineWidth}px; + left: 27px; + height: ${redLineWidth}px; + position: absolute; + border-left: 1px solid red; + `); + this.elementXAxisLabelWrapper.appendChild(this.elementXAxisLabel); + this.elementXAxisLabelWrapper.appendChild(elementXLine); + this.elementAxisWrapper.appendChild(this.elementXAxisLabelWrapper); + } + private initYLabelElement(paddingLeft: number, redLineWidth: number): void { + this.elementYAxisLabelWrapper = document.createElement('div'); + this.elementYAxisLabelWrapper.draggable = false; + this.elementYAxisLabelWrapper.setAttribute('style', ` + top: 0px; + left: ${-(paddingLeft - 2)}px; + color: #fff; + width: ${paddingLeft - 2 - redLineWidth}px; + display: none; + position: absolute; + margin-top: ${-redLineWidth}px; + text-align: right; + background: #000; + font-family: monospace; + padding-right: 3px; + vertical-align: middle; + ` + this.options.axisLabelStyle); + this.elementYAxisLabel = document.createElement('span'); + const elementYLine = document.createElement('div'); + elementYLine.setAttribute('style', ` + top: 9px; + right: -10px; + width: ${redLineWidth}px; + position: absolute; + border-top: 1px solid red; + `); + this.elementYAxisLabelWrapper.appendChild(this.elementYAxisLabel); + this.elementYAxisLabelWrapper.appendChild(elementYLine); + this.elementAxisWrapper.appendChild(this.elementYAxisLabelWrapper); + } + private initDragElement(): void { + this.elementDragWrapper = document.createElement('div'); + this.elementDragWrapper.setAttribute('style', ` + top: 0px; + left: 0px; + width: ${this.coordinateManager.getWidth()}px; + height: ${this.coordinateManager.getHeight()}px; + cursor: crosshair; + z-index: 601; + position: absolute; + background-color: rgba(0,0,0,0); + `); + this.elementDragArea = document.createElement('div'); + this.elementDragArea.setAttribute('style', ` + width: 0px; + height: 0px; + display: none; + position: absolute; + border: 1px solid #469AE4; + background-color: rgba(237, 242, 248, 0.5); + `); + this.elementDragWrapper.appendChild(this.elementDragArea); + this.elementContainer.appendChild(this.elementDragWrapper); + } + private initEvent() { + const padding = this.coordinateManager.getPadding(); + const areaWidth = this.coordinateManager.getWidth(); + const areaHeight = this.coordinateManager.getHeight(); + const axisArea = { + leftRevision: this.coordinateManager.getBubbleHalfSize() + padding.left, + width: areaWidth - this.coordinateManager.getBubbleHalfSize() + padding.left - padding.right, + topRevision: padding.top, + height: areaHeight - padding.top - padding.bottom - this.coordinateManager.getBubbleHalfSize() + }; + + let startDrag = false; + let dragStartX = 0; + let dragStartY = 0; + let calculatedOffsetX = 0; + let calculatedOffsetY = 0; + let previousDragX = -1; + let previousDragY = -1; + function forceMouseUp(userMouseUp: boolean) { + startDrag = false; + this.elementDragArea.style.display = 'none'; + if (userMouseUp) { + const fromX = (calculatedOffsetX >= dragStartX ? dragStartX : calculatedOffsetX) - axisArea.leftRevision; + const toX = (calculatedOffsetX >= dragStartX ? calculatedOffsetX : dragStartX) - axisArea.leftRevision; + const fromY = (calculatedOffsetY >= dragStartY ? calculatedOffsetY : dragStartY) - axisArea.topRevision; + const toY = (calculatedOffsetY >= dragStartY ? dragStartY : calculatedOffsetY) - axisArea.topRevision; + this.outDragArea.next({ + x: { + from: Math.max(fromX, 0), + to: Math.min(toX, axisArea.width) + }, + y: { + // y값은 from과 to를 뒤집어서 보내야 함. + from: Math.max(axisArea.height - fromY, 0), + to: Math.min(axisArea.height - toY, axisArea.height) + } + }); + } + this.elementDragArea.style.top = '0px'; + this.elementDragArea.style.left = '0px'; + this.elementDragArea.style.width = '0px'; + this.elementDragArea.style.height = '0px'; + previousDragX = -1; + previousDragY = -1; + } + this.elementDragWrapper.addEventListener('mousedown', (event: MouseEvent) => { + startDrag = true; + dragStartX = calculatedOffsetX = event.offsetX; + dragStartY = calculatedOffsetY = event.offsetY; + this.elementDragArea.style.display = 'block'; + this.elementDragArea.style.top = dragStartY + 'px'; + this.elementDragArea.style.left = dragStartX + 'px'; + event.preventDefault(); + }); + this.elementDragWrapper.addEventListener('mouseup', (event: MouseEvent) => { + forceMouseUp.call(this, true); + event.preventDefault(); + }); + + this.elementDragWrapper.addEventListener('mousemove', (event: MouseEvent) => { + calculatedOffsetX += event.movementX; + calculatedOffsetY += event.movementY; + if (startDrag) { + this.checkAxisLabel(calculatedOffsetX, calculatedOffsetY, axisArea); + if (previousDragX !== calculatedOffsetX) { + if (calculatedOffsetX <= areaWidth) { + if (calculatedOffsetX >= dragStartX) { + this.elementDragArea.style.left = dragStartX + 'px'; + this.elementDragArea.style.width = (calculatedOffsetX - dragStartX) + 'px'; + } else { + this.elementDragArea.style.left = calculatedOffsetX + 'px'; + this.elementDragArea.style.width = (dragStartX - calculatedOffsetX) + 'px'; + } + previousDragX = calculatedOffsetX; + } + } + if (previousDragY !== calculatedOffsetY) { + if (calculatedOffsetY <= areaHeight) { + if (calculatedOffsetY >= dragStartY) { + this.elementDragArea.style.top = dragStartY + 'px'; + this.elementDragArea.style.height = (calculatedOffsetY - dragStartY) + 'px'; + } else { + this.elementDragArea.style.top = calculatedOffsetY + 'px'; + this.elementDragArea.style.height = (dragStartY - calculatedOffsetY) + 'px'; + } + previousDragY = calculatedOffsetY; + } + } + } else { + this.checkAxisLabel(event.offsetX, event.offsetY, axisArea); + } + event.preventDefault(); + }); + this.elementDragWrapper.addEventListener('mouseleave', (event: MouseEvent) => { + forceMouseUp.call(this, false); + this.hideAxisLabel(); + event.preventDefault(); + return false; + }); + } + private checkAxisLabel(offsetX: number, offsetY: number, axisArea: any): void { + if (!this.options.showMouseGuideLine) { + return; + } + const x = offsetX - axisArea.leftRevision; + const y = offsetY - axisArea.topRevision; + if (x >= 0 && x <= axisArea.width || y >= 0 && y <= axisArea.height) { + if (x >= 0 && x <= axisArea.width) { + this.showXAxisLabel(); + } else { + this.hideXAxisLabel(); + } + if (y >= 0 && y <= axisArea.height) { + this.showYAxisLabel(); + } else { + this.hideYAxisLabel(); + } + this.setAndMoveAxisLabel(x, y); + } else { + this.hideAxisLabel(); + } + // if (x >= 0 && x <= axisArea.width && y >= 0 && y <= axisArea.height) { + // this.showAxisLabel(); + // this.setAndMoveAxisLabel(x, y); + // } else { + // this.hideAxisLabel(); + // } + } + private setAndMoveAxisLabel(x: number, y: number): void { + const height = this.coordinateManager.getHeight(); + const padding = this.coordinateManager.getPadding(); + const bubbleHalfSize = this.coordinateManager.getBubbleHalfSize(); + const xLabel = moment(this.coordinateManager.parseMouseXToXData(x - bubbleHalfSize)).tz(this.options.timezone).format(this.options.dateFormat[1]); + const yLabel = this.coordinateManager.parseMouseYToYData(height - y - padding.bottom - padding.top - bubbleHalfSize); + this.elementXAxisLabel.textContent = xLabel; + this.elementYAxisLabel.textContent = yLabel.toLocaleString(); + this.elementXAxisLabelWrapper.style.left = (x + bubbleHalfSize) + 'px'; + this.elementYAxisLabelWrapper.style.top = (y + bubbleHalfSize) + 'px'; + } + showXAxisLabel(): void { + this.elementXAxisLabelWrapper.style.display = 'block'; + } + showYAxisLabel(): void { + this.elementYAxisLabelWrapper.style.display = 'block'; + } + showAxisLabel(): void { + this.showXAxisLabel(); + this.showYAxisLabel(); + } + hideXAxisLabel(): void { + this.elementXAxisLabelWrapper.style.display = 'none'; + } + hideYAxisLabel(): void { + this.elementYAxisLabelWrapper.style.display = 'none'; + } + hideAxisLabel(): void { + this.hideXAxisLabel(); + this.hideYAxisLabel(); + } + // triggerDrag(welFakeSelectBox) { + // var oDragAreaPosition = this._adjustSelectBoxForChart(welFakeSelectBox); + // this._oCallback.onSelect(oDragAreaPosition, this._parseCoordinatesToXY(oDragAreaPosition)); + // } + // _adjustSelectBoxForChart(welSelectBox) { + // var oPadding = this._oSCManager.getPadding(); + // var bubbleSize = this._oSCManager.getBubbleSize(); + // var nMinTop = oPadding.top + bubbleSize; + // var nMinLeft = oPadding.left + bubbleSize; + // var nMaxRight = this._oSCManager.getWidth() - oPadding.right - bubbleSize; + // var nMaxBottom = this._oSCManager.getHeight() - oPadding.bottom - bubbleSize; + + // var nLeft = parseInt(welSelectBox.css("left"), 10); + // var nRight = nLeft + welSelectBox.width(); + // var nTop = parseInt(welSelectBox.css("top"), 10); + // var nBottom = nTop + welSelectBox.height(); + + // nTop = Math.max(nTop, nMinTop); + // nLeft = Math.max(nLeft, nMinLeft); + // nRight = Math.min(nRight, nMaxRight); + // nBottom = Math.min(nBottom, nMaxBottom); + + // var oNextInfo = { + // "top": nTop, + // "left": nLeft, + // "width": nRight - nLeft, + // "height": nBottom - nTop + // }; + // welSelectBox.animate(oNextInfo, 200); + // return oNextInfo; + // } + // _parseCoordinatesToXY(oPosition) { + // var oPadding = this._oSCManager.getPadding(); + // var bubbleSize = this._oSCManager.getBubbleSize(); + // return { + // "fromX": this._oSCManager.parseMouseXToXData(oPosition.left - oPadding.left - bubbleSize), + // "toX": this._oSCManager.parseMouseXToXData(oPosition.left + oPosition.width - oPadding.left - bubbleSize), + // "fromY": this._oSCManager.parseMouseYToYData(this._oSCManager.getHeight() - (oPadding.bottom + bubbleSize) - (oPosition.top + oPosition.height)), + // "toY": this._oSCManager.parseMouseYToYData(this._oSCManager.getHeight() - (oPadding.bottom + bubbleSize) - oPosition.top) + // }; + // } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-renderer-manager.class.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-renderer-manager.class.ts new file mode 100644 index 000000000000..7a45a8a2cf5a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-renderer-manager.class.ts @@ -0,0 +1,247 @@ +import { IOptions } from './scatter-chart.class'; +import { DataIndex, ScatterChartDataBlock } from './scatter-chart-data-block.class'; +import { ScatterChartSizeCoordinateManager } from './scatter-chart-size-coordinate-manager.class'; +import { ScatterChartTransactionTypeManager } from './scatter-chart-transaction-type-manager.class'; + +export class ScatterChartRendererManager { + private canvasMap: {[key: string]: HTMLCanvasElement[]}; + private ctxMap: {[key: string]: CanvasRenderingContext2D[]}; + + private elementScroller: HTMLElement; + private scrollOrder: number[]; + private requestAnimationFrameRef: any; + constructor(private options: IOptions, private coordinateManager: ScatterChartSizeCoordinateManager, private elementContainer: any, private typeManager: ScatterChartTransactionTypeManager) { + this.initVariable(); + this.initCanvasWrapper(); + } + private initVariable(): void { + this.canvasMap = {}; + this.ctxMap = {}; + } + private initCanvasWrapper() { + let zIndex = 100; + const bubbleSize = this.coordinateManager.getBubbleSize(); + const bubbleHalfSize = this.coordinateManager.getBubbleHalfSize(); + const widthOfChartSpace = this.coordinateManager.getWidthOfChartSpace(); + const heightOfChartSpace = this.coordinateManager.getHeightOfChartSpace(); + + this.elementScroller = document.createElement('div'); + this.elementScroller.setAttribute('style', 'top: 0px; left: 0px; position: absolute; background-color: grey; height:' + (heightOfChartSpace + bubbleSize) + 'px' ); + this.elementScroller.setAttribute('class', 'canvas-scroller'); + + const elementCanvasWrapper = document.createElement('div'); + const elementCanvasWrapperStyles = ` + top: ${this.coordinateManager.getTopPadding()}px; + left: ${(this.coordinateManager.getLeftPadding() + bubbleHalfSize)}px; + width: ${widthOfChartSpace}px; + height: ${heightOfChartSpace + bubbleSize}px; + z-index: ${zIndex++}; + overflow: hidden; + position: absolute; + `; + elementCanvasWrapper.setAttribute('class', 'canvas-wrapper'); + elementCanvasWrapper.setAttribute('style', elementCanvasWrapperStyles); + elementCanvasWrapper.appendChild(this.elementScroller); + this.elementContainer.appendChild(elementCanvasWrapper); + } + makeDataCanvas(dataBlock: ScatterChartDataBlock, agentList: string[]): void { + let zIndex = 110; + const bubbleSize = this.coordinateManager.getBubbleSize(); + const prefix = this.options.prefix; + const heightOfChartSpace = this.coordinateManager.getHeightOfChartSpace(); + const canvasWidth = this.coordinateManager.getCanvasWidth(); + + agentList.forEach((agentName: string, index: number) => { + this.typeManager.getTypeNameList().forEach((typeName: string) => { + const key = `${agentName}-${prefix}-${typeName}`; + if ((key in this.canvasMap) === false) { + const canvas1 = this.createCanvas({ + width: canvasWidth + 'px', + height: (heightOfChartSpace + bubbleSize) + 'px', + 'data-agent': agentName, + 'data-type': typeName, + 'data-key': key + }, ` + top: 0px; + left: 0px; + z-index: ${zIndex++}; + position: absolute; + `); + const canvas2 = this.createCanvas({ + width: canvasWidth + 'px', + height: (heightOfChartSpace + bubbleSize) + 'px', + 'data-agent': agentName, + 'data-type': typeName, + 'data-key': key + }, ` + top: 0px; + left: ${canvasWidth}px; + z-index: ${zIndex++}; + position: absolute; + `); + this.elementScroller.appendChild(canvas1); + this.elementScroller.appendChild(canvas2); + this.canvasMap[key] = [canvas1, canvas2]; + this.ctxMap[key] = [canvas1.getContext('2d'), canvas2.getContext('2d')]; + } + }); + }); + this.scrollOrder = [0, 1]; + } + private createCanvas(attrs: object, styles: string): HTMLCanvasElement { + const elementCanvas = document.createElement('canvas'); + Object.keys(attrs).forEach((key: string) => { + elementCanvas.setAttribute(key, attrs[key]); + }); + elementCanvas.setAttribute('style', styles); + return elementCanvas; + } + setTypeView(agentName: string, typeName: string, typeChecked: boolean): void { + const viewType = typeChecked ? 'block' : 'none'; + Object.keys(this.canvasMap).forEach((key: string) => { + this.canvasMap[key].forEach((canvas: HTMLCanvasElement) => { + if (key.endsWith(typeName)) { + canvas.style.display = viewType; + } + }); + }); + } + toggle(bIsAll: boolean, agentName: string, type: string): void { + Object.keys(this.canvasMap).forEach((key: string) => { + this.canvasMap[key].forEach((canvas: HTMLCanvasElement) => { + if ((bIsAll || key.startsWith(agentName)) && key.endsWith(type)) { + if ( canvas.style.display === 'none' ) { + canvas.style.display = 'block'; + } else { + canvas.style.display = 'none'; + } + } + }); + }); + } + showSelectedAgent(agentName: string): void { + if (agentName === '') { + Object.keys(this.canvasMap).forEach((key: string) => { + this.canvasMap[key].forEach((canvas: HTMLCanvasElement) => { + if (this.typeManager.isCheckedByName(key.split('-').pop())) { + canvas.style.display = 'block'; + } else { + canvas.style.display = 'none'; + } + }); + }); + } else { + Object.keys(this.canvasMap).forEach((key: string) => { + if (key.startsWith(agentName)) { + this.canvasMap[key].forEach((canvas: HTMLCanvasElement) => { + if (this.typeManager.isCheckedByName(key.split('-').pop())) { + canvas.style.display = 'block'; + } + }); + } else { + this.canvasMap[key].forEach((canvas: HTMLCanvasElement) => { + canvas.style.display = 'none'; + }); + } + }); + } + } + drawTransaction(key: string, color: string, data: number[]): void { + const bubbleRadius = this.options.bubbleRadius; + const rangeY = this.coordinateManager.getY(); + + let x = (data[DataIndex.X] - this.coordinateManager.getInitFromX()) * this.coordinateManager.getPixelPerTime(); + const y = this.coordinateManager.parseYDataToYChart(Math.min(rangeY.to, Math.max(rangeY.from, data[DataIndex.Y]))); + const r = this.coordinateManager.parseZDataToZChart(bubbleRadius); + + let ctxIndex = this.scrollOrder[0]; + const canvasWidth = this.coordinateManager.getCanvasWidth(); + const zeroLeft = Math.round(parseInt(this.canvasMap[key][ctxIndex].style.left, 10)); + const currentMaxX = zeroLeft + canvasWidth; + if (x > currentMaxX) { + ctxIndex = this.scrollOrder[1]; + x -= currentMaxX; + } else { + x -= zeroLeft; + } + + this.ctxMap[key][ctxIndex].beginPath(); + this.ctxMap[key][ctxIndex].fillStyle = color; + this.ctxMap[key][ctxIndex].strokeStyle = color; + this.ctxMap[key][ctxIndex].arc(x, y, r, 0, Math.PI * 2, true); + this.ctxMap[key][ctxIndex].globalAlpha = 0.3 + (0.1 * data[DataIndex.GROUP_COUNT]); + this.ctxMap[key][ctxIndex].fill(); + } + moveChart(moveXValue: number, duration: number): void { + const canvasWidth = this.coordinateManager.getCanvasWidth(); + const height = this.coordinateManager.getHeight(); + const baseLeft = parseInt(this.elementScroller.style.left, 10); + const nextLeft = baseLeft - moveXValue; + + const self = this; + let startTime = -1; + function moveElement(timestamp: number, inMoveXValue: number, inDuration: number): void { + const runTime = timestamp - startTime; + let progress = runTime / inDuration; + progress = Math.min(progress, 1); + + self.elementScroller.style.left = (baseLeft + -(inMoveXValue * progress)).toFixed(2) + 'px'; + if (runTime < inDuration) { + self.requestAnimationFrameRef = window.requestAnimationFrame((time: number) => { + moveElement(time, inMoveXValue, inDuration); + }); + } else { + const orderFirst = self.scrollOrder[0]; + const orderSecond = self.scrollOrder[1]; + let bOverBoundary = false; + Object.keys(self.canvasMap).forEach((key: string): void => { + const canvasArr = self.canvasMap[key]; + if (Math.abs(nextLeft) > (parseInt(canvasArr[orderFirst].style.left, 10) + canvasWidth)) { + bOverBoundary = true; + canvasArr[orderFirst].style.left = (parseInt(canvasArr[orderSecond].style.left, 10) + canvasWidth) + 'px'; + self.ctxMap[key][orderFirst].clearRect(0, 0, canvasWidth, height); + } + }); + if (bOverBoundary) { + self.scrollOrder[0] = orderSecond; + self.scrollOrder[1] = orderFirst; + } + } + } + this.requestAnimationFrameRef = window.requestAnimationFrame((timestamp: number) => { + startTime = timestamp; + moveElement(timestamp, moveXValue, 300); + }); + } + reset() { + window.cancelAnimationFrame(this.requestAnimationFrameRef); + this.scrollOrder = [0, 1]; + this.elementScroller.style.left = '0px'; + this.elementScroller.innerHTML = ''; + this.initVariable(); + } + clear() { + const width = this.coordinateManager.getCanvasWidth(); + const height = this.coordinateManager.getHeight(); + + Object.keys(this.ctxMap).forEach((key: string) => { + this.ctxMap[key].forEach((ctx: CanvasRenderingContext2D) => { + ctx.clearRect(0, 0, width, height); + }); + }); + } + drawToCanvas(ctxDownload: CanvasRenderingContext2D, topPadding: number): CanvasRenderingContext2D { + const padding = this.coordinateManager.getPadding(); + const bubbleHalfSize = this.coordinateManager.getBubbleHalfSize(); + // scatter + Object.keys(this.canvasMap).forEach((key: string) => { + this.canvasMap[key].forEach((canvas: HTMLCanvasElement) => { + if (canvas.style.display !== 'none') { + ctxDownload.drawImage(canvas, padding.left + bubbleHalfSize, padding.top + topPadding); + } + }); + }); + ctxDownload.textBaseline = 'top'; + return ctxDownload; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-size-coordinate-manager.class.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-size-coordinate-manager.class.ts new file mode 100644 index 000000000000..473072c8f132 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-size-coordinate-manager.class.ts @@ -0,0 +1,123 @@ +import { IOptions } from './scatter-chart.class'; + +export class ScatterChartSizeCoordinateManager { + private initFromX: number; // for realtime + private widthOfChartSpace: number; + private heightOfChartSpace: number; + private timePerPixel: number; + private pixelPerTime: number; + constructor(private options: IOptions) { + this.initVar(); + } + private initVar(): void { + const bubbleRaduis = this.options.bubbleRadius; + + this.initFromX = this.options.x.from; + this.widthOfChartSpace = (this.options.width - (this.options.padding.left + this.options.padding.right)) - bubbleRaduis * 2; + this.heightOfChartSpace = (this.options.height - (this.options.padding.top + this.options.padding.bottom)) - bubbleRaduis * 2; + + this.calcuUnitValue(); + } + private calcuUnitValue(): void { + this.timePerPixel = this.getGapX() / this.widthOfChartSpace; + this.pixelPerTime = this.widthOfChartSpace / this.getGapX(); + } + getInitFromX(): number { + return this.initFromX; + } + getLeftPadding(): number { + return this.options.padding.left; + } + getTopPadding(): number { + return this.options.padding.top; + } + getCanvasWidth(): number { + return this.widthOfChartSpace; + } + getWidth(): number { + return this.options.width; + } + getHeight(): number { + return this.options.height; + } + getX(): {from: number, to: number} { + return { + from: this.options.x.from, + to: this.options.x.to + }; + } + resetInitX(fromX: number): void { + this.initFromX = fromX; + } + setX(from: number, to: number, bReset?: boolean): void { + this.options.x.from = from; + this.options.x.to = to; + this.calcuUnitValue(); + } + getY(): {from: number, to: number} { + return { + from: this.options.y.from, + to: this.options.y.to + }; + } + setY(from: number, to: number): void { + this.options.y.from = from; + this.options.y.to = to; + } + getPadding(): {top: number, left: number, right: number, bottom: number} { + return { + top: this.options.padding.top, + left: this.options.padding.left, + right: this.options.padding.right, + bottom: this.options.padding.bottom + }; + } + getBubbleHalfSize(): number { + return this.options.bubbleRadius; + } + getBubbleSize(): number { + return this.options.bubbleRadius * 2; + } + getWidthOfChartSpace(): number { + return this.widthOfChartSpace; + } + getHeightOfChartSpace(): number { + return this.heightOfChartSpace; + } + getPixelPerTime(): number { + return this.pixelPerTime; + } + getTimePerPixel(): number { + return this.timePerPixel; + } + parseXDataToXChart(x: number, plusPadding: boolean): number { + return Math.round( ( ( x - this.options.x.from ) / this.getGapX() ) * this.widthOfChartSpace ) + this.getBubbleHalfSize() + ( plusPadding ? this.options.padding.left : 0 ); + } + parseYDataToYChart(y: number): number { + return Math.round(this.heightOfChartSpace - (((y - this.options.y.from) / this.getGapY()) * this.heightOfChartSpace)) + this.getBubbleHalfSize(); + } + parseZDataToZChart(z: number): number { + return Math.round(((z - this.options.z.from) / this.getGapZ()) * this.getBubbleHalfSize()); + } + getXOfPixel(): number { + return Math.round(this.getGapX() / this.widthOfChartSpace); + } + getYOfPixel(): number { + return Math.round(this.getGapY() / this.heightOfChartSpace); + } + parseMouseXToXData(x: number): number { + return Math.round((x / this.widthOfChartSpace) * this.getGapX()) + this.options.x.from; + } + parseMouseYToYData(y: number): number { + return Math.round(this.options.y.from + ((y / this.heightOfChartSpace) * this.getGapY())); + } + getGapX(): number { + return this.options.x.to - this.options.x.from; + } + getGapY(): number { + return this.options.y.to - this.options.y.from; + } + getGapZ(): number { + return this.options.z.to - this.options.z.from; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-transaction-type-manager.class.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-transaction-type-manager.class.ts new file mode 100644 index 000000000000..6219843cb74e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart-transaction-type-manager.class.ts @@ -0,0 +1,53 @@ +import { ITypeInfo } from './scatter-chart.class'; + +export class ScatterChartTransactionTypeManager { + private dataByIndex: { [key: number]: ITypeInfo } = {}; + private dataByName: { [key: string]: ITypeInfo } = {}; + + constructor(typeInfos: ITypeInfo[]) { + this.initData(typeInfos); + } + private initData(typeInfos: ITypeInfo[]): void { + typeInfos.forEach((typeInfo: ITypeInfo, index: number) => { + const newTypeInfo = { + name: typeInfo.name, + color: typeInfo.color, + order: typeInfo.order, + index: index, + checked: true + }; + this.dataByName[typeInfo.name] = newTypeInfo; + this.dataByIndex[index] = newTypeInfo; + }); + } + getTypeNameList(): string[] { + return Object.keys(this.dataByName); + } + setChecked(name: string, checked: boolean): void { + this.dataByName[name].checked = checked; + } + isCheckedByName(name: string): boolean { + return this.dataByName[name].checked; + } + isCheckedByIndex(index: number): boolean { + return this.dataByIndex[index].checked; + } + getColorByIndex(index: number): string { + return this.dataByIndex[index].color; + } + getColorByName(name: string): string { + return this.dataByName[name].color; + } + getNameByIndex(index: number): string { + return this.dataByIndex[index].name; + } + getCheckedTypeNameList(): string[] { + const list = []; + Object.keys(this.dataByName).forEach((name: string) => { + if (this.dataByName[name].checked) { + list.push(name); + } + }); + return list; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart.class.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart.class.ts new file mode 100644 index 000000000000..9e24b05c21f4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/class/scatter-chart.class.ts @@ -0,0 +1,520 @@ +import * as moment from 'moment-timezone'; +import { Subject, BehaviorSubject, Observable } from 'rxjs'; +import { ScatterChartSizeCoordinateManager } from './scatter-chart-size-coordinate-manager.class'; +import { ScatterChartRendererManager } from './scatter-chart-renderer-manager.class'; +import { ScatterChartDataBlock } from './scatter-chart-data-block.class'; +import { ScatterChartGridRenderer } from './scatter-chart-grid-renderer.class'; +import { ScatterChartAxisRenderer } from './scatter-chart-axis-renderer.class'; +import { ScatterChartTransactionTypeManager } from './scatter-chart-transaction-type-manager.class'; +import { ScatterChartMouseManager } from './scatter-chart-mouse-manager.class'; + +export interface IOptions { + mode: string; + prefix: string; + width: number; + height: number; + bubbleRadius: number; + padding: { + top: number; + left: number; + right: number; + bottom: number; + }; + axisLabelStyle: string; + axisColor: string; + lineColor: string; + x: { + from: number; + to: number; + }; + y: { + from: number; + to: number; + }; + z: { + from: number; + to: number; + }; + ticks: { + x: number; + y: number; + }; + tickLength: { + x: number; + y: number; + }; + gridAxisStyle: { + lineDash: number[]; + lineWidth: number; + globalAlpha: number; + strokeStyle: string + }; + axisUnit: { + x: string; + y: string; + }; + showMouseGuideLine: boolean; + animationDuration: number; + timezone: string; + dateFormat: string[]; +} +export interface ITypeInfo { + index?: number; + name?: string; + color: string; + order: number; + checked?: boolean; +} + +export class ScatterChart { + static MODE = { + REALTIME: 'realtime', + STATIC: 'static' + }; + private options: IOptions; + private typeManager: ScatterChartTransactionTypeManager; + private gridRenderer: ScatterChartGridRenderer; + private axisRenderer: ScatterChartAxisRenderer; + private coordinateManager: ScatterChartSizeCoordinateManager; + private rendererManager: ScatterChartRendererManager; + private mouseManager: ScatterChartMouseManager; + private dataBlocks: ScatterChartDataBlock[] = []; + private agentList: string[] = []; + private selectedAgent = ''; + + private downloadElement: HTMLElement; + + private outTransactionCount: BehaviorSubject<{ [key: string]: number }>; + private outSelect: Subject = new Subject(); + private outError: Subject = new Subject(); + private outChangeRangeX: Subject<{from: number, to: number}> = new Subject(); + onSelect$: Observable; + onError$: Observable; + onChangeRangeX$: Observable<{from: number, to: number}>; + onChangeTransactionCount$: Observable<{ [key: string]: number }>; + + constructor( + private mode: string, + private element: any, + private fromX: number, + private toX: number, + private fromY: number, + private toY: number, + typeInfos: ITypeInfo[], + private application: string, + agent: string, + private width: number, + private height: number, + private timezone: string, + private dateFormat: string[] + ) { + this.downloadElement = document.createElement('a'); + this.selectedAgent = agent; + this.setOptions(); + this.initManagers(typeInfos); + + this.onSelect$ = this.outSelect.asObservable(); + this.onError$ = this.outError.asObservable(); + this.onChangeRangeX$ = this.outChangeRangeX.asObservable(); + this.outTransactionCount = new BehaviorSubject(this.getTransactionCount(true)); + this.onChangeTransactionCount$ = this.outTransactionCount.asObservable(); + } + private isAllowedAgent(agent: string): boolean { + return this.selectedAgent === '' || this.selectedAgent === agent; + } + private getTransactionCount(isInit: boolean) { + const count: { [key: string]: number } = { }; + const xRange = this.coordinateManager.getX(); + if (isInit) { + this.typeManager.getTypeNameList().forEach((typeName: string) => { + count[typeName] = 0; + }); + } else { + this.typeManager.getTypeNameList().forEach((typeName: string) => { + count[typeName] = 0; + this.dataBlocks.forEach((dataBlock: ScatterChartDataBlock) => { + const dataBlockXRange = dataBlock.getXRange(); + if (dataBlockXRange.to >= xRange.from) { + const agentList = dataBlock.getAgentList(); + agentList.forEach((agentName: string) => { + if (this.isAllowedAgent(agentName)) { + count[typeName] += dataBlock.getCount(agentName, typeName, xRange.from, xRange.to); + } + }); + } + }); + }); + } + return count; + } + private setOptions() { + this.options = { + mode: this.mode, + prefix: 'scatter-chart-' + (Math.random() * 10000), + width: this.width, + height: this.height, + bubbleRadius: 3, + padding: { + top: 20, + left: 60, + right: 40, + bottom: 40 + }, + axisLabelStyle: 'font-size:10px; line-height: 12px; padding-top: 3px', + axisColor: '#000', + lineColor: '#3D3D3D', + x: { + from: this.fromX, + to: this.toX + }, + y: { + from: this.fromY, + to: this.toY + }, + z: { + from: 0, + to: 5 + }, + ticks: { + x: 5, + y: 5 + }, + tickLength: { + x: 10, + y: 10 + }, + gridAxisStyle: { + lineDash: [1, 0], + lineWidth: 1, + globalAlpha: 1, + strokeStyle : '#e3e3e3' + }, + axisUnit: { + x: '', + y: '(ms)' + }, + showMouseGuideLine: true, + animationDuration: 300, + timezone: this.timezone, + dateFormat: this.dateFormat + }; + } + private initManagers(typeInfos: ITypeInfo[]): void { + this.typeManager = new ScatterChartTransactionTypeManager(typeInfos); + this.coordinateManager = new ScatterChartSizeCoordinateManager(this.options); + this.gridRenderer = new ScatterChartGridRenderer(this.options, this.coordinateManager, this.element); + this.axisRenderer = new ScatterChartAxisRenderer(this.options, this.coordinateManager, this.element); + this.rendererManager = new ScatterChartRendererManager(this.options, this.coordinateManager, this.element, this.typeManager); + this.mouseManager = new ScatterChartMouseManager(this.options, this.coordinateManager, this.element); + this.mouseManager.onDragArea$.subscribe((area: any) => { + const fromX = this.coordinateManager.parseMouseXToXData(area.x.from); + const toX = this.coordinateManager.parseMouseXToXData(area.x.to); + const fromY = this.coordinateManager.parseMouseYToYData(area.y.from); + const toY = this.coordinateManager.parseMouseYToYData(area.y.to); + if (this.hasDataByXY(fromX, toX, fromY, toY)) { + this.outSelect.next({ + x: { + from: fromX, + to: toX + }, + y: { + from: fromY, + to: toY + }, + drag: area, + type: this.typeManager.getCheckedTypeNameList(), + agent: this.selectedAgent + }); + } + }); + } + changeShowType(typeInfo: {name: string, checked: boolean}): void { + this.typeManager.setChecked(typeInfo.name, typeInfo.checked); + this.rendererManager.setTypeView(this.selectedAgent, typeInfo.name, typeInfo.checked); + } + private redrawDataBlock(): void { + this.dataBlocks.forEach((dataBlock: ScatterChartDataBlock) => { + this.drawDataBlock(dataBlock); + }); + } + reset(application: string, agent: string, fromX: number, toX: number, mode: string): void { + this.fromX = fromX; + this.toX = toX; + this.options.mode = this.mode = mode; + this.coordinateManager.resetInitX(fromX); + this.coordinateManager.setX(fromX, toX); + this.application = application; + this.selectedAgent = agent; + + this.dataBlocks = []; + this.agentList = []; + this.axisRenderer.reset(); + this.rendererManager.reset(); + this.outTransactionCount.next(this.getTransactionCount(true)); + } + addAgent(agentList: string[]): void { + agentList.forEach((agentName: string) => { + if (this.agentList.lastIndexOf(agentName) === -1) { + this.agentList.push(agentName); + } + }); + this.agentList.sort(); + } + addData(dataBlock: ScatterChartDataBlock, nextRequestTime?: number): void { + const xRange = this.coordinateManager.getX(); + const dataBlockRange = dataBlock.getXRange(); + if (this.options.mode === ScatterChart.MODE.STATIC && dataBlockRange.from >= xRange.to) { + return; + } + this.addAgent(dataBlock.getAgentList()); + this.dataBlocks.push(dataBlock); + // if (this._bPause === true) return; + this.drawDataBlock(dataBlock); + if (this.options.mode !== ScatterChart.MODE.STATIC) { + this.moveChart(dataBlock, nextRequestTime || 300); + this.removeBubble(); + } + this.changeSelectedAgent(this.selectedAgent); + this.outTransactionCount.next(this.getTransactionCount(false)); + } + private drawDataBlock(dataBlock: ScatterChartDataBlock): void { + const prefix = this.options.prefix; + this.rendererManager.makeDataCanvas(dataBlock, dataBlock.getAgentList()); + this.agentList.forEach((agentName: string) => { + for (let i = 0, nLen = dataBlock.countByAgent(agentName) ; i < nLen ; i++) { + const data = dataBlock.getDataByAgentAndIndex(agentName, i); + const groupCount = dataBlock.getGroupCount(data); + if (groupCount !== 0) { + const typeIndex = dataBlock.getTypeIndex(data); + const typeName = this.typeManager.getNameByIndex(typeIndex); + const typeColor = this.typeManager.getColorByIndex(typeIndex); + this.rendererManager.drawTransaction(`${agentName}-${prefix}-${typeName}`, typeColor, data); + } + } + }); + } + private moveChart(dataBlock: ScatterChartDataBlock, nextRequestTime: number): void { + const xRange = this.coordinateManager.getX(); + const dataBlockXRange = dataBlock.getXRange(); + const duration = this.options.animationDuration; + + if (dataBlockXRange.from >= xRange.to) { + const moveXTime = dataBlockXRange.to - xRange.to; + const moveXValue = moveXTime * this.coordinateManager.getPixelPerTime(); + this.coordinateManager.setX(xRange.from + moveXTime, xRange.to + moveXTime); + this.axisRenderer.updateAxisValue(true, duration * 2); + this.rendererManager.moveChart(Math.floor(moveXValue), nextRequestTime < duration ? 0 : duration); + this.outChangeRangeX.next({ + from: xRange.from + moveXTime, + to: xRange.to + moveXTime + }); + } + } + private removeBubble() { + const fromX = this.coordinateManager.getX().from; + for (let i = 0 ; i < this.dataBlocks.length ; i++) { + const dataBlock = this.dataBlocks[i]; + if (dataBlock.getXRange().to < fromX) { + this.dataBlocks.shift(); + i--; + } else { + break; + } + } + } + getDataByRange(fromX: number, toX: number, fromY: number, toY: number, selectedAgent: string, selectedType: string[]): any[] { + fromX = +fromX; + toX = +toX; + fromY = +fromY; + toY = +toY; + + const data = []; + const yRange = this.coordinateManager.getY(); + const typeChecker = {}; + selectedType.forEach((type: string) => { + typeChecker[type] = true; + }); + for (let i = 0 ; i < this.dataBlocks.length ; i++) { + const dataBlock = this.dataBlocks[i]; + for (let j = 0, len = dataBlock.getTotalCount(); j < len ; j++) { + const xRange = dataBlock.getXRange(); + if ( xRange.to < fromX || xRange.from > toX ) { + continue; + } + const transactionData = dataBlock.getDataByIndex(j); + const agentName = dataBlock.getAgentName(transactionData); + if (selectedAgent === '' || selectedAgent === agentName) { + const x = dataBlock.getX(transactionData); + const y = dataBlock.getY(transactionData); + + if (this.isInRange(fromX, toX, x)) { + if (this.isInRange(fromY, toY, y) || (y > toY && toY <= yRange.to)) { + if (typeChecker[this.typeManager.getNameByIndex(dataBlock.getTypeIndex(transactionData))] === true) { + data.push([dataBlock.getTransactionID(transactionData), x, y]); + } + } + } + } + + } + } + return data; + } + hasDataByXY(fromX: number, toX: number, fromY: number, toY: number): boolean { + fromX = +fromX; + toX = +toX; + fromY = +fromY; + toY = +toY; + + const yRange = this.coordinateManager.getY(); + for (let i = 0 ; i < this.dataBlocks.length ; i++) { + const dataBlock = this.dataBlocks[i]; + for (let j = 0, len = dataBlock.getTotalCount() ; j < len ; j++) { + const transactionData = dataBlock.getDataByIndex(j); + const agentName = dataBlock.getAgentName(transactionData); + if (this.isAllowedAgent(agentName)) { + const x = dataBlock.getX(transactionData); + const y = dataBlock.getY(transactionData); + if (this.isInRange(fromX, toX, x)) { + if (this.typeManager.isCheckedByIndex(dataBlock.getTypeIndex(transactionData))) { + if (this.isInRange(fromY, toY, y) || y > toY && toY <= yRange.to) { + return true; + } + } + } + } + } + } + return false; + } + private isInRange(from: number, to: number, value: number): boolean { + return value >= from && value <= to; + } + // //destroy = function() { + // // var self = this; + // // this._unbindAllEvents(); + // // //this._empty(); + // // $.each(this, function (property, content) { + // // delete self[property]; + // // }); + // // this._bDestroied = true; + // // + // //}; + // //_empty = function() { + // // this._$elContainer.empty(); + // //}; + // //_unbindAllEvents = function() { + // // // this is for drag-selecting. it should be unbinded. + // // jQuery(document).unbind('mousemove').unbind('mouseup'); + // //}; + downloadChartAsImage(extension: string): void { + const xRange = this.coordinateManager.getX(); + const titleArea = 60; + const countArea = 40; + const width = this.coordinateManager.getWidth(); + const height = this.coordinateManager.getHeight() + titleArea + countArea; + + const elementDownloadCanvas = document.createElement('canvas'); + elementDownloadCanvas.setAttribute('width', width + 'px'); + elementDownloadCanvas.setAttribute('height', height + 'px'); + + const ctxDownloadCanvas = elementDownloadCanvas.getContext('2d'); + ctxDownloadCanvas.fillStyle = '#FFFFFF'; + ctxDownloadCanvas.fillRect(0, 0, width, height); + + this.gridRenderer.drawToCanvas(ctxDownloadCanvas, titleArea); + this.axisRenderer.drawToCanvas(ctxDownloadCanvas, titleArea); + this.rendererManager.drawToCanvas(ctxDownloadCanvas, titleArea); + + // draw Title + ctxDownloadCanvas.textAlign = 'left'; + ctxDownloadCanvas.font = '24px monospace'; + ctxDownloadCanvas.fillText(this.application, 10, 10); + ctxDownloadCanvas.font = '14px monospace'; + ctxDownloadCanvas.fillText(moment(xRange.from).tz(this.timezone).format(this.dateFormat[0] + ' ' + this.dateFormat[1]) + ' ~ ' + moment(xRange.to).tz(this.timezone).format(this.dateFormat[0] + ' ' + this.dateFormat[1]), 10, 40); + + // draw Count By Type + this.typeManager.getTypeNameList().forEach((typeName: string, index: number) => { + const color = this.typeManager.getColorByName(typeName); + const check = this.typeManager.isCheckedByName(typeName); + let sumType = 0; + this.dataBlocks.forEach((dataBlock: ScatterChartDataBlock) => { + sumType += dataBlock.getCount(this.selectedAgent, typeName); + }); + ctxDownloadCanvas.textAlign = 'left'; + ctxDownloadCanvas.font = '16px monospace'; + if (check) { + ctxDownloadCanvas.fillStyle = color; + ctxDownloadCanvas.fillRect((index * 200) + 10, height - countArea + 10, 20, 20); + } else { + ctxDownloadCanvas.lineWidth = 4; + ctxDownloadCanvas.strokeStyle = color; + ctxDownloadCanvas.strokeRect((index * 200) + 10, height - countArea + 10, 20, 20); + } + ctxDownloadCanvas.fillStyle = '#000'; + ctxDownloadCanvas.fillText(`${typeName} : ${sumType}`, (index * 200) + 40, height - countArea + 10); + }); + + this.downloadElement.setAttribute('href', elementDownloadCanvas.toDataURL('image/' + extension)); + this.downloadElement.setAttribute('download', `Pinpoint_Scatter_Chart[${moment(xRange.from).tz(this.timezone).format(this.dateFormat[0] + '_' + this.dateFormat[1])}~${moment(xRange.to).tz(this.timezone).format(this.dateFormat[0] + '_' + this.dateFormat[1])}].png`); + this.downloadElement.dispatchEvent(new MouseEvent('click')); + } + // _hideServerError() { + // this._$elContainer.css({ + // 'backgroundImage': 'none' + // }); + // } + // _showServerError() { + // this._$elContainer.css({ + // 'backgroundImage': 'url(' + this.option('errorImage') + ')', + // 'backgroundRepeat': 'no-repeat', + // 'backgroundPosition': '88% 21%', + // 'backgroundSize': '30px 30px' + // }); + // } + redraw() { + this.rendererManager.clear(); + this.axisRenderer.updateAxisValue(); + this.redrawDataBlock(); + } + // abort() { + // this._bPause = true; + // if (this._oDataLoadManager) { + // this._oDataLoadManager.abort(); + // } + // } + changeYRange(newYRange: {from: number, to: number}): void { + this.fromY = +newYRange.from; + this.toY = +newYRange.to; + this.coordinateManager.setY(+newYRange.from, +newYRange.to); + this.redraw(); + } + changeSelectedAgent(agentName: string): void { + this.selectedAgent = agentName; + this.rendererManager.showSelectedAgent(agentName); + this.outTransactionCount.next(this.getTransactionCount(false)); + } + getCurrentAgent(): string { + return this.selectedAgent; + } + isEmpty(): boolean { + if (this.options.mode === ScatterChart.MODE.STATIC) { + let empty = true; + this.dataBlocks.forEach((dataBlock: ScatterChartDataBlock) => { + empty = empty && dataBlock.isEmpty(); + }); + return empty; + } else { + return false; + } + } + getTypeManager(): ScatterChartTransactionTypeManager { + return this.typeManager; + } + setTimezone(timezone: string): void { + this.options.timezone = this.timezone = timezone; + } + setDateFormat(dateFormat: string[]): void { + this.options.dateFormat = this.dateFormat = dateFormat; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/index.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/index.ts new file mode 100644 index 000000000000..1e78ea568c2d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/index.ts @@ -0,0 +1,45 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { ScatterChartSettingPopupComponent } from './scatter-chart-setting-popup.component'; +import { ScatterChartOptionsComponent } from './scatter-chart-options.component'; +import { ScatterChartStateViewComponent } from './scatter-chart-state-view.component'; +import { ScatterChartComponent } from './scatter-chart.component'; +import { ScatterChartContainerComponent } from './scatter-chart-container.component'; +import { ScatterChartForFilteredMapSideBarContainerComponent } from './scatter-chart-for-filtered-map-side-bar-container.component'; +import { ScatterChartForFilteredMapInfoPerServerContainerComponent } from './scatter-chart-for-filtered-map-info-per-server-container.component'; +import { ScatterChartForInfoPerServerContainerComponent } from './scatter-chart-for-info-per-server-container.component'; +import { ScatterChartForFullScreenModeContainerComponent } from './scatter-chart-for-full-screen-mode-container.component'; +import { ScatterChartInteractionService } from './scatter-chart-interaction.service'; +import { ScatterChartDataService } from './scatter-chart-data.service'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + ScatterChartSettingPopupComponent, + ScatterChartOptionsComponent, + ScatterChartStateViewComponent, + ScatterChartComponent, + ScatterChartContainerComponent, + ScatterChartForFilteredMapSideBarContainerComponent, + ScatterChartForFilteredMapInfoPerServerContainerComponent, + ScatterChartForInfoPerServerContainerComponent, + ScatterChartForFullScreenModeContainerComponent + ], + imports: [ + CommonModule, + HelpViewerPopupModule + ], + exports: [ + ScatterChartContainerComponent, + ScatterChartForFilteredMapSideBarContainerComponent, + ScatterChartForFilteredMapInfoPerServerContainerComponent, + ScatterChartForInfoPerServerContainerComponent, + ScatterChartForFullScreenModeContainerComponent + ], + providers: [ + ScatterChartInteractionService, + ScatterChartDataService + ] +}) +export class ScatterChartModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-container.component.css b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-container.component.css new file mode 100644 index 000000000000..5297343d37ac --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-container.component.css @@ -0,0 +1,19 @@ +:host { + position: relative; +} +.l-chart-item { + margin: 15px 0; + height: 285px; + position: relative; + border-top: none; +} +.l-chart-item.l-popup-on:before { + display: block; + z-index: 490; + position: absolute; + content: ''; + width: 100%; + height: 100%; + background: #FFF; + opacity: 0.8; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-container.component.html b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-container.component.html new file mode 100644 index 000000000000..558b8249a070 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-container.component.html @@ -0,0 +1,43 @@ +
    + + + + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-container.component.ts new file mode 100644 index 000000000000..0b7b845cd238 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-container.component.ts @@ -0,0 +1,298 @@ +import { Component, ChangeDetectionStrategy, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core'; +import { combineLatest, of, Subject } from 'rxjs'; +import { takeUntil, filter, delay } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { + WebAppSettingDataService, + NewUrlStateNotificationService, + UrlRouteManagerService, + StoreHelperService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { EndTime } from 'app/core/models'; +import { ScatterChartDataService } from './scatter-chart-data.service'; +import { ScatterChart } from './class/scatter-chart.class'; +import { ScatterChartInteractionService } from './scatter-chart-interaction.service'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-scatter-chart-container', + templateUrl: './scatter-chart-container.component.html', + styleUrls: ['./scatter-chart-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ScatterChartContainerComponent implements OnInit, OnDestroy { + instanceKey = 'side-bar'; + addWindow = true; + i18nText: { [key: string]: string }; + currentRange: { from: number, to: number } = { + from : 0, + to: 0 + }; + selectedTarget: ISelectedTarget; + selectedApplication: string; + unsubscribe: Subject = new Subject(); + hideSettingPopup = true; + selectedAgent: string; + typeInfo = [{ + name: 'failed', + color: '#E95459', + order: 10 + }, { + name: 'success', + color: '#34B994', + order: 20 + }]; + typeCount: object; + width = 460; + height = 230; + min: number; + max: number; + fromX: number; + toX: number; + fromY: number; + toY: number; + application: string; + scatterChartMode: string; + timezone: string; + dateFormat: string[]; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private scatterChartDataService: ScatterChartDataService, + private scatterChartInteractionService: ScatterChartInteractionService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.setScatterY(); + combineLatest( + this.translateService.get('COMMON.NO_DATA'), + this.translateService.get('COMMON.FAILED_TO_FETCH_DATA') + ).subscribe((i18n: string[]) => { + this.i18nText = { + NO_DATA: i18n[0], + FAILED_TO_FETCH_DATA: i18n[1] + }; + }); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.APPLICATION); + }) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.scatterChartMode = urlService.isRealTimeMode() ? ScatterChart.MODE.REALTIME : ScatterChart.MODE.STATIC; + this.scatterChartDataService.setCurrentMode(this.scatterChartMode); + this.application = urlService.getPathValue(UrlPathId.APPLICATION).getKeyStr(); + this.selectedAgent = ''; + this.currentRange.from = this.fromX = urlService.getStartTimeToNumber(); + this.currentRange.to = this.toX = urlService.getEndTimeToNumber(); + this.changeDetectorRef.detectChanges(); + }); + this.scatterChartDataService.outScatterData$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((scatterData: IScatterData) => { + switch (this.scatterChartMode) { + case ScatterChart.MODE.STATIC: + this.scatterChartInteractionService.addChartData(this.instanceKey, scatterData); + if (scatterData.complete === false) { + this.scatterChartDataService.loadData( + this.selectedApplication.split('^')[0], + this.fromX, + scatterData.resultFrom - 1, + this.getGroupUnitX(), + this.getGroupUnitY(), + false + ); + } + break; + case ScatterChart.MODE.REALTIME: + if (scatterData.reset === true) { + this.fromX = scatterData.currentServerTime - this.webAppSettingDataService.getSystemDefaultPeriod().getMiliSeconds(); + this.toX = scatterData.currentServerTime; + this.scatterChartInteractionService.reset(this.instanceKey, this.selectedApplication, this.selectedAgent, this.fromX, this.toX, this.scatterChartMode); + of(1).pipe(delay(1000)).subscribe((useless: number) => { + this.getScatterData(); + }); + } else { + this.scatterChartInteractionService.addChartData(this.instanceKey, scatterData); + } + break; + } + }); + this.scatterChartDataService.outScatterErrorData$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((error: IServerErrorFormat) => { + this.scatterChartInteractionService.setError(error); + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private setScatterY() { + const scatterYData = this.webAppSettingDataService.getScatterY(this.instanceKey); + this.fromY = scatterYData.min; + this.toY = scatterYData.max; + } + private connectStore(): void { + this.storeHelperService.getTimezone(this.unsubscribe).subscribe((timezone: string) => { + this.timezone = timezone; + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getDateFormatArray(this.unsubscribe, 3, 4).subscribe((format: string[]) => { + this.dateFormat = format; + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getAgentSelection(this.unsubscribe).subscribe((agent: string) => { + if (this.selectedAgent !== agent) { + this.selectedAgent = agent; + this.scatterChartInteractionService.changeAgent(this.instanceKey, agent); + } + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.selectedTarget = target; + if (this.isHide() === false) { + this.selectedAgent = ''; + this.selectedApplication = this.selectedTarget.node[0]; + this.scatterChartInteractionService.reset(this.instanceKey, this.selectedApplication, this.selectedAgent, this.fromX, this.toX, this.scatterChartMode); + this.getScatterData(); + } + this.changeDetectorRef.detectChanges(); + }); + } + getScatterData(): void { + if (this.scatterChartMode === ScatterChart.MODE.STATIC) { + this.scatterChartDataService.loadData( + this.selectedApplication.split('^')[0], + this.fromX, + this.toX, + this.getGroupUnitX(), + this.getGroupUnitY() + ); + } else { + this.scatterChartDataService.loadRealTimeData( + this.selectedApplication.split('^')[0], + this.fromX, + this.toX, + this.getGroupUnitX(), + this.getGroupUnitY() + ); + } + } + getGroupUnitX(): number { + return Math.round((this.toX - this.fromX) / this.width); + } + getGroupUnitY(): number { + return Math.round((this.toY - this.fromY) / this.height); + } + isHide(): boolean { + if (this.selectedTarget) { + return !(this.selectedTarget.isNode && this.selectedTarget.isWAS && this.selectedTarget.isMerged === false); + } + return true; + } + checkClass(): string { + return this.hideSettingPopup ? '' : 'l-popup-on'; + } + isHideSettingPopup(): boolean { + return this.hideSettingPopup; + } + onApplySetting(params: any): void { + this.fromY = params.min; + this.toY = params.max; + this.scatterChartInteractionService.changeYRange({ + instanceKey: this.instanceKey, + from: params.min, + to: params.max + }); + this.hideSettingPopup = true; + this.webAppSettingDataService.setScatterY(this.instanceKey, { min: params.min, max: params.max }); + } + onCancelSetting(): void { + this.hideSettingPopup = true; + } + onShowSetting(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_SCATTER_SETTING); + this.hideSettingPopup = false; + } + onDownload(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.DOWNLOAD_SCATTER); + this.scatterChartInteractionService.downloadChart(this.instanceKey); + } + onOpenScatterPage(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.GO_TO_FULL_SCREEN_SCATTER); + if (this.scatterChartMode === ScatterChart.MODE.STATIC) { + this.urlRouteManagerService.openPage([ + UrlPath.SCATTER_FULL_SCREEN_MODE, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + this.selectedAgent + ]); + } else { + this.urlRouteManagerService.openPage([ + UrlPath.SCATTER_FULL_SCREEN_MODE, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + UrlPathId.REAL_TIME + ]); + } + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.SCATTER); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.SCATTER, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } + onChangedSelectType(params: {instanceKey: string, name: string, checked: boolean}): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CHANGE_SCATTER_CHART_STATE, `${params.name}: ${params.checked ? `on` : `off`}`); + this.scatterChartInteractionService.changeViewType(params); + } + onChangeTransactionCount(params: object): void { + this.typeCount = params; + } + onChangeRangeX(params: { from: number, to: number }): void { + this.currentRange.from = params.from; + this.currentRange.to = params.to; + this.storeHelperService.dispatch(new Actions.UpdateRealTimeScatterChartXRange(params)); + } + onSelectArea(params: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_TRANSACTION_LIST); + if (this.newUrlStateNotificationService.isRealTimeMode()) { + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_LIST, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.webAppSettingDataService.getSystemDefaultPeriod().getValueWithTime(), + EndTime.newByNumber(this.currentRange.to).getEndTime(), + ], `${this.selectedApplication}|${params.x.from}|${params.x.to}|${params.y.from}|${params.y.to}|${this.selectedAgent}|${params.type.join(',')}`); + } else { + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_LIST, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ], `${this.selectedApplication}|${params.x.from}|${params.x.to}|${params.y.from}|${params.y.to}|${this.selectedAgent}|${params.type.join(',')}`); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-data.service.ts new file mode 100644 index 000000000000..391196a6ec27 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-data.service.ts @@ -0,0 +1,152 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable, of, Subject } from 'rxjs'; +import { switchMap, delay, retry } from 'rxjs/operators'; +import { ScatterChart } from 'app/core/components/scatter-chart/class/scatter-chart.class'; + +interface IScatterRequest { + application: string; + fromX: number; + toX: number; + groupUnitX: number; + groupUnitY: number; + backwardDirection: boolean; +} + +@Injectable() +export class ScatterChartDataService { + private url = 'getScatterData.pinpoint'; + private realtime = { + interval: 2000, + // interval: 5000, + resetTimeGap: 20000 + }; + private currentMode: string; + private lastScatterData: IScatterData[] = []; + private requestTime: number; + private application: string; + private groupUnitX: number; + private groupUnitY: number; + private innerDataRequest = new Subject(); + private innerDataRequest$: Observable; + private outScatterData = new Subject(); + private outScatterErrorData = new Subject(); + outScatterData$: Observable; + outScatterErrorData$: Observable; + constructor(private http: HttpClient) { + this.innerDataRequest$ = this.innerDataRequest.asObservable(); + this.outScatterData$ = this.outScatterData.asObservable(); + this.outScatterErrorData$ = this.outScatterErrorData.asObservable(); + this.connectDataRequest(); + } + private connectDataRequest(): void { + this.innerDataRequest$.pipe( + switchMap((params: IScatterRequest) => { + return this.http.get(this.url, this.makeRequestOptionsArgs( + params.application, + params.fromX, + params.toX, + params.groupUnitX, + params.groupUnitY, + params.backwardDirection) + ).pipe( + retry(3) + ); + }) + ).subscribe((scatterData: IScatterData) => { + if ( this.currentMode === ScatterChart.MODE.REALTIME) { + this.subscribeRealTimeRequest(scatterData); + } else { + this.subscribeStaticRequest(scatterData); + } + }, (error: IServerErrorFormat) => { + if ( this.currentMode === ScatterChart.MODE.STATIC) { + this.outScatterErrorData.next(error); + } + }); + } + private getData(fromX: number, toX: number, backwardDirection: boolean): void { + this.requestTime = Date.now(); + return this.innerDataRequest.next({ + application: this.application, + fromX: fromX, + toX: toX, + groupUnitX: this.groupUnitX, + groupUnitY: this.groupUnitY, + backwardDirection: backwardDirection + }); + } + loadData(application: string, fromX: number, toX: number, groupUnitX: number, groupUnitY: number, initLastData?: boolean): void { + this.application = application; + this.groupUnitX = groupUnitX; + this.groupUnitY = groupUnitY; + this.lastScatterData = initLastData === false ? this.lastScatterData : []; + this.getData(fromX, toX, true); + } + private subscribeStaticRequest(scatterData: IScatterData): void { + this.lastScatterData.push(scatterData); + this.outScatterData.next(scatterData); + } + loadLastData(): IScatterData[] { + return this.lastScatterData; + } + loadRealTimeData(application: string, fromX: number, toX: number, groupUnitX: number, groupUnitY: number): void { + this.application = application; + this.groupUnitX = groupUnitX; + this.groupUnitY = groupUnitY; + this.getData(fromX, toX, false); + } + setCurrentMode(mode: string): void { + this.currentMode = mode; + } + private subscribeRealTimeRequest(scatterData: IScatterData): void { + const roundTripTime = Date.now() - this.requestTime; + let fromNext = 0; + let toNext = 0; + let delayTime = this.realtime.interval - roundTripTime; + + if (scatterData.complete) { + fromNext = scatterData.to; + toNext = fromNext + this.realtime.interval; + if (delayTime > 0) { + const timeGapInterServerAndClient = scatterData.currentServerTime - toNext; + if (timeGapInterServerAndClient >= delayTime) { + if ( timeGapInterServerAndClient >= this.realtime.interval ) { + delayTime = 0; + } else { + delayTime = Math.min(Math.abs(timeGapInterServerAndClient), delayTime); + } + } + } else { + delayTime = 0; + } + } else { + // TODO: 처리해야 함. + fromNext = scatterData.from; + toNext = scatterData.resultFrom; + delayTime = 0; + } + if (scatterData.currentServerTime - toNext >= this.realtime.resetTimeGap) { + scatterData.reset = true; + this.outScatterData.next(scatterData); + } else { + this.outScatterData.next(scatterData); + of(1).pipe(delay(delayTime)).subscribe((useless: number) => { + this.getData(fromNext, toNext, false); + }); + } + } + private makeRequestOptionsArgs(application: string, fromX: number, toX: number, groupUnitX: number, groupUnitY: number, backwardDirection: boolean): object { + return { + params: new HttpParams() + .set('application', application) + .set('from', fromX + '') + .set('to', toX + '') + .set('limit', '5000') + .set('filter', '') + .set('xGroupUnit', groupUnitX + '') + .set('yGroupUnit', groupUnitY + '') + .set('backwardDirection', backwardDirection + '') + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-download-plugin.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-download-plugin.ts new file mode 100644 index 000000000000..b7923e727f11 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-download-plugin.ts @@ -0,0 +1,52 @@ +export class ScatterChartDownloadPlugin { + constructor(imageData) { + // this._init(imageData); + } + // _init(imageData) { + // this._featureImage = imageData; + // this._aCallback = []; + // this._bDisabled = false; + // } + // initElement($elParent, $elPlugin, option) { + // this._bDisabled = option['realtime']; + // this._$element = $('
    ').css({ + // 'cursor': 'pointer', + // 'padding': '4px 0px 4px 20px' + // }).append( + // $('').attr({ + // 'alt': 'Download Scatter Chart', + // 'href': '', + // 'title': 'Download Scatter Chart', + // 'download': '' + // }).append( + // $('').attr({ + // 'src': this._featureImage + // }).css({ + // 'opacity': this._bDisabled ? 0.2 : 1 + // }) + // ) + // ).appendTo($elPlugin); + // return this; + // } + // initEvent(oChart) { + // var self = this; + // this._$element.find('a').on('click', function (event) { + // if (self._bDisabled) { + // event.preventDefault(); + // return; + // } + // $(this).attr({ + // 'href': oChart.getChartAsImage('png'), + // 'download': 'Pinpoint_Scatter_Chart[' + moment(oChart.option('minX')).format('YYYYMMDD_HHmm') + '~' + moment(oChart.option('maxX')).format('YYYYMMDD_HHmm') + ']' + // }); + // $.each(self._aCallback, function (index, fn) { + // fn(oChart); + // }); + // }); + // return this; + // } + // addCallback(fn) { + // this._aCallback.push(fn); + // return this; + // } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-info-per-server-container.component.css b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-info-per-server-container.component.css new file mode 100644 index 000000000000..5297343d37ac --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-info-per-server-container.component.css @@ -0,0 +1,19 @@ +:host { + position: relative; +} +.l-chart-item { + margin: 15px 0; + height: 285px; + position: relative; + border-top: none; +} +.l-chart-item.l-popup-on:before { + display: block; + z-index: 490; + position: absolute; + content: ''; + width: 100%; + height: 100%; + background: #FFF; + opacity: 0.8; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-info-per-server-container.component.html b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-info-per-server-container.component.html new file mode 100644 index 000000000000..558b8249a070 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-info-per-server-container.component.html @@ -0,0 +1,43 @@ +
    + + + + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-info-per-server-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-info-per-server-container.component.ts new file mode 100644 index 000000000000..36cc4ce0e20a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-info-per-server-container.component.ts @@ -0,0 +1,227 @@ +import { Component, ChangeDetectionStrategy, ChangeDetectorRef, OnInit, AfterViewInit, OnDestroy } from '@angular/core'; +import { combineLatest, Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { + WebAppSettingDataService, + NewUrlStateNotificationService, + UrlRouteManagerService, + StoreHelperService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ScatterChartDataService } from './scatter-chart-data.service'; +import { ScatterChart } from './class/scatter-chart.class'; +import { ScatterChartComponent } from './scatter-chart.component'; +import { ScatterChartInteractionService } from './scatter-chart-interaction.service'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-scatter-chart-for-filtered-map-info-per-server-container', + templateUrl: './scatter-chart-for-filtered-map-info-per-server-container.component.html', + styleUrls: ['./scatter-chart-for-filtered-map-info-per-server-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ScatterChartForFilteredMapInfoPerServerContainerComponent implements OnInit, AfterViewInit, OnDestroy { + instanceKey = 'filtered-map-info-per-server'; + addWindow = false; + i18nText: { [key: string]: string }; + isChangedTarget: boolean; + selectedTarget: ISelectedTarget; + selectedApplication: string; + unsubscribe: Subject = new Subject(); + hideSettingPopup = true; + selectedAgent: string; + typeInfo = [{ + name: 'failed', + color: '#E95459', + order: 10 + }, { + name: 'success', + color: '#34B994', + order: 20 + }]; + typeCount: object; + width = 460; + height = 230; + min: number; + max: number; + fromX: number; + toX: number; + fromY: number; + toY: number; + application: string; + scatterChartMode: string; + scatterChartDataOfAllNode: any[] = []; + timezone: string; + dateFormat: string[]; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private scatterChartDataService: ScatterChartDataService, + private scatterChartInteractionService: ScatterChartInteractionService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.setScatterY(); + combineLatest( + this.translateService.get('COMMON.NO_DATA'), + this.translateService.get('COMMON.FAILED_TO_FETCH_DATA') + ).subscribe((i18n: string[]) => { + this.i18nText = { + NO_DATA: i18n[0], + FAILED_TO_FETCH_DATA: i18n[1] + }; + }); + this.connectStore(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.APPLICATION); + }) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.scatterChartMode = urlService.isRealTimeMode() ? ScatterChart.MODE.REALTIME : ScatterChart.MODE.STATIC; + this.scatterChartDataService.setCurrentMode(this.scatterChartMode); + this.application = urlService.getPathValue(UrlPathId.APPLICATION).getKeyStr(); + this.selectedAgent = ''; + this.fromX = urlService.getStartTimeToNumber(); + this.toX = urlService.getEndTimeToNumber(); + this.changeDetectorRef.detectChanges(); + }); + } + ngAfterViewInit() { + this.storeHelperService.getInfoPerServerState(this.unsubscribe).subscribe((visibleState: boolean) => { + if (visibleState && this.isChangedTarget) { + this.scatterChartDataOfAllNode.forEach((scatterData: any) => { + this.scatterChartInteractionService.addChartData(this.instanceKey, scatterData[this.selectedApplication]); + }); + this.isChangedTarget = false; + } + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private setScatterY() { + const scatterYData = this.webAppSettingDataService.getScatterY(this.instanceKey); + this.fromY = scatterYData.min; + this.toY = scatterYData.max; + } + private connectStore(): void { + this.storeHelperService.getTimezone(this.unsubscribe).subscribe((timezone: string) => { + this.timezone = timezone; + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getDateFormatArray(this.unsubscribe, 3, 4).subscribe((format: string[]) => { + this.dateFormat = format; + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getAgentSelectionForServerList(this.unsubscribe).pipe( + filter((chartData: IAgentSelection) => { + return (chartData && chartData.agent) ? true : false; + }) + ).subscribe((chartData: IAgentSelection) => { + this.selectedAgent = chartData.agent; + this.changeDetectorRef.detectChanges(); + this.scatterChartInteractionService.changeAgent(this.instanceKey, chartData.agent); + }); + this.storeHelperService.getScatterChartData(this.unsubscribe).subscribe((scatterChartData: IScatterData[]) => { + this.scatterChartDataOfAllNode = scatterChartData; + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.isChangedTarget = true; + this.selectedTarget = target; + this.selectedAgent = ''; + this.selectedApplication = this.selectedTarget.node[0]; + this.scatterChartInteractionService.reset(this.instanceKey, this.selectedApplication, this.selectedAgent, this.fromX, this.toX, this.scatterChartMode); + this.changeDetectorRef.detectChanges(); + }); + } + isHide(): boolean { + return false; + } + checkClass(): string { + return this.hideSettingPopup ? '' : 'l-popup-on'; + } + isHideSettingPopup(): boolean { + return this.hideSettingPopup; + } + onApplySetting(params: any): void { + this.fromY = params.min; + this.toY = params.max; + this.scatterChartInteractionService.changeYRange({ + instanceKey: this.instanceKey, + from: params.min, + to: params.max + }); + this.hideSettingPopup = true; + this.webAppSettingDataService.setScatterY(this.instanceKey, { min: params.min, max: params.max }); + } + onCancelSetting(): void { + this.hideSettingPopup = true; + } + onShowSetting(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_SCATTER_SETTING); + this.hideSettingPopup = false; + } + onDownload(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.DOWNLOAD_SCATTER); + this.scatterChartInteractionService.downloadChart(this.instanceKey); + } + onOpenScatterPage(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.GO_TO_FULL_SCREEN_SCATTER); + this.urlRouteManagerService.openPage([ + UrlPath.SCATTER_FULL_SCREEN_MODE, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + this.selectedAgent + ]); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.SCATTER); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.SCATTER, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } + onChangedSelectType(params: {instanceKey: string, name: string, checked: boolean}): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CHANGE_SCATTER_CHART_STATE, `${params.name}: ${params.checked ? `on` : `off`}`); + this.scatterChartInteractionService.changeViewType(params); + } + onChangeTransactionCount(params: object): void { + this.typeCount = params; + } + onChangeRangeX(params: IScatterXRange): void { + this.storeHelperService.dispatch(new Actions.UpdateRealTimeScatterChartXRange(params)); + } + onSelectArea(params: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_TRANSACTION_LIST); + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_LIST, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ], `${this.selectedApplication}|${params.x.from}|${params.x.to}|${params.y.from}|${params.y.to}|${this.selectedAgent}|${params.type.join(',')}`); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-side-bar-container.component.css b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-side-bar-container.component.css new file mode 100644 index 000000000000..5297343d37ac --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-side-bar-container.component.css @@ -0,0 +1,19 @@ +:host { + position: relative; +} +.l-chart-item { + margin: 15px 0; + height: 285px; + position: relative; + border-top: none; +} +.l-chart-item.l-popup-on:before { + display: block; + z-index: 490; + position: absolute; + content: ''; + width: 100%; + height: 100%; + background: #FFF; + opacity: 0.8; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-side-bar-container.component.html b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-side-bar-container.component.html new file mode 100644 index 000000000000..558b8249a070 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-side-bar-container.component.html @@ -0,0 +1,43 @@ +
    + + + + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-side-bar-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-side-bar-container.component.ts new file mode 100644 index 000000000000..9d6ad55cdb47 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-filtered-map-side-bar-container.component.ts @@ -0,0 +1,237 @@ +import { Component, ChangeDetectionStrategy, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core'; +import { combineLatest, Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { + StoreHelperService, + WebAppSettingDataService, + NewUrlStateNotificationService, + UrlRouteManagerService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ScatterChart } from './class/scatter-chart.class'; +import { ScatterChartInteractionService } from './scatter-chart-interaction.service'; +import { ScatterChartDataService } from './scatter-chart-data.service'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-scatter-chart-for-filtered-map-side-bar-container', + templateUrl: './scatter-chart-for-filtered-map-side-bar-container.component.html', + styleUrls: ['./scatter-chart-for-filtered-map-side-bar-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ScatterChartForFilteredMapSideBarContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + instanceKey = 'filtered-map-side-bar'; + addWindow = true; + i18nText: { [key: string]: string }; + selectedTarget: ISelectedTarget; + selectedApplication: string; + hideSettingPopup = true; + selectedAgent: string; + typeInfo = [{ + name: 'failed', + color: '#E95459', + order: 10 + }, { + name: 'success', + color: '#34B994', + order: 20 + }]; + typeCount: object; + width = 460; + height = 230; + min: number; + max: number; + fromX: number; + toX: number; + fromY: number; + toY: number; + application: string; + scatterChartMode: string; + scatterChartDataOfAllNode: any[] = []; + timezone: string; + dateFormat: string[]; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private scatterChartDataService: ScatterChartDataService, + private scatterChartInteractionService: ScatterChartInteractionService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.setScatterY(); + combineLatest( + this.translateService.get('COMMON.NO_DATA'), + this.translateService.get('COMMON.FAILED_TO_FETCH_DATA') + ).subscribe((i18n: Array) => { + this.i18nText = { + NO_DATA: i18n[0], + FAILED_TO_FETCH_DATA: i18n[1] + }; + }); + this.connectStore(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.APPLICATION); + }) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.scatterChartMode = ScatterChart.MODE.STATIC; + this.scatterChartDataService.setCurrentMode(this.scatterChartMode); + this.application = urlService.getPathValue(UrlPathId.APPLICATION).getKeyStr(); + this.selectedAgent = ''; + this.fromX = urlService.getStartTimeToNumber(); + this.toX = urlService.getEndTimeToNumber(); + this.changeDetectorRef.detectChanges(); + }); + + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private setScatterY(): void { + const scatterYData = this.webAppSettingDataService.getScatterY(this.instanceKey); + this.fromY = scatterYData.min; + this.toY = scatterYData.max; + } + private connectStore(): void { + this.storeHelperService.getTimezone(this.unsubscribe).subscribe((timezone: string) => { + this.timezone = timezone; + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getDateFormatArray(this.unsubscribe, 3, 4).subscribe((format: string[]) => { + this.dateFormat = format; + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getAgentSelection(this.unsubscribe).subscribe((agent: string) => { + if (this.selectedAgent !== agent) { + this.selectedAgent = agent; + this.scatterChartInteractionService.changeAgent(this.instanceKey, agent); + } + }); + this.storeHelperService.getScatterChartData(this.unsubscribe).pipe( + filter((data: any) => { + return data.length > 0 && data.length > this.scatterChartDataOfAllNode.length; + }) + ).subscribe((scatterChartData: IScatterData[]) => { + const startIndex = this.scatterChartDataOfAllNode.length; + this.scatterChartDataOfAllNode = scatterChartData; + if (this.selectedTarget) { + this.getScatterData(startIndex); + } + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.selectedTarget = target; + if (this.isHide() === false) { + this.selectedAgent = ''; + this.selectedApplication = this.selectedTarget.node[0]; + this.scatterChartInteractionService.reset(this.instanceKey, this.selectedApplication, this.selectedAgent, this.fromX, this.toX, this.scatterChartMode); + this.getScatterData(0); + } + this.changeDetectorRef.detectChanges(); + }); + } + getScatterData(startIndex: number): void { + for (let i = startIndex ; i < this.scatterChartDataOfAllNode.length ; i++) { + this.scatterChartInteractionService.addChartData(this.instanceKey, this.scatterChartDataOfAllNode[i][this.selectedApplication]); + } + } + getGroupUnitX(): number { + return Math.round((this.toX - this.fromX) / this.width); + } + getGroupUnitY(): number { + return Math.round((this.toY - this.fromY) / this.height); + } + isHide(): boolean { + if (this.selectedTarget) { + return !(this.selectedTarget.isNode && this.selectedTarget.isWAS && this.selectedTarget.isMerged === false); + } + return true; + } + checkClass(): string { + return this.hideSettingPopup ? '' : 'l-popup-on'; + } + isHideSettingPopup(): boolean { + return this.hideSettingPopup; + } + onApplySetting(params: any): void { + this.fromY = params.min; + this.toY = params.max; + this.scatterChartInteractionService.changeYRange({ + instanceKey: this.instanceKey, + from: params.min, + to: params.max + }); + this.hideSettingPopup = true; + this.webAppSettingDataService.setScatterY(this.instanceKey, { min: params.min, max: params.max }); + } + onCancelSetting(): void { + this.hideSettingPopup = true; + } + onShowSetting(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_SCATTER_SETTING); + this.hideSettingPopup = false; + } + onDownload(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.DOWNLOAD_SCATTER); + this.scatterChartInteractionService.downloadChart(this.instanceKey); + } + onOpenScatterPage(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.GO_TO_FULL_SCREEN_SCATTER); + this.urlRouteManagerService.openPage([ + UrlPath.SCATTER_FULL_SCREEN_MODE, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + this.selectedAgent + ]); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.SCATTER); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.SCATTER, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } + onChangedSelectType(params: {instanceKey: string, name: string, checked: boolean}): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CHANGE_SCATTER_CHART_STATE, `${params.name}: ${params.checked ? `on` : `off`}`); + this.scatterChartInteractionService.changeViewType(params); + } + onChangeTransactionCount(params: object): void { + this.typeCount = params; + } + onChangeRangeX(params: IScatterXRange): void { + this.storeHelperService.dispatch(new Actions.UpdateRealTimeScatterChartXRange(params)); + } + onSelectArea(params: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_TRANSACTION_LIST); + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_LIST, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ], `${this.selectedApplication}|${params.x.from}|${params.x.to}|${params.y.from}|${params.y.to}|${this.selectedAgent}|${params.type.join(',')}`); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component.css b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component.css new file mode 100644 index 000000000000..e179f7e6cf0e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component.css @@ -0,0 +1,17 @@ +:host { + position: relative; +} +.l-chart-item { + margin: 15px 0 0 0; + height: 285px; + position: relative; + border-top: none; +} +.l-layer-background { + top: 0; + display: none; + opacity: 0.8; + z-index: 490; + position: absolute; + background: #FFF; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component.html b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component.html new file mode 100644 index 000000000000..201c56a3da7f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component.html @@ -0,0 +1,43 @@ +
    + + + + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component.ts new file mode 100644 index 000000000000..c3b8b1e677ac --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component.ts @@ -0,0 +1,235 @@ +import { Component, ChangeDetectionStrategy, ChangeDetectorRef, OnInit, OnDestroy, ViewChild, ElementRef, Renderer2 } from '@angular/core'; +import { Observable, Subject, of, combineLatest, Subscription } from 'rxjs'; +import { takeUntil, delay } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { + StoreHelperService, + WebAppSettingDataService, + NewUrlStateNotificationService, + UrlRouteManagerService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ScatterChartDataService } from './scatter-chart-data.service'; +import { ScatterChart } from './class/scatter-chart.class'; +import { ScatterChartInteractionService } from './scatter-chart-interaction.service'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-scatter-chart-for-full-screen-mode-container', + templateUrl: './scatter-chart-for-full-screen-mode-container.component.html', + styleUrls: ['./scatter-chart-for-full-screen-mode-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ScatterChartForFullScreenModeContainerComponent implements OnInit, OnDestroy { + @ViewChild('layerBackground') layerBackground: ElementRef; + private unsubscribe: Subject = new Subject(); + instanceKey = 'full-screen-mode'; + addWindow = true; + i18nText: { [key: string]: string }; + selectedTarget: ISelectedTarget; + selectedApplication: string; + scatterDataServiceSubscription: Subscription; + hideSettingPopup = true; + selectedAgent: string; + typeInfo = [{ + name: 'failed', + color: '#E95459', + order: 10 + }, { + name: 'success', + color: '#34B994', + order: 20 + }]; + typeCount: object; + width = 690; + height = 345; + min: number; + max: number; + fromX: number; + toX: number; + fromY: number; + toY: number; + application: string; + scatterChartMode: string; + timezone$: Observable; + dateFormat: string[]; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private renderer: Renderer2, + private translateService: TranslateService, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private scatterChartDataService: ScatterChartDataService, + private scatterChartInteractionService: ScatterChartInteractionService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.setScatterY(); + this.getI18NText(); + this.connectStore(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.scatterChartMode = urlService.isRealTimeMode() ? ScatterChart.MODE.REALTIME : ScatterChart.MODE.STATIC; + this.scatterChartDataService.setCurrentMode(this.scatterChartMode); + this.selectedApplication = this.application = urlService.getPathValue(UrlPathId.APPLICATION).getKeyStr(); + this.selectedAgent = urlService.hasValue(UrlPathId.AGENT_ID) ? urlService.getPathValue(UrlPathId.AGENT_ID) : ''; + this.fromX = urlService.getStartTimeToNumber(); + this.toX = urlService.getEndTimeToNumber(); + of(1).pipe(delay(1)).subscribe((num: number) => { + this.scatterChartInteractionService.reset(this.instanceKey, this.selectedApplication, this.selectedAgent, this.fromX, this.toX, this.scatterChartMode); + this.getScatterData(); + this.changeDetectorRef.detectChanges(); + }); + }); + this.scatterChartDataService.outScatterData$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((scatterData: IScatterData) => { + if (this.scatterChartMode === ScatterChart.MODE.STATIC) { + this.scatterChartInteractionService.addChartData(this.instanceKey, scatterData); + if (scatterData.complete === false) { + this.scatterChartDataService.loadData( + this.selectedApplication.split('^')[0], + this.fromX, + scatterData.resultFrom - 1, + this.getGroupUnitX(), + this.getGroupUnitY(), + false + ); + } + } else { + if (scatterData.reset === true) { + this.fromX = scatterData.currentServerTime - this.webAppSettingDataService.getSystemDefaultPeriod().getMiliSeconds(); + this.toX = scatterData.currentServerTime; + this.scatterChartInteractionService.reset(this.instanceKey, this.selectedApplication, this.selectedAgent, this.fromX, this.toX, this.scatterChartMode); + of(1).pipe(delay(1000)).subscribe((useless: number) => { + this.getScatterData(); + }); + } else { + this.scatterChartInteractionService.addChartData(this.instanceKey, scatterData); + } + } + }); + } + ngOnDestroy() { + if (this.scatterDataServiceSubscription) { + this.scatterDataServiceSubscription.unsubscribe(); + } + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private setScatterY(): void { + const scatterYData = this.webAppSettingDataService.getScatterY(this.instanceKey); + this.fromY = scatterYData.min; + this.toY = scatterYData.max; + } + private getI18NText(): void { + combineLatest( + this.translateService.get('COMMON.NO_DATA'), + this.translateService.get('COMMON.FAILED_TO_FETCH_DATA') + ).subscribe((i18n: string[]) => { + this.i18nText = { + NO_DATA: i18n[0], + FAILED_TO_FETCH_DATA: i18n[1] + }; + }); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + this.storeHelperService.getDateFormatArray(this.unsubscribe, 3, 4).subscribe((dateFormat: string[]) => { + this.dateFormat = dateFormat; + }); + } + getScatterData(): void { + if (this.scatterChartMode === ScatterChart.MODE.STATIC) { + this.scatterChartDataService.loadData( + this.selectedApplication.split('^')[0], + this.fromX, + this.toX, + this.getGroupUnitX(), + this.getGroupUnitY() + ); + } else { + this.scatterChartDataService.loadRealTimeData( + this.selectedApplication.split('^')[0], + this.fromX, + this.toX, + this.getGroupUnitX(), + this.getGroupUnitY() + ); + } + } + getGroupUnitX(): number { + return Math.round((this.toX - this.fromX) / this.width); + } + getGroupUnitY(): number { + return Math.round((this.toY - this.fromY) / this.height); + } + isHideSettingPopup(): boolean { + return this.hideSettingPopup; + } + onApplySetting(params: any): void { + this.fromY = params.min; + this.toY = params.max; + this.scatterChartInteractionService.changeYRange({ + instanceKey: this.instanceKey, + from: params.min, + to: params.max + }); + this.onHideSetting(); + this.webAppSettingDataService.setScatterY(this.instanceKey, { min: params.min, max: params.max }); + } + onHideSetting(): void { + this.renderer.setStyle(this.layerBackground.nativeElement, 'display', 'none'); + this.hideSettingPopup = true; + } + onShowSetting(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_SCATTER_SETTING); + this.renderer.setStyle(this.layerBackground.nativeElement, 'display', 'block'); + this.hideSettingPopup = false; + } + onDownload(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.DOWNLOAD_SCATTER); + this.scatterChartInteractionService.downloadChart(this.instanceKey); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.SCATTER); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.SCATTER, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } + onChangedSelectType(params: {instanceKey: string, name: string, checked: boolean}): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CHANGE_SCATTER_CHART_STATE, `${params.name}: ${params.checked ? `on` : `off`}`); + this.scatterChartInteractionService.changeViewType(params); + } + onChangeTransactionCount(params: object): void { + this.typeCount = params; + } + onChangeRangeX(params: IScatterXRange): void { + this.storeHelperService.dispatch(new Actions.UpdateRealTimeScatterChartXRange(params)); + } + onSelectArea(params: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_TRANSACTION_LIST); + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_LIST, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ], `${this.selectedApplication}|${params.x.from}|${params.x.to}|${params.y.from}|${params.y.to}|${this.selectedAgent}|${params.type.join(',')}`); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-info-per-server-container.component.css b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-info-per-server-container.component.css new file mode 100644 index 000000000000..5297343d37ac --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-info-per-server-container.component.css @@ -0,0 +1,19 @@ +:host { + position: relative; +} +.l-chart-item { + margin: 15px 0; + height: 285px; + position: relative; + border-top: none; +} +.l-chart-item.l-popup-on:before { + display: block; + z-index: 490; + position: absolute; + content: ''; + width: 100%; + height: 100%; + background: #FFF; + opacity: 0.8; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-info-per-server-container.component.html b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-info-per-server-container.component.html new file mode 100644 index 000000000000..421499e45e92 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-info-per-server-container.component.html @@ -0,0 +1,43 @@ +
    + + + + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-info-per-server-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-info-per-server-container.component.ts new file mode 100644 index 000000000000..5cdaf9a50dff --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-for-info-per-server-container.component.ts @@ -0,0 +1,221 @@ +import { Component, ChangeDetectionStrategy, ChangeDetectorRef, OnInit, AfterViewInit, OnDestroy } from '@angular/core'; +import { combineLatest, Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { + StoreHelperService, + WebAppSettingDataService, + NewUrlStateNotificationService, + UrlRouteManagerService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ScatterChart } from './class/scatter-chart.class'; +import { ScatterChartInteractionService } from './scatter-chart-interaction.service'; +import { ScatterChartDataService } from './scatter-chart-data.service'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-scatter-chart-for-info-per-server-container', + templateUrl: './scatter-chart-for-info-per-server-container.component.html', + styleUrls: ['./scatter-chart-for-info-per-server-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ScatterChartForInfoPerServerContainerComponent implements OnInit, AfterViewInit, OnDestroy { + instanceKey = 'info-per-server'; + addWindow = false; + i18nText: { [key: string]: string }; + isChangedTarget: boolean; + selectedTarget: ISelectedTarget; + selectedApplication: string; + unsubscribe: Subject = new Subject(); + hideSettingPopup = true; + selectedAgent: string; + typeInfo = [{ + name: 'failed', + color: '#E95459', + order: 10 + }, { + name: 'success', + color: '#34B994', + order: 20 + }]; + typeCount: object; + width = 460; + height = 230; + min: number; + max: number; + fromX: number; + toX: number; + fromY: number; + toY: number; + application: string; + scatterChartMode: string; + timezone: string; + dateFormat: string[]; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private scatterChartDataService: ScatterChartDataService, + private scatterChartInteractionService: ScatterChartInteractionService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.setScatterY(); + combineLatest( + this.translateService.get('COMMON.NO_DATA'), + this.translateService.get('COMMON.FAILED_TO_FETCH_DATA') + ).subscribe((i18n: string[]) => { + this.i18nText = { + NO_DATA: i18n[0], + FAILED_TO_FETCH_DATA: i18n[1] + }; + }); + this.connectStore(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.APPLICATION); + }) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.scatterChartMode = urlService.isRealTimeMode() ? ScatterChart.MODE.REALTIME : ScatterChart.MODE.STATIC; + this.scatterChartDataService.setCurrentMode(this.scatterChartMode); + this.application = urlService.getPathValue(UrlPathId.APPLICATION).getKeyStr(); + this.selectedAgent = ''; + this.fromX = urlService.getStartTimeToNumber(); + this.toX = urlService.getEndTimeToNumber(); + this.changeDetectorRef.detectChanges(); + }); + } + ngAfterViewInit() { + this.storeHelperService.getInfoPerServerState(this.unsubscribe).subscribe((visibleState: boolean) => { + if (visibleState && this.isChangedTarget) { + this.scatterChartDataService.loadLastData().forEach((data: IScatterData) => { + this.scatterChartInteractionService.addChartData(this.instanceKey, data); + }); + this.isChangedTarget = false; + } + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private setScatterY(): void { + const scatterYData = this.webAppSettingDataService.getScatterY(this.instanceKey); + this.fromY = scatterYData.min; + this.toY = scatterYData.max; + } + private connectStore(): void { + this.storeHelperService.getTimezone(this.unsubscribe).subscribe((timezone: string) => { + this.timezone = timezone; + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getDateFormatArray(this.unsubscribe, 3, 4).subscribe((format: string[]) => { + this.dateFormat = format; + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getAgentSelectionForServerList(this.unsubscribe).pipe( + filter((chartData: IAgentSelection) => { + return (chartData && chartData.agent) ? true : false; + }) + ).subscribe((chartData: IAgentSelection) => { + this.selectedAgent = chartData.agent; + this.scatterChartInteractionService.changeAgent(this.instanceKey, chartData.agent); + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.isChangedTarget = true; + this.selectedTarget = target; + this.selectedAgent = ''; + this.selectedApplication = this.selectedTarget.node[0]; + this.scatterChartInteractionService.reset(this.instanceKey, this.selectedApplication, this.selectedAgent, this.fromX, this.toX, this.scatterChartMode); + this.changeDetectorRef.detectChanges(); + }); + } + isHide(): boolean { + return false; + } + checkClass(): string { + return this.hideSettingPopup ? '' : 'l-popup-on'; + } + isHideSettingPopup(): boolean { + return this.hideSettingPopup; + } + onApplySetting(params: any): void { + this.fromY = params.min; + this.toY = params.max; + this.scatterChartInteractionService.changeYRange({ + instanceKey: this.instanceKey, + from: params.min, + to: params.max + }); + this.hideSettingPopup = true; + this.webAppSettingDataService.setScatterY(this.instanceKey, { min: params.min, max: params.max }); + } + onCancelSetting(): void { + this.hideSettingPopup = true; + } + onShowSetting(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_SCATTER_SETTING); + this.hideSettingPopup = false; + } + onDownload(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.DOWNLOAD_SCATTER); + this.scatterChartInteractionService.downloadChart(this.instanceKey); + } + onOpenScatterPage(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.GO_TO_FULL_SCREEN_SCATTER); + this.urlRouteManagerService.openPage([ + UrlPath.SCATTER_FULL_SCREEN_MODE, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + this.selectedAgent + ]); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.SCATTER); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.SCATTER, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } + onChangedSelectType(params: {instanceKey: string, name: string, checked: boolean}): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CHANGE_SCATTER_CHART_STATE, `${params.name}: ${params.checked ? `on` : `off`}`); + this.scatterChartInteractionService.changeViewType(params); + } + onChangeTransactionCount(params: object): void { + this.typeCount = params; + } + onChangeRangeX(params: IScatterXRange): void { + this.storeHelperService.dispatch(new Actions.UpdateRealTimeScatterChartXRange(params)); + } + onSelectArea(params: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_TRANSACTION_LIST); + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_LIST, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ], `${this.selectedApplication}|${params.x.from}|${params.x.to}|${params.y.from}|${params.y.to}|${this.selectedAgent}|${params.type.join(',')}`); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-interaction.service.ts new file mode 100644 index 000000000000..10ca7bba861c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-interaction.service.ts @@ -0,0 +1,93 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Subject, Observable } from 'rxjs'; + +export interface IChangedAgentParam { + instanceKey: string; + agent: string; +} +export interface IChangedViewTypeParam { + instanceKey: string; + name: string; + checked: boolean; +} +export interface IRangeParam { + instanceKey: string; + from: number; + to: number; +} +export interface IResetParam { + instanceKey: string; + application: string; + agent: string; + from: number; + to: number; + mode: string; +} + +@Injectable() +export class ScatterChartInteractionService { + + private outChartData = new BehaviorSubject<{instanceKey: string, data: IScatterData}>({instanceKey: '', data: null}); + public onChartData$: Observable<{instanceKey: string, data: IScatterData}>; + + private outViewType = new Subject(); + public onViewType$: Observable; + + private outChangeYRange = new Subject(); + public onChangeYRange$: Observable; + + private outSelectedAgent = new Subject(); + public onSelectedAgent$: Observable; + + private outInvokeDownloadChart = new Subject(); + public onInvokeDownloadChart$: Observable; + + private outReset = new Subject(); + public onReset$: Observable; + + private outError = new Subject(); + public onError$: Observable; + constructor() { + this.onChartData$ = this.outChartData.asObservable(); + this.onViewType$ = this.outViewType.asObservable(); + this.onChangeYRange$ = this.outChangeYRange.asObservable(); + this.onSelectedAgent$ = this.outSelectedAgent.asObservable(); + this.onInvokeDownloadChart$ = this.outInvokeDownloadChart.asObservable(); + this.onReset$ = this.outReset.asObservable(); + this.onError$ = this.outError.asObservable(); + } + addChartData(instanceKey: string, data: IScatterData): void { + this.outChartData.next({ + instanceKey: instanceKey, + data: data + }); + } + changeViewType(params: IChangedViewTypeParam): void { + this.outViewType.next(params); + } + changeYRange(yRange: IRangeParam): void { + this.outChangeYRange.next(yRange); + } + changeAgent(instanceKey: string, agent: string): void { + this.outSelectedAgent.next({ + instanceKey: instanceKey, + agent: agent + }); + } + downloadChart(instanceKey: string): void { + this.outInvokeDownloadChart.next(instanceKey); + } + reset(instanceKey: string, application: string, agent: string, from: number, to: number, mode: string): void { + this.outReset.next({ + instanceKey: instanceKey, + application: application, + agent: agent, + from: from, + to: to, + mode: mode + }); + } + setError(error: IServerErrorFormat): void { + this.outError.next(error); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-message-plugin.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-message-plugin.ts new file mode 100644 index 000000000000..bf2cd6dc037f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-message-plugin.ts @@ -0,0 +1,46 @@ +export class ScatterChartMessagePlugin { + constructor() { + // this._init(); + } + // _init() { + // this._aCallback = []; + // } + // initElement($elParent, $elPlugin, option) { + // this._$element = $('
    ') + // .css({ + // 'top': 0, + // 'width': option['width'], + // 'height': option['height'], + // 'cursor': 'crosshair', + // 'display': 'none', + // 'z-index': 1100, + // 'position': 'absolute', + // 'background-color': 'rgba(0,0,0,0)' // for ie10 + // }) + // .addClass('message-display') + // .append( + // $('
    ') + // .css(option['noDataStyle']) + // .css({ + // 'top': (option['height'] / 2) + 'px', + // 'width': option['width'] + 'px', + // 'position': 'absolute', + // 'text-align': 'center' + // } + // )).appendTo($elParent); + + // return this; + // } + // initEvent( /* oChart */) { + // return this; + // } + // addCallback(fn) { + // this._aCallback.push(fn); + // } + // show(message) { + // this._$element.find('> div').html(message).end().show(); + // } + // hide() { + // this._$element.hide(); + // } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-options.component.css b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-options.component.css new file mode 100644 index 000000000000..f4172f3425a5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-options.component.css @@ -0,0 +1,21 @@ +.l-tool-box { + font-size:14px; + color:#b3b5b9; + text-align:right; + position:relative; + padding: 0 25px 0 +} +.l-tool-box button { + margin:0 0 0 14px; +} +.l-tool-box button.l-last-child { + font-size:18px; + +} +.l-tool-box button.l-last-child:before { + padding-left: 14px; + border-left: 1px solid #e9ebec; +} +.fas { + font-size: 18px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-options.component.html b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-options.component.html new file mode 100644 index 000000000000..50bac318f8be --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-options.component.html @@ -0,0 +1,6 @@ +
    + + + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-options.component.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-options.component.ts new file mode 100644 index 000000000000..9bc36104e042 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-options.component.ts @@ -0,0 +1,20 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-scatter-chart-options', + templateUrl: './scatter-chart-options.component.html', + styleUrls: ['./scatter-chart-options.component.css'] +}) +export class ScatterChartOptionsComponent implements OnInit { + @Output() outShowSetting: EventEmitter = new EventEmitter(); + @Output() outDownload: EventEmitter = new EventEmitter(); + @Output() outOpenScatterPage: EventEmitter = new EventEmitter(); + @Output() outShowHelp: EventEmitter = new EventEmitter(); + @Input() instanceKey: string; + @Input() hiddenOptions: { setting: boolean, download: boolean, open: boolean, help: boolean }; + constructor() {} + ngOnInit() {} + onShowHelp($event: MouseEvent): void { + this.outShowHelp.emit($event); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-setting-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-setting-popup.component.css new file mode 100644 index 000000000000..022bf5bed571 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-setting-popup.component.css @@ -0,0 +1,58 @@ +:host { + width: 100%; + z-index: 1000; + position: absolute; +} +.l-chart-setting { + display: flex; + flex-flow: column; + align-items: center; + justify-content: center; + width: 60%; + border: 1px solid #E5E8F0; + text-align: left; + box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.15); + background: #FFF; + margin: 15% 20%; +} +.l-title-group { + height:auto; + padding: 10px 20px; + background-color: #FFF; +} +.l-title-group dt { + color: #4A8FD2; + font-size: 20px; + font-weight: 600; +} +.l-contents-group { + padding: 20px 20px 15px 20px +} +.l-contents-group ul li { + margin: 5px 0 0 0; + font-size: 13px; + font-weight: 600; +} +.l-contents-group ul li label { + width: 50%; + display: inline-block +} +.l-contents-group input { + border:1px solid #d7dde4; + font-size:13px; + color:#666; + height:22px; + padding:0 8px; +} +.l-bottom-group { + text-align: center; + margin: 0 0 20px; +} +input { + color: #666; + width: 40%; + height: 22px; + border: 1px solid #d7dde4; + padding: 0 8px; + font-size: 13px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-setting-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-setting-popup.component.html new file mode 100644 index 000000000000..48e47839ab8f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-setting-popup.component.html @@ -0,0 +1,17 @@ +
    +
    +
    +
    Setting
    +
    +
    +
    +
      +
    • +
    • +
    +
    +
    + + +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-setting-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-setting-popup.component.ts new file mode 100644 index 000000000000..ef87c85f80af --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-setting-popup.component.ts @@ -0,0 +1,32 @@ +import { Component, OnInit, Input, Output, ViewChild, ElementRef, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-scatter-chart-setting-popup', + templateUrl: './scatter-chart-setting-popup.component.html', + styleUrls: ['./scatter-chart-setting-popup.component.css'] +}) +export class ScatterChartSettingPopupComponent implements OnInit { + @ViewChild('minInput') minInput: ElementRef; + @ViewChild('maxInput') maxInput: ElementRef; + @Input() instanceKey: string; + @Input() min: number; + @Input() max: number; + @Output() outApply: EventEmitter<{key: string, min: number, max: number}> = new EventEmitter(); + @Output() outCancel: EventEmitter = new EventEmitter(); + constructor() {} + ngOnInit() {} + onApply(): void { + this.min = Number.parseInt(this.minInput.nativeElement.value, 10); + this.max = Number.parseInt(this.maxInput.nativeElement.value, 10); + this.outApply.emit({ + key: this.instanceKey, + min: this.min, + max: this.max + }); + } + onCancel(): void { + this.minInput.nativeElement.value = this.min; + this.maxInput.nativeElement.value = this.max; + this.outCancel.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-state-view.component.css b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-state-view.component.css new file mode 100644 index 000000000000..f69f6cac9436 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-state-view.component.css @@ -0,0 +1,36 @@ +:host { + display: block; +} +.l-checkbox-group { + color:#b3b3b4; + margin: 24px 0 0 0; + display: flex; + flex-flow: row wrap; + font-size:12px; + justify-content: space-around; +} +.l-checkbox-group span { + color:#333; + font-size:22px; +} +.l-checkbox-group .success:before { + width: 13px; + height: 13px; + margin: 0 6px 0 0; + content: ''; + display: inline-block; + background: #34b994; + border-radius: 50%; +} +.l-checkbox-group .failed:before { + width: 13px; + height: 13px; + margin: 0 6px 0 0; + content: ''; + display: inline-block; + background: #e95459; + border-radius: 50%; +} +input { + margin-left: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-state-view.component.html b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-state-view.component.html new file mode 100644 index 000000000000..ebf8c88bea5e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-state-view.component.html @@ -0,0 +1,8 @@ +
    +
    + + +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-state-view.component.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-state-view.component.ts new file mode 100644 index 000000000000..633371a6d97d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-state-view.component.ts @@ -0,0 +1,53 @@ +import { Component, OnInit, OnChanges, SimpleChanges, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-scatter-chart-state-view', + templateUrl: './scatter-chart-state-view.component.html', + styleUrls: ['./scatter-chart-state-view.component.css'] +}) +export class ScatterChartStateViewComponent implements OnInit, OnChanges { + innerTypeInfo: any[] = []; + @Input() instanceKey: string; + @Input() typeInfo: any[]; + @Input() typeCount: object; + @Output() outChanged: EventEmitter<{instanceKey: string, name: string, checked: boolean}> = new EventEmitter(); + constructor() {} + ngOnInit() {} + ngOnChanges(simpleChanges: SimpleChanges) { + if (simpleChanges['typeInfo'] && simpleChanges['typeInfo'].isFirstChange()) { + this.setInnerTypeInfo(); + } + } + private setInnerTypeInfo() { + this.typeInfo.forEach((info: object, index: number) => { + const obj = { + checked: true + }; + Object.keys(info).forEach((key: string) => { + obj[key] = info[key]; + }); + this.innerTypeInfo[index] = obj; + }); + const temp = this.innerTypeInfo[0]; + this.innerTypeInfo[0] = this.innerTypeInfo[1]; + this.innerTypeInfo[1] = temp; + } + upperFirstChar(str: string): string { + return str ? str.substr(0, 1).toUpperCase() + str.substr(1) : ''; + } + getTypeCount(name: string): number { + if (this.typeCount && this.typeCount[name]) { + return this.typeCount[name]; + } else { + return 0; + } + } + onCheck(type: any): void { + type.checked = !type.checked; + this.outChanged.emit({ + instanceKey: this.instanceKey, + name: type.name, + checked: type.checked + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-util.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-util.ts new file mode 100644 index 000000000000..f33edc790378 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart-util.ts @@ -0,0 +1,45 @@ +export default { + // compare(aData: any[][], dataIndex: number, fnCompare: (result: number) => boolean): any { + // let targetIndex = 0; + // for (let i = 1, len = aData.length; i < len; i++) { + // const result = aData[targetIndex][dataIndex] - aData[i][dataIndex]; + // if (fnCompare(result)) { + // targetIndex = i; + // } + // } + // return aData[targetIndex][dataIndex]; + // }, + // min(result: number): boolean { + // return result > 0; + // }, + // max(result: number): boolean { + // return result < 0; + // }, + // indexOf(aData: any[], value: any): number { + // for (let i = 0 ; i < aData.length ; i++) { + // if (aData[i] === value) { + // return i; + // } + // } + // return -1; + // }, + // getBoundaryValue(oRange: { min: number, max: number}, value: number): number { + // return Math.min(oRange.max, Math.max(oRange.min, value)); + // }, + // isInRange(from: number, to: number, value: number): boolean { + // return value >= from && value <= to; + // }, + // isEmpty(obj: any): boolean { + // let count = 0; + // Object.keys(obj).forEach((key: string) => { + // count += obj[key].length; + // }); + // return count === 0; + // }, + // makeKey(a: any, b: any, c: any): string { + // return a + '-' + b + '-' + c; + // }, + // isString(v: any): boolean { + // return typeof v === 'string'; + // }, +}; diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart.component.css b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart.component.css new file mode 100644 index 000000000000..1bc8488bc47f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart.component.css @@ -0,0 +1,30 @@ +:host { + display: block; + height: 100%; +} +.l-wrapper { + display: block; +} +.l-scatter { + width: 100%; + height: 100%; + display: block; + position: relative; +} +.l-message { + top: 0px; + width: 100%; + height: 100%; + display: flex; + position: absolute; + text-align: center; + justify-content: center; + align-items: center; +} +.l-message span { + font-weight: 600; +} +canvas { + width: 100%; + height: 100%; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart.component.html b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart.component.html new file mode 100644 index 000000000000..d71302020865 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart.component.html @@ -0,0 +1,5 @@ +
    +
    +
    Loading...
    +
    {{getMessage()}}
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart.component.ts b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart.component.ts new file mode 100644 index 000000000000..f197aa1512be --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/scatter-chart/scatter-chart.component.ts @@ -0,0 +1,185 @@ +import { Component, OnInit, OnDestroy, OnChanges, Input, Output, EventEmitter, ViewChild, ElementRef, SimpleChanges } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; +import { WindowRefService } from 'app/shared/services'; +import { ScatterChart, ITypeInfo } from './class/scatter-chart.class'; +import { ScatterChartDataBlock } from './class/scatter-chart-data-block.class'; +import { ScatterChartInteractionService, IChangedViewTypeParam, IRangeParam, IResetParam, IChangedAgentParam } from './scatter-chart-interaction.service'; + +@Component({ + selector: 'pp-scatter-chart', + templateUrl: './scatter-chart.component.html', + styleUrls: ['./scatter-chart.component.css'] +}) +export class ScatterChartComponent implements OnInit, OnDestroy, OnChanges { + @ViewChild('scatter') elementScatter: ElementRef; + @Input() instanceKey: string; + @Input() addWindow: boolean; + @Input() width: number; + @Input() height: number; + @Input() fromX: number; + @Input() toX: number; + @Input() fromY: number; + @Input() toY: number; + @Input() mode: string; + @Input() application: string; + @Input() agent: string; + @Input() typeInfo: ITypeInfo[]; + @Input() i18nText: { [key: string]: string }; + @Input() timezone: string; + @Input() dateFormat: string[]; + @Output() outTransactionCount: EventEmitter = new EventEmitter(); + @Output() outSelectArea: EventEmitter = new EventEmitter(); + @Output() outChangeRangeX: EventEmitter = new EventEmitter(); + private unsubscribe: Subject = new Subject(); + private hasError = false; + dataLoaded = false; + scatterChartInstance: ScatterChart = null; + constructor( + private windowRefService: WindowRefService, + private scatterChartInteractionService: ScatterChartInteractionService + ) {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if (this.mode && (this.fromX >= 0) && (this.toX >= 0) && (this.fromY >= 0) && (this.toY >= 0) && this.typeInfo && this.application && this.timezone && this.dateFormat) { + if (this.scatterChartInstance === null) { + this.scatterChartInstance = new ScatterChart( + this.mode, + this.elementScatter.nativeElement, + this.fromX, + this.toX, + this.fromY, + this.toY, + this.typeInfo, + this.application, + this.agent, + this.width, + this.height, + this.timezone, + this.dateFormat + ); + this.addSubscribeForInstance(); + this.addSubscribeForService(); + this.addToWindow(); + } else { + if (changes['timezone'] && changes['timezone'].currentValue) { + this.scatterChartInstance.setTimezone(this.timezone); + this.scatterChartInstance.redraw(); + } + if (changes['dateFormat'] && changes['dateFormat'].currentValue) { + this.scatterChartInstance.setDateFormat(this.dateFormat); + this.scatterChartInstance.redraw(); + } + } + } + } + private addToWindow(): void { + if (this.addWindow) { + if ('scatterChartInstance' in this.windowRefService.nativeWindow === false) { + this.windowRefService.nativeWindow['scatterChartInstance'] = {}; + } + this.windowRefService.nativeWindow['scatterChartInstance'][this.application] = this.scatterChartInstance; + } + } + private addSubscribeForInstance(): void { + this.scatterChartInstance.onSelect$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((area: any) => { + this.outSelectArea.emit(area); + }); + this.scatterChartInstance.onChangeTransactionCount$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((typeCount: any) => { + this.outTransactionCount.emit(typeCount); + }); + this.scatterChartInstance.onChangeRangeX$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((range: any) => { + this.outChangeRangeX.emit(range); + }); + } + private addSubscribeForService(): void { + this.scatterChartInteractionService.onChartData$.pipe( + takeUntil(this.unsubscribe), + filter((dataWrapper: any) => { + return dataWrapper.instanceKey === this.instanceKey ? true : false; + }) + ).subscribe((dataWrapper: {instanceKey: string, data: IScatterData}) => { + this.scatterChartInstance.addData(new ScatterChartDataBlock(dataWrapper.data, this.scatterChartInstance.getTypeManager())); + this.dataLoaded = true; + this.hasError = false; + }); + this.scatterChartInteractionService.onViewType$.pipe( + takeUntil(this.unsubscribe), + filter((data: any) => { + return data.instanceKey === this.instanceKey ? true : false; + }) + ).subscribe((typeCheck: IChangedViewTypeParam) => { + this.scatterChartInstance.changeShowType(typeCheck); + }); + this.scatterChartInteractionService.onChangeYRange$.pipe( + takeUntil(this.unsubscribe), + filter((data: any) => { + return data.instanceKey === this.instanceKey ? true : false; + }) + ).subscribe((yRange: IRangeParam) => { + this.scatterChartInstance.changeYRange(yRange); + }); + this.scatterChartInteractionService.onSelectedAgent$.pipe( + takeUntil(this.unsubscribe), + filter((data: any) => { + return data.instanceKey === this.instanceKey ? true : false; + }) + ).subscribe((data: IChangedAgentParam) => { + this.scatterChartInstance.changeSelectedAgent(data.agent); + }); + this.scatterChartInteractionService.onInvokeDownloadChart$.pipe( + takeUntil(this.unsubscribe), + filter((instanceKey: string) => { + return instanceKey === this.instanceKey ? true : false; + }) + ).subscribe(() => { + this.scatterChartInstance.downloadChartAsImage('png'); + }); + this.scatterChartInteractionService.onReset$.pipe( + takeUntil(this.unsubscribe), + filter((data: any) => { + return data.instanceKey === this.instanceKey ? true : false; + }) + ).subscribe((params: IResetParam) => { + this.hasError = false; + this.dataLoaded = false; + this.application = params.application; + this.agent = params.agent; + this.fromX = params.from; + this.toX = params.to; + this.mode = params.mode; + this.scatterChartInstance.reset(params.application, params.agent, params.from, params.to, params.mode); + this.addToWindow(); + }); + this.scatterChartInteractionService.onError$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((error: IServerErrorFormat) => { + this.hasError = true; + this.dataLoaded = true; + this.scatterChartInstance.reset(this.application, this.agent, this.fromX, this.toX, this.mode); + this.addToWindow(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + hideNoData(): boolean { + if (this.dataLoaded === false) { + return true; + } + if (this.mode === ScatterChart.MODE.REALTIME) { + return true; + } + return this.scatterChartInstance && !this.scatterChartInstance.isEmpty(); + } + getMessage(): string { + return this.hasError ? this.i18nText.FAILED_TO_FETCH_DATA : this.i18nText.NO_DATA; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/search-period/index.ts b/web/src/main/webapp/v2/src/app/core/components/search-period/index.ts new file mode 100644 index 000000000000..ee06fbf443fe --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/search-period/index.ts @@ -0,0 +1,21 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { SearchPeriodContainerComponent } from './search-period-container.component'; +import { SearchPeriodComponent } from './search-period.component'; + +@NgModule({ + declarations: [ + SearchPeriodContainerComponent, + SearchPeriodComponent + ], + imports: [ + SharedModule + ], + exports: [ + SearchPeriodContainerComponent, + SearchPeriodComponent + ], + providers: [] +}) +export class SearchPeriodModule {} diff --git a/web/src/main/webapp/v2/src/app/core/components/search-period/search-period-container.component.css b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period-container.component.css new file mode 100644 index 000000000000..65dd9f6ca2e9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period-container.component.css @@ -0,0 +1,5 @@ +:host { + display: inline-block; + margin-left: 15px; + width: 115px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/search-period/search-period-container.component.html b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period-container.component.html new file mode 100644 index 000000000000..0603bb09033a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period-container.component.html @@ -0,0 +1,5 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/search-period/search-period-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period-container.component.ts new file mode 100644 index 000000000000..bf5582c0e5f4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period-container.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; + +import { Period } from 'app/core/models/period'; +import { UrlPath } from 'app/shared/models'; +import { WebAppSettingDataService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; + +@Component({ + selector: 'pp-search-period-container', + templateUrl: './search-period-container.component.html', + styleUrls: ['./search-period-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SearchPeriodContainerComponent implements OnInit { + periodList: Period[]; + userDefaultPeriod: Period; + + constructor( + private webAppSettingDataService: WebAppSettingDataService, + private analyticsService: AnalyticsService, + ) {} + + ngOnInit() { + this.periodList = this.webAppSettingDataService.getPeriodList(UrlPath.MAIN); + this.userDefaultPeriod = this.webAppSettingDataService.getUserDefaultPeriod(); + } + + onChangeUserDefaultPeriod(value: Period): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SET_SEARCH_PERIOD_IN_CONFIGURATION, value.getValueWithTime()); + this.webAppSettingDataService.setUserDefaultPeriod(value); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/search-period/search-period.component.css b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period.component.css new file mode 100644 index 000000000000..dd1adaee7acc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period.component.css @@ -0,0 +1,25 @@ +:host { + display: block; + position: relative; + width: 100%; +} +.fa-angle-down { + position: absolute; + top: 8px; + right: 8px; + font-size: 15px; +} + +.l-app-select { + width: 100%; + cursor: pointer; + padding: 6px 12px; + background-color: #fff; + border: 1px solid #d7dde4 !important; + border-radius: 0px; + font-size: 13px; + color: #666; + appearance: none; + -webkit-appearance: none; + outline: 0; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/search-period/search-period.component.html b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period.component.html new file mode 100644 index 000000000000..5acd8ea60632 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period.component.html @@ -0,0 +1,4 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/search-period/search-period.component.ts b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period.component.ts new file mode 100644 index 000000000000..037125eaf5d0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/search-period/search-period.component.ts @@ -0,0 +1,24 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { Period } from 'app/core/models/period'; + +@Component({ + selector: 'pp-search-period', + templateUrl: './search-period.component.html', + styleUrls: ['./search-period.component.css'], +}) +export class SearchPeriodComponent implements OnInit { + @Input() periodList: Period[]; + @Input() userDefaultPeriod: Period; + @Output() outChangeUserDefaultPeriod = new EventEmitter(); + + constructor() {} + ngOnInit() {} + + onChangeUserDefaultPeriod(value: Period): void { + this.outChangeUserDefaultPeriod.emit(value); + } + + compareFn(o1: Period, o2: Period): boolean { + return o1 && o2 ? o1.equals(o2) : o1 === o2; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/index.ts b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/index.ts new file mode 100644 index 000000000000..64120fa1ba0b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/index.ts @@ -0,0 +1,27 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MatTooltipModule } from '@angular/material'; +import { ServerAndAgentListComponent } from './server-and-agent-list.component'; +import { ServerAndAgentListContainerComponent } from './server-and-agent-list-container.component'; +import { ServerAndAgentListDataService } from './server-and-agent-list-data.service'; +import { ServerErrorPopupModule } from 'app/core/components/server-error-popup'; + +@NgModule({ + declarations: [ + ServerAndAgentListComponent, + ServerAndAgentListContainerComponent + ], + imports: [ + CommonModule, + ServerErrorPopupModule, + MatTooltipModule + ], + exports: [ + ServerAndAgentListContainerComponent + ], + providers: [ + ServerAndAgentListDataService + ] +}) +export class ServerAndAgentListModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.html new file mode 100644 index 000000000000..27f8cf398229 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.ts new file mode 100644 index 000000000000..770c14ba199d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.ts @@ -0,0 +1,125 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { switchMap, takeUntil, filter } from 'rxjs/operators'; + +import { + NewUrlStateNotificationService, + UrlRouteManagerService, + WebAppSettingDataService, + StoreHelperService, + AnalyticsService, + DynamicPopupService, + TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ServerAndAgentListDataService } from './server-and-agent-list-data.service'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; + +@Component({ + selector: 'pp-server-and-agent-list-container', + templateUrl: './server-and-agent-list-container.component.html', + styleUrls: ['./server-and-agent-list-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ServerAndAgentListContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + filterStr: string; + agentId: string; + serverList: { [key: string]: IServerAndAgentData[] } = {}; + serverKeyList: string[]; + filteredServerList: { [key: string]: IServerAndAgentData[] }; + filteredServerKeyList: string[]; + funcImagePath: Function; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private webAppSettingDataService: WebAppSettingDataService, + private storeHelperService: StoreHelperService, + private serverAndAgentListDataService: ServerAndAgentListDataService, + private dynamicPopupService: DynamicPopupService, + private analyticsService: AnalyticsService, + ) {} + ngOnInit() { + this.funcImagePath = this.webAppSettingDataService.getImagePathMakeFunc(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.END_TIME); + }), + switchMap((urlService: NewUrlStateNotificationService) => { + this.agentId = urlService.hasValue(UrlPathId.AGENT_ID) ? urlService.getPathValue(UrlPathId.AGENT_ID) : ''; + return this.serverAndAgentListDataService.getData(); + }) + ).subscribe((res: {[key: string]: IServerAndAgentData[]}) => { + this.serverKeyList = this.filteredServerKeyList = Object.keys(res).sort(); + this.serverList = this.filteredServerList = res; + if (this.agentId) { + this.dispatchAgentData(); + } + this.changeDetectorRef.detectChanges(); + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent + }); + }); + this.storeHelperService.getServerAndAgentQuery(this.unsubscribe).subscribe((query: string) => { + this.filteringServerList(query); + this.changeDetectorRef.detectChanges(); + }); + } + private dispatchAgentData(): void { + this.serverKeyList.forEach((key: string) => { + this.serverList[key].forEach((agent: IServerAndAgentData) => { + if ( this.agentId === agent.agentId ) { + this.storeHelperService.dispatch(new Actions.UpdateAgentInfo(agent)); + } + }); + }); + } + private filteringServerList(query: string): void { + if ( query === '' ) { + this.filteredServerKeyList = this.serverKeyList; + this.filteredServerList = this.serverList; + } else { + const filteredKeyList: string[] = []; + const filteredServerList: { [key: string]: IServerAndAgentData[] } = {}; + this.serverKeyList.forEach((key: string) => { + let hasKey = false; + this.serverList[key].forEach((agent: IServerAndAgentData) => { + if ( agent.agentId.toLowerCase().indexOf(query.toLowerCase()) !== -1 ) { + if ( hasKey === false ) { + filteredKeyList.push(key); + filteredServerList[key] = []; + hasKey = true; + } + filteredServerList[key].push(agent); + } + }); + }); + this.filteredServerKeyList = filteredKeyList.sort(); + this.filteredServerList = filteredServerList; + } + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + onSelectAgent(agentName: string) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.GO_TO_AGENT_INSPECTOR); + this.urlRouteManagerService.moveOnPage({ + url: [ + UrlPath.INSPECTOR, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + agentName + ] + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-data.service.ts new file mode 100644 index 000000000000..fdc27ee5fe29 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list-data.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; +import { UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService } from 'app/shared/services'; + +@Injectable() +export class ServerAndAgentListDataService { + private url = 'getAgentList.pinpoint'; + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService + ) { } + getData(): Observable { + return this.http.get<{[key: string]: IServerAndAgentData[]}>(this.url, this.makeRequestOptionsArgs()).pipe( + retry(3) + ); + } + private makeRequestOptionsArgs(): any { + return { + params: new HttpParams() + .set('application', this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).applicationName) + .set('from', this.newUrlStateNotificationService.getStartTimeToNumber() + '') + .set('to', this.newUrlStateNotificationService.getEndTimeToNumber() + '') + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list.component.css b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list.component.css new file mode 100644 index 000000000000..a6553c91d9fe --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list.component.css @@ -0,0 +1,66 @@ +.l-servers-list { + height: 100%; + padding: 0 10px; + overflow-y: auto; + overflow-x: hidden; +} +.l-servers-list li { + margin: 15px 0 0 0; + font-size: 13px; +} +.l-servers-list li.first-child { + margin:0; +} +.l-servers-list li.first-child:before { + color: #999; + margin: 0 8px 0 0; + content: '\f0ae'; + font-size: 14px; + font-weight: normal; + font-family: FontAwesome; +} +.l-server-name { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.l-server-name i { + float :left; + margin: 2px 4px 0px 0px; +} +.l-agent-list { + margin: 8px 0 0 10px; +} +.l-agent-list li { + color: #333; + margin: 0px 0px; + display: block; + padding: 4px 4px 4px 10px; + font-size: 12px; + font-weight: 400; + align-items: center; +} +.l-agent-list li:hover { + color: #FFF; + cursor: pointer; + background-color: #418CD3; +} +.l-agent-name { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.l-agent-name i { + float: left; + margin: 4px 4px 0px 0px; +} +.l-icon-alert { + float: right; + margin: 0 0 0 13px; + height: 1em; +} +li.active { + box-shadow: 1px 1px 1px 0px rgba(53,61,117,1); +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list.component.html b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list.component.html new file mode 100644 index 000000000000..f1e72894b462 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list.component.html @@ -0,0 +1,18 @@ +
      +
    • +
      {{serverName}}
      +
        +
      • + +
        + {{agent.agentId}} +
        +
      • +
      +
    • +
    +
      +
    • + There is no agent. +
    • +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list.component.ts new file mode 100644 index 000000000000..1da8aa01f005 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-and-agent-list/server-and-agent-list.component.ts @@ -0,0 +1,37 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-server-and-agent-list', + templateUrl: './server-and-agent-list.component.html', + styleUrls: ['./server-and-agent-list.component.css'] +}) +export class ServerAndAgentListComponent implements OnInit { + @Input() funcImagePath: Function; + @Input() serverKeyList: string[] = []; + @Input() serverList: any = {}; + @Input() agentId: string; + @Output() outSelectAgent: EventEmitter = new EventEmitter(); + constructor() {} + ngOnInit() {} + getIconPath(iconState: number) { + let iconName = ''; + switch (iconState) { + case 200: + case 201: + iconName = 'icon-down'; + break; + case 300: + iconName = 'icon-disconnect'; + break; + case -1: + iconName = 'icon-error'; + break; + default: + break; + } + return this.funcImagePath(iconName); + } + onSelectAgent(agentName: string) { + this.outSelectAgent.emit(agentName); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-error-popup/index.ts b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/index.ts new file mode 100644 index 000000000000..ddf51f5cd0ed --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/index.ts @@ -0,0 +1,21 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ServerErrorPopupComponent } from './server-error-popup.component'; +import { ServerErrorPopupContainerComponent } from './server-error-popup-container.component'; + +@NgModule({ + declarations: [ + ServerErrorPopupComponent, + ServerErrorPopupContainerComponent + ], + imports: [ + CommonModule + ], + entryComponents: [ + ServerErrorPopupContainerComponent + ], + providers: [] +}) +export class ServerErrorPopupModule {} +export * from './server-error-popup-container.component'; diff --git a/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup-container.component.css new file mode 100644 index 000000000000..3c6a97654ec4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup-container.component.css @@ -0,0 +1,18 @@ +:host { + display: block; + background-color: transparent; + width: 100%; + height: 100%; +} + +:host::before { + content: ''; + display: block; + height: 100%; + width: 100%; + background: #000; + opacity: 0.6; + position: absolute; + left: 0; + top: 0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup-container.component.html new file mode 100644 index 000000000000..f4d32bdb4f78 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup-container.component.html @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup-container.component.ts new file mode 100644 index 000000000000..29d84cd69fd8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup-container.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit, AfterViewInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-server-error-popup-container', + templateUrl: './server-error-popup-container.component.html', + styleUrls: ['./server-error-popup-container.component.css'] +}) +export class ServerErrorPopupContainerComponent implements OnInit, AfterViewInit { + @Input() data: any; + @Output() outClose = new EventEmitter(); + @Output() outCreated = new EventEmitter(); + + constructor() {} + ngOnInit() {} + ngAfterViewInit() { + this.outCreated.emit({ coordX: 0, coordY: 0 }); + } + + onClosePopup() { + this.outClose.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup.component.css new file mode 100644 index 000000000000..9e1ef3fc5bb1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup.component.css @@ -0,0 +1,101 @@ +:host { + top: 50%; + left: 50%; + width: 100%; + border: 1px solid #e5e8f0; + display: block; + position: absolute; + min-width: 500px; + max-width: 1000px; + transform: translateX(-50%) translateY(-50%); + text-align: left; + box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.75); + background-color: #fff; +} +.l-title-group { + color: #FFF; + height: auto; + display: flex; + padding: 20px 20px; + position: relative; + font-size: 13px; + font-weight: 600; + align-items: center; + border-bottom: 1px solid #e5e8f0; + justify-content: space-between; + background-color: #d65b65; +} +.l-title-group dt { + font-size: 20px; + font-weight: 600; +} +.l-title-group button { + top: 16px; + right: 20px; + cursor: pointer; + position: absolute; + font-size: 30px; +} +.l-contents-group { + height: 500px; + padding: 17px 18px; + overflow: auto; + background: #f6f8fb; +} +.l-contents { + display: flex; + flex-direction: column; +} +.l-row { + margin: 2px 0px; + padding: 20px 0px; + display: flex; + flex-direction: row; + background-color: #FFF; +} +.l-toggle-btn { + color: #FFF; + display: block; + padding: 6px 10px; + background-color: #D65B65; +} +.l-red { + color: #d65b65; +} +.l-row-header { + width: 15%; + text-align: center; +} +.l-row-content { + width: 85%; +} +.l-row textarea { + width: 95%; + height: 400px; + padding: 4px; + font-size: 14px; + margin-top: 10px; + border: 1px solid #DDD; +} +.l-data-table { + display: flex; + margin-top: 10px; + align-items: center; + flex-direction: column; + background-color: #d65b65; +} +.l-data-table > div { + width: 100%; + margin: 1px 0px 0px 0px; + display: flex; + padding: 10px 0px; + align-items: center; + background-color: #FFF; +} +.l-data-table > div > div:first-child { + width: 25%; + padding-left: 4px; +} +.l-data-table > div > div:last-child { + width: 75%; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup.component.html new file mode 100644 index 000000000000..808bfdd64369 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup.component.html @@ -0,0 +1,54 @@ +
    +
    +
    Server Error
    +
    + +
    +
    +
    +
    +
    Message
    +
    {{errorInfo.exception.message}}
    +
    +
    +
    URL
    +
    {{errorInfo.exception.request.url}}
    +
    +
    +
    Method
    +
    {{errorInfo.exception.request.method}}
    +
    +
    +
    Header
    +
    + +
    +
    +
    {{header.key}}
    +
    {{header.value.join('')}}
    +
    +
    +
    +
    +
    +
    Parameters
    +
    + +
    +
    +
    {{header.key}}
    +
    {{header.value.join('')}}
    +
    +
    +
    +
    +
    +
    StackTrace
    +
    + + +
    +
    + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup.component.ts new file mode 100644 index 000000000000..f2786a311c90 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-error-popup/server-error-popup.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-server-error-popup', + templateUrl: './server-error-popup.component.html', + styleUrls: ['./server-error-popup.component.css'] +}) +export class ServerErrorPopupComponent implements OnInit { + @Input() data: any; + @Output() outClosePopup = new EventEmitter(); + errorInfo: IServerErrorFormat; + showHeader = false; + showParam = false; + showStackTrace = false; + constructor() {} + ngOnInit() { + this.errorInfo = this.data.contents; + } + onClose(): void { + this.outClosePopup.emit(); + } + getState(state: boolean): string { + return state ? 'fa-angle-up' : 'fa-angle-down'; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-list/index.ts b/web/src/main/webapp/v2/src/app/core/components/server-list/index.ts new file mode 100644 index 000000000000..d00c3d4efb2c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-list/index.ts @@ -0,0 +1,24 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +// import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { MatTooltipModule } from '@angular/material'; +import { ServerListComponent } from './server-list.component'; +import { ServerListContainerComponent } from './server-list-container.component'; + +@NgModule({ + declarations: [ + ServerListComponent, + ServerListContainerComponent + ], + imports: [ + CommonModule, + // BrowserAnimationsModule, + MatTooltipModule + ], + exports: [ + ServerListContainerComponent + ], + providers: [] +}) +export class ServerListModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/server-list/server-list-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/server-list/server-list-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list-container.component.html new file mode 100644 index 000000000000..8cd50314b116 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list-container.component.html @@ -0,0 +1,8 @@ + diff --git a/web/src/main/webapp/v2/src/app/core/components/server-list/server-list-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list-container.component.ts new file mode 100644 index 000000000000..e5e7b2b2c430 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list-container.component.ts @@ -0,0 +1,47 @@ +import { Component, OnInit, OnDestroy, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; + +import { WebAppSettingDataService, StoreHelperService } from 'app/shared/services'; + +@Component({ + selector: 'pp-server-list-container', + templateUrl: './server-list-container.component.html', + styleUrls: ['./server-list-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ServerListContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + @Output() outSelectAgent: EventEmitter = new EventEmitter(); + @Output() outOpenInspector: EventEmitter = new EventEmitter(); + serverList: any = {}; + agentData: any = {}; + isWas: boolean; + funcImagePath: Function; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + ) { + this.funcImagePath = this.webAppSettingDataService.getImagePathMakeFunc(); + } + ngOnInit() { + this.storeHelperService.getServerListData(this.unsubscribe).subscribe((agentData: any) => { + if ( agentData && agentData['serverList'] ) { + this.serverList = agentData['serverList']; + this.agentData = agentData['agentHistogram']; + this.isWas = agentData['isWas']; + this.changeDetectorRef.detectChanges(); + } + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + onSelectAgent(agentName: string) { + this.outSelectAgent.emit(agentName); + } + onOpenInspector(agentName: string) { + this.outOpenInspector.emit(agentName); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-list/server-list.component.css b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list.component.css new file mode 100644 index 000000000000..4e3f10d5db9f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list.component.css @@ -0,0 +1,97 @@ +.l-servers-list { + padding: 0 10px; +} +.l-server-name { + display: block; + overflow : hidden; + white-space : nowrap; + text-overflow : ellipsis; +} +.l-servers-list li { + font-size: 13px; + color:#333; + font-weight: 600; +} +.l-servers-list li { + margin: 15px 0 0 0; +} +.l-servers-list li.first-child { + margin:0; +} +.l-servers-list li.first-child:before { + font-family: FontAwesome; + content: '\f0ae'; + font-size: 14px; + margin: 0 8px 0 0; + color: #999; + font-weight: normal; +} +.l-servers-list li .l-category { + margin: 10px 0 0 27px; +} +.l-servers-list li .l-category span { + display: inline-block; + padding: 2px 5px; + font-size: 10px; + color: #fff; + font-weight: 600; +} +.l-servers-list li ul { + margin: 14px 0 0 27px; +} +.l-servers-list li ul li { + font-size: 12px; + color: #666; + font-weight: 400; + height: 20px; + margin: 5px 0px; + color: #999; +} +.l-servers-list li ul li input { + margin: 0 5px; +} +.l-servers-list li ul li div { + float: right; +} +.l-servers-list li ul li label { + display: block; + overflow : hidden; + white-space : nowrap; + text-overflow : ellipsis; +} +.l-servers-list li ul li:hover { + background:#f1f3f7; +} +.l-text-box { + padding: 3px 5px; + font-size: 10px; + color: #FFF; + margin-left: 13px; + background-color: #4b99e3; +} +.l-icon-alert { + height: 1em; +} +.l-servers-list ul li { + height: 30px; +} +.l-servers-list ul span { + cursor: pointer; +} +i.fas { + margin-right: 4px; +} +.l-category { + display: inline-block; + padding: 2px 5px; + font-size: 10px; + color: #fff; + font-weight: 600; + cursor: pointer; +} +.l-category.l-green { + background:#23c6c8; +} +.l-category.l-blue { + background:#5597d5; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-list/server-list.component.html b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list.component.html new file mode 100644 index 000000000000..c834bdb9d05a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list.component.html @@ -0,0 +1,17 @@ +
      +
    • +
      {{ serverName }}
      +
        +
      • +
        + + +
        + +
      • +
      +
    • +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-list/server-list.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list.component.ts new file mode 100644 index 000000000000..b10e66f99e19 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-list/server-list.component.ts @@ -0,0 +1,36 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-server-list', + templateUrl: './server-list.component.html', + styleUrls: ['./server-list.component.css'], +}) +export class ServerListComponent implements OnInit { + @Input() serverList: any = {}; + @Input() agentData: any = {}; + @Input() isWas: boolean; + @Input() funcImagePath: Function; + @Output() outSelectAgent: EventEmitter = new EventEmitter(); + @Output() outOpenInspector: EventEmitter = new EventEmitter(); + isChanged = false; + constructor() {} + ngOnInit() {} + getServerKeys(): string[] { + return Object.keys(this.serverList).sort(); + } + getAgentKeys(serverName: string): string[] { + return Object.keys(this.serverList[serverName]['instanceList']).sort(); + } + hasError(agentName: string): boolean { + return this.agentData[agentName] && this.agentData[agentName]['Error'] > 0; + } + getAlertImgPath(): string { + return this.funcImagePath('icon-alert'); + } + onSelectAgent(agentName: string) { + this.outSelectAgent.emit(agentName); + } + onOpenInspector(agentName: string): void { + this.outOpenInspector.emit(agentName); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/index.ts b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/index.ts new file mode 100644 index 000000000000..25f0f1e020da --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/index.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { ServerMapContextPopupContainerComponent } from 'app/core/components/server-map-context-popup/server-map-context-popup-container.component'; +import { ServerMapContextPopupComponent } from 'app/core/components/server-map-context-popup/server-map-context-popup.component'; + +@NgModule({ + declarations: [ + ServerMapContextPopupContainerComponent, + ServerMapContextPopupComponent + ], + imports: [ + SharedModule + ], + exports: [], + entryComponents: [ + ServerMapContextPopupContainerComponent + ], + providers: [], +}) +export class ServerMapContextPopupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup-container.component.css new file mode 100644 index 000000000000..7f26ddcb5503 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup-container.component.css @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup-container.component.html new file mode 100644 index 000000000000..6d7b441729d3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup-container.component.html @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup-container.component.ts new file mode 100644 index 000000000000..986badbb2be2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup-container.component.ts @@ -0,0 +1,44 @@ +import { Component, OnInit, Input, Output, EventEmitter, AfterViewInit } from '@angular/core'; + +import { ServerMapInteractionService } from 'app/core/components/server-map/server-map-interaction.service'; +import { ServerMapData } from 'app/core/components/server-map/class'; +import { DynamicPopup } from 'app/shared/services/dynamic-popup.service'; + +@Component({ + selector: 'pp-server-map-context-popup-container', + templateUrl: './server-map-context-popup-container.component.html', + styleUrls: ['./server-map-context-popup-container.component.css'] +}) +export class ServerMapContextPopupContainerComponent implements OnInit, AfterViewInit, DynamicPopup { + @Input() data: ServerMapData; + @Input() coord: ICoordinate; + @Output() outCreated = new EventEmitter(); + @Output() outClose = new EventEmitter(); + + constructor( + private serverMapInteractionService: ServerMapInteractionService, + ) {} + + ngOnInit() {} + ngAfterViewInit() { + this.outCreated.emit(this.coord); + } + + onInputChange({coord}: {coord: ICoordinate}): void { + this.outCreated.emit(coord); + } + + onClickMergeCheck(mergeState: IServerMapMergeState): void { + this.serverMapInteractionService.setMergeState(mergeState); + this.outClose.emit(); + } + + onClickRefresh(): void { + this.serverMapInteractionService.setRefresh(); + this.outClose.emit(); + } + + onClickOutside(): void { + this.outClose.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup.component.css new file mode 100644 index 000000000000..afa53b60d74c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup.component.css @@ -0,0 +1,40 @@ +:host { + display: block; +} +ul { + width: 100%; + margin: 0 0; + padding: 0 0; + list-style-type: none; +} +li { + padding: 10px; + list-style: none; +} +.l-one-depth-list > li { + border-bottom: 1px solid #E5E5E5; +} + +.l-one-depth-list > li > div { + padding: 2px 4px; +} + +.l-one-depth-list > li:last-of-type { + border-bottom: none; +} +li.l-selectable-command { + cursor: pointer; +} +li.l-selectable-command:hover { + color: #FFF; + background-color: #4B99E3; +} +.l-two-depth-list { + padding-top: 10px; +} +.l-two-depth-list li { + padding: 2px 4px 2px 14px; +} +.fas { + margin-right: 4px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup.component.html new file mode 100644 index 000000000000..0eab9a24f83f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup.component.html @@ -0,0 +1,11 @@ +
      +
    • +
      Merge
      +
        +
      • + {{key}} +
      • +
      +
    • +
    • Refresh
    • +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup.component.ts new file mode 100644 index 000000000000..460b79b298f5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-context-popup/server-map-context-popup.component.ts @@ -0,0 +1,42 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +import { ServerMapData } from 'app/core/components/server-map/class'; + +@Component({ + selector: 'pp-server-map-context-popup', + templateUrl: './server-map-context-popup.component.html', + styleUrls: ['./server-map-context-popup.component.css'] +}) +export class ServerMapContextPopupComponent implements OnInit { + @Input() data: ServerMapData; + @Output() outClickMergeCheck = new EventEmitter(); + @Output() outClickRefresh = new EventEmitter(); + + mergeNodeStateMap: { [key: string]: boolean }; + objectKeys = Object.keys; + + constructor() {} + ngOnInit() { + this.mergeNodeStateMap = this.data.getMergeState(); + } + + onClickMergeCheck(name: string): void { + this.mergeNodeStateMap[name] = !this.mergeNodeStateMap[name]; + this.outClickMergeCheck.emit({ + name, + state: this.mergeNodeStateMap[name] + }); + } + onClickRefresh(): void { + this.outClickRefresh.emit(); + } + getClassState(key: string): any { + return this.mergeNodeStateMap[key] ? { + fas: true, + 'fa-check-square': true + } : { + far: true, + 'fa-square': true + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-options/index.ts b/web/src/main/webapp/v2/src/app/core/components/server-map-options/index.ts new file mode 100644 index 000000000000..113d5df62677 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-options/index.ts @@ -0,0 +1,20 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { ServerMapOptionsComponent } from './server-map-options.component'; +import { ServerMapOptionsContainerComponent } from './server-map-options-container.component'; + +@NgModule({ + declarations: [ + ServerMapOptionsComponent, + ServerMapOptionsContainerComponent + ], + imports: [ + SharedModule + ], + exports: [ + ServerMapOptionsContainerComponent + ], + providers: [] +}) +export class ServerMapOptionsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options-container.component.css new file mode 100644 index 000000000000..bc32c5675c9f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options-container.component.css @@ -0,0 +1,4 @@ +:host { + display: block; + margin-right: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options-container.component.html new file mode 100644 index 000000000000..bf0dd79b6d2d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options-container.component.html @@ -0,0 +1,11 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options-container.component.ts new file mode 100644 index 000000000000..cfe9bd2bfb67 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options-container.component.ts @@ -0,0 +1,91 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, tap, map } from 'rxjs/operators'; + +import { + WebAppSettingDataService, + NewUrlStateNotificationService, + UrlRouteManagerService, + AnalyticsService, + TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { UrlQuery, UrlPathId } from 'app/shared/models'; + +@Component({ + selector: 'pp-server-map-options-container', + templateUrl: './server-map-options-container.component.html', + styleUrls: ['./server-map-options-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ServerMapOptionsContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + + funcImagePath: Function; + hiddenComponent: boolean; + inboundList: string[]; + outboundList: string[]; + selectedInbound: string; + selectedOutbound: string; + selectedBidirectional: boolean; + selectedWasOnly: boolean; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private analyticsService: AnalyticsService + ) { + this.funcImagePath = this.webAppSettingDataService.getImagePathMakeFunc(); + } + + ngOnInit() { + this.inboundList = this.webAppSettingDataService.getInboundList(); + this.outboundList = this.webAppSettingDataService.getOutboundList(); + + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + tap((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.APPLICATION, UrlPathId.PERIOD, UrlPathId.END_TIME)) { + this.hiddenComponent = false; + } else { + this.hiddenComponent = true; + } + }), + map((urlService: NewUrlStateNotificationService) => { + return { + inbound: urlService.hasValue(UrlQuery.INBOUND) ? urlService.getQueryValue(UrlQuery.INBOUND) : this.webAppSettingDataService.getUserDefaultInbound(), + outbound: urlService.hasValue(UrlQuery.OUTBOUND) ? urlService.getQueryValue(UrlQuery.OUTBOUND) : this.webAppSettingDataService.getUserDefaultOutbound(), + bidirectional: urlService.hasValue(UrlQuery.BIDIRECTIONAL) ? urlService.getQueryValue(UrlQuery.BIDIRECTIONAL) === 'true' : false, + wasOnly: urlService.hasValue(UrlQuery.WAS_ONLY) ? urlService.getQueryValue(UrlQuery.WAS_ONLY) === 'true' : false + }; + }) + ).subscribe(({inbound, outbound, bidirectional, wasOnly}: {inbound: string, outbound: string, bidirectional: boolean, wasOnly: boolean}) => { + this.selectedInbound = inbound; + this.selectedOutbound = outbound; + this.selectedBidirectional = bidirectional; + this.selectedWasOnly = wasOnly; + this.changeDetectorRef.detectChanges(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + onChangeBound(options: { inbound: string, outbound: string, wasOnly: boolean, bidirectional: boolean }): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SET_SERVER_MAP_OPTION, `inbound: ${options.inbound}, outbound: ${options.outbound}, wasOnly: ${options.wasOnly}, bidirectional: ${options.bidirectional}`); + this.urlRouteManagerService.moveOnPage({ + url: [ + this.newUrlStateNotificationService.getStartPath(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ], + queryParam: { + [UrlQuery.INBOUND]: options.inbound, + [UrlQuery.OUTBOUND]: options.outbound, + [UrlQuery.WAS_ONLY]: options.wasOnly, + [UrlQuery.BIDIRECTIONAL]: options.bidirectional + } + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options.component.css new file mode 100644 index 000000000000..e6375865bf3e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options.component.css @@ -0,0 +1,130 @@ +:host { + display: block; + position: relative; + width: 180px; +} +.fa-sign-in-alt, .fa-sign-out-alt { + color: #33b692; +} +button { + outline: none; +} +.l-dropdown-button { + width: 100%; + height: 32px; + border: 1px solid #4488CB; + padding: 4px 0 4px 0; + display: flex; + font-size: 13px; + text-align: left; + align-items: center; + background-color: #fff; +} +.l-dropdown-button .fa-angle-down { + font-size: 15px; + display: inline-block; + margin-left: 16px; + color: #33b692; +} + +.l-bound-text { + display: inline-block; + font-size: 14px; + margin-left: 11px; + color: #333; +} +.l-bound-double-text { + color: #DDD; + font-size: 8px; + text-align: center; + font-weight: 600; +} +.l-bound-double-text.selected { + color: #469ae4; +} + +.l-dropdown-menu-wrapper { + position: absolute; + top: 32px; + left: 0; + z-index: 9999; + display: flex; + flex-wrap: wrap; + border: 1px solid #4488CB; + background-color: #fff; + width: 180px; +} + +.l-inbound-list { + border-right: 1px solid #e5e8f0; +} + +.l-inbound-list, .l-outbound-list { + width: 50%; + text-align: center; +} + +.l-bound-list-item { + font-weight: 400; + color: #333; + font-size: 13px; + padding: 5px 10px; + cursor: pointer; +} + +.l-bound-title { + padding: 5px 10px; + color: #333; + background-color: #edf2f8; + font-weight: 600 !important; + font-size: 12px; + border-bottom: 1px solid #e5e8f0; +} +.l-bidirectional-title { + letter-spacing: -0.5px; +} + +.l-bound-list-item:hover { + background-color: #eee; +} + +.l-bound-list-item.active { + color: #edf2f8; + background-color: #4b99e3; +} +.l-bidirectional-selector { + text-align: center; + color: #469ae4; + margin: 10px; + cursor: pointer; +} +.l-was-only-selector { + text-align: center; + color: #DDD; + margin: 12px 10px 10px 10px; + font-size: 20px; + cursor:pointer; +} +.l-was-only-selector .selected { + color: #469ae4; +} + +.l-button-group-wrapper { + width: 100%; + border-top: 1px solid #e5e8f0; + padding: 6px; + text-align: right; +} +.l-apply-button { + background-color: #4a8fd2; + border: 1px solid #4a8fd2; + padding: 5px 11px; + margin-left: 2px; + color: #fff; +} + +.l-cancel-button { + border: 1px solid #e5e8f0; + padding: 5px 7px; + color: #333; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options.component.html new file mode 100644 index 000000000000..69f9ceb2efd7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options.component.html @@ -0,0 +1,36 @@ +
    + + +
    + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options.component.ts new file mode 100644 index 000000000000..a6e17e651141 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-options/server-map-options.component.ts @@ -0,0 +1,92 @@ +import { Component, EventEmitter, Input, Output, OnInit, OnChanges, SimpleChanges } from '@angular/core'; + +@Component({ + selector: 'pp-server-map-options', + templateUrl: './server-map-options.component.html', + styleUrls: ['./server-map-options.component.css'] +}) +export class ServerMapOptionsComponent implements OnInit, OnChanges { + hideList = true; + prevWasOnly: boolean; + prevBidirectional: boolean; + prevSelectedInbound: string; + prevSelectedOutbound: string; + bidirectionalPath: string; + @Input() funcImagePath: Function; + @Input() selectedWasOnly: boolean; + @Input() selectedBidirectional: boolean; + @Input() selectedInbound: string; + @Input() selectedOutbound: string; + @Input() inboundList: string[]; + @Input() outboundList: string[]; + @Output() outSelected: EventEmitter<{ + inbound: string, + outbound: string, + wasOnly: boolean, + bidirectional: boolean + }> = new EventEmitter(); + + constructor() {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if (changes['selectedBidirectional']) { + this.prevBidirectional = this.selectedBidirectional = changes['selectedBidirectional'].currentValue; + } + if (changes['selectedWasOnly']) { + this.prevWasOnly = this.selectedWasOnly = changes['selectedWasOnly'].currentValue; + } + if (changes['selectedInbound']) { + this.prevSelectedInbound = this.selectedInbound = changes['selectedInbound'].currentValue; + } + if (changes['selectedOutbound']) { + this.prevSelectedOutbound = this.selectedOutbound = changes['selectedOutbound'].currentValue; + } + } + private close(): void { + this.hideList = true; + } + getBidirectional(): string { + return this.funcImagePath('bidirect_' + (this.selectedBidirectional ? 'on' : 'off')); + } + isWasOnlySelected(): boolean { + return this.selectedWasOnly; + } + onChangeWasOnly(): void { + this.selectedWasOnly = !this.selectedWasOnly; + } + onChangeBidirectional(): void { + this.selectedBidirectional = !this.selectedBidirectional; + } + onSelectInbound(inbound: string): void { + this.selectedInbound = inbound; + } + + onSelectOutbound(outbound: string): void { + this.selectedOutbound = outbound; + } + onApply(): void { + if (!(this.selectedInbound === this.prevSelectedInbound && this.selectedOutbound === this.prevSelectedOutbound && this.selectedWasOnly === this.prevWasOnly && this.selectedBidirectional === this.prevBidirectional)) { + this.outSelected.emit({ + inbound: this.selectedInbound, + outbound: this.selectedOutbound, + wasOnly: this.selectedWasOnly, + bidirectional: this.selectedBidirectional + }); + } + this.close(); + } + + onCancel(): void { + this.selectedWasOnly = this.prevWasOnly; + this.selectedBidirectional = this.prevBidirectional; + this.selectedInbound = this.prevSelectedInbound; + this.selectedOutbound = this.prevSelectedOutbound; + this.close(); + } + toggleList(): void { + this.hideList = !this.hideList; + } + onClose(): void { + this.onCancel(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/index.ts b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/index.ts new file mode 100644 index 000000000000..cc8b5a37a936 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/index.ts @@ -0,0 +1,20 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ServerMapSearchResultViewerComponent } from './server-map-search-result-viewer.component'; +import { ServerMapSearchResultViewerContainerComponent } from './server-map-search-result-viewer-container.component'; + +@NgModule({ + declarations: [ + ServerMapSearchResultViewerComponent, + ServerMapSearchResultViewerContainerComponent + ], + imports: [ + CommonModule + ], + exports: [ + ServerMapSearchResultViewerContainerComponent + ], + providers: [] +}) +export class ServerMapSearchResultViewerModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer-container.component.html new file mode 100644 index 000000000000..d67e92f606ff --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer-container.component.html @@ -0,0 +1,7 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer-container.component.ts new file mode 100644 index 000000000000..2e38b66b141b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer-container.component.ts @@ -0,0 +1,68 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Subject, combineLatest, Observable } from 'rxjs'; +import { distinctUntilChanged, filter, map } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; +import { ServerMapInteractionService } from 'app/core/components/server-map/server-map-interaction.service'; +import { ServerMapSearchResultViewerComponent } from './server-map-search-result-viewer.component'; + +@Component({ + selector: 'pp-server-map-search-result-viewer-container', + templateUrl: './server-map-search-result-viewer-container.component.html', + styleUrls: ['./server-map-search-result-viewer-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ServerMapSearchResultViewerContainerComponent implements OnInit { + private minLength = 3; + i18nText: { [key: string]: string } = {}; + hiddenComponent$: Observable; + searchResultList$: Observable; + userInput: Subject = new Subject(); + + constructor( + private translateService: TranslateService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private serverMapInteractionService: ServerMapInteractionService, + private analyticsService: AnalyticsService + ) {} + + ngOnInit() { + this.getI18NText(); + this.hiddenComponent$ = this.newUrlStateNotificationService.onUrlStateChange$.pipe( + map((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.PERIOD, UrlPathId.END_TIME) ? false : true; + }) + ); + this.searchResultList$ = this.serverMapInteractionService.onSearchResult$; + this.userInput.pipe( + distinctUntilChanged(), + filter((query: string) => { + return query.length >= this.minLength; + }) + ).subscribe((query: string) => { + this.serverMapInteractionService.setSearchWord(query); + }); + } + + private getI18NText() { + combineLatest( + this.translateService.get('MAIN.SEARCH_SERVER_MAP_PLACE_HOLDER'), + this.translateService.get('MAIN.EMPTY_RESULT') + ).subscribe((i18n: string[]) => { + this.i18nText = { + [ServerMapSearchResultViewerComponent.I18NTEXT.PLACE_HOLDER]: i18n[0], + [ServerMapSearchResultViewerComponent.I18NTEXT.EMPTY_RESULT]: i18n[1] + }; + }); + } + onSearch($event: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SEARCH_NODE); + this.userInput.next($event); + } + onSelectApplication(app: IApplication): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_APPLICATION_IN_SEARCH_RESULT); + this.serverMapInteractionService.setSelectedApplication(app.getKeyStr()); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer.component.css new file mode 100644 index 000000000000..8722ec0d7084 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer.component.css @@ -0,0 +1,81 @@ +.l-search-group { + background: #fff; + height: 32px; + width: 183px; + color:#b3b3b4; + position:relative; + margin-right: 10px; +} +.l-search-group input { + width: 100%; + height: 100%; + border: 1px solid #d7dde4; + padding: 0 10px 0 10px; +} +.l-search-group input:focus { + border-color:#469ae4; + box-shadow: 0 0 10px -3px #4b99e3; + outline: none; +} +.l-search-group button { + position:absolute; + top: 50%; + right: 10px; + transform: translateY(-50%); +} +.fas { + color:#a8acb5; + font-size:18px; +} +.l-search-div { + position: absolute; + top: 35px; + right: 0px; + width: 231px; + height: 472px; +} +.l-search-div > div { + background-color: #3e506b; + border-bottom: 1px solid #D0D7DF; + padding: 4px 0px 4px 10px; + color: #FFF; +} +.l-search-div > div button { + position: absolute; + top: 13px; + color: white; +} +.l-search-div ul { + top: 26px; + height: 446px; + padding: 15px 10px; +} +.l-search-div li { + cursor: pointer; + padding: 0px 1px; +} +.l-search-div li:hover, .l-search-div li.selected { + color: #FFF; + background-color: #469AE4; +} +.l-search-list { + padding:15px; + background:#f8fafc; + position:absolute; + width:231px; + top: 35px; + right: 0; + overflow-y: auto; + height: 472px; +} +.l-search-list li { + color:#8a939e; + font-size:12px; + margin:8px 0 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.l-search-list li:first-child { + margin:0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer.component.html new file mode 100644 index 000000000000..acb762155cea --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer.component.html @@ -0,0 +1,13 @@ +
    + +
    +
    + Result +
    +
      +
    • {{app.applicationName}}({{app.serviceType}})
    • +
    • {{i18nText.EMPTY_RESULT}}
    • +
    +
    + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer.component.ts new file mode 100644 index 000000000000..40fe842de36e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map-search-result-viewer/server-map-search-result-viewer.component.ts @@ -0,0 +1,47 @@ +import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core'; + +@Component({ + selector: 'pp-server-map-search-result-viewer', + templateUrl: './server-map-search-result-viewer.component.html', + styleUrls: ['./server-map-search-result-viewer.component.css'] +}) +export class ServerMapSearchResultViewerComponent implements OnInit, OnChanges { + static I18NTEXT = { + PLACE_HOLDER: 'PLACE_HOLDER', + EMPTY_RESULT: 'EMPTY_RESULT' + }; + selectedApplication: IApplication; + hiddenList = true; + listCountZero = false; + @Input() i18nText = { + [ServerMapSearchResultViewerComponent.I18NTEXT.PLACE_HOLDER]: 'Favorite List' + }; + @Input() hiddenComponent = true; + @Input() applicationResultList: IApplication[]; + @Output() outSearch: EventEmitter = new EventEmitter(); + @Output() outSelectApplication: EventEmitter = new EventEmitter(); + constructor() {} + ngOnChanges(changes: SimpleChanges) { + if (changes['applicationResultList']) { + if (changes['applicationResultList'].firstChange) { + this.hiddenList = true; + } else { + this.hiddenList = false; + this.listCountZero = this.applicationResultList.length === 0; + } + } + } + ngOnInit() {} + onSearch(query: string): void { + if (query !== '') { + this.outSearch.emit(query); + } + } + onCloseResult() { + this.hiddenList = true; + } + onSelectApplication(application: IApplication): void { + this.selectedApplication = application; + this.outSelectApplication.emit(application); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/index.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/index.ts new file mode 100644 index 000000000000..180cbf58d3a4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/index.ts @@ -0,0 +1,10 @@ +export * from './link-group.class'; +export * from './merge-server-map-data.class'; +export * from './multi-connect-node-group.class'; +export * from './node-group.class'; +export * from './server-map-data.class'; +export * from './server-map-diagram.class'; +export * from './server-map-factory'; +export * from './server-map-template-with-gojs.class'; +export * from './server-map-template'; +export * from './server-map-theme'; diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/link-group.class.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/link-group.class.ts new file mode 100644 index 000000000000..ddc2a6b676b8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/link-group.class.ts @@ -0,0 +1,40 @@ +export class LinkGroup { + SEPERATOR = '~'; + linkData: any; + constructor(private fromNodeKey: string, private toNodeKey: string) { + this.init(); + } + init() { + this.linkData = { + 'key': this.fromNodeKey + this.SEPERATOR + this.toNodeKey, + 'from': this.fromNodeKey, + 'to': this.toNodeKey, + 'hasAlert': false, + 'slowCount': 0, + 'histogram': {}, + 'sourceInfo': {}, + 'targetInfo': [], + 'totalCount': 0, + 'errorCount': 0 + }; + } + addLinkData(link: any): void { + this.linkData.totalCount += link.totalCount; + this.linkData.errorCount += link.errorCount; + this.linkData.slowCount += link.slowCount; + this.linkData.sourceInfo = link.sourceInfo; + if (link.hasAlert) { + this.linkData.hasAlert = link.hasAlert; + } + this.linkData['targetInfo'].push(link); + } + sortLinkData(): LinkGroup { + this.linkData['targetInfo'].sort((v1, v2) => { + return v2.totalCount - v1.totalCount; + }); + return this; + } + getLinkGroupData(): any { + return this.linkData; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/merge-server-map-data.class.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/merge-server-map-data.class.ts new file mode 100644 index 000000000000..e91f642c0cc4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/merge-server-map-data.class.ts @@ -0,0 +1,134 @@ +export class MergeServerMapData { + static mergeNodeData(currentNodeData: INodeInfo, newNodeData: INodeInfo): void { + const old = currentNodeData; + const neo = newNodeData; + + old.hasAlert = neo.hasAlert; + old.slowCount += neo.slowCount; + old.errorCount += neo.errorCount; + old.totalCount += neo.totalCount; + old.instanceCount = Math.max(old.instanceCount, neo.instanceCount); + old.instanceErrorCount = Math.max(old.instanceErrorCount, neo.instanceErrorCount); + + mergeAgentIds(old, neo); + mergeHistogram(old, neo); + mergeAgentHistogram(old, neo); + mergeTimeSeriesHistogram(old, neo); + mergeAgentTimeSeriesHistogramByType(old, neo, 'agentTimeSeriesHistogram'); + mergeServerList(old, neo); + } + static mergeLinkData(currentLinkData: ILinkInfo, newLinkData: ILinkInfo): void { + const old = currentLinkData; + const neo = newLinkData; + + old.hasAlert = neo.hasAlert; + old.slowCount += neo.slowCount; + old.errorCount += neo.errorCount; + old.totalCount += neo.totalCount; + + mergeHistogram(old, neo); + mergeTimeSeriesHistogram(old, neo); + mergeAgentTimeSeriesHistogramByType(old, neo, 'sourceTimeSeriesHistogram'); + mergeHistogramByType(old, neo, 'sourceHistogram'); + mergeHistogramByType(old, neo, 'targetHistogram'); + } +} +function mergeAgentIds(old: INodeInfo, neo: INodeInfo): void { + neo.agentIds.forEach((agentId: string) => { + if (old.agentIds.indexOf(agentId) === -1) { + old.agentIds.push(agentId); + } + }); +} +function mergeHistogram(old: INodeInfo | ILinkInfo, neo: INodeInfo | ILinkInfo): void { + if (neo.histogram) { + if (old.histogram) { + mergeHistogramType(old.histogram, neo.histogram); + } else { + old.histogram = neo.histogram; + } + } +} +function mergeHistogramType(oldHistogram: IResponseTime | IResponseMilliSecondTime, neoHistogram: IResponseTime | IResponseMilliSecondTime): void { + if (neoHistogram) { + Object.keys(neoHistogram).forEach((key: string) => { + oldHistogram[key] += neoHistogram[key]; + }); + } +} +function mergeAgentHistogram(old: INodeInfo, neo: INodeInfo): void { + Object.keys(neo.agentHistogram).forEach((key: string) => { + if (old.agentHistogram[key]) { + mergeHistogramType(old.agentHistogram[key], neo.agentHistogram[key]); + } else { + old.agentHistogram[key] = neo.agentHistogram[key]; + } + }); +} +// 내부 값의 순서가 보장되어야한 유의미한 코드 +function mergeTimeSeriesHistogram(old: INodeInfo | ILinkInfo, neo: INodeInfo | ILinkInfo): void { + if (neo.timeSeriesHistogram) { + if (old.timeSeriesHistogram) { + neo.timeSeriesHistogram.forEach((obj: any, outerIndex: number) => { + obj.values.forEach((chartValue: any, innerIndex: number) => { + old.timeSeriesHistogram[outerIndex].values[innerIndex][1] += chartValue[1]; + }); + }); + } else { + old.timeSeriesHistogram = neo.timeSeriesHistogram; + } + } +} +function mergeAgentTimeSeriesHistogramByType(old: INodeInfo | ILinkInfo, neo: INodeInfo | ILinkInfo, type: string): void { + if (neo[type]) { + if (old[type]) { + Object.keys(neo[type]).forEach((agentId: string) => { + if (old[type][agentId]) { + neo[type][agentId].forEach((obj: any, outerIndex: number) => { + obj.values.forEach((chartValue: any, innerIndex: number) => { + old[type][agentId][outerIndex].values[innerIndex][1] += chartValue[1]; + }); + }); + } else { + old[type][agentId] = neo[type][agentId]; + } + }); + } else { + old[type] = neo[type]; + } + } +} +function mergeServerList(old: INodeInfo, neo: INodeInfo): void { + if (neo.serverList) { + if (old.serverList) { + Object.keys(neo.serverList).forEach((key: string) => { + if (old.serverList[key]) { + Object.keys(neo.serverList[key].instanceList).forEach((instanceKey: string) => { + if ((instanceKey in old.serverList[key].instanceList) === false) { + old.serverList[key].instanceList[instanceKey] = neo.serverList[key].instanceList[instanceKey]; + } + }); + } else { + old.serverList[key] = neo.serverList[key]; + } + }); + } else { + old.serverList = neo.serverList; + } + } +} +function mergeHistogramByType(old: ILinkInfo, neo: ILinkInfo, histogramType: string): void { + if (old[histogramType]) { + Object.keys(neo[histogramType]).forEach((key: string) => { + if (old[histogramType][key]) { + Object.keys(neo[histogramType][key]).forEach((histogramKey: string) => { + old[histogramType][key][histogramKey] += neo[histogramType][key][histogramKey]; + }); + } else { + old[histogramType][key] = neo[histogramType][key]; + } + }); + } else { + old[histogramType] = neo[histogramType]; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/multi-connect-node-group.class.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/multi-connect-node-group.class.ts new file mode 100644 index 000000000000..af75157af158 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/multi-connect-node-group.class.ts @@ -0,0 +1,120 @@ +import { NodeGroup } from './node-group.class'; + +interface ShortCutNode { + key: string; + isWas: boolean; + category: string; + serviceType: string; + mergedNodes: Array; + isAuthorized: boolean; + instanceCount: number; + topCountNodes: Array; + applicationName: string; + mergedSourceNodes: Array; + +} +export class MultiConnectNodeGroup extends NodeGroup { + // KEY_SEPERATOR: string = '^'; + // SEPERATOR: string = '_'; + NAME_PREFIX = 'MULTI_MERGE'; + // GROUP_POSTFIX: string = 'GROUP'; + // TOP_LIST_MAX_COUNT: number = 3; + // applicationName: string; + // groupKey: string; + // groupType: string; + // nodeData: any; + nodeData: ShortCutNode; + subNodeGroup: Array; + subNodeGroupMap: any; + constructor(protected type: string) { + super(type); + // this.init(); + } + init() { + super.init(); + // this.applicationName = this.NAME_PREFIX + this.SEPERATOR + this.randomValue(); + // this.groupType = this.type + this.SEPERATOR + this.GROUP_POSTFIX; + // this.groupKey = this.groupType + this.KEY_SEPERATOR + this.applicationName; + this.subNodeGroup = []; + this.subNodeGroupMap = {}; + } + initTemplateSet() { + this.nodeData = { + 'key': this.groupKey, + 'isWas': false, + 'category': this.groupType, + 'serviceType': this.groupType, + 'mergedNodes': [], + 'isAuthorized': false, + 'instanceCount': 0, + 'topCountNodes': [], + 'applicationName': this.applicationName, + 'mergedSourceNodes': [] + }; + } + // private randomValue(): string { + // return Math.floor(Math.random() * 10000000).toString(); + // } + // private setTopCountNodes(): void { + // this.nodeData['topCountNodes'].length = 0; + // this.nodeData['topCountNodes'].push({ + // 'applicationName': `Total : ${this.nodeData['mergedNodes'].length}`, + // 'totalCount': this.nodeData['mergedNodes'].reduce((preValue, nowNode) => { return preValue + nowNode.totalCount; }, 0), + // 'tableHeader': true + // }); + // for (let i = 0 ; i < Math.min(this.nodeData['mergedNodes'].length, this.TOP_LIST_MAX_COUNT) ; i++ ) { + // this.nodeData['topCountNodes'].push(this.nodeData['mergedNodes'][i]); + // } + // if ( this.nodeData['mergedNodes'].length > this.TOP_LIST_MAX_COUNT ) { + // this.nodeData['topCountNodes'].push({ + // 'applicationName': '...', + // 'totalCount': '' + // }); + // } + // } + // addNodeData(node: any): void { + // delete node.category; + // this.nodeData['instanceCount'] += node.instanceCount; + // this.nodeData['mergedNodes'].push(node); + // } + addSubNodeGroup(key: string): void { + const subNodeGroup = { + group: [], + isLast: false, + applicationName: key + }; + this.subNodeGroupMap[key] = subNodeGroup; + this.subNodeGroup.push(subNodeGroup); + } + addSubNodeGroupData(key: string, link: any): void { + this.subNodeGroupMap[key].group.push({ + key: link.to, + hasAlert: link.hasAlert || false, + totalCount: link.totalCount, + serviceType: link.serviceType, + applicationName: link.targetInfo.applicationName + }); + } + sortNodeData(): MultiConnectNodeGroup { + function fnSort(v1, v2) { + return v2.totalCount - v1.totalCount; + } + this.nodeData['mergedNodes'].sort(fnSort); + this.subNodeGroup.sort(fnSort); + this.subNodeGroup.forEach((subGroup) => { + subGroup['group'].sort(fnSort); + }); + return this; + } + // getGroupKey(): string{ + // return this.groupKey; + // } + // getGroupServiceType(): string { + // return this.groupType; + // } + + // getNodeGroupData(): any { + // this.setTopCountNodes(); + // return this.nodeData; + // } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/node-group.class.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/node-group.class.ts new file mode 100644 index 000000000000..eb8da2525d5d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/node-group.class.ts @@ -0,0 +1,99 @@ +interface ShortCutNode { + key: string; + category: string; + serviceType: string; + mergedNodes: Array; + instanceCount: number; + topCountNodes: Array; + applicationName: string; +} + +const SPECIAL_STR = { + KEY_SEPERATOR: '^', + SEPERATOR: '_', + NAME_PREFIX: 'MERGE', + GROUP_POSTFIX: 'GROUP' +}; +export class NodeGroup { + TOP_LIST_MAX_COUNT = 3; + applicationName: string; + groupKey: string; + groupType: string; + nodeData: ShortCutNode; + static isGroupKey(key: string): boolean { + return new RegExp( + '.*' + + '\\' + SPECIAL_STR.SEPERATOR + + SPECIAL_STR.GROUP_POSTFIX + + '\\' + SPECIAL_STR.KEY_SEPERATOR + + SPECIAL_STR.NAME_PREFIX + + '\\' + SPECIAL_STR.SEPERATOR + + '\\' + 'd{7}$', + 'g' + ).test(key); + } + constructor(protected type: string) { + this.init(); + } + init() { + this.applicationName = SPECIAL_STR.NAME_PREFIX + SPECIAL_STR.SEPERATOR + this.randomValue(); + this.groupType = this.type + SPECIAL_STR.SEPERATOR + SPECIAL_STR.GROUP_POSTFIX; + this.groupKey = this.groupType + SPECIAL_STR.KEY_SEPERATOR + this.applicationName; + this.initTemplateSet(); + } + protected initTemplateSet() { + this.nodeData = { + 'key': this.groupKey, + 'category': this.groupType, + 'mergedNodes': [], + 'serviceType': this.groupType, + 'instanceCount': 0, + 'topCountNodes': [], + 'applicationName': this.applicationName + }; + } + protected randomValue(): string { + return Math.random().toString().slice(2, 9); + } + protected setTopCountNodes(): void { + this.nodeData['topCountNodes'].length = 0; + this.nodeData['topCountNodes'].push({ + 'applicationName': `Total: ${this.nodeData['mergedNodes'].length}`, + 'totalCount': this.nodeData['mergedNodes'].reduce((preValue, nowNode) => { return preValue + nowNode.totalCount; }, 0), + 'tableHeader': true + }); + for (let i = 0; i < Math.min(this.nodeData['mergedNodes'].length, this.TOP_LIST_MAX_COUNT); i++) { + this.nodeData['topCountNodes'].push(this.nodeData['mergedNodes'][i]); + } + if (this.nodeData['mergedNodes'].length > this.TOP_LIST_MAX_COUNT) { + this.nodeData['topCountNodes'].push({ + 'applicationName': '...', + 'totalCount': '' + }); + } + } + addNodeData(node: any): void { + delete node.category; + this.nodeData['instanceCount'] += node.instanceCount; + this.nodeData['mergedNodes'].push(node); + } + sortNodeData(): NodeGroup { + this.nodeData['mergedNodes'].sort((v1, v2) => { + return v2.totalCount - v1.totalCount; + }); + return this; + } + getGroupKey(): string { + return this.groupKey; + } + getType(): string { + return this.type; + } + getGroupServiceType(): string { + return this.groupType; + } + getNodeGroupData(): ShortCutNode { + this.setTopCountNodes(); + return this.nodeData; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-data.class.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-data.class.ts new file mode 100644 index 000000000000..cef9ca2e6c1f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-data.class.ts @@ -0,0 +1,382 @@ +import { NodeGroup } from './node-group.class'; +import { LinkGroup } from './link-group.class'; +import { MultiConnectNodeGroup } from './multi-connect-node-group.class'; +import { Filter } from 'app/core/models'; + +export class ServerMapData { + private nodeList: { [key: string]: any }[]; + private linkList: { [key: string]: any }[]; + private usableNodePropertyInServerMap: string[] = [ + 'key', + 'isWas', + 'isQueue', + 'category', + 'hasAlert', + 'slowCount', + 'histogram', + 'errorCount', + 'totalCount', + 'serviceType', + 'isAuthorized', + 'instanceCount', + 'applicationName' + ]; + private usableLinkPropertyInServerMap: string[] = [ + 'to', + 'key', + 'from', + 'hasAlert', + 'slowCount', + 'targetInfo', + 'totalCount', + 'sourceInfo', + 'errorCount' + ]; + private mergeableServiceType: { [key: string]: boolean } = {}; + private canNotMergeableServiceTypeList: string[] = ['USER']; + private countMap: { [key: string]: any } = {}; + private nodeMap: { [key: string]: any } = {}; + private linkMap: { [key: string]: any } = {}; + private mergeStateMap: { [key: string]: boolean } = {}; + private groupServiceTypeMap: { [key: string]: boolean } = {}; + private originalNodeMap: { [key: string]: INodeInfo } = {}; + private originalLinkMap: { [key: string]: ILinkInfo } = {}; + + constructor( + private originalNodeList: INodeInfo[], + private originalLinkList: ILinkInfo[], + private filters?: Filter[]) { + this.init(); + } + reset(originalNodeList: INodeInfo[], originalLinkList: ILinkInfo[]) { + this.originalNodeList = originalNodeList; + this.originalLinkList = originalLinkList; + this.init(); + } + private init() { + this.convertToMap(); + this.extractUsableData(); + this.extractInboundAndOutboundCountOfEachNode(); + this.extractServiceTypeWhichCanMerge(); + // option set merge + // if ( showMergedStatus ) { + this.mergeGroup(); + this.mergeMultiLinkGroup(); + this.addFilterFlag(); + // } + } + private convertToMap(): void { + console.time('convertTimeToMapFromList'); + this.originalNodeList.forEach((value: INodeInfo) => { + this.originalNodeMap[value.key] = value; + }); + this.originalLinkList.forEach((value: ILinkInfo) => { + this.originalLinkMap[value.key] = value; + }); + console.timeEnd('convertTimeToMapFromList'); + } + private extractUsableData(): void { + this.nodeList = this.extractData(this.originalNodeList, this.usableNodePropertyInServerMap, this.nodeMap); + this.linkList = this.extractData(this.originalLinkList, this.usableLinkPropertyInServerMap, this.linkMap); + } + // extract necessary data from source data. + private extractData(dataList: any[], keys: string[], map: any): any[] { + const necessaryData = []; + dataList.forEach((data) => { + const oNew = {}; + keys.forEach((key) => { + oNew[key] = data[key]; + }); + necessaryData.push(oNew); + map[oNew['key']] = oNew; + }); + return necessaryData; + } + /** + * collect in and out node count of each node + */ + private extractInboundAndOutboundCountOfEachNode(): void { + this.nodeList.forEach((node: any) => { + this.countMap[node.key] = { + inCount: 0, + outCount: 0 + }; + }); + this.linkList.forEach((link: any) => { + this.countMap[link.to].inCount++; + this.countMap[link.from].outCount++; + }); + } + // extract serviceType list which can merge from source data. + private extractServiceTypeWhichCanMerge() { + this.mergeableServiceType = {}; + this.nodeList.forEach((node) => { + if (this.canMergeType(node)) { + this.mergeableServiceType[node.serviceType] = true; + } + }); + } + // @TODO 병합 가능한 serviceType에 대한 조건이 좀 이상한 듯... + // @TODO isQueue는 뭐지? + private canMergeType(nodeData: any): boolean { + return nodeData.isWas === false && nodeData.isQueue === false && this.canNotMergeableServiceTypeList.indexOf(nodeData.serviceType) === -1; + } + private isRootNode(key: string) { + return this.countMap[key].inCount === 0; + } + private isLeafNode(key: string) { + return this.countMap[key].outCount === 0; + } + private mergeGroup(): void { + console.time('mergeGroup()'); + // from 이 동일한 servcieType을 하나의 데이터로 묶음. + const collectMergeLink = {}; + this.linkList.forEach((link) => { + if (this.hasMergeableNode(link) === false) { + return; + } + if ((link.from in collectMergeLink) === false) { + collectMergeLink[link.from] = {}; + } + if ((link.targetInfo.serviceType in collectMergeLink[link.from]) === false) { + collectMergeLink[link.from][link.targetInfo.serviceType] = { + relatedLink: [] + }; + } + // same from-key and same service-type + collectMergeLink[link.from][link.targetInfo.serviceType].relatedLink.push(link); + }); + const removeNodeKeys = {}; + const removeLinkKeys = {}; + for (const nodeKey in collectMergeLink) { + if (collectMergeLink.hasOwnProperty(nodeKey)) { + for (const type in collectMergeLink[nodeKey]) { + if (collectMergeLink[nodeKey][type].relatedLink.length < 2 || this.mergeStateMap[type] === false) { + continue; + } + const nodeGroup = new NodeGroup(type); + const linkGroup = new LinkGroup(nodeKey, nodeGroup.getGroupKey()); + + collectMergeLink[nodeKey][type].relatedLink.forEach((link) => { + nodeGroup.addNodeData(this.nodeMap[link.to]); + linkGroup.addLinkData(link); + removeNodeKeys[link.to] = true; // link.to is key of target node. + removeLinkKeys[link.key] = true; + delete this.nodeMap[link.to]; + delete this.linkMap[link.key]; + }); + this.countMap[nodeGroup.getGroupKey()] = { + inCount: 1, + outCount: 0 + }; + this.nodeList.push(nodeGroup.sortNodeData().getNodeGroupData()); + this.linkList.push(linkGroup.sortLinkData().getLinkGroupData()); + this.groupServiceTypeMap[nodeGroup.getGroupServiceType()] = true; + this.mergeStateMap[type] = true; + } + } + } + this.removeByKey(this.nodeList, removeNodeKeys); + this.removeByKey(this.linkList, removeLinkKeys); + console.timeEnd('mergeGroup()'); + } + private hasMergeableNode(link: any): boolean { + if (this.mergeableServiceType[link.targetInfo.serviceType] !== true) { + return false; + } + if (this.countMap[link.to].inCount !== 1) { + return false; + } + if (this.isLeafNode(link.to) === false) { + return false; + } + return true; + } + setMergeState({name, state}: IServerMapMergeState): void { + this.mergeStateMap[name] = state; + } + resetMergeState(): void { + this.extractUsableData(); + this.mergeGroup(); + this.mergeMultiLinkGroup(); + } + removeByKey(data: any, removeList: any) { + const removeIndex: Array = []; + data.forEach((thing, index) => { + if (removeList[thing.key] === true) { + removeIndex.push(index); + } + }); + removeIndex.sort(function (v1, v2) { + return v1 - v2; + }); + for (let i = removeIndex.length - 1; i >= 0; i--) { + data.splice(removeIndex[i], 1); + } + } + mergeMultiLinkGroup(): void { + console.time('mergeMultiLinkGroup()'); + // 일단 두번째 병합 조건에 해당하는 노드들을 추림 + const targetNodeList = this.getMergeTargetNodes(); + const checkedNodes = {}; + const removeNodeKeys = {}; + const removeLinkKeys = {}; + + targetNodeList.forEach((outerNode) => { + const outerLoopNodeKey = outerNode.key; + if (checkedNodes[outerLoopNodeKey] === true) { + return; + } + checkedNodes[outerLoopNodeKey] = true; + const outerLoopNodeFromKeys: Array = this.getFromNodeKeys(outerLoopNodeKey); + const mergeTargetLinks: any = {}; + const mergeTargetNodeList: Array = []; + + targetNodeList.forEach((innerNode) => { + const innerLoopNodeKey = innerNode.key; + if (checkedNodes[innerLoopNodeKey] === true) { + return; + } + if (outerNode.serviceType !== innerNode.serviceType) { + return; + } + const innerLoopNodeFromKeys: Array = this.getFromNodeKeys(innerLoopNodeKey); + if (this.hasSameNodeList(outerLoopNodeFromKeys, innerLoopNodeFromKeys) === false) { + return; + } + checkedNodes[innerLoopNodeKey] = true; + + this.extractConnectLink(mergeTargetLinks, innerLoopNodeFromKeys, innerLoopNodeKey); + mergeTargetNodeList.push(innerNode); + }); + if (mergeTargetNodeList.length > 0) { + this.extractConnectLink(mergeTargetLinks, outerLoopNodeFromKeys, outerLoopNodeKey); + mergeTargetNodeList.push(outerNode); + + const multiConnectNodeGroup = new MultiConnectNodeGroup(outerNode.serviceType); + mergeTargetNodeList.forEach((node) => { + multiConnectNodeGroup.addNodeData(node); + removeNodeKeys[node.key] = true; + delete this.nodeMap[node.key]; + }); + + for (const fromKey in mergeTargetLinks) { + if (mergeTargetLinks.hasOwnProperty(fromKey)) { + multiConnectNodeGroup.addSubNodeGroup(fromKey); + const linkGroup = new LinkGroup(fromKey, multiConnectNodeGroup.getGroupKey()); + for (let i = 0; i < mergeTargetLinks[fromKey].length; i++) { + const link = mergeTargetLinks[fromKey][i]; + multiConnectNodeGroup.addSubNodeGroupData(fromKey, link); + linkGroup.addLinkData(link); + removeLinkKeys[link.key] = true; + delete this.linkMap[link.key]; + } + this.linkList.push(linkGroup.sortLinkData().getLinkGroupData()); + } + } + this.nodeList.push(multiConnectNodeGroup.sortNodeData().getNodeGroupData()); + this.groupServiceTypeMap[multiConnectNodeGroup.getGroupServiceType()] = true; + } + }); + this.removeByKey(this.nodeList, removeNodeKeys); + this.removeByKey(this.linkList, removeLinkKeys); + console.timeEnd('mergeMultiLinkGroup()'); + } + private extractConnectLink(mergeTargetLinks: any, fromKeys: Array, key: string): void { + fromKeys.forEach((fromKey) => { + if ((fromKey in mergeTargetLinks) === false) { + mergeTargetLinks[fromKey] = []; + } + mergeTargetLinks[fromKey].push(this.linkMap[fromKey + '~' + key]); + }); + } + private getMergeTargetNodes(): any { + const targetNodeList = []; + this.nodeList.forEach((node) => { + if (this.countMap[node.key].outCount > 0) { + return; + } + if (this.countMap[node.key].inCount < 2) { + return; + } + targetNodeList.push(node); + }); + return targetNodeList; + } + private hasSameNodeList(firstNodeList: Array, secondNodeList: Array): boolean { + if (firstNodeList.length !== secondNodeList.length) { + return false; + } + for (let i = 0; i < firstNodeList.length; i++) { + if (secondNodeList.indexOf(firstNodeList[i]) === -1) { + return false; + } + } + return true; + } + private getFromNodeKeys(nodeKey: string): any { + const fromNodeKeys = []; + this.linkList.forEach((link) => { + if (link.to === nodeKey) { + fromNodeKeys.push(link.from); + } + }); + return fromNodeKeys; + } + getNodeList(): { [key: string]: any }[] { + return this.nodeList; + } + getLinkList(): { [key: string]: any }[] { + return this.linkList; + } + getGroupTypes(): Array { + const types: Array = []; + for (const type in this.groupServiceTypeMap) { + if (this.groupServiceTypeMap.hasOwnProperty(type)) { + types.push(type); + } + } + return types; + } + getMergeState(): any { + return Object.keys(this.mergeStateMap).reduce((accumulator, key) => { + accumulator[key] = this.mergeStateMap[key]; + return accumulator; + }, {}); + } + getMergedNodeData(key: string): any { + return this.nodeList.find((node: {[key: string]: any}) => node.key === key); + } + getMergedLinkData(key: string): any { + return this.linkList.find((link: {[key: string]: any}) => link.key === key); + } + getNodeData(key: string): INodeInfo { + return this.originalNodeMap[key]; + } + getLinkData(key: string): ILinkInfo { + return this.originalLinkMap[key]; + } + addFilterFlag(): void { + if (this.filters) { + // this.nodeList.forEach((node: any) => { + // this.filters.forEach((filter: Filter) => { + // if ( filter.getFromKey() === node.key || filter.getToKey() === node.key ) { + // node['isFiltered'] = true; + // return; + // } + // }); + // }); + this.linkList.forEach((link: any) => { + this.filters.forEach((filter: Filter) => { + if (filter.getFromKey() === link.from && filter.getToKey() === link.to) { + link['isFiltered'] = true; + return; + } + }); + }); + } + } + getNodeCount(): number { + return this.nodeList.length; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-diagram-with-gojs.class.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-diagram-with-gojs.class.ts new file mode 100644 index 000000000000..21200401f8d0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-diagram-with-gojs.class.ts @@ -0,0 +1,262 @@ +import * as go from 'gojs'; + +import ServerMapTheme from './server-map-theme'; +import { ServerMapTemplateWithGojs } from './server-map-template-with-gojs.class'; +import { ServerMapDiagram } from './server-map-diagram.class'; +import { ServerMapData } from './server-map-data.class'; +import { IServerMapOption } from './server-map-factory'; + +export class ServerMapDiagramWithGojs extends ServerMapDiagram { + private diagram: go.Diagram = null; + private groupServiceTypeList: string[]; + + constructor( + private option: IServerMapOption + ) { + super(); + ServerMapTheme.general.common.funcServerMapImagePath = this.option.funcServerMapImagePath; + this.makeDiagram(); + this.setNodeDefaultTemplate(); + this.setLinkTemplate(); + this.setDiagramEnvironment(); + this.setEvent(); + } + makeDiagram(): void { + this.diagram = go.GraphObject.make(go.Diagram, this.option.container, { + allowDelete: false, + maxSelectionCount: 1, + initialContentAlignment: go.Spot.Center + }); + this.diagram.animationManager.isEnabled = false; + this.diagram.scrollMode = go.Diagram.InfiniteScroll; + } + setNodeDefaultTemplate(): void { + this.diagram.nodeTemplate = ServerMapTemplateWithGojs.makeNodeTemplate(this); + } + setNodeTemplateMap(): void { + this.groupServiceTypeList.forEach((groupType) => { + this.diagram.nodeTemplateMap.add(groupType, ServerMapTemplateWithGojs.makeNodeGroupTemplate(this)); + }); + } + setLinkTemplate(): void { + this.diagram.linkTemplate = ServerMapTemplateWithGojs.makeLinkTemplate(this); + } + setDiagramEnvironment(): void { + const $ = go.GraphObject.make; + + this.diagram.toolManager.mouseWheelBehavior = go.ToolManager.WheelZoom; + this.diagram.allowDrop = false; + + this.diagram.initialAutoScale = go.Diagram.Uniform; + this.diagram.toolManager.draggingTool.doCancel(); + this.diagram.toolManager.draggingTool.doDeactivate(); + this.diagram.toolManager.dragSelectingTool.isEnabled = false; + this.diagram.initialContentAlignment = go.Spot.Center; + this.diagram.padding = new go.Margin(10, 10, 10, 10); + this.diagram.layout = $( + go.LayeredDigraphLayout, + { + isOngoing: false, + layerSpacing: 100, + columnSpacing: 30, + setsPortSpots: false + } + ); + } + setEvent(): void { + const self = this; + this.diagram.addDiagramListener('InitialLayoutCompleted', (event: go.DiagramEvent) => { + if (self.serverMapData) { + self.outRenderCompleted.emit(event.diagram); + } + }); + this.diagram.addDiagramListener('BackgroundSingleClicked', () => { + self.outClickBackground.emit(); + }); + this.diagram.addDiagramListener('BackgroundDoubleClicked', (event: go.DiagramEvent) => { + event.diagram.zoomToFit(); + self.outDoubleClickBackground.emit('dbclickBackground'); + }); + // this.diagram.addDiagramListener('BackgroundContextClicked', (event: go.DiagramEvent) => { + // console.log('Background context click', event); + // self.outContextClickBackground.emit({ + // event: event + // }); + // }); + this.diagram.addDiagramListener('BackgroundContextClicked', (event: go.DiagramEvent) => { + const { pageX, pageY } = event.diagram.lastInput.event as MouseEvent; + + self.outContextClickBackground.emit({ + coordX: pageX, + coordY: pageY + }); + }); + } + setMapData(serverMapData: ServerMapData, baseApplicationKey = '') { + this.serverMapData = serverMapData; + this.groupServiceTypeList = serverMapData.getGroupTypes(); + this.baseApplicationKey = baseApplicationKey; + this.setNodeTemplateMap(); + + this.diagram.model = go.Model.fromJson({ + nodeDataArray: this.serverMapData.getNodeList(), + linkDataArray: this.serverMapData.getLinkList() + }); + // this.diagram.undoManager.isEnabled = true; + this.selectBaseApplication(); + } + private selectBaseApplication() { + if (this.baseApplicationKey !== '') { + const node = this.diagram.findNodeForKey(this.baseApplicationKey); + if (node) { + const part = this.diagram.findPartForKey(this.baseApplicationKey); + this.diagram.select(part); + this.onClickNodeManually(part); + } + } + } + private onClickNodeManually(obj: go.Part): void { + this.updateHighlights(obj); + this.outClickNode.emit(obj['data']); + } + private updateHighlights(selection: go.Part): void { + this.removeHighlightMark(); + selection['highlight'] = 'self'; + if (selection instanceof go.Node) { + this.addHighlightMarkToLink(selection); + } else if (selection instanceof go.Link) { + this.addHighlightMarkToNode(selection); + } + this.drawHighlight(); + } + private removeHighlightMark(): void { + const allNodes = this.diagram.nodes; + const allLinks = this.diagram.links; + while (allNodes.next()) { + delete allNodes.value['highlight']; + } + while (allLinks.next()) { + delete allLinks.value['highlight']; + } + } + private addHighlightMarkToLink(selection: go.Part) { + const intoLinks = (selection).findLinksInto(); + while (intoLinks.next()) { + intoLinks.value['highlight'] = 'from'; + } + const outofLinks = (selection).findLinksOutOf(); + while (outofLinks.next()) { + outofLinks.value['highlight'] = 'to'; + } + } + private addHighlightMarkToNode(selection: go.Part) { + (selection).fromNode['highlight'] = 'from'; + (selection).toNode['highlight'] = 'to'; + } + private drawHighlight(): void { + const allNodes = this.diagram.nodes; + const allLinks = this.diagram.links; + + while (allNodes.next()) { + this.highlightNode(allNodes.value); + } + while (allLinks.next()) { + this.highlightLink(allLinks.value); + } + } + private highlightNode(targetNode: go.Node): void { + const shape: go.Shape = targetNode.findObject('BORDER_SHAPE'); + const nodeStyle = targetNode['highlight'] ? ServerMapTheme.general.node.highlight : ServerMapTheme.general.node.normal; + + shape['stroke'] = nodeStyle.border.stroke; + shape['strokeWidth'] = nodeStyle.border.strokeWidth; + shape.part.isShadowed = false; + } + private highlightLink(selectedLink: go.Link, theme?: any, toFill?: any): void { + const line: go.Shape = selectedLink.findObject('LINK'); + const arrow: go.Shape = selectedLink.findObject('ARROW'); + const text: go.TextBlock = selectedLink.findObject('LINK_TEXT'); + const linkStyle = selectedLink['highlight'] ? ServerMapTheme.general.link.highlight : ServerMapTheme.general.link.normal; + + line['stroke'] = linkStyle.line.stroke; + arrow['stroke'] = linkStyle.arrow.stroke; + arrow['fill'] = linkStyle.arrow.fill; + text['font'] = linkStyle.fontFamily; + } + isBaseApplication(key: string): boolean { + return this.baseApplicationKey === key; + } + selectNodeBySearch(highlightApplicationKey: string): void { + const node: go.Node = this.searchHighlightNode(highlightApplicationKey); + this.diagram.select(node); + this.diagram.centerRect(node.actualBounds); + this.updateHighlights(node); + this.outClickNode.emit(node['data']); + } + private searchHighlightNode(highlightApplicationKey: string): go.Node { + const allNodes = this.diagram.nodes; + let resultNode: go.Node; + + while (allNodes.next()) { + const node: go.Node = allNodes.value; + if (node.data.mergedNodes) { + const mergedNodes = node.data.mergedNodes; + for (let i = 0; i < mergedNodes.length ; i++ ) { + if (mergedNodes[i].key === highlightApplicationKey) { + resultNode = node; + break; + } + } + } else { + if (node.data.key === highlightApplicationKey) { + resultNode = node; + break; + } + } + } + return resultNode; + } + refresh(): void { + this.diagram.model = go.Model.fromJson({ + nodeDataArray: this.serverMapData.getNodeList(), + linkDataArray: this.serverMapData.getLinkList() + }); + this.diagram.rebuildParts(); + this.selectBaseApplication(); + } + clear(): void { + this.diagram.model = go.Model.fromJson({}); + } + onClickNode(event: go.DiagramEvent, obj: go.GraphObject): void { + this.updateHighlights(obj); + this.outClickNode.emit(obj['data']); + } + onDoubleClickNode(event: go.DiagramEvent, obj: go.GraphObject): void { + console.log('onDoubleClick-Node :', event, obj); + this.diagram.centerRect(obj.actualBounds); + this.diagram.scale *= 1.3; + } + onContextClickNode(event: go.DiagramEvent, obj: go.GraphObject): void { + console.log('onContextClick-Node :', event, obj); + this.outContextClickNode.emit(obj); + } + onClickLink(event: go.DiagramEvent, obj: go.GraphObject): void { + console.log('onClick-Link :', event, obj); + this.updateHighlights(obj); + this.outClickLink.emit(obj['data']); + } + onContextClickLink(event: any, obj: go.GraphObject): void { + const { key, targetInfo } = (obj as go.Link).data; + const { pageX, pageY } = event.event; + + if (!Array.isArray(targetInfo)) { + this.outContextClickLink.emit({ + key, + coord: { + coordX: pageX, + coordY: pageY + } + }); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-diagram-with-visjs.class.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-diagram-with-visjs.class.ts new file mode 100644 index 000000000000..e49f9b130741 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-diagram-with-visjs.class.ts @@ -0,0 +1,306 @@ +import { Network, NodeOptions, EdgeOptions, Color, Node, Edge, Options } from 'vis'; +import { from as fromArray, fromEvent, iif, zip, merge } from 'rxjs'; +import { mergeMap, map, pluck, take, reduce, switchMap } from 'rxjs/operators'; + +import ServerMapTheme from './server-map-theme'; +import { ServerMapDiagram } from './server-map-diagram.class'; +import { ServerMapData } from './server-map-data.class'; +import { IServerMapOption } from './server-map-factory'; +import { ServerMapTemplate } from './server-map-template'; +import { NodeGroup } from './node-group.class'; + +export class ServerMapDiagramWithVisjs extends ServerMapDiagram { + private diagram: Network; + + constructor( + private option: IServerMapOption + ) { + super(); + ServerMapTheme.general.common.funcServerMapImagePath = this.option.funcServerMapImagePath; + this.makeDiagram(); + this.setEvent(); + } + + private makeDiagram(): void { + const container = this.option.container; + const data = { + nodes: [] as Node[], + edges: [] as Edge[] + }; + const options = { + interaction: { + hover: true, + }, + nodes: { + borderWidth: 2.5, + color: { + border: 'transparent', + highlight: { + border: ServerMapTheme.general.node.highlight.border.stroke, + } + } as Color, + labelHighlightBold: false, + shape: 'circularImage', + shapeProperties: { + useBorderWithImage: false, + useImageSize: true + }, + size: 65 + } as NodeOptions, + edges: { + arrows: { + to: { + enabled: true, + scaleFactor: 0.75 + } + }, + // arrowStrikethrough: false, + color: { + color: ServerMapTheme.general.link.normal.line.stroke, + highlight: ServerMapTheme.general.link.highlight.line.stroke + }, + font: { + align: 'horizontal', + size: 18, + background: ServerMapTheme.general.link.normal.textBox.fill, + }, + } as EdgeOptions, + groups: { + main: { + color: { + background: ServerMapTheme.general.node.main.fill.top, + highlight: { + background: ServerMapTheme.general.node.main.fill.top + } + } + }, + normal: { + color: { + background: ServerMapTheme.general.node.normal.fill.top, + highlight: { + background: ServerMapTheme.general.node.normal.fill.top + } + } + } + }, + layout: { + hierarchical: { + enabled: true, + levelSeparation: 300, + nodeSpacing: 235, + // blockShifting: false, + // edgeMinimization: false, + direction: 'LR', + sortMethod: 'directed' + } + }, + physics: { + enabled: false + } + } as Options; + this.diagram = new Network(container, data, options); + } + + private setEvent(): void { + this.diagram.on('afterDrawing', () => { + if (!this.serverMapData) { + return; + } + + this.outRenderCompleted.emit(); + }); + this.diagram.on('click', (({nodes, edges}: {nodes: string[], edges: string[]}) => { + const isNodeClicked = nodes.length !== 0; + const isEdgeClicked = !isNodeClicked && edges.length !== 0; + const isBackgroundClicked = !(isNodeClicked || isEdgeClicked); + + if (isNodeClicked) { + const nodeId = nodes[0]; + const nodeData = this.getNodeData(nodeId); + + this.outClickNode.emit(nodeData); + } else if (isEdgeClicked) { + const edgeId = edges[0]; + const linkData = this.getLinkData(edgeId); + + this.outClickLink.emit(linkData); + } else if (isBackgroundClicked) { + this.outClickBackground.emit(); + } + })); + this.diagram.on('hoverNode', () => this.changeCursor('pointer')); + this.diagram.on('hoverEdge', () => this.changeCursor('pointer')); + this.diagram.on('blurNode', () => this.changeCursor('default')); + this.diagram.on('blurEdge', () => this.changeCursor('default')); + this.diagram.on('oncontext', (({event, pointer}: {event: MouseEvent, pointer: {[key: string]: any}}) => { + event.preventDefault(); + const { x, y } = pointer.DOM; + const nodeId = this.diagram.getNodeAt({x, y}) as string; + const edgeId = this.diagram.getEdgeAt({x, y}) as string; + + if (nodeId || NodeGroup.isGroupKey(edgeId)) { + return; + } + + edgeId ? ( + this.outContextClickLink.emit({ + key: edgeId, + coord: { + coordX: x, + coordY: y + } + }) + ) : ( + this.outContextClickBackground.emit({ + coordX: x, + coordY: y + }) + ); + })); + } + + setMapData(serverMapData: ServerMapData, baseApplicationKey = ''): void { + const nodeList = serverMapData.getNodeList(); + const isDataEmpty = nodeList.length === 0; + + if (isDataEmpty) { + return; + } + + const edges = serverMapData.getLinkList().map((link: {[key: string]: any}) => { + const { from, to, key, totalCount, isFiltered, hasAlert } = link; + + return { + from, + to, + id: key, + // [임시]label에서 이미지를 지원하지않아서, filteredMap페이지에서 필터아이콘을 "Filtered" 텍스트로 대체. + label: isFiltered ? ` [Filtered]\n${totalCount.toLocaleString()} ` : ` ${totalCount.toLocaleString()} `, + font: { + color: hasAlert ? ServerMapTheme.general.link.normal.fontColor.alert : ServerMapTheme.general.link.normal.fontColor.normal + } + }; + }); + + fromArray(nodeList).pipe( + mergeMap((node: {[key: string]: any}) => { + const { key, applicationName, serviceType, isAuthorized, topCountNodes, hasAlert } = node; + const isMergedNode = NodeGroup.isGroupKey(key); + const serviceTypeImg = new Image(); + + serviceTypeImg.src = ServerMapTheme.general.common.funcServerMapImagePath(serviceType); + + const serviceTypeImgLoadEvent$ = merge( + fromEvent(serviceTypeImg, 'load'), + fromEvent(serviceTypeImg, 'error').pipe( + switchMap(() => { + // 해당 serviceType 이름의 이미지가 없을 경우, NO_IMAGE_FOUND 이미지로 대체 + const tempImg = new Image(); + + tempImg.src = ServerMapTheme.general.common.funcServerMapImagePath('NO_IMAGE_FOUND'); + return fromEvent(tempImg, 'load'); + }) + ) + ); + const innerObs$ = iif(() => hasAlert && isAuthorized, + (() => { + const alertImg = new Image(); + + alertImg.src = ServerMapTheme.general.common.funcServerMapImagePath(ServerMapTheme.general.common.icon.error); + return zip( + serviceTypeImgLoadEvent$.pipe(pluck('target')), + fromEvent(alertImg, 'load').pipe(pluck('target')) + ); + })(), + serviceTypeImgLoadEvent$.pipe(map((v: Event) => [v.target])) + ); + + return innerObs$.pipe( + map((img: HTMLImageElement[]) => { + const svg = ServerMapTemplate.getSVGString(img, node); + + return 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg); + }), + map((image: string) => { + return { + id: key, + label: isMergedNode ? this.getMergedNodeLabel(topCountNodes) : applicationName, + image, + group: key === baseApplicationKey ? 'main' : 'normal' + }; + }) + ); + }), + take(nodeList.length), + reduce((acc: Node[], curr: Node) => { + return [...acc, curr]; + }, [] as Node[]), + ).subscribe((nodes: Node[]) => { + this.diagram.setData({nodes, edges}); + this.serverMapData = serverMapData; + this.baseApplicationKey = baseApplicationKey; + this.selectBaseApplication(); + }); + } + + private getMergedNodeLabel(topCountNodes: {[key: string]: any}[]): string { + // [임시] 일단은 "Total: 4(Merge된 노드 개수)"만 표시 + return topCountNodes[0].applicationName; + } + + private getNodeData(key: string): {[key: string]: any} { + return NodeGroup.isGroupKey(key) ? this.serverMapData.getMergedNodeData(key) : this.serverMapData.getNodeData(key); + } + + private getLinkData(key: string): {[key: string]: any} { + return NodeGroup.isGroupKey(key) ? this.serverMapData.getMergedLinkData(key) : this.serverMapData.getLinkData(key); + } + + private selectBaseApplication(): void { + const key = this.baseApplicationKey; + + if (key === '' || !this.isNodeInDiagram(key)) { + return; + } + + this.setNodeClicked(key); + } + + private isNodeInDiagram(key: string): boolean { + return this.diagram.findNode(key).length !== 0; + } + + private setNodeClicked(key: string): void { + this.diagram.selectNodes([key]); + this.outClickNode.emit(this.getNodeData(key)); + } + + private changeCursor(cursorStyle: string): void { + this.option.container.querySelector('canvas').style.cursor = cursorStyle; + } + + refresh(): void { + this.setMapData(this.serverMapData, this.baseApplicationKey); + } + + clear(): void { + this.diagram.destroy(); + } + + selectNodeBySearch(selectedAppKey: string): void { + let selectedNodeId = selectedAppKey; + const isMergedNode = !this.isNodeInDiagram(selectedAppKey); + + if (isMergedNode) { + const groupKey = selectedAppKey.split('^')[1]; + const selectedMergedNode = this.serverMapData.getNodeList().find(({key}: {key: string}) => { + return NodeGroup.isGroupKey(key) && key.includes(groupKey); + }); + + selectedNodeId = selectedMergedNode.key; + } + + this.diagram.focus(selectedNodeId); + this.setNodeClicked(selectedNodeId); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-diagram.class.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-diagram.class.ts new file mode 100644 index 000000000000..d1ba06f102c2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-diagram.class.ts @@ -0,0 +1,51 @@ +import { EventEmitter } from '@angular/core'; + +import { ServerMapData } from './server-map-data.class'; +import { NodeGroup } from './node-group.class'; +import { Application } from 'app/core/models'; + +export abstract class ServerMapDiagram { + protected serverMapData: ServerMapData; + protected baseApplicationKey: string; + + outClickNode: EventEmitter = new EventEmitter(); + outClickGroupNode: EventEmitter = new EventEmitter(); + outContextClickNode: EventEmitter = new EventEmitter(); + outClickLink: EventEmitter = new EventEmitter(); + outContextClickLink: EventEmitter = new EventEmitter(); + outClickBackground: EventEmitter = new EventEmitter(); + outContextClickBackground: EventEmitter = new EventEmitter(); + outDoubleClickBackground: EventEmitter = new EventEmitter(); + outRenderCompleted: EventEmitter = new EventEmitter(); + + abstract setMapData(mapData: ServerMapData, baseApplicationKey?: string): void; + abstract selectNodeBySearch(appKey: string): void; + abstract refresh(): void; + abstract clear(): void; + + searchNode(query: string): IApplication[] { + return this.serverMapData.getNodeList() + .reduce((prev: {[key: string]: any}[], curr: {[key: string]: any}) => { + const { key, mergedNodes } = curr; + + return NodeGroup.isGroupKey(key) ? [...prev, ...mergedNodes] : [...prev, curr]; + }, []) + .filter(({applicationName}: {applicationName: string}) => { + const regCheckQuery = new RegExp(query, 'i'); + + return regCheckQuery.test(applicationName); + }) + .map(({key, applicationName, serviceType}: {key: string, applicationName: string, serviceType: string}) => { + return new Application(applicationName, serviceType, 0, key); + }); + } + + setMergeState(mergeState: IServerMapMergeState): void { + this.serverMapData.setMergeState(mergeState); + } + + resetMergeState(): void { + this.serverMapData.resetMergeState(); + this.refresh(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-factory.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-factory.ts new file mode 100644 index 000000000000..fdeebc4c7d92 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-factory.ts @@ -0,0 +1,26 @@ +import { InjectionToken } from '@angular/core'; + +import { ServerMapDiagram } from 'app/core/components/server-map/class/server-map-diagram.class'; +import { ServerMapDiagramWithGojs } from 'app/core/components/server-map/class/server-map-diagram-with-gojs.class'; +import { ServerMapDiagramWithVisjs } from 'app/core/components/server-map/class/server-map-diagram-with-visjs.class'; + +export const SERVER_MAP_TYPE = new InjectionToken('server-map-type'); +export const enum ServerMapType { + GOJS = 'gojs', + VISJS = 'visjs' +} +export interface IServerMapOption { + container: HTMLElement; + funcServerMapImagePath: Function; +} + +export class ServerMapFactory { + static createServerMap(type: ServerMapType, option: IServerMapOption): ServerMapDiagram { + switch (type) { + case ServerMapType.GOJS: + return new ServerMapDiagramWithGojs(option); + case ServerMapType.VISJS: + return new ServerMapDiagramWithVisjs(option); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-template-with-gojs.class.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-template-with-gojs.class.ts new file mode 100644 index 000000000000..51d59e2b99ab --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-template-with-gojs.class.ts @@ -0,0 +1,635 @@ +import * as go from 'gojs'; +import ServerMapTheme from './server-map-theme'; + +export class ServerMapTemplateWithGojs { + public static NO_IMAGE_FOUND = 'NO_IMAGE_FOUND'; + public static circleMaxSize = 360; + public static circleMinPercentage = 5; + public static calcuResponseSummaryCircleSize(sum: number, value: number) { + let size = 0; + if (value === 0) { + return 0; + } + const percentage = (value * 100) / sum; + if (percentage < ServerMapTemplateWithGojs.circleMinPercentage) { + size = Math.floor((ServerMapTemplateWithGojs.circleMaxSize * ServerMapTemplateWithGojs.circleMinPercentage) / 100); + } else { + size = Math.floor((ServerMapTemplateWithGojs.circleMaxSize * percentage) / 100); + } + return size; + } + public static makeNodeTemplate(serverMapComponent: any) { + /* + template structure + Node + Panel.Auto + Shape + Panel.Table + Shape ( row: 0 ) - background + Picture ( row: 0, col: 0 ) - icon + Shape ( row: 0, col: 0 ) - red circle + Shape( yellow circle ) + Shape( green circle) + Shape ( row: 1 ) - background + TextBlock ( applicationName ) + Panel.Auto + Shape + TextBlock ( instance count ) + Panel.Vertical + Picture ( error.png ) + Picture ( filter.png ) + */ + const $ = go.GraphObject.make; + return $( + go.Node, + go.Panel.Auto, + { + position: new go.Point(0, 0), + selectionAdorned: false, + click: function (event: go.DiagramEvent, obj: go.GraphObject) { + serverMapComponent.onClickNode(event, obj); + }, + doubleClick: function(event: go.DiagramEvent, obj: go.GraphObject) { + serverMapComponent.onDoubleClickNode(event, obj); + }, + contextClick: function(event: go.DiagramEvent, obj: go.GraphObject) { + serverMapComponent.onContextClickNode(event, obj); + } + }, + new go.Binding('key', 'key'), + new go.Binding('category', 'serviceType'), + $( + go.Shape, + 'Rectangle', + { + name: 'BORDER_SHAPE', + stroke: '#D0D7DF', + strokeWidth: 0, + portId: '', + fromLinkable: true, fromLinkableSelfNode: true, fromLinkableDuplicates: true, + toLinkable: true, toLinkableSelfNode: true, toLinkableDuplicates: true, + } + ), + $( + go.Panel, + go.Panel.Table, + { + cursor: 'pointer' + // locationSpot: go.Spot.Center, + // selectionAdorned: false, + }, + // new go.Binding('scale', 'isSelected', (isSelected) => { + // return isSelected ? 1.2 : 1.0; + // }).ofObject(), + $(go.RowColumnDefinition, {column: 0, minimum: 140}), + $( + go.Shape, + 'Rectangle', + { + row: 0, + column: 0, + height: 95, + stretch: go.GraphObject.Horizontal, + }, + new go.Binding('fill', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].fill.top; + }), + new go.Binding('stroke', 'key', function(key, node) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].stroke; + }), + new go.Binding('strokeWidth', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].strokeWidth; + }) + ), + $( + go.Picture, + { + row: 0, + column: 0, + width: 90, + height: 90, + imageStretch: go.GraphObject.Uniform, + errorFunction: function(e: any) { + e.source = ServerMapTheme.general.common.funcServerMapImagePath(ServerMapTemplateWithGojs.NO_IMAGE_FOUND); + } + }, + new go.Binding('source', 'serviceType', function (type) { + return ServerMapTheme.general.common.funcServerMapImagePath(type); + }) + ), + $( + go.Shape, { + row: 0, + column: 0, + stroke: ServerMapTheme.general.circle.bad.stroke, + strokeWidth: ServerMapTheme.general.circle.bad.strokeWidth + }, + new go.Binding('visible', '', function (data) { + return data.isAuthorized && data.isWas; + }), + new go.Binding('geometry', 'histogram', function (histogram) { + return go.Geometry.parse('M30 0 B270 360 30 30 30 30'); + }) + ), + $( + go.Shape, { + row: 0, + column: 0, + stroke: ServerMapTheme.general.circle.slow.stroke, + strokeWidth: ServerMapTheme.general.circle.slow.strokeWidth + }, + new go.Binding('visible', '', function (data) { + return data.isAuthorized && data.isWas; + }), + new go.Binding('geometry', 'histogram', function (histogram) { + if (histogram['Slow'] === 0) { + return go.Geometry.parse('M30 0'); + } + const sum = Object.keys(histogram).reduce((prevSum: number, curKey: string) => { + return prevSum + histogram[curKey]; + }, 0); + return go.Geometry.parse('M30 0 B270 ' + (ServerMapTemplateWithGojs.circleMaxSize - ServerMapTemplateWithGojs.calcuResponseSummaryCircleSize(sum, histogram['Error'])) + ' 30 30 30 30'); + }) + ), + $( + go.Shape, { + row: 0, + column: 0, + stroke: ServerMapTheme.general.circle.good.stroke, + strokeWidth: ServerMapTheme.general.circle.good.strokeWidth + }, + new go.Binding('visible', '', function (data) { + return data.isAuthorized && data.isWas; + }), + new go.Binding('geometry', 'histogram', function (histogram) { + const sum = Object.keys(histogram).reduce((prevSum: number, curKey: string) => { + return prevSum + histogram[curKey]; + }, 0); + const size = ServerMapTemplateWithGojs.circleMaxSize - ServerMapTemplateWithGojs.calcuResponseSummaryCircleSize(sum, histogram['Slow']) - ServerMapTemplateWithGojs.calcuResponseSummaryCircleSize(sum, histogram['Error']); + if (size >= 180) { + return go.Geometry.parse('M30 0 B270 ' + size + ' 30 30 30 30'); + } else { + return go.Geometry.parse('M30 -60 B270 ' + size + ' 30 -30 30 30'); + } + }) + ), + $( + go.Shape, + 'Rectangle', + { + row: 1, + column: 0, + height: 34, + margin: new go.Margin(-1, 0, 0, 0), + stretch: go.GraphObject.Horizontal, + }, + new go.Binding('fill', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].fill.bottom; + }), + new go.Binding('stroke', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].stroke; + }), + new go.Binding('strokeWidth', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].strokeWidth; + }) + ), + $( + go.TextBlock, + { + row: 1, + column: 0, + margin: new go.Margin(0, 10, 0, 10) + }, + new go .Binding('font', '', function() { + return ServerMapTheme.general.common.font.normal; + }), + new go .Binding('stroke', '', function() { + return ServerMapTheme.general.node.normal.text.stroke; + }), + new go.Binding('text', 'applicationName') + ), + $( + go.Panel, + go.Panel.Auto, + { + minSize: new go.Size(20, 20), + alignment: go.Spot.TopRight + }, + new go.Binding('visible', 'instanceCount', function (v) { + return v > 1 ? true : false; + }), + $( + go.Shape, + { + figure: 'Rectangle' + }, + new go .Binding('fill', '', function() { + return ServerMapTheme.general.instance.shape.fill; + }), + new go .Binding('stroke', '', function() { + return ServerMapTheme.general.instance.shape.stroke; + }), + new go .Binding('strokeWidth', '', function() { + return ServerMapTheme.general.instance.shape.strokeWidth; + }) + ), + $( + go.TextBlock, + { + height: 20, + editable: false, + textAlign: 'center', + verticalAlignment: go.Spot.Center + }, + new go .Binding('font', '', function() { + return ServerMapTheme.general.common.font.small; + }), + new go .Binding('stroke', '', function() { + return ServerMapTheme.general.instance.text.stroke; + }), + new go.Binding('text', 'instanceCount') + ) + ), + $( + go.Panel, + go.Panel.Vertical, + { + margin: new go.Margin(0, 0, 0, 0), + alignment: go.Spot.TopLeft + }, + $( + go.Picture, + { + width: 20, + height: 20, + source: ServerMapTheme.general.common.funcServerMapImagePath(ServerMapTheme.general.common.icon.error), + imageStretch: go.GraphObject.Uniform + }, + new go.Binding('visible', '', function (data) { + return data.isAuthorized && data.hasAlert; + }) + ), + $( + go.Picture, + { + width: 28, + height: 28, + source: ServerMapTheme.general.common.funcServerMapImagePath(ServerMapTheme.general.common.icon.filter), + visible: false, + imageStretch: go.GraphObject.Uniform + }, + new go.Binding('visible', 'isFiltered') + ) + ) + ) + ); + } + public static makeNodeGroupTemplate(serverMapComponent: any) { + /* + template structure + Node + Panel.Auto + Shape + Panel.Table + Shape ( row: 0, col: 0 ) - background + Button + Picture ( row: 1, col: 0 ) - icon + Shape ( row: 1, col: 0 ) - background + Panel.Vertical( row: 1, col: 0 ) : bind>mergedNodes + Panel.Table + Panel.TableRow + Picture ( Error.png ) + TextBlock ( index ) + TextBlock ( applicationName ) + TextBlock ( totalCount ) + + Panel.Vertical( row: 1, col: 0 ) : bind>mergedMultiSourceNodes + Panel.Vertical + TextBlock - applicaitonName + Panel.Table : bind>group + Panel.TableRow + Picture ( Error.png ) + TextBlock ( index ) + TextBlock ( applicationName ) + TextBlock ( totalCount ) + Panel + Shape + TextBlock ( instaceCount ) + */ + const $ = go.GraphObject.make; + const groupTableTemplate = $( + go.Panel, + go.Panel.TableRow, + $( + go.Picture, { + column: 1, + source: ServerMapTheme.general.common.funcServerMapImagePath(ServerMapTheme.general.common.icon.error), + margin: new go.Margin(1, 2), + visible: false, + desiredSize: new go.Size(10, 10), + imageStretch: go.GraphObject.Uniform + }, + new go.Binding('visible', 'hasAlert') + ), + $( + go.TextBlock, { + name: 'NODE_APPLICATION_NAME', + font: ServerMapTheme.general.common.font.small, + margin: new go.Margin(1, 2), + column: 2, + alignment: go.Spot.Left + }, + new go.Binding('stroke', 'tableHeader', function( tableHeader ) { + return tableHeader === true ? '#1BABF4' : '#000'; + }), + new go.Binding('text', 'applicationName') + ), + $( + go.TextBlock, { + font: ServerMapTheme.general.common.font.small, + margin: new go.Margin(1, 2), + column: 3, + alignment: go.Spot.Right + }, + new go.Binding('text', 'totalCount', function (val) { + return val === '' ? '' : parseInt(val, 10).toLocaleString(); + }) + ) + ); + return $( + go.Node, + go.Panel.Auto, + { + position: new go.Point(0, 0), + selectionAdorned: false, + click: function (event: go.DiagramEvent, obj: go.GraphObject) { + serverMapComponent.onClickNode(event, obj); + }, + doubleClick: function(event: go.DiagramEvent, obj: go.GraphObject) { + serverMapComponent.onDoubleClickNode(event, obj); + }, + contextClick: function(event: go.DiagramEvent, obj: go.GraphObject) { + serverMapComponent.onContextClickNode(event, obj); + } + }, + $( + go.Shape, + 'Rectangle', + { + name: 'BORDER_SHAPE', + fill: '#FFF', + stroke: '#D0D7DF', + strokeWidth: 0 + } + ), + $( + go.Panel, + go.Panel.Table, + { + cursor: 'pointer' + }, + $(go.RowColumnDefinition, {row: 0, column: 0, width: 140, height: 95}), + $(go.RowColumnDefinition, {row: 1, minimum: 30, stretch: go.GraphObject.Fill}), + $( + go.Shape, + 'Rectangle', + { + row: 0, + name: 'TOP_RECT', + column: 0, + height: 95, + strokeWidth: 1, + stretch: go.GraphObject.Horizontal, + stroke: '#D0D7DF' + }, + new go.Binding('fill', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].fill.top; + }), + new go.Binding('stroke', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].stroke; + }), + new go.Binding('strokeWidth', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].strokeWidth; + }) + ), + $( + go.Picture, + { + row: 0, + column: 0, + width: 90, + height: 90, + imageStretch: go.GraphObject.Uniform, + errorFunction: function(e: any) { + e.source = ServerMapTheme.general.common.funcServerMapImagePath(ServerMapTemplateWithGojs.NO_IMAGE_FOUND); + } + }, + new go.Binding('source', 'serviceType', function (type) { + return ServerMapTheme.general.common.funcServerMapImagePath(type); + }) + ), + $( + go.Shape, + 'Rectangle', + { + row: 1, + name: 'BOTTOM_RECT', + column: 0, + margin: new go.Margin(-1, 0, 0, 0), + minSize: new go.Size(140, 30), + stretch: go.GraphObject.Fill + }, + new go.Binding('fill', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].fill.bottom; + }), + new go.Binding('stroke', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].stroke; + }), + new go.Binding('strokeWidth', 'key', function(key) { + const type = serverMapComponent.isBaseApplication(key) ? 'main' : 'normal'; + return ServerMapTheme.general.node[type].strokeWidth; + }) + ), + $( + go.Panel, + go.Panel.Vertical, { + row: 1, + column: 0, + margin: new go.Margin(3, 0, 3, 0), + minSize: new go.Size(138, NaN), + alignment: go.Spot.TopLeft, + alignmentFocus: go.Spot.TopLeft + }, + $( + go.Panel, + go.Panel.Table, { + padding: 6, + visible: true, + minSize: new go.Size(138, NaN), + itemTemplate: groupTableTemplate, + defaultStretch: go.GraphObject.Horizontal + }, + new go.Binding('itemArray', 'topCountNodes') + ) + ), + $( + go.Panel, + go.Panel.Auto, + { + minSize: new go.Size(20, 20), + alignment: go.Spot.TopRight + }, + new go.Binding('visible', 'instanceCount', function (v) { + return v > 1 ? true : false; + }), + $( + go.Shape, + { + figure: 'Rectangle' + }, + new go .Binding('fill', '', function() { + return ServerMapTheme.general.instance.shape.fill; + }), + new go .Binding('stroke', '', function() { + return ServerMapTheme.general.instance.shape.stroke; + }), + new go .Binding('strokeWidth', '', function() { + return ServerMapTheme.general.instance.shape.strokeWidth; + }) + ), + $( + go.TextBlock, + { + height: 20, + editable: false, + textAlign: 'center', + verticalAlignment: go.Spot.Center + }, + new go .Binding('font', '', function() { + return ServerMapTheme.general.common.font.small; + }), + new go .Binding('stroke', '', function() { + return ServerMapTheme.general.instance.text.stroke; + }), + new go.Binding('text', 'instanceCount') + ) + ) + ) + ); + } + public static makeLinkTemplate(serverMapComponent: any) { + const $ = go.GraphObject.make; + return $( + go.Link, + { + corner: 10, + cursor: 'pointer', + layerName: 'Foreground', + reshapable: false, + selectionAdorned: false, + click: function (event: go.DiagramEvent, obj: go.GraphObject) { + serverMapComponent.onClickLink(event, obj); + }, + doubleClick: function(event: go.DiagramEvent, obj: go.GraphObject) { + serverMapComponent.onDoubleClickLink(event, obj); + }, + contextClick: function (event: go.DiagramEvent, obj: go.GraphObject) { + serverMapComponent.onContextClickLink(event, obj); + } + }, + $( + go.Shape, + { + name: 'LINK', + stroke: ServerMapTheme.general.link.normal.line.stroke, + isPanelMain: true, + strokeWidth: ServerMapTheme.general.link.normal.line.strokeWidth + } + ), + $( + go.Shape, + { + name: 'ARROW', + fill: ServerMapTheme.general.link.normal.arrow.fill, + scale: 1.5, + stroke: ServerMapTheme.general.link.normal.arrow.stroke, + toArrow: 'standard' + } + ), + $( + go.Panel, + go.Panel.Auto, + $( + go.Shape, + 'Rectangle', + { + fill: ServerMapTheme.general.link.normal.textBox.fill, + stroke: ServerMapTheme.general.link.normal.textBox.stroke, + portId: '', + fromLinkable: true, + toLinkable: true + } + ), + $( + go.Panel, + go.Panel.Horizontal, + { + margin: 4 + }, + $( + go.Picture, + { + source: ServerMapTheme.general.common.funcServerMapImagePath(ServerMapTheme.general.common.icon.filter), + width: 28, + height: 28, + margin: 1, + visible: false, + imageStretch: go.GraphObject.Uniform + }, + new go.Binding('visible', 'isFiltered') + ), + $( + go.TextBlock, + { + name: 'LINK_TEXT', + font: ServerMapTheme.general.common.font.normal, + margin: new go.Margin(1), + textAlign: 'center' + }, + new go.Binding('text', 'totalCount', function (val) { + return parseInt(val, 10).toLocaleString(); + }), + new go.Binding('stroke', 'hasAlert', function (hasAlert) { + if ( hasAlert ) { + return ServerMapTheme.general.link.normal.fontColor.alert; + } else { + return ServerMapTheme.general.link.normal.fontColor.normal; + } + }) + ) + ) + ), + new go.Binding('curve', 'curve', function (val) { + console.log( 'curve', val ); + return go.Link[val]; + }), + new go.Binding('routing', 'routing', function (val) { + console.log( 'routing', val ); + return go.Link[val]; + }), + new go.Binding('curviness', 'curviness') + ); + } + +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-template.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-template.ts new file mode 100644 index 000000000000..f67c64baf94b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-template.ts @@ -0,0 +1,111 @@ +import ServerMapTheme from './server-map-theme'; +import { NodeGroup } from './node-group.class'; + +export abstract class ServerMapTemplate { + private static readonly MIN_ARC_RATIO = 0.05; + private static readonly RADIUS = 62; + private static readonly DIAMETER = 2 * Math.PI * ServerMapTemplate.RADIUS; + + private static getCompleteSVGCircleString(showDefault: boolean, responseTime: IResponseTime): string { + if (showDefault) { + return ServerMapTemplate.getSVGCircleString({ + stroke: ServerMapTheme.general.circle.default.stroke, + strokeWidth: ServerMapTheme.general.circle.default.strokeWidth + }); + } else { + const sum = Object.keys(responseTime).reduce((prev: number, curr: keyof IResponseTime) => prev + responseTime[curr], 0); + const slowArc = ServerMapTemplate.calcArc(sum, responseTime.Slow); + const badArc = ServerMapTemplate.calcArc(sum, responseTime.Error); + // 원의 중심을 (0,0)이라고 할때, stroke-dashoffset 시작점이 12시방향(0,r)이 아니라 3시방향(r,0)이라서 3/4지름을 기준으로 사용 + const slowArcOffset = -1 * (0.75 * ServerMapTemplate.DIAMETER - (slowArc + badArc)); + const badArcOffset = -1 * (0.75 * ServerMapTemplate.DIAMETER - badArc); + + return ServerMapTemplate.getSVGCircleString({ + stroke: ServerMapTheme.general.circle.good.stroke, + strokeWidth: ServerMapTheme.general.circle.default.strokeWidth, + }) + ServerMapTemplate.getSVGCircleString({ + stroke: ServerMapTheme.general.circle.slow.stroke, + strokeWidth: ServerMapTheme.general.circle.default.strokeWidth, + strokeDashOffset: slowArcOffset, + strokeDashArray: slowArc + }) + ServerMapTemplate.getSVGCircleString({ + stroke: ServerMapTheme.general.circle.bad.stroke, + strokeWidth: ServerMapTheme.general.circle.default.strokeWidth, + strokeDashOffset: badArcOffset, + strokeDashArray: badArc + }); + } + } + + private static getSVGCircleString(styleOption: {[key: string]: any}): string { + const { stroke, strokeWidth, strokeDashOffset = 0, strokeDashArray = 'none' } = styleOption; + + return ` + `; + } + + private static calcArc(sum: number, value: number): number { + return value === 0 ? 0 + : value / sum < ServerMapTemplate.MIN_ARC_RATIO ? ServerMapTemplate.DIAMETER * ServerMapTemplate.MIN_ARC_RATIO + : value / sum * ServerMapTemplate.DIAMETER; + } + + private static getAlertSVGImgString(img: HTMLImageElement): string { + const dataURL = this.getDataURLFromImg(img); + + return ``; + } + + private static getDataURLFromImg(img: HTMLImageElement): string { + const canvas = document.createElement('canvas'); + + canvas.getContext('2d').drawImage(img, 0, 0); + return canvas.toDataURL(); + } + + private static getSVGImageStyle(width: number, height: number): {[key: string]: any} { + /** + * ServerMap Image Size Group + * 1. 100 * 65 + * 2. 142 * 74 + * 3. 92 * 25 + * 4. 63 * 87? + */ + // TODO: static한 수치가아니라 비율로? + return { + size: width > 100 ? 200 : 300, + transform: { + translateX: width > 100 ? -45 : -50, + translateY: height > 65 ? -20 : height > 30 ? -45 : -20 + } + }; + } + + private static getServiceTypeSVGImgString(img: HTMLImageElement): string { + const dataURL = ServerMapTemplate.getDataURLFromImg(img); + const { size, transform } = ServerMapTemplate.getSVGImageStyle(img.width, img.height); + + return ``; + } + + private static getInstanceCountTextString(instanceCount: number): string { + return `${instanceCount >= 2 ? instanceCount : ''}`; + } + + public static getSVGString(img: HTMLImageElement[], nodeData: {[key: string]: any}): string { + const { key, isAuthorized, isWas, histogram, instanceCount } = nodeData; + const isMergedNode = NodeGroup.isGroupKey(key); + + return `` + + ServerMapTemplate.getCompleteSVGCircleString(isMergedNode || !(isAuthorized && isWas), histogram) + + (img[1] ? ServerMapTemplate.getAlertSVGImgString(img[1]) : ``) + + ServerMapTemplate.getServiceTypeSVGImgString(img[0]) + + ServerMapTemplate.getInstanceCountTextString(instanceCount) + + ``; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-theme.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-theme.ts new file mode 100644 index 000000000000..98c9e15a9c9e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/class/server-map-theme.ts @@ -0,0 +1,122 @@ +export default { + general: { + common: { + funcServerMapImagePath: null, + icon: { + error: 'ERROR_s', + filter: 'FILTER' + }, + font: { + small: '8pt avn55,NanumGothic,ng,dotum,AppleGothic,sans-serif', + normal: '10pt avn85,NanumGothic,ng,dotum,AppleGothic,sans-serif', + big: 'bold 12pt avn55,NanumGothic,ng,dotum,AppleGothic,sans-serif' + } + }, + circle: { + default: { + stroke: '#D0D7DF', + strokeWidth: 6 + }, + good: { + stroke: '#32BA94', + strokeWidth: 4, + }, + slow: { + stroke: '#E48022', + strokeWidth: 4, + }, + bad: { + stroke: '#F0515B', + strokeWidth: 4, + } + }, + instance: { + shape: { + fill: '#90A1AB', + stroke: '#90A1AB', + strokeWidth: 1 + }, + text: { + stroke: '#FFF' + } + }, + node: { + main: { + border: { + stroke: '#FFF', + strokeWidth: 0 + }, + stroke: '#D0D7DF', + strokeWidth: 1, + fill: { + top: '#F3F4F6', + bottom: '#FFF' + }, + text: { + stroke: '#000' + } + }, + normal: { + border: { + stroke: '#FFF', + strokeWidth: 0 + }, + stroke: '#D0D7DF', + strokeWidth: 1, + fill: { + top: '#FFF', + bottom: '#F3F4F6' + }, + text: { + stroke: '#000' + } + }, + highlight: { + border: { + stroke: '#4A61D1', + strokeWidth: 4 + } + } + }, + link: { + normal: { + line: { + stroke: '#C0C3C8', + strokeWidth: 1.5 + }, + arrow: { + fill: '#C0C3C8', + stroke: '#C0C3C8', + }, + textBox: { + fill: '#EDF2F8', + stroke: '#EDF2F8' + }, + fontColor: { + normal: '#000', + alert: '#FF1300' + }, + fontFamily: '10pt avn85,NanumGothic,ng,dotum,AppleGothic,sans-serif' + }, + highlight: { + line: { + stroke: '#4763D0', + strokeWidth: 1.5 + }, + arrow: { + fill: '#4763D0', + stroke: '#4763D0', + }, + textBox: { + fill: '#EDF2F8', + stroke: '#EDF2F8' + }, + fontColor: { + normal: '#000', + alert: '#FF1300' + }, + fontFamily: 'bold 12pt avn55,NanumGothic,ng,dotum,AppleGothic,sans-serif' + } + } + } +}; diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/index.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/index.ts new file mode 100644 index 000000000000..0f5f60410823 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/index.ts @@ -0,0 +1,46 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { ServerMapInteractionService } from './server-map-interaction.service'; +import { ServerMapOverviewComponent } from './server-map-overview.component'; +import { ServerMapComponent } from './server-map.component'; +import { ServerMapContainerComponent } from './server-map-container.component'; +import { ServerMapForFilteredMapContainerComponent } from './server-map-for-filtered-map-container.component'; +import { ServerMapForTransactionListContainerComponent } from './server-map-for-transaction-list-container.component'; +import { ServerMapForTransactionViewContainerComponent } from './server-map-for-transaction-view-container.component'; +import { ServerMapDataService } from './server-map-data.service'; +import { ServerMapForFilteredMapDataService } from './server-map-for-filtered-map-data.service'; +import { LinkContextPopupModule } from 'app/core/components/link-context-popup'; +import { ServerMapContextPopupModule } from 'app/core/components/server-map-context-popup'; +import { ServerErrorPopupModule } from 'app/core/components/server-error-popup'; + +@NgModule({ + declarations: [ + ServerMapComponent, + ServerMapOverviewComponent, + ServerMapContainerComponent, + ServerMapForFilteredMapContainerComponent, + ServerMapForTransactionListContainerComponent, + ServerMapForTransactionViewContainerComponent + ], + imports: [ + SharedModule, + ServerErrorPopupModule, + LinkContextPopupModule, + ServerMapContextPopupModule + ], + exports: [ + ServerMapComponent, + ServerMapOverviewComponent, + ServerMapContainerComponent, + ServerMapForFilteredMapContainerComponent, + ServerMapForTransactionListContainerComponent, + ServerMapForTransactionViewContainerComponent + ], + providers: [ + ServerMapInteractionService, + ServerMapDataService, + ServerMapForFilteredMapDataService + ] +}) +export class ServerMapModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-container.component.css new file mode 100644 index 000000000000..36925ca792b8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-container.component.css @@ -0,0 +1,56 @@ +.l-popup-section { + display: flex; + z-index: 9; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + justify-content: center; + align-items: center; +} +.l-popup-section:before { + content:''; + display:block; + height:100%; + width:100%; + background:#000; + opacity:0.6; + position:absolute; + left:0; + top:0; +} +.l-popup-section article { + width: 90%; + min-width: 500px; + max-width: 1000px; + box-shadow: 1 1 10px 0 rgba(0, 0, 0, 0.75); + position: static; + background: #fff; + border: 1px solid #e5e8f0; + text-align: left; + z-index: 10; +} +.l-contents-group { + background: #F6F8FB; + padding: 17px 18px; + overflow-y: auto; +} +.l-sql-list { + margin: 0; +} +.l-sql-list dt { + font-size: 13px; + font-weight: 600; + color: #333; + margin: 0 0 12px; +} +.l-sql-list dd { + border: 1px solid #cfd7e1; + background: #fff; + padding: 28px 28px; + font-size: 13px; + color: #999; + line-height: 2em; + position: relative; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-container.component.html new file mode 100644 index 000000000000..d84fdd0920b8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-container.component.html @@ -0,0 +1,27 @@ + + + + + +
    +
    +
    +
    +
    Notice
    +
    {{i18nText['NO_AGENTS']}}
    +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-container.component.ts new file mode 100644 index 000000000000..a3afa77ea1f2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-container.component.ts @@ -0,0 +1,234 @@ +import { Component, OnInit, OnDestroy, Inject } from '@angular/core'; +import { Router, NavigationStart, RouterEvent } from '@angular/router'; +import { Subject } from 'rxjs'; +import { takeUntil, filter, map, switchMap } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { + StoreHelperService, + NewUrlStateNotificationService, + UrlRouteManagerService, + WebAppSettingDataService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPathId } from 'app/shared/models'; +import { EndTime } from 'app/core/models'; +import { SERVER_MAP_TYPE, ServerMapType, NodeGroup, ServerMapData } from 'app/core/components/server-map/class'; +import { ServerMapDataService } from './server-map-data.service'; +import { LinkContextPopupContainerComponent } from 'app/core/components/link-context-popup/link-context-popup-container.component'; +import { ServerMapContextPopupContainerComponent } from 'app/core/components/server-map-context-popup/server-map-context-popup-container.component'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; + +@Component({ + selector: 'pp-server-map-container', + templateUrl: './server-map-container.component.html', + styleUrls: ['./server-map-container.component.css'] +}) +export class ServerMapContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + i18nText: { [key: string]: string } = { + NO_AGENTS: '' + }; + funcServerMapImagePath: Function; + baseApplicationKey: string; + showOverview = false; + showLoading = true; + useDisable = true; + mapData: ServerMapData; + endTime: string; + period: string; + constructor( + private router: Router, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private urlRouteManagerService: UrlRouteManagerService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private serverMapDataService: ServerMapDataService, + private webAppSettingDataService: WebAppSettingDataService, + private dynamicPopupService: DynamicPopupService, + private analyticsService: AnalyticsService, + @Inject(SERVER_MAP_TYPE) public type: ServerMapType + ) {} + ngOnInit() { + this.funcServerMapImagePath = this.webAppSettingDataService.getServerMapIconPathMakeFunc(); + this.addPageLoadingHandler(); + this.getI18NText(); + + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + map((urlService: NewUrlStateNotificationService) => { + if (urlService.isRealTimeMode()) { + const endTime = urlService.getUrlServerTimeData(); + const period = this.webAppSettingDataService.getSystemDefaultPeriod(); + this.initVarBeforeDataLoad( + EndTime.formatDate(endTime), + period.getValueWithTime(), + urlService.getPathValue(UrlPathId.APPLICATION) + ); + return [endTime - (period.getValue() * 60 * 1000), endTime]; + } else { + this.storeHelperService.dispatch(new Actions.UpdateServerMapTargetSelected(null)); + this.initVarBeforeDataLoad( + urlService.getPathValue(UrlPathId.END_TIME).getEndTime(), + urlService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + urlService.getPathValue(UrlPathId.APPLICATION) + ); + return [urlService.getStartTimeToNumber(), urlService.getEndTimeToNumber()]; + } + }), + switchMap((range: number[]) => { + return this.serverMapDataService.getData(range); + }) + ).subscribe((res: IServerMapInfo) => { + this.mapData = new ServerMapData(res.applicationMapData.nodeDataArray, res.applicationMapData.linkDataArray); + this.storeHelperService.dispatch(new Actions.UpdateServerMapData(this.mapData)); + if (this.hasNodeData() === false) { + this.storeHelperService.dispatch(new Actions.UpdateServerMapTargetSelected(null)); + } + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Server Error', + contents: error + }, + component: ServerErrorPopupContainerComponent, + onCloseCallback: () => { + this.urlRouteManagerService.move({ + url: [ + this.newUrlStateNotificationService.getStartPath() + ], + needServerTimeRequest: false + }); + } + }); + }); + this.storeHelperService.getServerMapDisableState(this.unsubscribe).subscribe((disabled: boolean) => { + this.useDisable = disabled; + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private addPageLoadingHandler(): void { + this.router.events.pipe( + filter((e: RouterEvent) => { + return e instanceof NavigationStart; + }) + ).subscribe((e) => { + this.showLoading = true; + this.useDisable = true; + }); + } + private getI18NText(): void { + this.translateService.get('COMMON.NO_AGENTS').subscribe((i18n: string) => { + this.i18nText['NO_AGENTS'] = i18n; + }); + } + private initVarBeforeDataLoad(endTime: string, period: string, application: IApplication): void { + this.endTime = endTime; + this.period = period; + this.showLoading = true; + this.useDisable = true; + this.baseApplicationKey = application.getKeyStr(); + } + private hasNodeData(): boolean { + return this.mapData && this.mapData.getNodeCount() !== 0; + } + showGuide(): boolean { + return this.hasNodeData() === false && this.showLoading === false; + } + onRenderCompleted({showOverView}: {showOverView: boolean}): void { + this.showLoading = false; + this.useDisable = false; + this.showOverview = this.hasNodeData() && showOverView; + } + onClickBackground($event: any): void { + } + onClickNode(nodeData: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_NODE); + let payload; + if (NodeGroup.isGroupKey(nodeData.key)) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SHOW_GROUPED_NODE_VIEW); + payload = { + period: this.period, + endTime: this.endTime, + isAuthorized: nodeData.isAuthorized, + isNode: true, + isLink: false, + isMerged: true, + isWAS: nodeData.isWas, + node: nodeData.mergedNodes.map((nodeInfo: any) => { + return nodeInfo.key; + }) + }; + } else { + payload = { + period: this.period, + endTime: this.endTime, + isAuthorized: nodeData.isAuthorized, + isNode: true, + isLink: false, + isMerged: false, + isWAS: nodeData.isWas, + node: [nodeData.key], + hasServerList: nodeData.instanceCount > 0 ? true : false + }; + } + this.storeHelperService.dispatch(new Actions.UpdateServerMapTargetSelected(payload)); + } + onClickLink(linkData: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_LINK); + let payload; + if (NodeGroup.isGroupKey(linkData.key)) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SHOW_GROUPED_LINK_VIEW); + payload = { + period: this.period, + endTime: this.endTime, + isAuthorized: linkData.isAuthorized, + isNode: false, + isLink: true, + isMerged: true, + isWAS: false, + node: [linkData.from], + link: linkData.targetInfo.map((linkInfo: any) => { + return linkInfo.key; + }), + hasServerList: false + }; + } else { + payload = { + period: this.period, + endTime: this.endTime, + isAuthorized: linkData.isAuthorized, + isNode: false, + isLink: true, + isMerged: false, + isWAS: false, + node: [linkData.from], + link: [linkData.key], + hasServerList: false + }; + } + this.storeHelperService.dispatch(new Actions.UpdateServerMapTargetSelected(payload)); + } + onDoubleClickBackground($event: any): void {} + onContextClickBackground(coord: ICoordinate): void { + this.dynamicPopupService.openPopup({ + data: this.mapData, + coord, + component: ServerMapContextPopupContainerComponent + }); + } + onContextClickNode($event: any): void {} + onContextClickLink({key, coord}: {key: string, coord: ICoordinate}): void { + this.dynamicPopupService.openPopup({ + data: this.mapData.getLinkData(key), + coord, + component: LinkContextPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-data.service.ts new file mode 100644 index 000000000000..3989a4e0f484 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-data.service.ts @@ -0,0 +1,37 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + +import { UrlQuery, UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService, WebAppSettingDataService } from 'app/shared/services'; + +@Injectable() +export class ServerMapDataService { + private url = 'getServerMapDataV2.pinpoint'; + constructor( + private http: HttpClient, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService + ) {} + + getData([from, to]: number[]): Observable { + return this.http.get(this.url, this.makeRequestOptionsArgs(from, to)).pipe( + retry(3) + ); + } + + private makeRequestOptionsArgs(from: number, to: number): object { + return { + params: new HttpParams() + .set('applicationName', this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getApplicationName()) + .set('serviceTypeName', this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getServiceType()) + .set('from', from + '') + .set('to', to + '') + .set('calleeRange', this.newUrlStateNotificationService.hasValue(UrlQuery.INBOUND) ? this.newUrlStateNotificationService.getQueryValue(UrlQuery.INBOUND) : this.webAppSettingDataService.getSystemDefaultInbound()) + .set('callerRange', this.newUrlStateNotificationService.hasValue(UrlQuery.OUTBOUND) ? this.newUrlStateNotificationService.getQueryValue(UrlQuery.OUTBOUND) : this.webAppSettingDataService.getSystemDefaultOutbound()) + .set('wasOnly', this.newUrlStateNotificationService.hasValue(UrlQuery.WAS_ONLY) ? this.newUrlStateNotificationService.getQueryValue(UrlQuery.WAS_ONLY) : false) + .set('bidirectional', this.newUrlStateNotificationService.hasValue(UrlQuery.BIDIRECTIONAL) ? this.newUrlStateNotificationService.getQueryValue(UrlQuery.BIDIRECTIONAL) : false) + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-container.component.css new file mode 100644 index 000000000000..36925ca792b8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-container.component.css @@ -0,0 +1,56 @@ +.l-popup-section { + display: flex; + z-index: 9; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + justify-content: center; + align-items: center; +} +.l-popup-section:before { + content:''; + display:block; + height:100%; + width:100%; + background:#000; + opacity:0.6; + position:absolute; + left:0; + top:0; +} +.l-popup-section article { + width: 90%; + min-width: 500px; + max-width: 1000px; + box-shadow: 1 1 10px 0 rgba(0, 0, 0, 0.75); + position: static; + background: #fff; + border: 1px solid #e5e8f0; + text-align: left; + z-index: 10; +} +.l-contents-group { + background: #F6F8FB; + padding: 17px 18px; + overflow-y: auto; +} +.l-sql-list { + margin: 0; +} +.l-sql-list dt { + font-size: 13px; + font-weight: 600; + color: #333; + margin: 0 0 12px; +} +.l-sql-list dd { + border: 1px solid #cfd7e1; + background: #fff; + padding: 28px 28px; + font-size: 13px; + color: #999; + line-height: 2em; + position: relative; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-container.component.html new file mode 100644 index 000000000000..469691ba1cc9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-container.component.html @@ -0,0 +1,28 @@ + + + + + +
    +
    +
    +
    +
    Notice
    +
    {{i18nText['NO_AGENTS']}}
    +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-container.component.ts new file mode 100644 index 000000000000..d4a033b7446d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-container.component.ts @@ -0,0 +1,258 @@ +import { Component, OnInit, OnDestroy, Inject } from '@angular/core'; +import { Router, NavigationStart } from '@angular/router'; +import { Subject, combineLatest } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { Actions } from 'app/shared/store'; +import { + StoreHelperService, + NewUrlStateNotificationService, + WebAppSettingDataService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { UrlPathId } from 'app/shared/models'; +import { Filter } from 'app/core/models'; +import { SERVER_MAP_TYPE, ServerMapType, NodeGroup, ServerMapData, MergeServerMapData } from 'app/core/components/server-map/class'; +import { ServerMapForFilteredMapDataService } from './server-map-for-filtered-map-data.service'; +import { LinkContextPopupContainerComponent } from 'app/core/components/link-context-popup/link-context-popup-container.component'; +import { ServerMapContextPopupContainerComponent } from 'app/core/components/server-map-context-popup/server-map-context-popup-container.component'; + +@Component({ + selector: 'pp-server-map-for-filtered-map-container', + templateUrl: './server-map-for-filtered-map-container.component.html', + styleUrls: ['./server-map-for-filtered-map-container.component.css'] +}) +export class ServerMapForFilteredMapContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + i18nText: { [key: string]: string } = { + NO_AGENTS: '' + }; + mergedNodeDataList: INodeInfo[] = []; + mergedLinkDataList: ILinkInfo[] = []; + mergedServerMapData: any = {}; + mergedScatterData: any; + loadingCompleted = false; + + mapData: ServerMapData; + baseApplicationKey: string; + showOverview = false; + useDisable = true; + showLoading = true; + funcServerMapImagePath: Function; + endTime: string; + period: string; + constructor( + private router: Router, + private storeHelperService: StoreHelperService, + private translateService: TranslateService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private serverMapForFilteredMapDataService: ServerMapForFilteredMapDataService, + private webAppSettingDataService: WebAppSettingDataService, + private dynamicPopupService: DynamicPopupService, + private analyticsService: AnalyticsService, + @Inject(SERVER_MAP_TYPE) public type: ServerMapType + ) {} + ngOnInit() { + this.funcServerMapImagePath = this.webAppSettingDataService.getServerMapIconPathMakeFunc(); + this.getI18NText(); + this.router.events.pipe( + filter(e => e instanceof NavigationStart) + ).subscribe((e) => { + this.showLoading = true; + this.useDisable = true; + }); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.endTime = urlService.getPathValue(UrlPathId.END_TIME).getEndTime(); + this.period = urlService.getPathValue(UrlPathId.PERIOD).getValueWithTime(); + this.showLoading = true; + this.useDisable = true; + this.baseApplicationKey = urlService.getPathValue(UrlPathId.APPLICATION).getKeyStr(); + this.serverMapForFilteredMapDataService.startDataLoad(); + }); + this.serverMapForFilteredMapDataService.onServerMapData$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((serverMapAndScatterData: any) => { + this.storeHelperService.dispatch(new Actions.AddScatterChartData(serverMapAndScatterData.applicationScatterData)); + this.mergeServerMapData(serverMapAndScatterData); + this.mapData = new ServerMapData(this.mergedNodeDataList, this.mergedLinkDataList, Filter.instanceFromString(this.newUrlStateNotificationService.hasValue(UrlPathId.FILTER) ? this.newUrlStateNotificationService.getPathValue(UrlPathId.FILTER) : '')); + this.storeHelperService.dispatch(new Actions.UpdateServerMapData(this.mapData)); + if (this.hasNodeData() === false) { + this.storeHelperService.dispatch(new Actions.UpdateServerMapTargetSelected(null)); + } + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getServerMapLoadingState(this.unsubscribe).subscribe((state: string) => { + switch (state) { + case 'loading': + this.loadingCompleted = false; + this.showLoading = true; + this.useDisable = true; + break; + case 'pause': + this.loadingCompleted = false; + this.showLoading = false; + this.useDisable = false; + break; + case 'completed': + this.loadingCompleted = true; + break; + } + }); + this.storeHelperService.getServerMapDisableState(this.unsubscribe).subscribe((disabled: boolean) => { + this.useDisable = disabled; + }); + } + private getI18NText(): void { + combineLatest( + this.translateService.get('COMMON.NO_AGENTS') + ).subscribe((i18n: string[]) => { + this.i18nText['NO_AGENTS'] = i18n[0]; + }); + } + private hasNodeData(): boolean { + return this.mapData && this.mapData.getNodeCount() !== 0; + } + showGuide(): boolean { + return this.hasNodeData() === false && this.showLoading === false; + } + onRenderCompleted({showOverView}: {showOverView: boolean}): void { + if (this.loadingCompleted === true) { + this.showLoading = false; + this.useDisable = false; + this.showOverview = this.hasNodeData() && showOverView; + } + } + onClickBackground($event: any): void { + } + onClickGroupNode($event: any): void { + } + onClickNode(nodeData: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_NODE); + let payload; + if (NodeGroup.isGroupKey(nodeData.key)) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SHOW_GROUPED_NODE_VIEW); + payload = { + period: this.period, + endTime: this.endTime, + isAuthorized: nodeData.isAuthorized, + isNode: true, + isLink: false, + isMerged: true, + isWAS: nodeData.isWas, + node: nodeData.mergedNodes.map((nodeInfo: any) => { + return nodeInfo.key; + }) + }; + } else { + payload = { + period: this.period, + endTime: this.endTime, + isAuthorized: nodeData.isAuthorized, + isNode: true, + isLink: false, + isMerged: false, + isWAS: nodeData.isWas, + node: [nodeData.key], + hasServerList: nodeData.instanceCount > 0 ? true : false + }; + } + this.storeHelperService.dispatch(new Actions.UpdateServerMapTargetSelected(payload)); + } + onClickLink(linkData: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_LINK); + let payload; + if (NodeGroup.isGroupKey(linkData.key)) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SHOW_GROUPED_LINK_VIEW); + payload = { + period: this.period, + endTime: this.endTime, + isAuthorized: linkData.isAuthorized, + isNode: false, + isLink: true, + isMerged: true, + isWAS: false, + node: [linkData.from], + link: linkData.targetInfo.map((linkInfo: any) => { + return linkInfo.key; + }) + }; + } else { + payload = { + period: this.period, + endTime: this.endTime, + isAuthorized: linkData.isAuthorized, + isNode: false, + isLink: true, + isMerged: false, + isWAS: false, + node: [linkData.from], + link: [linkData.key] + }; + } + this.storeHelperService.dispatch(new Actions.UpdateServerMapTargetSelected(payload)); + } + onDoubleClickBackground($event: any): void {} + onContextClickBackground(coord: ICoordinate): void { + this.dynamicPopupService.openPopup({ + data: this.mapData, + coord, + component: ServerMapContextPopupContainerComponent + }); + } + onContextClickNode($event: any): void {} + onContextClickLink({key, coord}: {key: string, coord: ICoordinate}): void { + this.dynamicPopupService.openPopup({ + data: this.mapData.getLinkData(key), + coord, + component: LinkContextPopupContainerComponent + }); + } + mergeServerMapData(serverMapAndScatterData: any): void { + console.time('merge server-map data'); + const newNodeDataList = serverMapAndScatterData.applicationMapData.nodeDataArray; + const newLinkDataList = serverMapAndScatterData.applicationMapData.linkDataArray; + + if (this.mergedNodeDataList.length === 0) { + this.mergedNodeDataList = newNodeDataList; + } else { + this.mergeNodeDataList(newNodeDataList); + } + if (this.mergedLinkDataList.length === 0) { + this.mergedLinkDataList = newLinkDataList; + } else { + this.mergeLinkDataList(newLinkDataList); + } + console.timeEnd('merge server-map data'); + } + mergeNodeDataList(newNodeData: INodeInfo[]): void { + newNodeData.forEach((nodeData: INodeInfo) => { + if (this.mapData && this.mapData.getNodeData(nodeData.key)) { + const currentNodeData = this.mapData.getNodeData(nodeData.key); + MergeServerMapData.mergeNodeData(currentNodeData, nodeData); + } else { + this.mergedNodeDataList.push(nodeData); + } + }); + } + mergeLinkDataList(newLinkData: ILinkInfo[]): void { + newLinkData.forEach((linkData: ILinkInfo) => { + if (this.mapData && this.mapData.getLinkData(linkData.key)) { + const currentLinkData = this.mapData.getLinkData(linkData.key); + MergeServerMapData.mergeLinkData(currentLinkData, linkData); + } else { + this.mergedLinkDataList.push(linkData); + } + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-data.service.ts new file mode 100644 index 000000000000..c78687f36dcf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-filtered-map-data.service.ts @@ -0,0 +1,102 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Subject, Observable } from 'rxjs'; +import { map, retry } from 'rxjs/operators'; + +import { Actions } from 'app/shared/store'; +import { UrlQuery, UrlPathId, UrlPath } from 'app/shared/models'; +import { WebAppSettingDataService, NewUrlStateNotificationService, StoreHelperService, DynamicPopupService, UrlRouteManagerService } from 'app/shared/services'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; + +@Injectable() +export class ServerMapForFilteredMapDataService { + private url = 'getFilteredServerMapDataMadeOfDotGroup.pinpoint'; + private REQUEST_LIMIT = 5000; + // 아래 두 값은 scatter-chart에서 사용되는 파라미터 값 + private X_GROUP_UNIT = 987; + private Y_GROUP_UNIT = 57; + private requsting = false; + private flagLoadData = true; + private nextTo: number; + private serverMapData = new Subject(); + onServerMapData$: Observable; + constructor( + private http: HttpClient, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private urlRouteManagerService: UrlRouteManagerService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private dynamicPopupService: DynamicPopupService + ) { + this.onServerMapData$ = this.serverMapData.asObservable(); + } + startDataLoad(to?: number): void { + this.loadData(to); + } + stopDataLoad(): void { + this.flagLoadData = false; + } + resumeDataLoad(): void { + if (this.requsting === false) { + this.flagLoadData = true; + this.startDataLoad(this.nextTo); + } + } + private loadData(to?: number): void { + this.requsting = true; + this.storeHelperService.dispatch(new Actions.UpdateServerMapLoadingState('loading')); + this.http.get(this.url, this.makeRequestOptionsArgs(to)).pipe( + retry(3), + map(res => { + return res || {}; + }) + ).subscribe((res: any) => { + if (res['lastFetchedTimestamp'] > res['applicationMapData']['range']['from']) { + this.nextTo = res['lastFetchedTimestamp'] - 1; + if (this.flagLoadData) { + this.loadData(this.nextTo); + } else { + this.storeHelperService.dispatch(new Actions.UpdateServerMapLoadingState('pause')); + } + } else { + this.storeHelperService.dispatch(new Actions.UpdateServerMapLoadingState('completed')); + } + this.serverMapData.next(res); + this.requsting = false; + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Server Error', + contents: error + }, + component: ServerErrorPopupContainerComponent, + onCloseCallback: () => { + this.urlRouteManagerService.move({ + url: [ + UrlPath.MAIN + ], + needServerTimeRequest: false + }); + } + }); + }); + } + private makeRequestOptionsArgs(to?: number): any { + return { + params: new HttpParams() + .set('applicationName', this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).applicationName) + .set('serviceTypeName', this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).serviceType) + .set('from', this.newUrlStateNotificationService.getStartTimeToNumber() + '') + .set('to', (to || this.newUrlStateNotificationService.getEndTimeToNumber()) + '') + .set('originTo', this.newUrlStateNotificationService.getEndTimeToNumber() + '') + .set('calleeRange', this.newUrlStateNotificationService.hasValue(UrlQuery.INBOUND) ? this.newUrlStateNotificationService.getQueryValue(UrlQuery.INBOUND) : this.webAppSettingDataService.getUserDefaultInbound()) + .set('callerRange', this.newUrlStateNotificationService.hasValue(UrlQuery.OUTBOUND) ? this.newUrlStateNotificationService.getQueryValue(UrlQuery.OUTBOUND) : this.webAppSettingDataService.getUserDefaultOutbound()) + .set('filter', this.newUrlStateNotificationService.hasValue(UrlPathId.FILTER) ? encodeURIComponent(this.newUrlStateNotificationService.getPathValue(UrlPathId.FILTER)) : '') + .set('hint', this.newUrlStateNotificationService.hasValue(UrlPathId.HINT) ? encodeURIComponent(this.newUrlStateNotificationService.getPathValue(UrlPathId.HINT)) : '') + .set('v', '4') + .set('limit', this.REQUEST_LIMIT + '') + .set('xGroupUnit', this.X_GROUP_UNIT + '') // for scatter-chart + .set('yGroupUnit', this.Y_GROUP_UNIT + '') // for scatter-chart + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-list-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-list-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-list-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-list-container.component.html new file mode 100644 index 000000000000..1c3f9895ce2b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-list-container.component.html @@ -0,0 +1,16 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-list-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-list-container.component.ts new file mode 100644 index 000000000000..505d0f11a353 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-list-container.component.ts @@ -0,0 +1,96 @@ +import { Component, OnInit, OnDestroy, Inject, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { StoreHelperService, NewUrlStateNotificationService, WebAppSettingDataService , TransactionViewTypeService, VIEW_TYPE } from 'app/shared/services'; +import { ServerMapData } from './class/server-map-data.class'; +import { SERVER_MAP_TYPE, ServerMapType } from './class/server-map-factory'; + + +@Component({ + selector: 'pp-server-map-for-transaction-list-container', + templateUrl: './server-map-for-transaction-list-container.component.html', + styleUrls: ['./server-map-for-transaction-list-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ServerMapForTransactionListContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private transactionDetailInfo: ITransactionDetailData; + transactionInfo: ITransactionMetaData; + hiddenComponent = false; + baseApplicationKey = ''; + mapData: ServerMapData; + showLoading = true; + funcServerMapImagePath: Function; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private transactionViewTypeService: TransactionViewTypeService, + @Inject(SERVER_MAP_TYPE) public type: ServerMapType + ) { + this.funcServerMapImagePath = this.webAppSettingDataService.getServerMapIconPathMakeFunc(); + this.showLoading = false; + } + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.APPLICATION); + }) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.baseApplicationKey = urlService.getPathValue(UrlPathId.APPLICATION).getKeyStr(); + this.changeDetectorRef.detectChanges(); + }); + this.transactionViewTypeService.onChangeViewType$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((viewType: string) => { + if ( viewType === VIEW_TYPE.SERVER_MAP ) { + this.hiddenComponent = false; + this.initCheck(); + } else { + this.hiddenComponent = true; + } + this.changeDetectorRef.detectChanges(); + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTransactionDetailData(this.unsubscribe).pipe( + filter((transactionDetailInfo: ITransactionDetailData) => { + return transactionDetailInfo && transactionDetailInfo.transactionId ? true : false; + }) + ).subscribe((transactionDetailInfo: ITransactionDetailData) => { + this.mapData = null; + this.transactionDetailInfo = transactionDetailInfo; + this.initCheck(); + this.changeDetectorRef.detectChanges(); + }); + } + private initCheck() { + if (this.hiddenComponent === false && this.transactionDetailInfo) { + this.loadTransactionData(); + } + } + private loadTransactionData(): void { + this.mapData = new ServerMapData(this.transactionDetailInfo.applicationMapData.nodeDataArray, this.transactionDetailInfo.applicationMapData.linkDataArray); + } + onRenderCompleted(msg: string): void { + this.showLoading = false; + this.changeDetectorRef.detectChanges(); + } + onClickBackground($event: any): void {} + onClickGroupNode($event: any): void {} + onClickNode($event: any): void {} + onClickLink($event: any): void {} + onDoubleClickBackground($event: any): void {} + onContextClickBackground($event: any): void {} + onContextClickNode($event: any): void {} + onContextClickLink($param: any): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-view-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-view-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-view-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-view-container.component.html new file mode 100644 index 000000000000..b3c53702c8f6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-view-container.component.html @@ -0,0 +1,18 @@ + + + + + diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-view-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-view-container.component.ts new file mode 100644 index 000000000000..9740edd9c6ad --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-for-transaction-view-container.component.ts @@ -0,0 +1,61 @@ +import { Component, OnInit, Inject, ChangeDetectionStrategy } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { switchMap, map, takeUntil } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService, WebAppSettingDataService, TransactionDetailDataService, GutterEventService } from 'app/shared/services'; +import { ServerMapInteractionService } from './server-map-interaction.service'; +import { ServerMapData } from './class/server-map-data.class'; +import { SERVER_MAP_TYPE, ServerMapType } from './class/server-map-factory'; + +@Component({ + selector: 'pp-server-map-for-transaction-view-container', + templateUrl: './server-map-for-transaction-view-container.component.html', + styleUrls: ['./server-map-for-transaction-view-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ServerMapForTransactionViewContainerComponent implements OnInit { + private unsubscribe: Subject = new Subject(); + baseApplicationKey = ''; + mapData$: Observable; + funcServerMapImagePath: Function; + showLoading = true; + constructor( + private newUrlStateNotificationService: NewUrlStateNotificationService, + private webAppSettingDataService: WebAppSettingDataService, + private transactionDetailDataService: TransactionDetailDataService, + private gutterEventService: GutterEventService, + private serverMapInteractionService: ServerMapInteractionService, + @Inject(SERVER_MAP_TYPE) public type: ServerMapType + ) { } + + ngOnInit() { + this.funcServerMapImagePath = this.webAppSettingDataService.getServerMapIconPathMakeFunc(); + // TODO: ServiceType Empty이슈 체크 #174 + this.mapData$ = this.newUrlStateNotificationService.onUrlStateChange$.pipe( + switchMap((urlService: NewUrlStateNotificationService) => this.transactionDetailDataService.getData( + urlService.getPathValue(UrlPathId.AGENT_ID), + urlService.getPathValue(UrlPathId.SPAN_ID), + urlService.getPathValue(UrlPathId.TRACE_ID), + urlService.getPathValue(UrlPathId.FOCUS_TIMESTAMP) + )), + map((applicationMapData: ITransactionDetailData) => { + return new ServerMapData(applicationMapData.applicationMapData.nodeDataArray, applicationMapData.applicationMapData.linkDataArray); + }) + ); + this.gutterEventService.onGutterResized$.pipe( + takeUntil(this.unsubscribe) + ).subscribe(() => this.serverMapInteractionService.setRefresh()); + } + onRenderCompleted(msg: string): void { + this.showLoading = false; + } + onClickBackground($event: any): void {} + onClickGroupNode($event: any): void {} + onClickNode($event: any): void {} + onClickLink($event: any): void {} + onDoubleClickBackground($event: any): void {} + onContextClickBackground($event: any): void {} + onContextClickNode($event: any): void {} + onContextClickLink($param: any): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-interaction.service.ts new file mode 100644 index 000000000000..77c57361273f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-interaction.service.ts @@ -0,0 +1,48 @@ +import { Injectable } from '@angular/core'; +import * as go from 'gojs'; +import { Subject, Observable } from 'rxjs'; + +@Injectable() +export class ServerMapInteractionService { + private outSearchWordSource = new Subject(); + private outSearchResultSource = new Subject(); + private outSelectedApplicationSource = new Subject(); + private outCurrentDiagramSource = new Subject(); + private outRefresh = new Subject(); + private outChangeMergeState = new Subject(); + + public onSearchWord$: Observable; + public onSearchResult$: Observable; + public onSelectedApplication$: Observable; + public onCurrentDiagram$: Observable; + public onRefresh$: Observable; + public onChangeMergeState$: Observable; + + constructor() { + this.onSearchWord$ = this.outSearchWordSource.asObservable(); + this.onSearchResult$ = this.outSearchResultSource.asObservable(); + this.onSelectedApplication$ = this.outSelectedApplicationSource.asObservable(); + this.onCurrentDiagram$ = this.outCurrentDiagramSource.asObservable(); + this.onRefresh$ = this.outRefresh.asObservable(); + this.onChangeMergeState$ = this.outChangeMergeState.asObservable(); + } + + setSearchWord(word: string): void { + this.outSearchWordSource.next(word); + } + setSearchResult(result: IApplication[]): void { + this.outSearchResultSource.next(result); + } + setSelectedApplication(appKey: string): void { + this.outSelectedApplicationSource.next(appKey); + } + setCurrentDiagram(diagram: go.Diagram): void { + this.outCurrentDiagramSource.next(diagram); + } + setRefresh(): void { + this.outRefresh.next(); + } + setMergeState(mergeState: IServerMapMergeState): void { + this.outChangeMergeState.next(mergeState); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-overview.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-overview.component.css new file mode 100644 index 000000000000..dadedc20f03a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-overview.component.css @@ -0,0 +1,10 @@ +div { + width: 180px; + height: 160px; + right: 20px; + bottom: 20px; + z-index: 8; + position: absolute; + background-color: #FFF; + border: 2px solid #BCBFC5; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-overview.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-overview.component.html new file mode 100644 index 000000000000..edc0374881cd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-overview.component.html @@ -0,0 +1 @@ +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-overview.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-overview.component.ts new file mode 100644 index 000000000000..262a1b15c17d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map-overview.component.ts @@ -0,0 +1,47 @@ +import { Component, OnInit, ElementRef, Input, ViewChild, OnDestroy } from '@angular/core'; +import * as go from 'gojs'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { ServerMapInteractionService } from './server-map-interaction.service'; + +@Component({ + selector: 'pp-server-map-overview', + templateUrl: './server-map-overview.component.html', + styleUrls: ['./server-map-overview.component.css'] +}) +export class ServerMapOverviewComponent implements OnInit, OnDestroy { + @ViewChild('wrapper') overviewWrapper: ElementRef; + @Input() showOverview = false; + overview: go.Overview; + initialized = false; + unsubscribe: Subject = new Subject(); + constructor( + private serverMapInteractionService: ServerMapInteractionService + ) {} + ngOnInit() { + this.serverMapInteractionService.onCurrentDiagram$.pipe( + takeUntil(this.unsubscribe), + filter((diagram: go.Diagram) => { + // TODO: visjs구현체에서 overview핸들링이 되기전까지 visjs옵션의 경우(null)엔 잠시 막아둠. + return !!diagram; + }) + ).subscribe((diagram: go.Diagram) => { + if (this.initialized === true) { + this.overview.observed = diagram; + } else { + this.overview = go.GraphObject.make(go.Overview, this.overviewWrapper.nativeElement, { + observed: diagram + }); + this.overview.box.elt(0)['figure'] = 'Rectangle'; + this.overview.box.elt(0)['stroke'] = '#E7555A'; + this.overview.box.elt(0)['strokeWidth'] = .5; + this.initialized = true; + } + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.component.css b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.component.css new file mode 100644 index 000000000000..8b14713a6ba5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.component.css @@ -0,0 +1,14 @@ +div { + width: 100%; + height: 100%; + position: relative; +} +.show-map { + visibility: visible; + opacity: 1; + transition: all 1.5s; +} +.hide-map { + visibility: hidden; + opacity: 0; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.component.html b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.component.html new file mode 100644 index 000000000000..b07125417d4f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.component.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.component.ts new file mode 100644 index 000000000000..75c1542fa3fd --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.component.ts @@ -0,0 +1,129 @@ +import { Component, Input, Output, EventEmitter, OnInit, OnChanges, OnDestroy, AfterViewInit, SimpleChanges, ElementRef, ViewChild } from '@angular/core'; +import * as go from 'gojs'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { ServerMapData } from './class/server-map-data.class'; +import { ServerMapInteractionService } from './server-map-interaction.service'; +import { ServerMapDiagram } from './class/server-map-diagram.class'; +import { AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; +import { ServerMapFactory, ServerMapType } from './class/server-map-factory'; + +@Component({ + selector: 'pp-server-map', + templateUrl: './server-map.component.html', + styleUrls: ['./server-map.component.css'], +}) + +export class ServerMapComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit { + @ViewChild('serverMap') el: ElementRef; + @Input() mapData: ServerMapData; + @Input() baseApplicationKey: string; + @Input() funcImagePath: Function; + @Input() funcServerMapImagePath: Function; + @Input() type: ServerMapType; + @Output() outClickNode: EventEmitter = new EventEmitter(); + @Output() outClickGroupNode: EventEmitter = new EventEmitter(); + @Output() outContextClickNode: EventEmitter = new EventEmitter(); + @Output() outClickLink: EventEmitter = new EventEmitter(); + @Output() outContextClickLink: EventEmitter = new EventEmitter(); + @Output() outClickBackground: EventEmitter = new EventEmitter(); + @Output() outDoubleClickBackground: EventEmitter = new EventEmitter(); + @Output() outContextClickBackground: EventEmitter = new EventEmitter(); + @Output() outRenderCompleted: EventEmitter<{[key: string]: boolean}> = new EventEmitter(); + + private hasRenderData = false; + private serverMapDiagram: ServerMapDiagram; + private unsubscribe: Subject = new Subject(); + + constructor( + private serverMapInteractionService: ServerMapInteractionService, + private analyticsService: AnalyticsService, + ) {} + ngOnChanges(changes: SimpleChanges) { + if (changes['mapData'] && changes['mapData']['currentValue']) { + if (this.serverMapDiagram) { + this.serverMapDiagram.setMapData(this.mapData, this.baseApplicationKey); + this.hasRenderData = false; + } else { + this.hasRenderData = true; + } + } + } + ngOnInit() { + this.serverMapInteractionService.onSearchWord$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((query: string) => { + this.serverMapInteractionService.setSearchResult(this.serverMapDiagram.searchNode(query)); + }); + this.serverMapInteractionService.onSelectedApplication$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((appKey: string) => { + this.serverMapDiagram.selectNodeBySearch(appKey); + }); + this.serverMapInteractionService.onRefresh$.pipe( + takeUntil(this.unsubscribe) + ).subscribe(() => { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.REFRESH_SERVER_MAP); + this.serverMapDiagram.refresh(); + }); + this.serverMapInteractionService.onChangeMergeState$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((params: IServerMapMergeState) => { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_SERVER_MAP_MERGE_STATE, `${params.state}`); + this.serverMapDiagram.setMergeState(params); + this.serverMapDiagram.resetMergeState(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + + ngAfterViewInit() { + this.serverMapDiagram = ServerMapFactory.createServerMap(this.type, { + container: this.el.nativeElement, + funcServerMapImagePath: this.funcServerMapImagePath + }); + this.addEventHandler(); + if (this.hasRenderData) { + this.serverMapDiagram.setMapData(this.mapData, this.baseApplicationKey); + this.hasRenderData = false; + } + } + addEventHandler(): void { + this.serverMapDiagram.outRenderCompleted.subscribe((diagram: go.Diagram) => { + this.serverMapInteractionService.setCurrentDiagram(diagram); + this.outRenderCompleted.emit({ + showOverView: !!diagram + }); + }); + this.serverMapDiagram.outClickNode.subscribe((nodeData: any) => { + this.outClickNode.emit(nodeData); + }); + this.serverMapDiagram.outClickGroupNode.subscribe((nodeData: any) => { + this.outClickGroupNode.emit(nodeData); + }); + this.serverMapDiagram.outContextClickNode.subscribe((node: any) => { + this.outContextClickNode.emit(node); + }); + this.serverMapDiagram.outClickLink.subscribe((linkData: any) => { + this.outClickLink.emit(linkData); + }); + this.serverMapDiagram.outContextClickLink.subscribe((linkObj: any) => { + this.outContextClickLink.emit(linkObj); + }); + this.serverMapDiagram.outClickBackground.subscribe(() => { + this.outClickBackground.emit(); + }); + this.serverMapDiagram.outDoubleClickBackground.subscribe((msg: any) => { + this.outDoubleClickBackground.emit(msg); + }); + this.serverMapDiagram.outContextClickBackground.subscribe((coord: ICoordinate) => { + this.outContextClickBackground.emit(coord); + }); + } + clear(): void { + this.serverMapDiagram.clear(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.interface.ts b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.interface.ts new file mode 100644 index 000000000000..9269f65024b9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-map/server-map.interface.ts @@ -0,0 +1,18 @@ +export interface IHistogramType1 { + '1s': number; + '3s': number; + '5s': number; + 'Slow': number; + 'Error': number; +} +export interface IHistogramType2 { + '100ms': number; + '300ms': number; + '500ms': number; + Error: number; + Slow: number; +} +export interface IHistogramType3 { + key: string; + values: number[]; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/server-status/index.ts b/web/src/main/webapp/v2/src/app/core/components/server-status/index.ts new file mode 100644 index 000000000000..33dcee3bcb53 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-status/index.ts @@ -0,0 +1 @@ +export * from './server-status-container.component'; diff --git a/web/src/main/webapp/v2/src/app/core/components/server-status/server-status-container.component.css b/web/src/main/webapp/v2/src/app/core/components/server-status/server-status-container.component.css new file mode 100644 index 000000000000..1214e029d60e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-status/server-status-container.component.css @@ -0,0 +1,41 @@ +.l-status { + padding: 10px 16px 10px 16px; +} +.l-status:after { + content:""; + display:block; + width:100%; + height:0; + visibility:hidden; + clear:both; +} +.l-status button { + float: left; +} +.l-status button.disable { + background-color: #CCC; +} +.l-status-count { + float: right; +} +.l-status-count li { + font-size: 12px; + color: #B3B3B4; + float: left; +} +.l-status-count li:first-child { + margin: 0 15px 0 0; + padding: 0 15px 0 0; + position: relative; +} +.l-status-count span { + font-size: 18px; + font-weight: 600; + color: #EB4747; +} +.l-status-count span.l-total { + color: #000; +} +button:first-child { + margin-right: 10px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-status/server-status-container.component.html b/web/src/main/webapp/v2/src/app/core/components/server-status/server-status-container.component.html new file mode 100644 index 000000000000..2d89e1754818 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-status/server-status-container.component.html @@ -0,0 +1,8 @@ +
    + + +
      +
    • Total {{node.instanceCount}}
    • +
    • Error {{node.instanceErrorCount || 0}}
    • +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/server-status/server-status-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/server-status/server-status-container.component.ts new file mode 100644 index 000000000000..417c93778100 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/server-status/server-status-container.component.ts @@ -0,0 +1,91 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { Actions } from 'app/shared/store'; +import { StoreHelperService, NewUrlStateNotificationService, UrlRouteManagerService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; +import { ServerMapData } from 'app/core/components/server-map/class/server-map-data.class'; + +@Component({ + selector: 'pp-server-status-container', + templateUrl: './server-status-container.component.html', + styleUrls: ['./server-status-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ServerStatusContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private enableRealTime: boolean; + node: INodeInfo; + isInfoPerServerShow = false; + isLoading = false; + serverMapData: ServerMapData; + selectedTarget: ISelectedTarget; + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private analyticsService: AnalyticsService + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.enableRealTime = urlService.isRealTimeMode(); + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: ServerMapData) => { + this.serverMapData = serverMapData; + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return (target) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.selectedTarget = target; + this.node = (target.isNode === true ? this.serverMapData.getNodeData(target.node[0]) : null); + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getInfoPerServerState(this.unsubscribe).subscribe((visibleState: boolean) => { + this.isLoading = false; + this.isInfoPerServerShow = visibleState; + this.changeDetector.detectChanges(); + }); + } + onClickViewServer(): void { + if (this.isLoading === true || this.enableRealTime === true) { + return; + } + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SHOW_SERVER_LIST); + this.isLoading = !this.isLoading; + this.storeHelperService.dispatch(new Actions.ChangeServerMapDisableState(!this.isInfoPerServerShow)); + this.storeHelperService.dispatch(new Actions.ChangeInfoPerServerVisibleState(!this.isInfoPerServerShow)); + } + hasServerList(): boolean { + if (this.selectedTarget) { + if (this.selectedTarget.isNode && this.selectedTarget.isMerged === false) { + return this.selectedTarget.hasServerList; + } + } + return false; + } + enableViewServer(): boolean { + return !this.enableRealTime; + } + onClickOpenInspector(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_INSPECTOR); + this.urlRouteManagerService.openInspectorPage(this.enableRealTime); + } + getAngle(): string { + return this.isInfoPerServerShow ? 'right' : 'left'; + } + isWAS(): boolean { + return this.selectedTarget.isWAS; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar-title/index.ts b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/index.ts new file mode 100644 index 000000000000..f877102d8044 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/index.ts @@ -0,0 +1,24 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +// import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { MatTooltipModule } from '@angular/material'; +import { SideBarTitleComponent } from './side-bar-title.component'; +import { SideBarTitleContainerComponent } from './side-bar-title-container.component'; + +@NgModule({ + declarations: [ + SideBarTitleComponent, + SideBarTitleContainerComponent + ], + imports: [ + CommonModule, + // BrowserAnimationsModule, + MatTooltipModule + ], + exports: [ + SideBarTitleContainerComponent + ], + providers: [] +}) +export class SideBarTitleModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title-container.component.css b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title-container.component.css new file mode 100644 index 000000000000..10e12cc739ba --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title-container.component.css @@ -0,0 +1,5 @@ +:host { + width: 100%; + align-items: center; + justify-content: space-between; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title-container.component.html b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title-container.component.html new file mode 100644 index 000000000000..e33587b64538 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title-container.component.html @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title-container.component.ts new file mode 100644 index 000000000000..a419e569dd61 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title-container.component.ts @@ -0,0 +1,121 @@ +import { Component, OnInit, OnDestroy, HostBinding, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +import { Actions } from 'app/shared/store'; +import { WebAppSettingDataService, StoreHelperService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; + +interface IAppData { + applicationName: string; + serviceType: string; + agentList?: string[]; +} + +@Component({ + selector: 'pp-side-bar-title-container', + templateUrl: './side-bar-title-container.component.html', + styleUrls: ['./side-bar-title-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SideBarTitleContainerComponent implements OnInit, OnDestroy { + @HostBinding('class.flex-container') flexContainerClass = true; + @HostBinding('class.flex-row') flexRowClass = true; + isWAS: boolean; + isNode: boolean; + fromAppData: IAppData = null; + toAppData: IAppData = null; + selectedTarget: ISelectedTarget; + serverMapData: any; + funcImagePath: Function; + unsubscribe: Subject = new Subject(); + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private analyticsService: AnalyticsService, + ) { + } + ngOnInit() { + this.funcImagePath = this.webAppSettingDataService.getIconPathMakeFunc(); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: IServerMapInfo) => { + this.serverMapData = serverMapData; + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + if ( target.isNode || target.isLink ) { + this.selectedTarget = target; + this.makeFromToData(); + this.changeDetector.detectChanges(); + } + }); + } + makeFromToData() { + if ( this.selectedTarget.isNode ) { + this.isWAS = this.selectedTarget.isWAS; + this.isNode = true; + const node = this.serverMapData.getNodeData(this.selectedTarget.node[0]); + this.toAppData = this.formatToAppData({ node: node }); + } else if ( this.selectedTarget.isLink ) { + this.isWAS = false; + this.isNode = false; + const link = this.serverMapData.getLinkData(this.selectedTarget.link[0]); + this.fromAppData = this.formatFromAppData(link); + this.toAppData = this.formatToAppData({ link: link }); + } + } + private isUserType(type: string): boolean { + return type.toUpperCase() === 'USER'; + } + private formatFromAppData(link: any): IAppData { + return { + applicationName: this.isUserType(link.sourceInfo.serviceType) ? link.sourceInfo.serviceType : link.sourceInfo.applicationName, + serviceType: link.sourceInfo.serviceType + }; + } + private formatToAppData({ node, link }: { node?: any, link?: any }): IAppData { + if (this.isNode) { + if (this.selectedTarget.isMerged) { + return { + applicationName: `[ ${this.selectedTarget.node.length} ] ${node.serviceType} GROUP`, + serviceType: node.serviceType, + agentList: [] + }; + } else { + return { + applicationName: node.applicationName, + serviceType: node.serviceType, + agentList: node.agentIds.sort() + }; + } + } else { + if (this.selectedTarget.isMerged) { + return { + applicationName: `[ ${this.selectedTarget.link.length} ] ${link.targetInfo.serviceType} GROUP`, + serviceType: link.targetInfo.serviceType, + agentList: [] + }; + } else { + return { + applicationName: link.targetInfo.applicationName, + serviceType: link.targetInfo.serviceType, + agentList: [] + }; + } + } + } + onChangeAgent(agentName: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_AGENT); + agentName = agentName === 'All' ? '' : agentName; + this.storeHelperService.dispatch(new Actions.ChangeAgent(agentName)); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title.component.css b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title.component.css new file mode 100644 index 000000000000..4c5a7a6365a5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title.component.css @@ -0,0 +1,45 @@ +:host { + width: 100%; +} + +.l-wrapper { + width: 100%; + display:flex; + flex-wrap: nowrap; + flex-flow: row; + align-items: center; + justify-content: space-between; +} +.l-wrapper select { + width: 152px; + border: 1px solid #d7dde4; + height: 32px; + padding: 0 9px; + font-size: 13px; + border-radius: 2px; + color: #666; + appearance: none; + -webkit-appearance:none; + background:url(../../../../assets/img/select-down-arrow.png) no-repeat right 10px center; +} +.l-wrapper-grid { + display: grid; + grid-template-columns: 50% 20px 50%; + grid-template-rows: auto; +} + +.l-wrapper .l-title, .l-wrapper-grid .l-title { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 16px; + font-weight: 600; + padding: 0px; +} +.l-wrapper .l-title img, .l-wrapper-grid .l-title img { + float: left; +} +.l-wrapper .l-title span, .l-wrapper-grid .l-title span { + margin-left: 6px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title.component.html b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title.component.html new file mode 100644 index 000000000000..d1e4293279c6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title.component.html @@ -0,0 +1,18 @@ +
    +
    + {{toAppData?.applicationName}} +
    + +
    +
    +
    + {{fromAppData?.applicationName}} +
    +
    +
    + {{toAppData?.applicationName}} +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title.component.ts b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title.component.ts new file mode 100644 index 000000000000..a883d6f649a7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar-title/side-bar-title.component.ts @@ -0,0 +1,33 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-side-bar-title', + templateUrl: './side-bar-title.component.html', + styleUrls: ['./side-bar-title.component.css'] +}) +export class SideBarTitleComponent implements OnInit { + @Input() isWAS: boolean; + @Input() isNode: boolean; + @Input() fromAppData: any; + @Input() toAppData: any; + @Input() funcImagePath: Function; + @Output() outChangeAgent: EventEmitter = new EventEmitter(); + constructor() {} + ngOnInit() {} + getIconPath(serviceType: string): string { + return this.funcImagePath(serviceType); + } + onChangeAgent($agent: string): void { + this.outChangeAgent.emit($agent); + } + showAgentList(): boolean { + if (this.toAppData) { + return this.toAppData.agentList.length > 0; + } else { + return false; + } + } + onLoadError(img: HTMLImageElement): void { + img.src = this.funcImagePath('NO_IMAGE_FOUND'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar/index.ts b/web/src/main/webapp/v2/src/app/core/components/side-bar/index.ts new file mode 100644 index 000000000000..ed1446f66d9f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar/index.ts @@ -0,0 +1,37 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { LoadChartModule } from 'app/core/components/load-chart'; +import { TargetListModule } from 'app/core/components/target-list'; +import { SideBarTitleModule } from 'app/core/components/side-bar-title'; +import { ScatterChartModule } from 'app/core/components/scatter-chart'; +import { InfoPerServerModule } from 'app/core/components/info-per-server'; +import { ResponseSummaryChartModule } from 'app/core/components/response-summary-chart'; +import { ServerStatusContainerComponent } from 'app/core/components/server-status'; +import { FilterInformationContainerComponent } from 'app/core/components/filter-information'; +import { SideBarContainerComponent } from './side-bar-container.component'; +import { SideBarForFilteredMapContainerComponent } from './side-bar-for-filtered-map-container.component'; + +@NgModule({ + declarations: [ + SideBarContainerComponent, + SideBarForFilteredMapContainerComponent, + ServerStatusContainerComponent, + FilterInformationContainerComponent + ], + imports: [ + SharedModule, + InfoPerServerModule, + SideBarTitleModule, + ScatterChartModule, + TargetListModule, + ResponseSummaryChartModule, + LoadChartModule + ], + exports: [ + SideBarContainerComponent, + SideBarForFilteredMapContainerComponent + ], + providers: [] +}) +export class SideBarModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-container.component.css b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-container.component.css new file mode 100644 index 000000000000..15cfddb82d08 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-container.component.css @@ -0,0 +1,40 @@ +:host { + position: relative; + border-left: 1px solid #e5e8f0; + border-right: 1px solid #e5e8f0; +} +.l-sidemenu-wrap { + display: flex; + flex-flow: column nowrap; + height: 100%; + overflow-y: auto; + overflow-x: hidden; +} +.l-sidemenu { + height: 100%; + z-index: 10; + background-color: #fff; +} +.l-title-group { + display: flex; + flex-flow: row wrap; + color: #666; + justify-content: space-between; + align-items: center; + padding: 0 15px; + background: #F9FAFC; + border-bottom: 1px solid #EAEEF4; + height: 50px; +} +.l-contents-group { + padding-bottom: 16px; + overflow-y: auto; + overflow-x: hidden; +} +.l-chart-group-list { + flex: 1; +} +hr { + height: 1px; + border-top: 1px solid #EAEEF4; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-container.component.html b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-container.component.html new file mode 100644 index 000000000000..76d48d8c726b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-container.component.html @@ -0,0 +1,21 @@ +
    +
    +
    + +
    +
    + +
    + + +
    + +
    + +
    +
    +
    + +
    + + diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-container.component.ts new file mode 100644 index 000000000000..50b4e2dbaa96 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-container.component.ts @@ -0,0 +1,75 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { StoreHelperService, NewUrlStateNotificationService } from 'app/shared/services'; + +@Component({ + selector: 'pp-side-bar-container', + templateUrl: './side-bar-container.component.html', + styleUrls: ['./side-bar-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SideBarContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + target: any; + sideBarWidth = 0; + useDisable = true; + showLoading = true; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.APPLICATION)) { + this.showLoading = true; + this.useDisable = true; + } else { + this.sideBarWidth = 0; + this.showLoading = false; + this.useDisable = false; + } + this.changeDetectorRef.detectChanges(); + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getServerMapData(this.unsubscribe).pipe( + filter((target: any) => { + return target.nodeList ? true : false; + }) + ).subscribe((target: any) => { + if (target.nodeList.length === 0) { + this.sideBarWidth = 0; + } + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.target = target; + if ( target.isNode === true || target.isLink === true ) { + this.sideBarWidth = 461; + } else { + this.sideBarWidth = 0; + } + this.showLoading = false; + this.useDisable = false; + this.changeDetectorRef.detectChanges(); + }); + } + hasTopElement(): boolean { + return this.target && (this.target.isNode || this.target.isMerged); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-for-filtered-map-container.component.css b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-for-filtered-map-container.component.css new file mode 100644 index 000000000000..15cfddb82d08 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-for-filtered-map-container.component.css @@ -0,0 +1,40 @@ +:host { + position: relative; + border-left: 1px solid #e5e8f0; + border-right: 1px solid #e5e8f0; +} +.l-sidemenu-wrap { + display: flex; + flex-flow: column nowrap; + height: 100%; + overflow-y: auto; + overflow-x: hidden; +} +.l-sidemenu { + height: 100%; + z-index: 10; + background-color: #fff; +} +.l-title-group { + display: flex; + flex-flow: row wrap; + color: #666; + justify-content: space-between; + align-items: center; + padding: 0 15px; + background: #F9FAFC; + border-bottom: 1px solid #EAEEF4; + height: 50px; +} +.l-contents-group { + padding-bottom: 16px; + overflow-y: auto; + overflow-x: hidden; +} +.l-chart-group-list { + flex: 1; +} +hr { + height: 1px; + border-top: 1px solid #EAEEF4; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-for-filtered-map-container.component.html b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-for-filtered-map-container.component.html new file mode 100644 index 000000000000..f31272f073fe --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-for-filtered-map-container.component.html @@ -0,0 +1,22 @@ +
    +
    +
    + +
    +
    + + +
    + + +
    + +
    + +
    +
    +
    + +
    + + diff --git a/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-for-filtered-map-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-for-filtered-map-container.component.ts new file mode 100644 index 000000000000..7673ad852248 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/side-bar/side-bar-for-filtered-map-container.component.ts @@ -0,0 +1,58 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +import { StoreHelperService } from 'app/shared/services'; + +@Component({ + selector: 'pp-side-bar-for-filtered-map-container', + templateUrl: './side-bar-for-filtered-map-container.component.html', + styleUrls: ['./side-bar-for-filtered-map-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SideBarForFilteredMapContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + target: any; + sideBarWidth = 0; + useDisable = true; + showLoading = true; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService + ) {} + ngOnInit() { + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getServerMapLoadingState(this.unsubscribe).subscribe((state: string) => { + switch (state) { + case 'loading': + this.showLoading = true; + this.useDisable = true; + break; + case 'pause': + case 'completed': + this.showLoading = false; + this.useDisable = false; + break; + } + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: any) => { + this.target = target; + this.sideBarWidth = 461; + this.changeDetectorRef.detectChanges(); + }); + } + hasTopElement(): boolean { + return this.target && (this.target.isNode || this.target.isMerged); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/index.ts b/web/src/main/webapp/v2/src/app/core/components/state-button/index.ts new file mode 100644 index 000000000000..6ea0bfd30820 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/index.ts @@ -0,0 +1,25 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { StateButtonComponent } from './state-button.component'; +import { StateButtonForFilteredMapContainerComponent } from './state-button-for-filtered-map-container.component'; +import { StateButtonForTransactionListContainerComponent } from './state-button-for-transaction-list-container.component'; +import { TransactionTableGridModule } from 'app/core/components/transaction-table-grid'; + +@NgModule({ + declarations: [ + StateButtonComponent, + StateButtonForFilteredMapContainerComponent, + StateButtonForTransactionListContainerComponent + ], + imports: [ + CommonModule, + TransactionTableGridModule + ], + exports: [ + StateButtonForFilteredMapContainerComponent, + StateButtonForTransactionListContainerComponent + ], + providers: [] +}) +export class StateButtonModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-filtered-map-container.component.css b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-filtered-map-container.component.css new file mode 100644 index 000000000000..c3329127e37a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-filtered-map-container.component.css @@ -0,0 +1,3 @@ +:host { + display: flex; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-filtered-map-container.component.html b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-filtered-map-container.component.html new file mode 100644 index 000000000000..559ca402504e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-filtered-map-container.component.html @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-filtered-map-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-filtered-map-container.component.ts new file mode 100644 index 000000000000..9600c6eedbc3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-filtered-map-container.component.ts @@ -0,0 +1,53 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; + +import { StoreHelperService } from 'app/shared/services'; +import { ServerMapForFilteredMapDataService } from 'app/core/components/server-map/server-map-for-filtered-map-data.service'; +import { BUTTON_STATE } from './state-button.component'; + +@Component({ + selector: 'pp-state-button-for-filtered-map-container', + templateUrl: './state-button-for-filtered-map-container.component.html', + styleUrls: ['./state-button-for-filtered-map-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class StateButtonForFilteredMapContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + showCountInfo = false; + currentState = BUTTON_STATE.PAUSE; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private serverMapForFilteredMapDataService: ServerMapForFilteredMapDataService + ) {} + ngOnInit() { + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getServerMapLoadingState(this.unsubscribe).subscribe((state: string) => { + switch (state) { + case 'loading': + this.currentState = BUTTON_STATE.PAUSE; + break; + case 'pause': + this.currentState = BUTTON_STATE.RESUME; + break; + case 'completed': + this.currentState = BUTTON_STATE.COMPLETED; + break; + } + this.changeDetectorRef.detectChanges(); + }); + } + onChangeState(event: string) { + if ( event === BUTTON_STATE.RESUME ) { + this.serverMapForFilteredMapDataService.resumeDataLoad(); + } else if ( event === BUTTON_STATE.PAUSE ) { + this.serverMapForFilteredMapDataService.stopDataLoad(); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-transaction-list-container.component.css b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-transaction-list-container.component.css new file mode 100644 index 000000000000..c3329127e37a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-transaction-list-container.component.css @@ -0,0 +1,3 @@ +:host { + display: flex; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-transaction-list-container.component.html b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-transaction-list-container.component.html new file mode 100644 index 000000000000..1ce6d47d1b6c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-transaction-list-container.component.html @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-transaction-list-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-transaction-list-container.component.ts new file mode 100644 index 000000000000..7f09a26009c4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button-for-transaction-list-container.component.ts @@ -0,0 +1,33 @@ +import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; + +import { TransactionMetaDataService } from 'app/core/components/transaction-table-grid/transaction-meta-data.service'; +import { BUTTON_STATE } from './state-button.component'; + +@Component({ + selector: 'pp-state-button-for-transaction-list-container', + templateUrl: './state-button-for-transaction-list-container.component.html', + styleUrls: ['./state-button-for-transaction-list-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class StateButtonForTransactionListContainerComponent implements OnInit { + countInfo = [0, 0]; + showCountInfo = true; + currentState = BUTTON_STATE.MORE; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private transactionMetaDataService: TransactionMetaDataService + ) {} + ngOnInit() { + this.transactionMetaDataService.onTransactionDataCount$.subscribe((counter: number[]) => { + this.countInfo = counter.concat(); + this.currentState = this.isLoadCompleted() ? BUTTON_STATE.DONE : BUTTON_STATE.MORE; + this.changeDetectorRef.detectChanges(); + }); + } + private isLoadCompleted(): boolean { + return this.countInfo[0] === this.countInfo[1]; + } + onChangeState(state: string) { + this.transactionMetaDataService.loadData(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/state-button.component.css b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button.component.css new file mode 100644 index 000000000000..16c293648f0c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button.component.css @@ -0,0 +1,4 @@ +.l-wrapper { + display: flex; + padding: 10px 20px 10px 10px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/state-button.component.html b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button.component.html new file mode 100644 index 000000000000..d178ffb2d67c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button.component.html @@ -0,0 +1,3 @@ +
    + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/state-button/state-button.component.ts b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button.component.ts new file mode 100644 index 000000000000..a8cc1cc19449 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/state-button/state-button.component.ts @@ -0,0 +1,64 @@ +import { Component, OnInit, Output, OnChanges, EventEmitter, SimpleChanges, Input } from '@angular/core'; + +import { AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; + +export enum BUTTON_STATE { + PAUSE = 'Pause', + RESUME = 'Resume', + COMPLETED = 'Completed', + MORE = 'More', + DONE = 'Done' +} + +@Component({ + selector: 'pp-state-button', + templateUrl: './state-button.component.html', + styleUrls: ['./state-button.component.css'] +}) +export class StateButtonComponent implements OnInit, OnChanges { + currentStateText = BUTTON_STATE.PAUSE.toString(); + @Input() width: number; + @Input() showCountInfo: boolean; + @Input() countInfo: number[]; + @Input() currentState = BUTTON_STATE.PAUSE; + @Output() outChangeState: EventEmitter = new EventEmitter(); + constructor( + private analyticsService: AnalyticsService, + ) { + this.currentStateText = this.currentState.toString(); + } + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if (changes['currentState'] && changes['currentState']['currentValue']) { + this.currentStateText = this.currentState.toString(); + } + } + private changeState(state: BUTTON_STATE): void { + this.currentState = state; + this.currentStateText = this.currentState.toString(); + } + onClick() { + switch (this.currentState) { + case BUTTON_STATE.COMPLETED: + this.outChangeState.emit(this.currentState); + this.changeState(BUTTON_STATE.COMPLETED); + break; + case BUTTON_STATE.DONE: + this.outChangeState.emit(this.currentState); + this.changeState(BUTTON_STATE.DONE); + break; + case BUTTON_STATE.PAUSE: + this.outChangeState.emit(this.currentState); + this.changeState(BUTTON_STATE.RESUME); + break; + case BUTTON_STATE.RESUME: + this.outChangeState.emit(this.currentState); + this.changeState(BUTTON_STATE.PAUSE); + break; + case BUTTON_STATE.MORE: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_MORE_STATE_BUTTON); + this.outChangeState.emit(this.currentState); + break; + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/index.ts b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/index.ts new file mode 100644 index 000000000000..bac356ebc202 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/index.ts @@ -0,0 +1,27 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ClipboardModule } from 'ngx-clipboard'; + +import { SyntaxHighlightPopupComponent } from './syntax-highlight-popup.component'; +import { SyntaxHighlightPopupContainerComponent } from './syntax-highlight-popup-container.component'; +import { SyntaxHighlightDataService } from './syntax-highlight-data.service'; + +@NgModule({ + declarations: [ + SyntaxHighlightPopupComponent, + SyntaxHighlightPopupContainerComponent + ], + imports: [ + CommonModule, + ClipboardModule, + ], + exports: [], + entryComponents: [ + SyntaxHighlightPopupContainerComponent + ], + providers: [ + SyntaxHighlightDataService + ] +}) +export class SyntaxHighlightPopupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-data.service.ts new file mode 100644 index 000000000000..65d5ace63db6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-data.service.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + +enum TYPE { + SQL = 'SQL', + JSON = 'JSON' +} + +@Injectable() +export class SyntaxHighlightDataService { + private url = 'bind.pinpoint'; + constructor(private http: HttpClient) { } + getData({type, originalContents, bindValue}: ISyntaxHighlightData): Observable { + let requestType; + switch (type) { + case TYPE.SQL: + requestType = 'sql'; + break; + case TYPE.JSON: + requestType = 'mongoJson'; + break; + } + return this.http.post( + this.url, + `type=${requestType}&metaData=${encodeURIComponent(originalContents)}&bind=${encodeURIComponent(bindValue)}`, + { + headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded') + } + ).pipe( + retry(3) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component.css b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component.css new file mode 100644 index 000000000000..3c6a97654ec4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component.css @@ -0,0 +1,18 @@ +:host { + display: block; + background-color: transparent; + width: 100%; + height: 100%; +} + +:host::before { + content: ''; + display: block; + height: 100%; + width: 100%; + background: #000; + opacity: 0.6; + position: absolute; + left: 0; + top: 0; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component.html b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component.html new file mode 100644 index 000000000000..78be554fce0e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component.html @@ -0,0 +1,6 @@ +
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component.ts new file mode 100644 index 000000000000..7d3748317a2a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup-container.component.ts @@ -0,0 +1,42 @@ +import { Component, OnInit, Input, Output, EventEmitter, AfterViewInit } from '@angular/core'; +import { Observable, iif, of } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { DynamicPopup } from 'app/shared/services'; +import { SyntaxHighlightDataService } from './syntax-highlight-data.service'; + +@Component({ + selector: 'pp-syntax-highlight-popup-container', + templateUrl: './syntax-highlight-popup-container.component.html', + styleUrls: ['./syntax-highlight-popup-container.component.css'], +}) +export class SyntaxHighlightPopupContainerComponent implements OnInit, AfterViewInit, DynamicPopup { + @Input() data: ISyntaxHighlightData; + @Output() outClose = new EventEmitter(); + @Output() outCreated = new EventEmitter(); + + data$: Observable; + + constructor( + private syntaxHighlightDataService: SyntaxHighlightDataService + ) {} + + ngOnInit() { + this.data$ = iif(() => !!this.data.bindValue, + this.syntaxHighlightDataService.getData(this.data).pipe( + map((bindedContents: string) => { + return { ...this.data, bindedContents }; + }) + ), + of(this.data) + ); + } + + ngAfterViewInit() { + this.outCreated.emit({ coordX: 0, coordY: 0 }); + } + + onClosePopup(): void { + this.outClose.emit(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup.component.css b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup.component.css new file mode 100644 index 000000000000..ca1ac5fc7ec6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup.component.css @@ -0,0 +1,79 @@ +:host{ + display: block; + position: absolute; + width: 100%; + min-width: 500px; + max-width: 1000px; + background-color: #fff; + border: 1px solid #e5e8f0; + box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.75); + text-align: left; + top: 50%; + transform: translateX(-50%) translateY(-50%); + left: 50%; +} +.l-title-group { + padding: 17px 18px; + height: auto; + background-color: #fff; + border-bottom: 1px solid #e5e8f0; + position: relative; + font-size: 13px; + font-weight: 600; + color: #333; + display: flex; + align-items: center; + justify-content: space-between; +} +.l-title-group dt { + font-size: 20px; + font-weight: 600; + color: #4a8fd2; +} +.l-title-group button { + position:absolute; + right:27px; + top:50%; + transform:translateY(-50%); + color:#4a8fd2; + font-size: 30px; + width:20px; + height:20px; + background:url(../../../../assets/img/icon-close.png) no-repeat 0 0; +} +.l-contents-group { + background: #f6f8fb; + padding: 17px 18px; + overflow: auto; +} +.l-sql-list { + margin: 10px 0 0 0; +} +.l-sql-list:first-child { + margin: 0; +} +.l-sql-list dt { + font-size: 13px; + font-weight: 600; + color: #333; + margin: 0 0 12px; +} +.l-sql-list dd { + border: 1px solid #cfd7e1; + background: #fff; + padding: 18px 18px; + font-size: 13px; + color: #999; + line-height: 2em; + position: relative; +} +.l-sql-list button { + position: absolute; + right: 0; + bottom: 0; +} +pre { + height: 250px; + overflow: auto; + border-radius: 0px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup.component.html b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup.component.html new file mode 100644 index 000000000000..ee67369eff9f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup.component.html @@ -0,0 +1,27 @@ +
    +
    {{data.type}}
    + +
    +
    +
    +
    Binded {{data.type}}
    +
    +
    
    +            
    +        
    +
    +
    +
    Original {{data.type}}
    +
    +
    
    +            
    +        
    +
    +
    +
    {{data.type}} Bind Value
    +
    + {{data.bindValue}} + +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup.component.ts b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup.component.ts new file mode 100644 index 000000000000..50ddff09c92d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/syntax-highlight-popup/syntax-highlight-popup.component.ts @@ -0,0 +1,42 @@ +declare var PR: any; +import { Component, OnInit, Input, Output, EventEmitter, HostBinding, AfterViewChecked } from '@angular/core'; +import { ClipboardService } from 'ngx-clipboard'; +import { js_beautify } from 'js-beautify'; +import sqlFormatter from 'sql-formatter'; +@Component({ + selector: 'pp-syntax-highlight-popup', + templateUrl: './syntax-highlight-popup.component.html', + styleUrls: ['./syntax-highlight-popup.component.css'] +}) +export class SyntaxHighlightPopupComponent implements OnInit, AfterViewChecked { + @Input() data: ISyntaxHighlightData; + @Output() outClosePopup = new EventEmitter(); + @HostBinding('class.font-opensans') fontFamily = true; + + constructor(private clipboardService: ClipboardService) {} + ngOnInit() {} + ngAfterViewChecked() { + PR.prettyPrint(); + } + onCopyOriginalContents() { + this.clipboardService.copyFromContent(this.formatting(this.data.originalContents)); + } + onCopyBindedContents() { + this.clipboardService.copyFromContent(this.formatting(this.data.bindedContents)); + } + onCopyBindValue() { + this.clipboardService.copyFromContent(this.data.bindValue); + } + onClose() { + this.outClosePopup.emit(); + } + hasBind(): boolean { + return !!this.data.bindValue; + } + getClassName(): string { + return 'lang-' + this.data.type.toLowerCase(); + } + formatting(code: string): string { + return this.data.type === 'SQL' ? sqlFormatter.format(code) : js_beautify(code); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/target-list/index.ts b/web/src/main/webapp/v2/src/app/core/components/target-list/index.ts new file mode 100644 index 000000000000..2553bb3825e1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/target-list/index.ts @@ -0,0 +1,23 @@ + +import { NgModule } from '@angular/core'; + +import { CommonModule } from '@angular/common'; +import { TargetListComponent } from './target-list.component'; +import { TargetListContainerComponent } from './target-list-container.component'; +import { FilterTransactionWizardPopupModule } from 'app/core/components/filter-transaction-wizard-popup'; + +@NgModule({ + declarations: [ + TargetListComponent, + TargetListContainerComponent + ], + imports: [ + CommonModule, + FilterTransactionWizardPopupModule + ], + exports: [ + TargetListContainerComponent + ], + providers: [] +}) +export class TargetListModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/target-list/target-list-container.component.css b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list-container.component.css new file mode 100644 index 000000000000..e91a2913301f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list-container.component.css @@ -0,0 +1,63 @@ +.l-target-container-wrapper { + margin: 0; + position: relative; + width: 459px; + height: 361px; + font-size: 14px; +} +.l-target-container { + display: grid; + grid-template-columns: auto; + grid-template-rows: 32px 299px 30px; +} +.l-target-container .l-search-header { + /* autoprefixer: off */ + color: #B3B3B4; + grid-column: 1 / 2; + grid-row: 1 / 2; +} +.l-target-container .l-search-header input { + width: 457px; + height: 30px; + padding: 0px 8px; + margin: 0px; + border: 1px solid #D7DDE4; +} +.l-target-container .l-search-header button { + position: absolute; + right: 10px; + top: 8px; + color: #B3B3B4; +} +.l-target-container .l-target-list { + /* autoprefixer: off */ + grid-column: 1 / 2; + grid-row: 2 / 3; + padding: 4px 0px; + overflow-x: hidden; + overflow-y: auto; +} + +.l-target-container .l-summary { + /* autoprefixer: off */ + grid-column: 1 / 2; + grid-row: 3 / 4; + background-color: #469ae4; +} +.l-target-container .l-summary > div { + display: flex; + color: #FFF; + cursor: pointer; + flex-wrap: nowrap; + align-items: center; + flex-direction: row; + justify-content: space-between; + height: 100%; + padding: 0px 28px 0px 8px; +} +button { + cursor: pointer; + background: none; + border: none; + font-size: 14px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/target-list/target-list-container.component.html b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list-container.component.html new file mode 100644 index 000000000000..6c56da0ada07 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list-container.component.html @@ -0,0 +1,23 @@ +
    +
    +
    + + +
    +
    + + +
    +
    +
    + {{targetList.length}} application{{targetList.length > 1 ? 's' : ''}} + {{getRequestSum() | number}} +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/target-list/target-list-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list-container.component.ts new file mode 100644 index 000000000000..5bad897cfaf3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list-container.component.ts @@ -0,0 +1,172 @@ +import { Component, OnInit, OnDestroy, AfterViewInit, AfterViewChecked, ElementRef, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, debounceTime, distinctUntilChanged, filter } from 'rxjs/operators'; + +import { Actions } from 'app/shared/store'; +import { UrlPathId } from 'app/shared/models'; +import { Filter } from 'app/core/models/filter'; +import { + UrlRouteManagerService, + StoreHelperService, + NewUrlStateNotificationService, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { ServerMapData } from 'app/core/components/server-map/class/server-map-data.class'; +import { FilterTransactionWizardPopupContainerComponent } from 'app/core/components/filter-transaction-wizard-popup/filter-transaction-wizard-popup-container.component'; + +@Component({ + selector: 'pp-target-list-container', + templateUrl: './target-list-container.component.html', + styleUrls: ['./target-list-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TargetListContainerComponent implements OnInit, OnDestroy, AfterViewInit, AfterViewChecked { + minLength = 2; + isLink = false; + filterQuery = ''; + selectedTarget: ISelectedTarget; + serverMapData: ServerMapData; + notFilteredTargetList: any[]; + targetList: any[]; + unsubscribe: Subject = new Subject(); + userInputChange = new Subject(); + inputElement: HTMLInputElement; + constructor( + private changeDetector: ChangeDetectorRef, + private elementRef: ElementRef, + private urlRouteManagerService: UrlRouteManagerService, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private dynamicPopupService: DynamicPopupService, + private analyticsService: AnalyticsService + ) {} + ngOnInit() { + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + ngAfterViewInit(): void { + this.inputElement = this.elementRef.nativeElement.querySelector('input'); + this.setFocusToInput(); + } + ngAfterViewChecked(): void { + this.inputElement = this.elementRef.nativeElement.querySelector('input'); + } + private connectStore(): void { + this.storeHelperService.getServerMapTargetSelected(this.unsubscribe).pipe( + filter((target: ISelectedTarget) => { + return target && (target.isNode === true || target.isNode === false) ? true : false; + }) + ).subscribe((target: ISelectedTarget) => { + this.selectedTarget = target; + if (target.isMerged === true) { + this.isLink = target.isLink; + if ( this.inputElement ) { + this.inputElement.value = ''; + } + this.gatherTargets(); + } + this.changeDetector.detectChanges(); + }); + this.storeHelperService.getServerMapData(this.unsubscribe).subscribe((serverMapData: ServerMapData) => { + this.serverMapData = serverMapData; + }); + this.userInputChange.pipe( + debounceTime(300), + distinctUntilChanged(), + takeUntil(this.unsubscribe) + ).subscribe((res: string) => { + const len = res.length; + if ( len === 0 || len >= this.minLength ) { + this.setFilterQuery(res); + } + }); + } + isGroup(): boolean { + return this.selectedTarget && this.selectedTarget.isMerged === true ? true : false; + } + gatherTargets(): void { + if ( this.selectedTarget.isMerged ) { + const targetList: any = []; + if ( this.selectedTarget.isNode ) { + this.selectedTarget.node.forEach(nodeKey => { + targetList.push([this.serverMapData.getNodeData(nodeKey), '']); + }); + } else if ( this.selectedTarget.isLink ) { + // Link 인 경우 필터 관련 버튼을 추가해야 함. + this.selectedTarget.link.forEach(linkKey => { + targetList.push([this.serverMapData.getNodeData(this.serverMapData.getLinkData(linkKey).to), linkKey]); + }); + } + this.notFilteredTargetList = this.targetList = targetList; + } + } + onSelectTarget(target: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_NODE_IN_GROUPED_VIEW); + this.storeHelperService.dispatch(new Actions.UpdateServerMapSelectedTargetByList(target[0])); + } + onOpenFilter(target: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_FILTER_TRANSACTION); + const link = this.serverMapData.getLinkData(target[1]); + this.urlRouteManagerService.openPage(this.urlRouteManagerService.makeFilterMapUrl({ + applicationName: link.filterApplicationName, + serviceType: link.filterApplicationServiceTypeName, + periodStr: this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithAddedWords(), + timeStr: this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getEndTime(), + filterStr: this.newUrlStateNotificationService.getPathValue(UrlPathId.FILTER), + hintStr: this.newUrlStateNotificationService.getPathValue(UrlPathId.HINT), + addedFilter: new Filter( + link.sourceInfo.applicationName, + link.sourceInfo.serviceType, + link.targetInfo.applicationName, + link.targetInfo.serviceType + )} + )); + } + getRequestSum(): number { + return this.targetList.reduce((accumulator: number, target: any) => { + return accumulator + target[0].totalCount; + }, 0); + } + onOpenFilterWizard(target: any): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_FILTER_TRANSACTION_WIZARD); + this.dynamicPopupService.openPopup({ + data: this.serverMapData.getLinkData(target[1]), + component: FilterTransactionWizardPopupContainerComponent + }); + } + onKeyUp($event: any): void { + if ( $event.keyCode === 27 ) { + this.inputElement.value = ''; + this.setFilterQuery(''); + } else { + this.userInputChange.next($event.target.value); + } + } + setFocusToInput(): void { + if ( this.inputElement ) { + this.inputElement.focus(); + } + } + setFilterQuery(query: string): void { + this.filterQuery = query; + this.targetList = this.filterList(); + this.changeDetector.detectChanges(); + } + filterList(): any[] { + if ( this.filterQuery === '' ) { + return this.notFilteredTargetList; + } + const filteredList: any = []; + this.notFilteredTargetList.forEach(aTarget => { + if ( aTarget[0].applicationName.indexOf(this.filterQuery) !== -1 ) { + filteredList.push(aTarget); + } + }); + return filteredList; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/target-list/target-list.component.css b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list.component.css new file mode 100644 index 000000000000..1ae0b6ff9cbc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list.component.css @@ -0,0 +1,42 @@ +.l-target-item { + display: flex; + padding: 4px 10px 4px 4px; + cursor: pointer; + flex-wrap: nowrap; + align-items: center; + flex-direction: row; + justify-content: space-between; + border-bottom: 1px solid #F3F3F3; +} +.l-target-item:hover { + background-color: #c1ecff; +} +.l-target-item.selected { + color: #1BABF4; + font-weight: 600; +} +.l-target-item:last-of-type { + border-bottom: none; +} +.l-application-name { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +button { + font-size: 11px; + padding: 1px 3px 0px 3px; +} + +button:first-of-type { + color: #4b99e3; + border: #CCC 1px solid; + margin-right: 1px; +} +button:last-of-type { + color: #e95459; + border: #CCC 1px solid; + margin-right: 8px; +} + diff --git a/web/src/main/webapp/v2/src/app/core/components/target-list/target-list.component.html b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list.component.html new file mode 100644 index 000000000000..18049e33a3ce --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list.component.html @@ -0,0 +1,8 @@ +
    + + + + {{target[0].applicationName}} + + {{target[0].totalCount | number}} +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/target-list/target-list.component.ts b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list.component.ts new file mode 100644 index 000000000000..5a5a81f445e6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/target-list/target-list.component.ts @@ -0,0 +1,28 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-target-list', + templateUrl: './target-list.component.html', + styleUrls: ['./target-list.component.css'] +}) +export class TargetListComponent implements OnInit { + selectedAppName = ''; + @Input() isLink: boolean; + @Input() targetList: any[]; + @Output() outSelectTarget: EventEmitter = new EventEmitter(); + @Output() outOpenFilter: EventEmitter = new EventEmitter(); + @Output() outOpenFilterWizard: EventEmitter = new EventEmitter(); + constructor() { } + ngOnInit() { + } + onSelectTarget(target): void { + this.selectedAppName = target[0].applicationName; + this.outSelectTarget.emit(target); + } + onOpenFilter($event, target): void { + this.outOpenFilter.emit(target); + } + onOpenFilterWizard($event, target): void { + this.outOpenFilterWizard.emit(target); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/active-thread-dump-list-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/active-thread-dump-list-data.service.ts new file mode 100644 index 000000000000..e58bc2283165 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/active-thread-dump-list-data.service.ts @@ -0,0 +1,43 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + +export interface IActiveThreadDump { + threadId: string; + threadName: string; + threadState: string; + startTime: number; + execTime: number; + localTraceId: number; + sampled: boolean; + transactionId: string; + entryPoint: string; + detailMessage: string; +} + +export interface IActiveThreadDumpResponse { + code: number; + message: { + subType: string; + threadDumpData: IActiveThreadDump[]; + type: string; + version: string; + }; +} + +@Injectable() +export class ActiveThreadDumpListDataService { + private requestURL = 'agent/activeThreadLightDump.pinpoint'; + constructor(private http: HttpClient) {} + getData(applicationName: string, agentId: string): Observable { + return this.http.get(this.requestURL, this.makeRequestOptionsArgs(applicationName, agentId)).pipe( + retry(3) + ); + } + private makeRequestOptionsArgs(applicationName: string, agentId: string): object { + return { + params: new HttpParams().set('applicationName', applicationName).set('agentId', agentId) + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/index.ts b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/index.ts new file mode 100644 index 000000000000..8f2018b77fe3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/index.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { AgGridModule } from 'ag-grid-angular/main'; +import { ThreadDumpListContainerComponent } from './thread-dump-list-container.component'; +import { ThreadDumpListComponent } from './thread-dump-list.component'; +import { ActiveThreadDumpListDataService } from './active-thread-dump-list-data.service'; + +@NgModule({ + declarations: [ + ThreadDumpListComponent, + ThreadDumpListContainerComponent + ], + imports: [ + SharedModule, + AgGridModule.withComponents([]) + ], + exports: [ + ThreadDumpListContainerComponent + ], + providers: [ + ActiveThreadDumpListDataService + ] +}) +export class ThreadDumpListModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list-container.component.css b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list-container.component.css new file mode 100644 index 000000000000..cbb7ab917be5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list-container.component.css @@ -0,0 +1,17 @@ +.there-is-no-data { + position: absolute; + width: 100%; + height: 100%; + padding-top: 40%; + text-align: center; +} +.when-has-message > span { + color: #F00; +} +.when-has-message > div { + padding-top: 10px; +} +.when-has-message > ul { + list-style: none; + padding-top: 10px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list-container.component.html b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list-container.component.html new file mode 100644 index 000000000000..85f2675a4598 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list-container.component.html @@ -0,0 +1,21 @@ + +
    + There is no data +
    +
    + {{errorMessage}} +
    +
    For the above reasons, this agent does not support thread dump.
    +
      +
    • 1. check this agent version is 1.6.1+
    • +
    • 2. check cluster feature is enabled.
    • +
    +
    +
    + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list-container.component.ts new file mode 100644 index 000000000000..1d16a9cdbcf1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list-container.component.ts @@ -0,0 +1,93 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { takeUntil, filter, switchMap } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { StoreHelperService, NewUrlStateNotificationService} from 'app/shared/services'; +import { ThreadDumpLogInteractionService, IParam } from 'app/core/components/thread-dump-log/thread-dump-log-interaction.service'; +import { ActiveThreadDumpListDataService, IActiveThreadDump } from './active-thread-dump-list-data.service'; +import { IThreadDumpData } from './thread-dump-list.component'; + + +@Component({ + selector: 'pp-thread-dump-list-container', + templateUrl: './thread-dump-list-container.component.html', + styleUrls: ['./thread-dump-list-container.component.css'] +}) +export class ThreadDumpListContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private applicationName: string; + private agentId: string; + rowData: IThreadDumpData[] = []; + serverResponseError = true; + hasErrorResponse = false; + errorMessage: string; + showLoading = true; + loaded = false; + timezone$: Observable; + dateFormat$: Observable; + constructor( + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private activeThreadDumpListDataService: ActiveThreadDumpListDataService, + private threadDumpLogInteractionService: ThreadDumpLogInteractionService + ) {} + ngOnInit() { + this.connectStore(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.APPLICATION, UrlPathId.AGENT_ID); + }), + switchMap((urlService: NewUrlStateNotificationService) => { + this.applicationName = urlService.getPathValue(UrlPathId.APPLICATION).getApplicationName(); + this.agentId = urlService.getPathValue(UrlPathId.AGENT_ID); + return this.activeThreadDumpListDataService.getData(this.applicationName, this.agentId); + }) + ).subscribe((data: any) => { + if (data.code === -1) { + this.serverResponseError = true; + this.hasErrorResponse = true; + this.errorMessage = data.message; + } else { + this.rowData = data.message.threadDumpData.map((threadDump: IActiveThreadDump, index: number) => { + return { + index: index + 1, + id: threadDump.threadId, + name: threadDump.threadName, + state: threadDump.threadState, + startTime: threadDump.startTime, + exec: threadDump.execTime, + sampled: threadDump.sampled, + path: threadDump.entryPoint, + transactionId: threadDump.transactionId, + localTraceId: threadDump.localTraceId + }; + }); + } + this.showLoading = false; + }, (error: IServerErrorFormat) => { + this.serverResponseError = false; + this.hasErrorResponse = true; + this.errorMessage = error.exception.message; + this.showLoading = false; + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + this.dateFormat$ = this.storeHelperService.getDateFormat(this.unsubscribe, 2); + } + hasData(): boolean { + return this.rowData.length > 0; + } + hasError(): boolean { + return this.hasErrorResponse; + } + onSelectThread($param: IParam): void { + this.threadDumpLogInteractionService.sendParam($param); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list.component.css b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list.component.css new file mode 100644 index 000000000000..f943a2791973 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list.component.css @@ -0,0 +1,76 @@ +:host { + width: 100%; + height: 100%; +} +#thread-dump-table .ag-root { + border: none; + font-size: 12px; + font-family: 'Open Sans', sans-serif; +} +#thread-dump-table .ag-cell { + padding: 4px; + font-family: 'Open Sans', sans-serif; +} +#thread-dump-table .ag-column-moving .ag-cell { + transition: left 0.2s; +} +#thread-dump-table .ag-header-cell-moving .ag-header-cell-label { + opacity: 0; + filter: alpha(opacity=0); +} +#thread-dump-table .ag-header-cell-moving { + background-color: #bebebe; +} +#thread-dump-table .ag-header-cell-moving-clone { + border-right: 1px solid #808080; + border-left: 1px solid #808080; + background-color: rgba(220,220,220,0.8); +} +#thread-dump-table .ag-header { + background: #f6f8fb; + border-top: 1px solid #e6e8ec; + line-height: 2; +} +#thread-dump-table .ag-header-cell { + font-size: 12px; + font-weight: 600; + font-family: 'Open Sans', sans-serif; + padding-left: 2px; + padding-right: 2px; +} +#thread-dump-table .ag-header-cell-resize:after { + border-right: none; +} +#thread-dump-table .ag-header-cell-label { + padding: 4px; +} +#thread-dump-table .ag-group-expanded span { + margin-right: 4px; +} +#thread-dump-table .ag-row:hover { + cursor: pointer; + background-color: #F5F5F5; +} +#thread-dump-table .ag-row { + line-height: 2; + border-bottom: 1px solid #e6e8ec; +} +#thread-dump-table .ag-body { + background-color: #ffffff; +} +#thread-dump-table .ag-body-viewport { + background-color: #ffffff; +} +#thread-dump-table .ag-menu { + background-color: #ffffff; + border: 1px solid grey; +} +#thread-dump-table .fa { + font-size: 14px; +} +#thread-dump-table .ag-row-exception { + background-color: #fff1f1; +} +#thread-dump-table .ag-row-selected { + background-color: #e4f5e3; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list.component.html b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list.component.html new file mode 100644 index 000000000000..13fcc4a3fc83 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list.component.html @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list.component.ts b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list.component.ts new file mode 100644 index 000000000000..e12c21e2ae9a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-list/thread-dump-list.component.ts @@ -0,0 +1,147 @@ +import { Component, OnInit, OnDestroy, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core'; +import * as moment from 'moment-timezone'; +import { GridOptions } from 'ag-grid'; + +export interface IThreadDumpData { + index: number; + id: string; + name: string; + state: string; + startTime: number; + exec: number; + sampled: boolean; + path: string; + transactionId: string; + localTraceId: number; +} + +@Component({ + selector: 'pp-thread-dump-list', + templateUrl: './thread-dump-list.component.html', + styleUrls: ['./thread-dump-list.component.css'], + encapsulation: ViewEncapsulation.None +}) +export class ThreadDumpListComponent implements OnInit, OnDestroy { + @Input() rowData: IThreadDumpData[]; + @Input() timezone: string; + @Input() dateFormat: string; + @Output() outSelectThread: EventEmitter = new EventEmitter(); + gridOptions: GridOptions; + constructor() {} + ngOnInit() { + this.initGridOptions(); + } + private initGridOptions(): void { + this.gridOptions = { + rowHeight: 30, + columnDefs: this.makeColumnDefs(), + animateRows: true, + rowSelection: 'single', + headerHeight: 34, + enableSorting: false, + enableColResize: true, + onCellClicked: (params: any) => { + if ( params.colDef.field === 'localTraceId' ) { + const tag = params.event.target.tagName.toUpperCase(); + if (tag === 'I' || tag === 'BUTTON' ) { + this.outSelectThread.next({ + threadName: params.data.name, + localTraceId: params.data.localTraceId + }); + return; + } + } + } + }; + } + private makeColumnDefs(): any { + return [ + { + headerName: '#', + field: 'index', + width: 30, + cellStyle: () => { + return {'text-align': 'center'}; + }, + suppressSizeToFit: true + }, + { + headerName: 'id', + field: 'id', + width: 60, + cellStyle: () => { + return {'text-align': 'center'}; + }, + suppressSizeToFit: true + }, + { + headerName: 'name', + field: 'name', + width: 150, + tooltipField: 'name' + }, + { + headerName: 'state', + field: 'state', + width: 120, + suppressSizeToFit: true + }, + { + headerName: 'start time', + field: 'startTime', + width: 140, + valueFormatter: (params: any) => { + return moment(params.value).tz(this.timezone).format(this.dateFormat); + }, + suppressSizeToFit: true, + tooltipField: 'startTime' + }, + { + headerName: 'exec(ms)', + field: 'exec', + width: 120, + suppressSizeToFit: true + }, + { + headerName: 'sampled', + field: 'sampled', + width: 90, + suppressSizeToFit: true + }, + { + headerName: 'path', + field: 'path', + width: 200, + tooltipField: 'path' + }, + { + headerName: 'transaction id', + field: 'transactionId', + width: 220, + suppressSizeToFit: true, + tooltipField: 'transactionId' + }, + { + headerName: '', + field: 'localTraceId', + width: 40, + cellStyle: () => { + return {'text-align': 'center'}; + }, + cellRenderer: () => { + return ''; + }, + suppressSizeToFit: true + } + ]; + } + ngOnDestroy() { + } + onGridReady(params: GridOptions): void { + this.gridOptions.api.sizeColumnsToFit(); + } + onGridSizeChanged(params: GridOptions): void { + this.gridOptions.api.sizeColumnsToFit(); + } + +} diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/active-thread-dump-detail-info-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/active-thread-dump-detail-info-data.service.ts new file mode 100644 index 000000000000..f1e01dc20912 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/active-thread-dump-detail-info-data.service.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + +export interface IActiveThreadDump { + threadId: string; + threadName: string; + threadState: string; + startTime: number; + execTime: number; + localTraceId: number; + sampled: boolean; + transactionId: string; + entryPoint: string; + detailMessage: string; +} +export interface IActiveThreadDumpResponse { + code: number; + message: { + subType: string; + threadDumpData: IActiveThreadDump[]; + type: string; + version: string; + }; +} + +@Injectable() +export class ActiveThreadDumpDetailInfoDataService { + private requestURL = 'agent/activeThreadDump.pinpoint'; + constructor(private http: HttpClient) {} + getData(applicationName: string, agentId: string, threadName: string, localTraceId: number): Observable { + return this.http.get(this.requestURL, this.makeRequestOptionsArgs(applicationName, agentId, threadName, localTraceId)).pipe( + retry(3) + ); + } + private makeRequestOptionsArgs(applicationName: string, agentId: string, threadName: string, localTraceId: number): object { + return { + params: new HttpParams() + .set('applicationName', applicationName) + .set('agentId', agentId) + .set('threadName', threadName) + .set('localTraceId', '' + localTraceId) + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/index.ts b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/index.ts new file mode 100644 index 000000000000..6dda36aad50f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/index.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; + +import { ThreadDumpLogContainerComponent } from './thread-dump-log-container.component'; +import { ThreadDumpLogInteractionService } from './thread-dump-log-interaction.service'; +import { ActiveThreadDumpDetailInfoDataService } from './active-thread-dump-detail-info-data.service'; + +@NgModule({ + declarations: [ + ThreadDumpLogContainerComponent + ], + imports: [ + SharedModule + ], + exports: [ + ThreadDumpLogContainerComponent + ], + providers: [ + ThreadDumpLogInteractionService, + ActiveThreadDumpDetailInfoDataService + ] +}) +export class ThreadDumpLogModule {} diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-container.component.css b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-container.component.css new file mode 100644 index 000000000000..3fb81075194e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-container.component.css @@ -0,0 +1,9 @@ +textarea { + width: calc(100% - 40px); + height: calc(100% - 65px); + resize: none; + padding: 10px; + margin: 20px; + background-color: #FFF; + border: 1px solid #D0D7E1; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-container.component.html b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-container.component.html new file mode 100644 index 000000000000..3b9086fdc4ea --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-container.component.html @@ -0,0 +1,2 @@ + + diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-container.component.ts new file mode 100644 index 000000000000..8379a05de2e8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-container.component.ts @@ -0,0 +1,66 @@ +import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService } from 'app/shared/services'; +import { ActiveThreadDumpDetailInfoDataService } from './active-thread-dump-detail-info-data.service'; +import { ThreadDumpLogInteractionService, IParam } from './thread-dump-log-interaction.service'; + +@Component({ + selector: 'pp-thread-dump-log-container', + templateUrl: './thread-dump-log-container.component.html', + styleUrls: ['./thread-dump-log-container.component.css'], +}) +export class ThreadDumpLogContainerComponent implements OnInit, OnDestroy { + @ViewChild('logDisplay') target: ElementRef; + private unsubscribe: Subject = new Subject(); + private applicationName: string; + private agentId: string; + showLoading = false; + constructor( + private newUrlStateNotificationService: NewUrlStateNotificationService, + private activeThreadDumpDetailInfoDataService: ActiveThreadDumpDetailInfoDataService, + private threadDumpLogInteractionService: ThreadDumpLogInteractionService + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.APPLICATION, UrlPathId.AGENT_ID); + } + )).subscribe((urlService: NewUrlStateNotificationService) => { + this.applicationName = urlService.getPathValue(UrlPathId.APPLICATION).getApplicationName(); + this.agentId = urlService.getPathValue(UrlPathId.AGENT_ID); + }); + this.threadDumpLogInteractionService.onParam$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((param: IParam) => { + this.showLoading = true; + this.loadData(param.threadName, param.localTraceId); + }); + } + private loadData(threadName: string, localTraceId: number): void { + this.activeThreadDumpDetailInfoDataService.getData(this.applicationName, this.agentId, threadName, localTraceId).subscribe((data: any) => { + let msg = ''; + if (data.code === -1) { + msg = data.message; + } else { + if (data.message.threadDumpData.length > 0) { + msg = data.message.threadDumpData[0].detailMessage; + } else { + msg = 'There is no message( may be completed )'; + } + } + this.target.nativeElement.value = msg; + this.showLoading = false; + }, (error: IServerErrorFormat) => { + this.target.nativeElement.value = error.exception.message; + this.showLoading = false; + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-interaction.service.ts new file mode 100644 index 000000000000..c7563354b6df --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/thread-dump-log/thread-dump-log-interaction.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; + +export interface IParam { + threadName: string; + localTraceId: number; +} + +@Injectable() +export class ThreadDumpLogInteractionService { + private outParam: Subject = new Subject(); + onParam$: Observable; + constructor() { + this.onParam$ = this.outParam.asObservable(); + } + sendParam(param: IParam): void { + this.outParam.next(param); + } +} + diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/index.ts b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/index.ts new file mode 100644 index 000000000000..6edf79987899 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/index.ts @@ -0,0 +1,22 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { TimelineCommandGroupComponent } from './timeline-command-group.component'; +import { TimelineCommandGroupContainerComponent } from './timeline-command-group-container.component'; + +@NgModule({ + declarations: [ + TimelineCommandGroupComponent, + TimelineCommandGroupContainerComponent + ], + imports: [ + CommonModule + ], + exports: [ + TimelineCommandGroupContainerComponent + ], + providers: [ + + ] +}) +export class TimelineCommandGroupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group-container.component.css b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group-container.component.css new file mode 100644 index 000000000000..1620771952cf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group-container.component.css @@ -0,0 +1,6 @@ +.l-command-group { + display: flex; + padding: 4px 12px; + justify-content: flex-end; + background-color: #F5F5F5; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group-container.component.html b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group-container.component.html new file mode 100644 index 000000000000..86a6d9bf04ee --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group-container.component.html @@ -0,0 +1,3 @@ +
    + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group-container.component.ts new file mode 100644 index 000000000000..b662cb019bf1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group-container.component.ts @@ -0,0 +1,40 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import * as moment from 'moment-timezone'; +import { Subject, Observable, combineLatest } from 'rxjs'; + +import { StoreHelperService } from 'app/shared/services'; + +@Component({ + selector: 'pp-timeline-command-group-container', + templateUrl: './timeline-command-group-container.component.html', + styleUrls: ['./timeline-command-group-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TimelineCommandGroupContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + pointingTime: string; + pointingTime$: Observable; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService + ) {} + ngOnInit() { + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + combineLatest( + this.storeHelperService.getDateFormat(this.unsubscribe, 0), + this.storeHelperService.getTimezone(this.unsubscribe), + this.storeHelperService.getInspectorTimelineSelectedTime(this.unsubscribe) + ).subscribe((data: [string, string, number]) => { + const dateFormat = data[0]; + const timezone = data[1]; + this.pointingTime = moment(data[2]).tz(timezone).format(dateFormat); + this.changeDetectorRef.detectChanges(); + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group.component.css b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group.component.css new file mode 100644 index 000000000000..41c09c3f6814 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group.component.css @@ -0,0 +1,42 @@ +:host { + display: flex; +} +.l-current-time { + height: 28px; + display: flex; +} +.l-current-time label { + color: #FFF; + cursor: pointer; + height: 100%; + display: inline-block; + padding: 7px 10px; + font-size: 13px; + font-weight: 600; + background-color: #4A8FD2; +} +.l-current-time input { + width: 180px; + height: 100%; + border: 1px solid #4A8FD2; + display: inline-block; + font-size: 13px; + text-align: center; + background-color: #FFF; +} +.l-command-group { + display: inline-block; +} +.l-command-group:first-child { + margin-right: 30px; +} +.l-command-group:nth-child(2) { + margin-right: 10px; +} +.l-command-group .current-time { + font-size: 14px; + text-decoration: underline; +} +.l-command-group button { + border-radius: 0px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group.component.html b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group.component.html new file mode 100644 index 000000000000..6621bc822c17 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group.component.html @@ -0,0 +1,12 @@ +
    +
    + + +
    +
    +
    + +
    +
    + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group.component.ts b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group.component.ts new file mode 100644 index 000000000000..41d00f858f2a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline-command-group/timeline-command-group.component.ts @@ -0,0 +1,28 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { TimelineInteractionService } from 'app/core/components/timeline/timeline-interaction.service'; + +@Component({ + selector: 'pp-timeline-command-group', + templateUrl: './timeline-command-group.component.html', + styleUrls: ['./timeline-command-group.component.css'], +}) +export class TimelineCommandGroupComponent implements OnInit { + @Input() pointingTime: string; + constructor(private timelineInteractionService: TimelineInteractionService) {} + ngOnInit() {} + onClickZoomIn(): void { + this.timelineInteractionService.setZoomIn(); + } + onClickZoomOut(): void { + this.timelineInteractionService.setZoomOut(); + } + onClickPrev(): void { + this.timelineInteractionService.setPrev(); + } + onClickNext(): void { + this.timelineInteractionService.setNext(); + } + onClickNow(): void { + this.timelineInteractionService.setNow(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/agent-inspector-timeline-container.component.css b/web/src/main/webapp/v2/src/app/core/components/timeline/agent-inspector-timeline-container.component.css new file mode 100644 index 000000000000..da48c3f40268 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/agent-inspector-timeline-container.component.css @@ -0,0 +1,4 @@ +:host { + display: block; + margin: 18px 12px 0px 12px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/agent-inspector-timeline-container.component.html b/web/src/main/webapp/v2/src/app/core/components/timeline/agent-inspector-timeline-container.component.html new file mode 100644 index 000000000000..923ae4fdedd0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/agent-inspector-timeline-container.component.html @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/agent-inspector-timeline-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/agent-inspector-timeline-container.component.ts new file mode 100644 index 000000000000..87b5c6d4049d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/agent-inspector-timeline-container.component.ts @@ -0,0 +1,162 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { takeUntil, withLatestFrom } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { Actions } from 'app/shared/store'; +import { StoreHelperService, NewUrlStateNotificationService, UrlRouteManagerService, AnalyticsService, DynamicPopupService, TRACKED_EVENT_LIST } from 'app/shared/services'; +import { Timeline, ITimelineEventSegment, TimelineUIEvent } from './class'; +import { TimelineComponent } from './timeline.component'; +import { TimelineInteractionService, ITimelineCommandParam, TimelineCommand } from './timeline-interaction.service'; +import { AgentTimelineDataService, IAgentTimeline, IRetrieveTime } from './agent-timeline-data.service'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; +@Component({ + selector: 'pp-agent-inspector-timeline-container', + templateUrl: './agent-inspector-timeline-container.component.html', + styleUrls: ['./agent-inspector-timeline-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AgentInspectorTimelineContainerComponent implements OnInit, OnDestroy { + @ViewChild(TimelineComponent) + private timelineComponent: TimelineComponent; + private unsubscribe: Subject = new Subject(); + private agentId = ''; + timelineStartTime: number; + timelineEndTime: number; + selectionStartTime: number; + selectionEndTime: number; + pointingTime: number; + timelineData: IAgentTimeline; + timezone$: Observable; + dateFormat$: Observable; + + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private agentTimelineDataService: AgentTimelineDataService, + private timelineInteractionService: TimelineInteractionService, + private dynamicPopupService: DynamicPopupService, + private analyticsService: AnalyticsService, + ) {} + + ngOnInit() { + this.connectStore(); + this.timelineInteractionService.onCommand$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((param: ITimelineCommandParam) => { + switch (param.command) { + case TimelineCommand.zoomIn: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.ZOOM_IN_TIMELINE); + this.timelineComponent.zoomIn(); + break; + case TimelineCommand.zoomOut: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.ZOOM_OUT_TIMELINE); + this.timelineComponent.zoomOut(); + break; + case TimelineCommand.prev: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.MOVE_TO_PREV_ON_TIMELINE); + this.timelineComponent.movePrev(); + break; + case TimelineCommand.next: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.MOVE_TO_NEXT_ON_TIMELINE); + this.timelineComponent.moveNext(); + break; + case TimelineCommand.now: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.MOVE_TO_NOW_ON_TIMELINE); + this.timelineComponent.moveNow(); + break; + } + this.updateTimelineData(); + }); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + withLatestFrom(this.storeHelperService.getInspectorTimelineData(this.unsubscribe)) + ).subscribe(([urlService, savedTimelineData]: [NewUrlStateNotificationService, ITimelineInfo]) => { + this.agentId = this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID); + const selectionStartTime = urlService.getStartTimeToNumber(); + const selectionEndTime = urlService.getEndTimeToNumber(); + const range = this.calcuRetrieveTime(selectionStartTime, selectionEndTime); + let timelineInfo: ITimelineInfo = { + range: [range.start, range.end], + selectedTime: selectionEndTime, + selectionRange: [selectionStartTime, selectionEndTime] + }; + if (urlService.isChanged(UrlPathId.APPLICATION) === false && urlService.isChanged(UrlPathId.PERIOD) === false) { + if (savedTimelineData.selectedTime !== 0) { + timelineInfo = savedTimelineData; + } + } + this.agentTimelineDataService.getData(this.agentId, { + start: timelineInfo.range[0], + end: timelineInfo.range[1] + }).subscribe((response: IAgentTimeline) => { + this.timelineStartTime = timelineInfo.range[0]; + this.timelineEndTime = timelineInfo.range[1]; + this.selectionStartTime = timelineInfo.selectionRange[0]; + this.selectionEndTime = timelineInfo.selectionRange[1]; + this.pointingTime = timelineInfo.selectedTime; + this.timelineData = response; + this.storeHelperService.dispatch(new Actions.UpdateTimelineData(timelineInfo)); + this.changeDetector.detectChanges(); + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent, + onCloseCallback: () => { + this.urlRouteManagerService.reload(); + } + }); + }); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + this.dateFormat$ = this.storeHelperService.getDateFormatArray(this.unsubscribe, 0, 5, 6); + } + calcuRetrieveTime(startTime: number, endTime: number ): IRetrieveTime { + const allowedMaxRagne = Timeline.MAX_TIME_RANGE; + const timeGap = endTime - startTime; + if ( timeGap > allowedMaxRagne ) { + return { + start: endTime - allowedMaxRagne, + end: endTime + }; + } else { + const calcuStart = timeGap * 3; + return { + start: endTime - (calcuStart > allowedMaxRagne ? allowedMaxRagne : calcuStart), + end: endTime + }; + } + } + updateTimelineData(): void { + const range = this.timelineComponent.getTimelineRange(); + this.agentTimelineDataService.getData(this.agentId, { + start: range[0], + end: range[1] + }).subscribe((response: IAgentTimeline) => { + this.timelineComponent.updateData(response); + }); + } + onSelectEventStatus($eventObj: ITimelineEventSegment): void { + this.timelineInteractionService.sendSelectedEventStatus($eventObj); + } + onChangeTimelineUIEvent(event: TimelineUIEvent): void { + if (event.changedSelectedTime) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CHANGE_POINTING_TIME_ON_TIMELINE); + } + if (event.changedSelectionRange) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CHANGE_SELECTION_RANGE_ON_TIMELINE); + } + this.storeHelperService.dispatch(new Actions.UpdateTimelineData(event.data)); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/agent-timeline-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/agent-timeline-data.service.ts new file mode 100644 index 000000000000..ab81f38812c9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/agent-timeline-data.service.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams, HttpErrorResponse } from '@angular/common/http'; +import { Observable, throwError } from 'rxjs'; +import { catchError, retry } from 'rxjs/operators'; + +export interface IAgentTimeline { + agentEventTimeline: { + timelineSegments: any + }; + agentStatusTimeline: { + includeWarning: boolean; + timelineSegments: { + endTimestamp: number; + startTimestamp: number; + value: string; + }[] + }; +} +export interface IRetrieveTime { + start: number; + end: number; +} + +@Injectable() +export class AgentTimelineDataService { + requestURL = 'getAgentStatusTimeline.pinpoint'; + constructor(private http: HttpClient) { } + getData(agentId: string, retrieveTime: IRetrieveTime): Observable { + return this.http.get(this.requestURL, this.makeRequestOptionsArgs(agentId, retrieveTime)).pipe( + retry(3) + ); + } + private makeRequestOptionsArgs(agentId: string, { start: from, end: to }: IRetrieveTime): { 'params': { [key: string]: any } } { + return { + params: new HttpParams() + .set('agentId', agentId) + .set('from', from + '') + .set('to', to + '') + .set('exclude', 10199 + '') + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/application-inspector-timeline-container.component.css b/web/src/main/webapp/v2/src/app/core/components/timeline/application-inspector-timeline-container.component.css new file mode 100644 index 000000000000..da48c3f40268 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/application-inspector-timeline-container.component.css @@ -0,0 +1,4 @@ +:host { + display: block; + margin: 18px 12px 0px 12px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/application-inspector-timeline-container.component.html b/web/src/main/webapp/v2/src/app/core/components/timeline/application-inspector-timeline-container.component.html new file mode 100644 index 000000000000..923ae4fdedd0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/application-inspector-timeline-container.component.html @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/application-inspector-timeline-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/application-inspector-timeline-container.component.ts new file mode 100644 index 000000000000..e639536a7dc4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/application-inspector-timeline-container.component.ts @@ -0,0 +1,152 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { takeUntil, withLatestFrom } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { Actions } from 'app/shared/store'; +import { StoreHelperService, NewUrlStateNotificationService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; +import { Timeline, ITimelineEventSegment, TimelineUIEvent } from './class'; +import { TimelineComponent } from './timeline.component'; +import { TimelineInteractionService, ITimelineCommandParam, TimelineCommand } from './timeline-interaction.service'; +import { IAgentTimeline, IRetrieveTime } from './agent-timeline-data.service'; + +@Component({ + selector: 'pp-application-inspector-timeline-container', + templateUrl: './application-inspector-timeline-container.component.html', + styleUrls: ['./application-inspector-timeline-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ApplicationInspectorTimelineContainerComponent implements OnInit, OnDestroy { + @ViewChild(TimelineComponent) + private timelineComponent: TimelineComponent; + private unsubscribe: Subject = new Subject(); + timelineStartTime: number; + timelineEndTime: number; + selectionStartTime: number; + selectionEndTime: number; + pointingTime: number; + timelineData: IAgentTimeline; + timezone$: Observable; + dateFormat$: Observable; + + constructor( + private changeDetector: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private timelineInteractionService: TimelineInteractionService, + private analyticsService: AnalyticsService, + ) {} + + ngOnInit() { + this.connectStore(); + this.timelineInteractionService.onCommand$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((param: ITimelineCommandParam) => { + switch (param.command) { + case TimelineCommand.zoomIn: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.ZOOM_IN_TIMELINE); + this.timelineComponent.zoomIn(); + break; + case TimelineCommand.zoomOut: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.ZOOM_OUT_TIMELINE); + this.timelineComponent.zoomOut(); + break; + case TimelineCommand.prev: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.MOVE_TO_PREV_ON_TIMELINE); + this.timelineComponent.movePrev(); + break; + case TimelineCommand.next: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.MOVE_TO_NEXT_ON_TIMELINE); + this.timelineComponent.moveNext(); + break; + case TimelineCommand.now: + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.MOVE_TO_NOW_ON_TIMELINE); + this.timelineComponent.moveNow(); + break; + } + }); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + withLatestFrom(this.storeHelperService.getInspectorTimelineData(this.unsubscribe)), + ).subscribe(([urlService, savedTimelineData]: [NewUrlStateNotificationService, ITimelineInfo]) => { + /* + if ( application.changed or period.changed ) { + url 값 사용 + } else { + store에 저장된 값 있나? + - 있다면 사용 + - 없다면 URL 값 사용 + } + */ + const selectionStartTime = urlService.getStartTimeToNumber(); + const selectionEndTime = urlService.getEndTimeToNumber(); + const range = this.calcuRetrieveTime(selectionStartTime, selectionEndTime); + let timelineInfo: ITimelineInfo = { + range: [range.start, range.end], + selectedTime: selectionEndTime, + selectionRange: [selectionStartTime, selectionEndTime] + }; + if (urlService.isChanged(UrlPathId.APPLICATION) === false && urlService.isChanged(UrlPathId.PERIOD) === false) { + if (savedTimelineData.selectedTime !== 0) { + timelineInfo = savedTimelineData; + } + } + this.timelineStartTime = timelineInfo.range[0]; + this.timelineEndTime = timelineInfo.range[1]; + this.selectionStartTime = timelineInfo.selectionRange[0]; + this.selectionEndTime = timelineInfo.selectionRange[1]; + this.pointingTime = timelineInfo.selectedTime; + this.timelineData = { + 'agentStatusTimeline': { + 'timelineSegments': [ + { + 'startTimestamp': timelineInfo.range[0], + 'endTimestamp': timelineInfo.range[1], + 'value': 'EMPTY' + } + ], + 'includeWarning': false + }, + 'agentEventTimeline': { + 'timelineSegments': [] + } + }; + this.storeHelperService.dispatch(new Actions.UpdateTimelineData(timelineInfo)); + this.changeDetector.detectChanges(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + this.dateFormat$ = this.storeHelperService.getDateFormatArray(this.unsubscribe, 0, 5, 6); + } + calcuRetrieveTime(startTime: number, endTime: number ): IRetrieveTime { + const allowedMaxRagne = Timeline.MAX_TIME_RANGE; + const timeGap = endTime - startTime; + if ( timeGap > allowedMaxRagne ) { + return { + start: endTime - allowedMaxRagne, + end: endTime + }; + } else { + const calcuStart = timeGap * 3; + return { + start: endTime - (calcuStart > allowedMaxRagne ? allowedMaxRagne : calcuStart), + end: endTime + }; + } + } + onSelectEventStatus($eventObj: ITimelineEventSegment): void {} + onChangeTimelineUIEvent(event: TimelineUIEvent): void { + if (event.changedSelectedTime) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CHANGE_POINTING_TIME_ON_TIMELINE); + } + if (event.changedSelectionRange) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CHANGE_SELECTION_RANGE_ON_TIMELINE); + } + this.storeHelperService.dispatch(new Actions.UpdateTimelineData(event.data)); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/index.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/index.ts new file mode 100644 index 000000000000..abd5e75590c0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/index.ts @@ -0,0 +1,13 @@ +export * from './timeline-background.class'; +export * from './timeline-data.class'; +export * from './timeline-events.class'; +export * from './timeline-handler.class'; +export * from './timeline-loading-indicator.class'; +export * from './timeline-position-manager.class'; +export * from './timeline-selection-manager.class'; +export * from './timeline-selection-point.class'; +export * from './timeline-signboard.class'; +export * from './timeline-state-line.class'; +export * from './timeline-x-axis.class'; +export * from './timeline-ui-event'; +export * from './timeline.class'; diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-background.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-background.class.ts new file mode 100644 index 000000000000..e2faaa846b96 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-background.class.ts @@ -0,0 +1,17 @@ +declare var Snap: any; +declare var mina: any; + +export class TimelineBackground { + private backgroundRect: any; + constructor(private snap: any, private group: any, private options: { [key: string]: number }) { + this.addElements(); + } + addElements(): void { + this.backgroundRect = this.snap.rect(this.options.left, this.options.top, this.options.width, this.options.height); + this.group.add(this.backgroundRect); + } + reset(width: number): void { + this.backgroundRect.animate({ 'width': width }, this.options.duration, mina.easein); + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-data.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-data.class.ts new file mode 100644 index 000000000000..6c444b9cc21d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-data.class.ts @@ -0,0 +1,88 @@ +import { BehaviorSubject } from 'rxjs'; + +export interface ITimelineData { + agentEventTimeline: IAgentEventTimeline; + agentStatusTimeline: IAgentStatusTimeline; +} +export interface IAgentEventTimeline { + timelineSegments: ITimelineEventSegment[]; +} +export interface ITimelineEventSegment { + startTimestamp: number; + endTimestamp: number; + value: { + totalCount: number; + typeCounts: ITimelineEventSegmentTypeCount[]; + }; +} +export interface ITimelineEventSegmentTypeCount { + code: number; + desc: string; + count: number; +} +export interface IAgentStatusTimeline { + includeWarning: boolean; + timelineSegments: ITimelineStatusSegment[]; +} +export interface ITimelineStatusSegment { + endTimestamp: number; + startTimestamp: number; + value: string; +} + +export class TimelineData { + aStatusRawData: ITimelineStatusSegment[]; + oStatusRawHash: { [key: string]: ITimelineStatusSegment }; + aEventRawData: ITimelineEventSegment[]; + + onChangeStatusData$: BehaviorSubject = new BehaviorSubject(null); + onChangeEventData$: BehaviorSubject = new BehaviorSubject(null); + constructor(aRawData: ITimelineData) { + this.initData(aRawData); + this.onChangeStatusData$.next(this.aStatusRawData); + this.onChangeEventData$.next(this.aEventRawData); + } + initData(aRawData: ITimelineData): void { + this.initStatusData(aRawData.agentStatusTimeline); + this.initEventData(aRawData.agentEventTimeline); + } + initStatusData(oStatusRawData: IAgentStatusTimeline): void { + this.aStatusRawData = oStatusRawData.timelineSegments || []; + this.oStatusRawHash = {}; + this.aStatusRawData.forEach((segment: ITimelineStatusSegment) => { + this.oStatusRawHash[this.makeID(segment)] = segment; + }); + } + initEventData(oEventRawData: IAgentEventTimeline): void { + this.aEventRawData = oEventRawData.timelineSegments || []; + } + makeID(segment: ITimelineStatusSegment): string { + return segment.endTimestamp + ''; + } + eventCount(): number { + return this.aEventRawData.length; + } + statusCount(): number { + return this.aStatusRawData.length; + } + getDataByIndex(index: number): ITimelineStatusSegment { + return this.aStatusRawData[index]; + } + getDataByKey(key: string): ITimelineStatusSegment { + return this.oStatusRawHash[key]; + } + getEventDataByIndex(index: number): ITimelineEventSegment { + return this.aEventRawData[index]; + } + emptyData(): void { + this.aStatusRawData = []; + this.oStatusRawHash = {}; + this.aEventRawData = []; + } + addData(oNewData: ITimelineData): void { + this.initData(oNewData); + this.onChangeStatusData$.next(this.aStatusRawData); + this.onChangeEventData$.next(this.aEventRawData); + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-events.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-events.class.ts new file mode 100644 index 000000000000..11b5aa2a564b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-events.class.ts @@ -0,0 +1,127 @@ +declare var Snap: any; +import { Subject } from 'rxjs'; +import { ITimelineEventSegment } from './timeline-data.class'; +import { TimelinePositionManager } from './timeline-position-manager.class'; + +export class TimelineEvents { + private aEventGroupElement: any[] = []; + private aEventStatusData: ITimelineEventSegment[]; + clickEvent$: Subject = new Subject(); + constructor(private snap: any, private group: any, private options: { [key: string]: any }, private oPositionManager: TimelinePositionManager ) { + this.initOptions(); + this.addEvents(); + } + initOptions() { + const options = { + 'y': 4, + 'barLength': 4, + 'gapBarNCircle': 2, + 'circleRadius': 8, + 'filter': this.snap.filter( Snap.filter.shadow(1, 1, 1, '#000', 0.3)) + }; + Object.keys(options).forEach((key) => { + this.options[key] = options[key]; + }); + } + addEvents() { + this.group.click((event: any, x: number, y: number) => { + const targetElement = this.getElement(event, 'g'); + const dataIndex = Math.floor(targetElement.getAttribute('data-id')); + // const dataTime = targetElement.getAttribute('data-time'); + this.clickEvent$.next(this.aEventStatusData[dataIndex]); + }); + } + getElement(event: any, elementName: string): any | null { + let target = event.target; + while (target) { + if ( target.tagName.toLowerCase() === elementName ) { + break; + } + target = target.parentElement; + } + return target; + } + updateData(data: ITimelineEventSegment[]): void { + this.aEventStatusData = data; + this.emptyData(); + this.reset(); + } + emptyData(): void { + this.aEventGroupElement.forEach((g: any) => { + g.attr('display', 'none'); + }); + } + reset(): void { + const oldLen = this.aEventGroupElement.length; + const newLen = this.aEventStatusData.length; + let index; + + if ( oldLen === newLen ) { + for ( index = 0 ; index < newLen ; index++ ) { + this.reposition(this.aEventGroupElement[index], index); + } + } else if ( oldLen > newLen ) { + for ( index = newLen ; index < oldLen ; index++ ) { + this.aEventGroupElement[index].attr('display', 'none'); + } + for ( index = 0 ; index < newLen ; index++ ) { + this.reposition(this.aEventGroupElement[index], index); + } + } else { // oldLen < newLen + for ( index = 0 ; index < oldLen ; index++ ) { + this.reposition(this.aEventGroupElement[index], index); + } + for ( index = oldLen ; index < newLen ; index++ ) { + this.addEventElement(this.aEventStatusData[index], index); + } + } + } + reposition(elEventGroup: any, index: number): void { + const oEvent = this.aEventStatusData[index]; + const time = oEvent.startTimestamp + (oEvent.endTimestamp - oEvent.startTimestamp) / 2; + const x = this.oPositionManager.getPositionByTime(time); + const oTextInfo = this.getEventTextInfo(oEvent.value.totalCount); + elEventGroup[2].attr({ + x: oTextInfo.x, + y: oTextInfo.y, + text: oTextInfo.text + }); + elEventGroup.attr('display', 'block'); + elEventGroup.animate({ + 'transform': `translate(${x}, 0)` + }, this.options.duration); + } + addEventElement(oEvent: ITimelineEventSegment, index: number): void { + this.group.add(this.makeElement(oEvent, index)); + } + makeElement(oEvent: ITimelineEventSegment, index: number): any { + const time = oEvent.startTimestamp + (oEvent.endTimestamp - oEvent.startTimestamp) / 2; + const oTextInfo = this.getEventTextInfo(oEvent.value.totalCount); + const elEventGroup = this.group.g().attr({ + 'data-id': index, + 'data-time': time, + 'transform': `translate(${this.oPositionManager.getPositionByTime(time)}, 0)` + }); + elEventGroup.add( + this.snap.line(0, this.options.y, 0, this.options.y + this.options.barLength), + this.snap.circle(0, this.options.y + this.options.circleRadius + this.options.gapBarNCircle + this.options.barLength, this.options.circleRadius).attr({ + 'class': 'event', + 'filter': this.options.filter, + 'data-time': time + }), + this.snap.text(oTextInfo.x, oTextInfo.y, oTextInfo.text).attr({ + 'class': 'event' + }) + ); + this.aEventGroupElement.push(elEventGroup); + return elEventGroup; + } + getEventTextInfo(totalCount: number): { x: number, y: number, text: string } { + return { + x: totalCount < 10 ? -(this.options.circleRadius / 3 ) : -(this.options.circleRadius / 4 ) * 3, + y: this.options.y + this.options.circleRadius + (this.options.circleRadius / 2) + this.options.gapBarNCircle + this.options.barLength, + text: totalCount >= 100 ? '...' : totalCount + '' + }; + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-handler.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-handler.class.ts new file mode 100644 index 000000000000..baba9ea5031f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-handler.class.ts @@ -0,0 +1,87 @@ +declare var Snap: any; +declare var mina: any; +import { Subject } from 'rxjs'; + +export class TimelineHandler { + static HANDLER_IMAGE_WIDTH = 30; + static HANDLER_IMAGE_HEIGHT = 18; + + previousX: number; + handlerGrip: any; + handlerGroup: any; + onDragStart$: Subject = new Subject(); + onDragging$: Subject = new Subject(); + onDragEnd$: Subject<{ dragged: boolean, x: number }> = new Subject(); + + constructor(private snap: any, private group: any, private options: { [key: string]: any }) { + this.previousX = options.x; + this.addElements(); + this.setX(options.x); + this.addEvent(); + } + addElements(): void { + this.handlerGrip = this.snap.circle(0, 3, 5).attr({ + 'fill': '#777af9', + 'cursor': 'pointer', + 'stroke': '#4E50C8', + 'stroke-width': '3px' + }); + this.handlerGroup = this.group.g(); + this.handlerGroup.add( + this.snap.line( 0, 0, 0, this.options.height ), + this.snap.circle(0, 3, 7).attr({ + 'fill': '#000', + 'filter': Snap.filter.shadow(0, 0, 2, '#000', .5) + }), + this.handlerGrip + ); + } + addEvent(): void { + let lastX = -1; + this.handlerGrip.click((event: any) => { + event.stopPropagation(); + }); + this.handlerGrip.mousedown((event: any) => { + event.stopPropagation(); + }); + this.handlerGrip.drag((dx: number, dy: number, x: number, y: number, event: any) => { + const newX = x - this.options.margin; + if ( this.isInRestrictionZone(newX) === false ) { + return; + } + this.handlerGroup.attr({ + 'transform': `translate(${newX}, 0)` + }); + lastX = newX; + this.onDragging$.next(newX); + }, (x: number, y: number, event: any) => { + event.stopPropagation(); + this.onDragStart$.next(x - this.options.margin); + }, (event: any) => { + event.stopPropagation(); + if ( this.previousX !== lastX && lastX !== -1 ) { + this.onDragEnd$.next({ dragged: true, x: lastX }); + this.previousX = lastX; + } else { + this.onDragEnd$.next({ dragged: false, x: -1 }); + } + }); + } + setX(x: number): void { + this.handlerGroup.animate({ + 'transform': `translate(${x}, 0)` + }, this.options.duration, mina.easeout); + } + isInRestrictionZone(x: number): boolean { + return (x <= this.options.zone[0] || x >= this.options.zone[1]) ? false : true; + } + setZone(start: number, end: number): void { + this.options.zone = [start, end]; + } + setPositionAndZone(x: number, aZone: number[]): void { + this.setX(x); + this.onDragging$.next(x); + this.setZone(aZone[0], aZone[1]); + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-loading-indicator.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-loading-indicator.class.ts new file mode 100644 index 000000000000..101a18fa3a23 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-loading-indicator.class.ts @@ -0,0 +1,52 @@ +declare var Snap: any; +declare var mina: any; + +export class TimelineLoadingIndicator { + private clockWiseRect: any; + private antiClockWiseRect: any; + private bRun = false; + + constructor(private snap: any, private group: any, private options: { [key: string]: number }) { + this.addElements(); + this.show(); + } + addElements(): void { + const centerPosition = this.getCenterPosition(this.options.width, this.options.height, this.options.size); + const backgroundRect = this.snap.rect(0, 0, this.options.width, this.options.height); + + this.clockWiseRect = this.snap.rect(centerPosition.x, centerPosition.y, this.options.size, this.options.size).attr({ + 'stroke': 'rgba(197, 197, 197, .9)' + }); + this.antiClockWiseRect = this.snap.rect(centerPosition.x, centerPosition.y, this.options.size, this.options.size).attr({ + 'stroke': 'rgba(239, 246, 105)' + }); + this.group.add(backgroundRect, this.clockWiseRect, this.antiClockWiseRect); + } + getCenterPosition(width: number, height: number, size: number): {x: number, y: number} { + const halfSize = size / 2; + return { + x: width / 2 - halfSize, + y: height / 2 - halfSize + }; + } + show() { + this.group.attr('display', 'block'); + this.bRun = true; + this.animate( this.clockWiseRect, 0, 360, mina.easeout ); + this.animate( this.antiClockWiseRect, 45, -315, mina.easein ); + } + animate(ele, from, to, fnEase) { + Snap.animate(from, to, (val) => { + ele.attr('transform', 'rotate(' + val + 'deg)'); + }, this.options.duration, fnEase, () => { + if ( this.bRun === true ) { + this.animate( ele, to, from, fnEase ); + } + }); + } + hide() { + this.group.attr('display', 'none'); + this.bRun = false; + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-position-manager.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-position-manager.class.ts new file mode 100644 index 000000000000..34f1db70fb6a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-position-manager.class.ts @@ -0,0 +1,254 @@ +import * as moment from 'moment-timezone'; + +export class TimelinePositionManager { + static X_AXIS_TICKS = 5; + + width: number; + startTime: number; + endTime: number; + timePerPoint: number; + xAxisTicks: number; + pointingTime: number; + pointingPosition: number; + minTimeRange: number; + maxSelectionTimeRange; + aSelectionTimeRange: number[] = []; + aSelectionPosition: number[] = []; + + constructor(private options: any) { + this.width = options.width; + this.minTimeRange = options.minTimeRange; + this.maxSelectionTimeRange = options.maxSelectionTimeRange; + + this.initInnerVar(); + this.setTimelineRange(options.timelineRange[0], options.timelineRange[1]); + this.initSelectionTimeRange(options.selectionTimeRange || []); + this.resetSelectionByTime(); + this.xAxisTicks = options.xAxisTicks || TimelinePositionManager.X_AXIS_TICKS; + this.setPointingTime( options.pointingTime ); + } + initInnerVar(): void { + this.aSelectionTimeRange = []; + this.aSelectionPosition = []; + } + setTimelineRange(start: number, end: number): void { + this.startTime = start; + this.endTime = end; + this.calcuTimePerPoint(); + } + initSelectionTimeRange(aTime: number[]): void { + if ( aTime.length !== 2 ) { + aTime = [ this.startTime, this.endTime ]; + } + if ( aTime[1] - aTime[0] > this.maxSelectionTimeRange ) { + aTime[0] = aTime[1] - this.maxSelectionTimeRange; + } + this.setSelectionTimeRange(aTime[0], aTime[1]); + } + resetSelectionByTime(): void { + this.setSelectionPosition(this.getPositionByTime(this.aSelectionTimeRange[0]), this.getPositionByTime(this.aSelectionTimeRange[1])); + } + + calcuTimePerPoint(): void { + this.timePerPoint = ( this.endTime - this.startTime ) / this.width; + } + setSelectionTimeRange(start: number, end: number): void { + this.aSelectionTimeRange[0] = start === null ? this.aSelectionTimeRange[0] : start; + this.aSelectionTimeRange[1] = end === null ? this.aSelectionTimeRange[1] : end; + } + setSelectionPosition(start: number, end: number): void { + this.aSelectionPosition[0] = start === null ? this.aSelectionPosition[0] : start; + this.aSelectionPosition[1] = end === null ? this.aSelectionPosition[1] : end; + } + getPositionByTime(time: number): number { + return Math.floor((time - this.startTime) / this.timePerPoint); + } + setPointingTime(time: number ): void { + this.pointingTime = time; + this.pointingPosition = this.getPositionByTime(time); + } + isInMaxSelectionTimeRange(start: number, end: number): boolean { + return (end - start) <= this.maxSelectionTimeRange; + } + getNewSelectionTimeRangeFromStart(start: number): number[] { + return [start, start + this.maxSelectionTimeRange]; + } + getNewSelectionTimeRangeFromEnd(end: number): number[] { + return [end - this.maxSelectionTimeRange, end]; + } + isBeforeSliderStartTime(time: number): boolean { + return time < this.startTime; + } + isAfterSliderEndTime(time: number): boolean { + return time > this.endTime; + } + getTimelineEndTime(): number { + return this.endTime; + } + setWidth(width: number): void { + this.width = width; + this.calcuTimePerPoint(); + this.reset(); + } + getTimelineEndPosition(): number { + return this.width; + } + getTimelineStartTimeStr(): string { + return this.formatDate(new Date(this.startTime)); + } + getTimelineEndTimeStr(): string { + return this.formatDate( new Date(this.endTime) ); + } + getFullTimeStr(x: number): string { + return this.formatDate( new Date(this.getTimeFromPosition(x)) ); + } + formatDate(d: Date): string { + return moment(d).tz(this.options.timezone).format(this.options.dateFormat[0]); + } + isInSelectionZone(): boolean { + return (this.pointingTime >= this.aSelectionTimeRange[0] && this.pointingTime <= this.aSelectionTimeRange[1] ) ? true : false; + } + isInTimelineRange(time: number): boolean { + return (time >= this.startTime && time <= this.endTime ) ? true : false; + } + getTimelineRange(): number[] { + return [this.startTime, this.endTime]; + } + getSelectionTimeRange(): number[] { + return [this.aSelectionTimeRange[0], this.aSelectionTimeRange[1]]; + } + getSelectionPosition(): number[] { + return [this.aSelectionPosition[0], this.aSelectionPosition[1]]; + } + getPointingPosition(): number { + return this.pointingPosition; + } + getPointingTime(): number { + return this.pointingTime; + } + getPrevTime(): number { + const gap = this.aSelectionTimeRange[1] - this.aSelectionTimeRange[0]; + return this.aSelectionTimeRange[0] - Math.floor(gap / 2) - 1; + } + getNextTime(): number { + const gap = this.aSelectionTimeRange[1] - this.aSelectionTimeRange[0]; + const nextTime = this.aSelectionTimeRange[1] + Math.floor(gap / 2) + 1; + if ( nextTime > Date.now() ) { + return Date.now(); + } else { + return nextTime; + } + } + getTimeFromPosition(x: number): number { + return this.startTime + Math.floor(this.timePerPoint * x); + } + calcuSelectionZone(): void { + const currentSelectionSize = this.aSelectionTimeRange[1] - this.aSelectionTimeRange[0]; + const currentSelectionHalfSize = Math.round( currentSelectionSize / 2 ); + let selectionStart = this.pointingTime - currentSelectionHalfSize; + let selectionEnd = this.pointingTime + currentSelectionHalfSize; + if ( selectionStart < this.startTime ) { + selectionEnd = selectionStart + currentSelectionSize; + selectionStart = this.startTime; + } else if ( selectionEnd > this.endTime ) { + selectionStart = this.endTime - currentSelectionSize; + selectionEnd = this.endTime; + } + this.setSelectionTimeRange(selectionStart, selectionEnd); + this.setSelectionPosition(this.getPositionByTime(selectionStart), this.getPositionByTime(selectionEnd)); + } + getXAxisPositionData(): any { + const max = TimelinePositionManager.X_AXIS_TICKS + 1; + const space = Math.floor(this.width / max); + const a = []; + for ( let i = 0 ; i < max ; i++ ) { + if ( i === 0 ) { + continue; + } + const x = i * space; + a.push( { + x: x, + time: this.getTimeStr(x) + }); + } + return a; + } + getTimeStr(x: number): string { + const timeX = Math.floor( x * this.timePerPoint ) + this.startTime; + return moment(new Date(timeX)).tz(this.options.timezone).format(this.options.dateFormat[1]) + ' ' + moment(new Date(timeX)).tz(this.options.timezone).format(this.options.dateFormat[2]); + } + setSelectionStartTime(time: number): void { + this.setSelectionTimeRange(time, null); + this.setSelectionPosition(this.getPositionByTime(time), null); + } + setSelectionEndTime(time: number): void { + this.setSelectionTimeRange( null, time ); + this.setSelectionPosition( null, this.getPositionByTime( time ) ); + } + setSelectionStartPosition(x: number): void { + this.setSelectionTimeRange(this.getTimeFromPosition(x), null); + this.setSelectionPosition(x, null); + } + setSelectionEndPosition(x: number): void { + this.setSelectionTimeRange(null, this.getTimeFromPosition(x)); + this.setSelectionPosition(null, x); + } + zoomIn(): void { + // 선택 영역 중심으로 확대 + if ( this.startTime === this.aSelectionTimeRange[0] && this.endTime === this.aSelectionTimeRange[1] ) { + return; + } + const quarterTimeline = Math.floor((this.endTime - this.startTime) / 4); + let tempStartTime = this.pointingTime - quarterTimeline; + let tempEndTime = this.pointingTime + quarterTimeline; + + if ( tempEndTime - tempStartTime < this.minTimeRange ) { + const minHalf = Math.floor(this.minTimeRange / 2); + tempStartTime = this.pointingTime - minHalf; + tempEndTime = this.pointingTime + minHalf; + } + let gap; + if ( this.aSelectionTimeRange[0] < tempStartTime ) { + gap = tempStartTime - this.aSelectionTimeRange[0]; + const tempSelectionEndTime = (this.aSelectionTimeRange[1] + gap > tempEndTime) ? tempEndTime : this.aSelectionTimeRange[1] + gap; + this.setSelectionTimeRange(tempStartTime, tempSelectionEndTime); + } + if ( this.aSelectionTimeRange[1] > tempEndTime ) { + gap = this.aSelectionTimeRange[1] - tempEndTime; + const tempSelectionStartTime = (this.aSelectionTimeRange[0] - gap < tempStartTime) ? tempStartTime : this.aSelectionTimeRange[0] - gap; + this.setSelectionTimeRange(tempSelectionStartTime, tempEndTime); + } + this.setTimelineRange(tempStartTime, tempEndTime); + this.reset(); + } + zoomOut(): void { + const one = this.endTime - this.startTime; + const tempCenterTime = this.aSelectionTimeRange[0] + Math.floor((this.aSelectionTimeRange[1] - this.aSelectionTimeRange[0] ) / 2); + this.setTimelineRange(tempCenterTime - one, tempCenterTime + one); + this.reset(); + } + resetBySelectTime(time: number, bIsNow: boolean): void { + const halfSliderTimeRange = Math.floor((this.endTime - this.startTime) / 2); + const halfSelectionTimeRange = Math.floor((this.aSelectionTimeRange[1] - this.aSelectionTimeRange[0] ) / 2); + if ( bIsNow === true ) { + this.setTimelineRange(time - halfSliderTimeRange * 2, time); + this.setSelectionTimeRange(time - halfSelectionTimeRange * 2, time); + } else { + this.setTimelineRange(time - halfSliderTimeRange, time + halfSliderTimeRange); + this.setSelectionTimeRange(time - halfSelectionTimeRange, time + halfSelectionTimeRange); + } + this.resetSelectionByTime(); + this.setPointingTime(time); + } + reset(): void { + this.setPointingTime(this.pointingTime); + this.resetSelectionByTime(); + } + setTimezone(timezone: string): void { + this.options.timezone = timezone; + } + setDateFormat(dateFormat: string[]): void { + this.options.dateFormat = dateFormat; + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-selection-manager.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-selection-manager.class.ts new file mode 100644 index 000000000000..de12c0f0ac63 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-selection-manager.class.ts @@ -0,0 +1,179 @@ +import { Subject, Subscription } from 'rxjs'; +import { TimelinePositionManager } from './timeline-position-manager.class'; +import { TimelineSelectionZone } from './timeline-selection-zone.class'; +import { TimelineSelectionPoint } from './timeline-selection-point.class'; +import { TimelineHandler } from './timeline-handler.class'; +import { TimelineSignboard } from './timeline-signboard.class'; +import { TimelineUIEvent } from './timeline-ui-event'; + +export class TimelineSelectionManager { + + unsubscribe: Subscription; + onChangeTimelineUIEvent$: Subject = new Subject(); + onReset$: Subject = new Subject(); + constructor( + private options: { [key: string]: any }, + private oSelectionZone: TimelineSelectionZone, + private oSelectionPoint: TimelineSelectionPoint, + private oLeftHandler: TimelineHandler, + private oRightHandler: TimelineHandler, + private oLeftTimeSignboard: TimelineSignboard, + private oRightTimeSignboard: TimelineSignboard, + private oPositionManager: TimelinePositionManager + ) { + this.initClass(); + } + initClass(): void { + this.unsubscribe = this.oLeftHandler.onDragStart$.subscribe((x: number) => { + this.oLeftTimeSignboard.onDragStart(x); + }); + this.unsubscribe.add(this.oLeftHandler.onDragging$.subscribe((x: number) => { + this.oSelectionZone.onDragXStart(x); + this.oLeftTimeSignboard.onDrag(x); + })); + this.unsubscribe.add(this.oLeftHandler.onDragEnd$.subscribe((res: { dragged: boolean, x: number }) => { + this.oLeftTimeSignboard.onDragEnd(); + if (res.dragged) { + this.movedLeftHandler(res.x); + } + })); + + this.unsubscribe.add(this.oRightHandler.onDragStart$.subscribe((x: number) => { + this.oRightTimeSignboard.onDragStart(x); + })); + this.unsubscribe.add(this.oRightHandler.onDragging$.subscribe((x: number) => { + this.oSelectionZone.onDragXEnd(x); + this.oRightTimeSignboard.onDrag(x); + })); + this.unsubscribe.add(this.oRightHandler.onDragEnd$.subscribe((res: { dragged: boolean, x: number }) => { + this.oRightTimeSignboard.onDragEnd(); + if (res.dragged) { + this.movedRightHandler(res.x); + } + })); + } + movedLeftHandler(x: number): void { + let selectedTime = this.oPositionManager.getPointingTime(); + const event = new TimelineUIEvent(); + const aCurrentSelectionTimeRange = this.oPositionManager.getSelectionTimeRange(); + const newLeftTime = this.oPositionManager.getTimeFromPosition(x); + if ( this.oPositionManager.isInMaxSelectionTimeRange(newLeftTime, aCurrentSelectionTimeRange[1])) { + this.oRightHandler.setZone(x, this.oPositionManager.getTimelineEndPosition()); + this.oPositionManager.setSelectionStartPosition(x); + + if ( this.oPositionManager.isInSelectionZone() === false ) { + this.oPositionManager.setPointingTime(newLeftTime); + this.oSelectionPoint.setPointing(x); + selectedTime = newLeftTime; + event.setOnChangedSelectedTime(); + } + } else { + const aNewSelectionTimeSeries = this.oPositionManager.getNewSelectionTimeRangeFromStart(newLeftTime); + const newRightX = this.oPositionManager.getPositionByTime(aNewSelectionTimeSeries[1]); + this.oRightHandler.setZone(x, this.oPositionManager.getTimelineEndPosition()); + this.oPositionManager.setSelectionStartPosition(x); + this.oRightHandler.setX(newRightX); + this.oRightTimeSignboard.onDrag(newRightX); + this.oLeftHandler.setZone(0, newRightX); + this.oPositionManager.setSelectionEndPosition(newRightX); + + if ( this.oPositionManager.isInSelectionZone() === false ) { + this.oPositionManager.setPointingTime(aNewSelectionTimeSeries[1]); + this.oSelectionPoint.setPointing(newRightX); + selectedTime = aNewSelectionTimeSeries[1]; + event.setOnChangedSelectedTime(); + } + } + this.oSelectionZone.redraw(); + event.setOnChangedSelectionRange(); + event.setData( + selectedTime, + this.oPositionManager.getSelectionTimeRange(), + this.oPositionManager.getTimelineRange() + ); + this.onChangeTimelineUIEvent$.next(event); + } + movedRightHandler(x: number): void { + let selectedTime = this.oPositionManager.getPointingTime(); + const event = new TimelineUIEvent(); + const aCurrentSelectionTimeRange = this.oPositionManager.getSelectionTimeRange(); + const newRightTime = this.oPositionManager.getTimeFromPosition(x); + if ( this.oPositionManager.isInMaxSelectionTimeRange(aCurrentSelectionTimeRange[0], newRightTime) ) { + this.oLeftHandler.setZone(0, x); + this.oPositionManager.setSelectionEndPosition(x); + + if ( this.oPositionManager.isInSelectionZone() === false ) { + this.oPositionManager.setPointingTime(newRightTime); + this.oSelectionPoint.setPointing(x); + selectedTime = newRightTime; + event.setOnChangedSelectedTime(); + } + } else { + const aNewSelectionTimeSeries = this.oPositionManager.getNewSelectionTimeRangeFromEnd(newRightTime); + const newLeftX = this.oPositionManager.getPositionByTime(aNewSelectionTimeSeries[0]); + this.oLeftHandler.setZone(0, x); + this.oPositionManager.setSelectionEndPosition(x); + this.oLeftHandler.setX(newLeftX); + this.oLeftTimeSignboard.onDrag(newLeftX); + this.oRightHandler.setZone(newLeftX, this.oPositionManager.getTimelineEndPosition()); + this.oPositionManager.setSelectionStartPosition(newLeftX); + + if ( this.oPositionManager.isInSelectionZone() === false ) { + this.oPositionManager.setPointingTime(aNewSelectionTimeSeries[0]); + this.oSelectionPoint.setPointing(newLeftX); + selectedTime = aNewSelectionTimeSeries[0]; + event.setOnChangedSelectedTime(); + } + } + this.oSelectionZone.redraw(); + event.setOnChangedSelectionRange(); + event.setData( + selectedTime, + this.oPositionManager.getSelectionTimeRange(), + this.oPositionManager.getTimelineRange() + ); + this.onChangeTimelineUIEvent$.next(event); + } + moveSelectionAndHandler(): void { + const aNewSelectionZone = this.oPositionManager.getSelectionPosition(); + this.oLeftHandler.setPositionAndZone(aNewSelectionZone[0], [0, aNewSelectionZone[1]]); + this.oRightHandler.setPositionAndZone(aNewSelectionZone[1], [aNewSelectionZone[0], this.oPositionManager.getTimelineEndPosition()]); + this.oSelectionZone.redraw(); + } + onSetPointingByPosition(x: number): void { + this.onSetPointingByTime(this.oPositionManager.getTimeFromPosition(x)); + } + onSetPointingByTime(time: number, bIsNow?: boolean): void { + const event = new TimelineUIEvent(); + event.setOnChangedSelectedTime(); + if ( this.oPositionManager.isInTimelineRange(time) ) { + this.oPositionManager.setPointingTime(time); + if ( this.oPositionManager.isInSelectionZone() === false ) { + this.oPositionManager.calcuSelectionZone(); + this.moveSelectionAndHandler(); + event.setOnChangedSelectionRange(); + } + this.oSelectionPoint.setPointing(this.oPositionManager.getPointingPosition()); + } else { + this.oPositionManager.resetBySelectTime(time, bIsNow); + this.onReset$.next(); + event.setOnChangedSelectionRange(); + } + event.setData( + this.oPositionManager.getPointingTime(), + this.oPositionManager.getSelectionTimeRange(), + this.oPositionManager.getTimelineRange() + ); + this.onChangeTimelineUIEvent$.next(event); + } + reset(): void { + const aNewSelectionZone = this.oPositionManager.getSelectionPosition(); + this.oLeftHandler.setPositionAndZone(aNewSelectionZone[0], [0, aNewSelectionZone[1]]); + this.oRightHandler.setPositionAndZone(aNewSelectionZone[1], [aNewSelectionZone[0], this.oPositionManager.getTimelineEndPosition()]); + this.oSelectionZone.redraw(); + this.oSelectionPoint.setPointing(this.oPositionManager.getPointingPosition()); + } + destroy(): void { + this.unsubscribe.unsubscribe(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-selection-point.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-selection-point.class.ts new file mode 100644 index 000000000000..3659b6d33ded --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-selection-point.class.ts @@ -0,0 +1,24 @@ +declare var Snap: any; +declare var mina: any; + +export class TimelineSelectionPoint { + constructor(private snap: any, private group: any, private options: { [key: string]: number } ) { + this.addElements(); + this.setPointing( options.x ); + } + addElements(): void { + const halfRadius = this.options.radius / 2; + this.group.add( + this.snap.line(0, 0, 0, this.options.height), + this.snap.circle(0, this.options.height / 2, this.options.radius).attr({ + 'filter': this.snap.filter( Snap.filter.shadow(0, 0, 4, '#FF0', 1)) + }) + ); + } + setPointing(x: number): void { + this.group.animate({ + 'transform': `translate(${x}, ${this.options.y})` + }, this.options.duration, mina.easein); + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-selection-zone.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-selection-zone.class.ts new file mode 100644 index 000000000000..bcf88b289771 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-selection-zone.class.ts @@ -0,0 +1,36 @@ +declare var Snap: any; +import { TimelinePositionManager } from './timeline-position-manager.class'; + +export class TimelineSelectionZone { + private elZone: any; + constructor(private snap: any, private group: any, private options: { [key: string]: number }, private oPositionManager: TimelinePositionManager ) { + this.addElements(); + } + addElements() { + const aSelectionZone = this.oPositionManager.getSelectionPosition(); + this.elZone = this.snap.rect(aSelectionZone[0], this.options.top, aSelectionZone[1] - aSelectionZone[0], this.options.height); + this.group.add(this.elZone); + } + redraw() { + const aSelectionZone = this.oPositionManager.getSelectionPosition(); + this.elZone.animate({ + 'x': aSelectionZone[0], + 'width': aSelectionZone[1] - aSelectionZone[0] + }, this.options.duration); + } + onDragXStart(x: number): void { + const width = this.oPositionManager.getSelectionPosition()[1] - x; + this.elZone.attr({ + 'x': x, + 'width': width + }); + } + onDragXEnd(x: number): void { + const selectionStartPosition = this.oPositionManager.getSelectionPosition()[0]; + this.elZone.attr({ + 'x': selectionStartPosition, + 'width': x - selectionStartPosition + }); + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-signboard.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-signboard.class.ts new file mode 100644 index 000000000000..e7f912a52421 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-signboard.class.ts @@ -0,0 +1,45 @@ +declare var Snap: any; +import { TimelinePositionManager } from './timeline-position-manager.class'; + +export class TimelineSignboard { + private timeText: any; + private textMaxWidth = 10; + private xPadding = 10; + constructor(private snap: any, private group: any, private options: { [key: string]: any }, private oPositionManager: TimelinePositionManager ) { + this.addElements(); + } + addElements(): void { + const isIn = this.isIn(this.options.x); + const x = this.options.x + (isIn ? this.xPadding : -this.xPadding); + this.timeText = this.group.text(x, 26, this.oPositionManager.getFullTimeStr(this.options.x) ).attr({ + 'text-anchor': this.getAnchorPosition(isIn) + }); + this.group.add( this.timeText ); + } + setX(x: number): void { + const isIn = this.isIn(x); + this.timeText.attr({ + 'x': x + ( isIn ? this.xPadding : -this.xPadding ), + 'text': this.oPositionManager.getFullTimeStr(x), + 'text-anchor': this.getAnchorPosition(isIn) + }); + } + getAnchorPosition(innerPosition: boolean): string { + return innerPosition ? 'start' : 'end'; + } + isIn(x: number): boolean { + if ( this.options.direction === 'left' ) { + return x < this.textMaxWidth; + } else { + return x + this.textMaxWidth < this.oPositionManager.getTimelineEndPosition(); + } + } + onDragStart(x: number): void { + this.setX(x); + } + onDragEnd(): void {} + onDrag(x: number): void { + this.setX(x); + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-state-line.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-state-line.class.ts new file mode 100644 index 000000000000..ce92a2a2b784 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-state-line.class.ts @@ -0,0 +1,119 @@ +declare var Snap: any; +declare var mina: any; +import { TimelinePositionManager } from './timeline-position-manager.class'; +import { ITimelineStatusSegment } from './timeline-data.class'; + +export class TimelineStateLine { + static ID_SPLITER = '+'; + static ID_PREFIX_BASE = 'base-'; + static ID_POSTFIX = '+state-line'; + + statusData: ITimelineStatusSegment[]; + aBaseLine: any[] = []; + aLineElement: any[] = []; + + constructor(private snap: any, private group: any, private options: { [key: string]: any }, private oPositionManager: TimelinePositionManager) { + this.initBaseLine(); + } + initBaseLine(): void { + this.aBaseLine.push( + this.makeRect(0, this.options.width, 0, this.options.height, this.options.statusColor['BASE'], TimelineStateLine.ID_PREFIX_BASE + Date.now()) + ); + this.aBaseLine.forEach((line: any) => { + this.group.add(line); + }); + } + addStatus(oStatus: ITimelineStatusSegment, index: number): void { + if ( this.isOutsideOfTimeline(oStatus.startTimestamp, oStatus.endTimestamp) ) { + return; + } + this.addLine( + this.oPositionManager.getPositionByTime(oStatus.startTimestamp), + this.getX2(oStatus.endTimestamp), + this.options.statusColor[oStatus.value], + this.makeID(oStatus) + ); + } + isOutsideOfTimeline(start: number, end: number): boolean { + return this.oPositionManager.isInTimelineRange(start) === false && this.oPositionManager.isInTimelineRange(end) === false; + } + makeID(oStatus: ITimelineStatusSegment): string { + return oStatus.endTimestamp + TimelineStateLine.ID_POSTFIX; + } + addLine(x: number, x2: number, backgroundColor: string, id: string): void { + const line = this.makeRect(x, x2, 0, this.options.height, backgroundColor, id); + this.aLineElement.push(line); + this.group.add(line); + } + makeRect(x: number, x2: number, y: number, y2: number, color: string, id: string): any { + return this.snap.rect(x, y, x2, y2).attr({ + 'fill': color, + 'data-id': id + }); + } + getX2(end: number): number { + return this.oPositionManager.getPositionByTime(end === -1 ? this.oPositionManager.getTimelineEndTime() : end); + } + updateData(statusData: ITimelineStatusSegment[]): void { + this.statusData = statusData; + this.updateRender(); + } + updateRender(): void { + let index; + const curLen = this.aLineElement.length; + const newLen = this.statusData.length; + if ( curLen === newLen ) { + for ( index = 0 ; index < curLen ; index++ ) { + this.show(this.aLineElement[index]); + } + } else if ( curLen > newLen ) { + for ( index = newLen ; index < curLen ; index++ ) { + this.hide(this.aLineElement[index]); + } + } else { // curLen < newLen + for ( index = 0 ; index < curLen ; index++ ) { + this.show(this.aLineElement[index]); + } + for ( index = curLen ; index < newLen ; index++ ) { + this.addStatus(this.statusData[index], index); + } + } + this.reset(); + } + emptyData(): void { + this.aLineElement.forEach((line: any) => { + this.hide(line); + }); + } + reset() { + for ( let i = 0 ; i < this.aLineElement.length ; i++ ) { + const line = this.aLineElement[i]; + const oStatus = this.statusData[i]; + if ( oStatus ) { + const x = this.oPositionManager.getPositionByTime(oStatus.startTimestamp); + this.show(line); + line.animate({ + 'x': x, + 'width': this.getX2(oStatus.endTimestamp) - x + }, this.options.duration, mina.easeOut, () => { + line.attr('fill', this.options.statusColor[oStatus.value]); + }); + } else { + this.hide(line); + } + } + const endPosition = this.oPositionManager.getTimelineEndPosition(); + this.aBaseLine.forEach((elBase: any) => { + elBase.animate({ + 'width': endPosition + }, this.options.duration); + }); + } + show(el: any) { + el.attr('display', 'block'); + } + hide(el: any) { + el.attr('display', 'none'); + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-ui-event.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-ui-event.ts new file mode 100644 index 000000000000..755662264891 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-ui-event.ts @@ -0,0 +1,46 @@ +export class TimelineUIEvent { + changedSelectedTime = false; + changedSelectionRange = false; + changedRange = false; + data = { + selectedTime: 0, + range: [0, 0], + selectionRange: [0, 0] + }; + setData(time: number, selectionRange: number[], range: number[]): TimelineUIEvent { + this.data.selectedTime = time; + this.data.selectionRange = selectionRange; + this.data.range = range; + return this; + } + setSelectedTime(time: number): TimelineUIEvent { + this.data.selectedTime = time; + return this; + } + setSelectionRange(range: number[]): TimelineUIEvent { + this.data.selectionRange = range; + return this; + } + setRange(range: number[]): TimelineUIEvent { + this.data.range = range; + return this; + } + setOnChangedSelectedTime(): void { + this.changedSelectedTime = true; + } + setOffChangedSelectedTime(): void { + this.changedSelectedTime = false; + } + setOnChangedSelectionRange(): void { + this.changedSelectionRange = true; + } + setOffChangedSelectionRange(): void { + this.changedSelectionRange = false; + } + setOnRange(): void { + this.changedRange = true; + } + setOffRange(): void { + this.changedRange = false; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-x-axis.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-x-axis.class.ts new file mode 100644 index 000000000000..589a8d2bda01 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline-x-axis.class.ts @@ -0,0 +1,40 @@ +declare var Snap: any; +import { TimelinePositionManager } from './timeline-position-manager.class'; + +export class TimelineXAxis { + aText: any[]; + aAxisGroup: any[] = []; + + constructor(private snap: any, private group: any, private options: { [key: string]: any }, private oPositionManager: TimelinePositionManager) { + this.aText = []; + this.init(); + } + init() { + const aXBarPosition = this.oPositionManager.getXAxisPositionData(); + const centerX = this.options.width / 2; + + aXBarPosition.forEach((xBar: any, index: number) => { + const g = this.group.g(); + const text = this.snap.text(0, this.options.textY, aXBarPosition[index].time); + this.aText.push(text); + g.attr('transform', 'translate(' + centerX + ', 0)'); + g.add(text, this.snap.line(0, this.options.startY, 0, this.options.endY)); + this.group.add(g); + this.aAxisGroup.push(g); + this.resetXPosition(g, aXBarPosition[index].x, centerX); + }); + } + resetXPosition(g: any, x: number, startX: number): void { + Snap.animate(startX, x, (val: number) => { + g.attr('transform', `translate(${val}, 0)`); + }, this.options.duration); + } + reset() { + const aYBarPosition = this.oPositionManager.getXAxisPositionData(); + for ( let i = 0 ; i < aYBarPosition.length ; i++ ) { + this.aAxisGroup[i].attr('transform', `translate(${aYBarPosition[i].x}, 0)`); + this.aText[i].attr('text', aYBarPosition[i].time); + } + } + destroy(): void {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline.class.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline.class.ts new file mode 100644 index 000000000000..e0f5e7ebdd38 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/class/timeline.class.ts @@ -0,0 +1,386 @@ +declare var Snap: any; + +import { Subject } from 'rxjs'; +import { TimelineData, ITimelineData, ITimelineStatusSegment, ITimelineEventSegment } from './timeline-data.class'; +import { TimelinePositionManager } from './timeline-position-manager.class'; +import { TimelineLoadingIndicator } from './timeline-loading-indicator.class'; +import { TimelineBackground } from './timeline-background.class'; +import { TimelineStateLine } from './timeline-state-line.class'; +import { TimelineSelectionZone } from './timeline-selection-zone.class'; +import { TimelineSelectionPoint } from './timeline-selection-point.class'; +import { TimelineHandler } from './timeline-handler.class'; +import { TimelineSignboard } from './timeline-signboard.class'; +import { TimelineSelectionManager } from './timeline-selection-manager.class'; +import { TimelineXAxis } from './timeline-x-axis.class'; +import { TimelineEvents } from './timeline-events.class'; +import { TimelineUIEvent } from './timeline-ui-event'; + +// TODO: Reset 확인 +// TODO: Resize 확인 +// TODO: 데이터 업데이트시 동작 확인 +// TODO: timeline-selection-manager.onSetPointingByTime의 timeline.reset() 확인 +export class Timeline { + static MAX_TIME_RANGE = 604800000; // 7day + static GROUP_TYPE: { [key: string]: string } = { + TOP_BASE: 'TOP-BASE', + CONTENT_BASE: 'CONTENT-BASE', + BOTTOM_BASE: 'BOTTOM-BASE' + }; + static DRAWING_ORDER: { [key: string]: number } = { + 'background': 0, + 'state-line': 3, + 'selection-zone': 5, + 'x-axis': 10, + 'events': 10, + 'time-signboard': 15, + 'selection-point': 15, + 'left-handler': 25, + 'right-handler': 25, + 'guide': 30, + 'loading': 100 + }; + static DEFAULT_STATUS_COLOR: { [key: string]: string } = { + 'BASE': 'rgba(187, 187, 187, 0.3)', + 'UNKNOWN': 'rgba(220, 214, 214, 0.8)', + 'RUNNING': 'rgba(0, 158, 0, 0.4)', + 'SHUTDOWN': 'rgba(209, 82, 96, 0.7)', + 'UNSTABLE_RUNNING': 'rgba(255, 102, 0, 0.4)', + 'EMPTY': 'rgba(165, 219, 245, 0.7)' + }; + private snap: any; + + private oLoading: TimelineLoadingIndicator; + private oBackground: TimelineBackground; + private oTimelineData: TimelineData; + private oPositionManager: TimelinePositionManager; + private oStateLine: TimelineStateLine; + private oSelectionManager: TimelineSelectionManager; + private oXAxis: TimelineXAxis; + private oEvents: TimelineEvents; + + private svgGroups: { [key: string]: any} = {}; + private options: { [key: string]: any } = { + 'top': 0, + 'left': 0, + 'duration': 50, + 'xAxisTicks': 5, + 'minTimeRange': 6000, // 6sec + 'eventZoneHeight': 30, // 하단 이벤트 영역의 height + 'headerZoneHeight': 20, // 상단 시간 표시영역의 height + 'stateLineThickness': 4, // 상태선의 두께 + 'maxSelectionTimeRange': Timeline.MAX_TIME_RANGE, // 7day + 'headerTextTopPadding': 10, // 상단 상태선과 시간 text의 간격 + 'pointerRadius': 6 + }; + onChangeTimelineUIEvent$: Subject = new Subject(); + onSelectEventStatus$: Subject = new Subject(); + + constructor(private element: any, options: { [key: string]: any }) { + this.snap = Snap(element); + this.snap.attr({'height': options.height }); + this.initOptions(options); + this.initDataClass(options.timelineData); + this.checkOffset(); + this.initControlClass(); + this.addEventListener(); + } + initOptions(options: { [key: string]: any }) { + Object.keys(options).forEach((key: string) => { + this.options[key] = options[key]; + }); + this.setDefaultStatusColor(); + this.checkOffset(); + } + setDefaultStatusColor() { + if ( this.options['statusColor'] ) { + Object.keys(Timeline.DEFAULT_STATUS_COLOR).forEach((key: string) => { + if ( !this.options['statusColor'][key] ) { + this.options['statusColor'][key] = Timeline.DEFAULT_STATUS_COLOR[key]; + } + }); + } else { + const statusColor = {}; + Object.keys(Timeline.DEFAULT_STATUS_COLOR).forEach((key: string) => { + statusColor[key] = Timeline.DEFAULT_STATUS_COLOR[key]; + }); + this.options['statusColor'] = statusColor; + } + } + initDataClass(timelineData: ITimelineData) { + this.oTimelineData = new TimelineData(timelineData || { + agentEventTimeline: { + timelineSegments: [] + }, + agentStatusTimeline: { + includeWarning: false, + timelineSegments: [] + } + }); + } + checkOffset() { + const offset = this.element.getBoundingClientRect(); + this.options.top = offset.top; + this.options.left = offset.left; + } + initControlClass() { + this.oPositionManager = new TimelinePositionManager( { + 'width': this.options.width, + 'xAxisTicks': this.options.xAxisTicks, + 'pointingTime': this.options.pointingTime, + 'minTimeRange': this.options.minTimeRange, + 'timelineRange': this.options.timelineRange, + 'selectionTimeRange': this.options.selectionTimeRange, + 'maxSelectionTimeRange': this.options.maxSelectionTimeRange, + 'timezone': this.options.timezone, + 'dateFormat': this.options.dateFormat + }); + const contentZoneHeight = this.options.height - this.options.headerZoneHeight - this.options.eventZoneHeight; + + this.oLoading = new TimelineLoadingIndicator(this.snap, this.getGroup('loading', Timeline.GROUP_TYPE.TOP_BASE, Timeline.DRAWING_ORDER['loading']), { + 'size': 30, + 'width': this.options.width, + 'height': this.options.height, + 'duration': 2000 + }); + this.oBackground = new TimelineBackground(this.snap, this.getGroup('background', Timeline.GROUP_TYPE.CONTENT_BASE, Timeline.DRAWING_ORDER['background']), { + 'top': 0, + 'left': 0, + 'size': 30, + 'width': this.options.width, + 'height': contentZoneHeight, + 'duration': this.options.duration + }); + this.oStateLine = new TimelineStateLine(this.snap, this.getGroup('state-line', Timeline.GROUP_TYPE.CONTENT_BASE, Timeline.DRAWING_ORDER['state-line']), { + 'width': this.options.width, + 'height': contentZoneHeight, + 'duration': this.options.duration, + 'thickness': this.options.stateLineThickness, + 'statusColor': this.options.statusColor + }, this.oPositionManager); + + const aSelectionZone = this.oPositionManager.getSelectionPosition(); + const oSelectionZone = new TimelineSelectionZone(this.snap, this.getGroup('selection-zone', Timeline.GROUP_TYPE.CONTENT_BASE, Timeline.DRAWING_ORDER['selection-zone']), { + 'top': 0, + 'left': aSelectionZone[0], + 'width': aSelectionZone[1] - aSelectionZone[0], + 'height': contentZoneHeight, + 'duration': this.options.duration + }, this.oPositionManager); + const oSelectionPoint = new TimelineSelectionPoint(this.snap, this.getGroup('selection-point', Timeline.GROUP_TYPE.CONTENT_BASE, Timeline.DRAWING_ORDER['selection-point']), { + 'y': this.options.headerZoneHeight, + 'x': this.oPositionManager.getPointingPosition(), + 'radius': this.options.pointerRadius, + 'height': contentZoneHeight, + 'duration': this.options.duration + }); + const oLeftHandler = new TimelineHandler(this.snap, this.getGroup('left-handler', Timeline.GROUP_TYPE.CONTENT_BASE, Timeline.DRAWING_ORDER['left-handler']), { + 'x': aSelectionZone[0], + 'zone': [0, aSelectionZone[1]], + 'height': contentZoneHeight, + 'margin': this.options.left, + 'duration': this.options.duration + }); + const oRightHandler = new TimelineHandler(this.snap, this.getGroup('right-handler', Timeline.GROUP_TYPE.CONTENT_BASE, Timeline.DRAWING_ORDER['right-handler']), { + 'x': aSelectionZone[1], + 'zone': [ aSelectionZone[0], this.oPositionManager.getTimelineEndPosition() ], + 'height': contentZoneHeight, + 'margin': this.options.left, + 'duration': this.options.duration + }); + const oLeftTimeSignboard = new TimelineSignboard(this.snap, this.getGroup('time-left-signboard', Timeline.GROUP_TYPE.CONTENT_BASE, Timeline.DRAWING_ORDER['time-signboard']), { + 'x': aSelectionZone[0], + 'direction': 'left' + }, this.oPositionManager); + const oRightTimeSignboard = new TimelineSignboard(this.snap, this.getGroup('time-right-signboard', Timeline.GROUP_TYPE.CONTENT_BASE, Timeline.DRAWING_ORDER['time-signboard']), { + 'x': aSelectionZone[1], + 'direction': 'right' + }, this.oPositionManager); + this.oSelectionManager = new TimelineSelectionManager({ + 'headerZoneHeight': this.options.headerZoneHeight, + 'contentZoneHeight': contentZoneHeight + }, oSelectionZone, oSelectionPoint, oLeftHandler, oRightHandler, oLeftTimeSignboard, oRightTimeSignboard, this.oPositionManager); + + this.oXAxis = new TimelineXAxis(this.snap, this.getGroup('x-axis', Timeline.GROUP_TYPE.TOP_BASE, Timeline.DRAWING_ORDER['x-axis']), { + 'endY': this.options.height - this.options.eventZoneHeight, + 'width': this.options.width, + 'textY': this.options.headerTextTopPadding, + 'startY': this.options.headerZoneHeight, + 'duration': this.options.duration + }, this.oPositionManager); + this.oEvents = new TimelineEvents(this.snap, this.getGroup('events', Timeline.GROUP_TYPE.BOTTOM_BASE, Timeline.DRAWING_ORDER['events']), { + 'duration': this.options.duration + }, this.oPositionManager ); + + this.oLoading.hide(); + } + getGroup(name: string, type: string, zIndex: number) { + if ( this.svgGroups[name] ) { + return this.svgGroups[name]; + } + const g: any = this.svgGroups[name] = this.snap.g().attr({ + 'class': name, + 'data-order': zIndex + }); + this.setTransform(g, type); + this.sortGroup(g, zIndex); + return g; + } + setTransform(newGroup: any, type: string) { + switch ( type ) { + case Timeline.GROUP_TYPE.TOP_BASE: + newGroup.attr({ 'transform': `translate(0, 0)` }); + break; + case Timeline.GROUP_TYPE.CONTENT_BASE: + newGroup.attr({ 'transform': `translate(0, ${this.options.headerZoneHeight})` }); + break; + case Timeline.GROUP_TYPE.BOTTOM_BASE: + newGroup.attr({ 'transform': `translate(0, ${this.options.height - this.options.eventZoneHeight})` }); + break; + } + } + sortGroup(newGroup: any, zIndex: number) { + const aGroups = this.snap.selectAll('g'); + let afterGroup = null; + for ( let i = aGroups.length - 1; i >= 0 ; i-- ) { + if ( aGroups[i] === newGroup ) { + continue; + } + if ( zIndex < Math.floor(aGroups[i].attr('data-order')) ) { + afterGroup = aGroups[i]; + } + } + if ( afterGroup !== null ) { + afterGroup.before(newGroup); + } + } + addEventListener() { + let mousedownX = -1; + window.addEventListener('resize', () => { + this.checkOffset(); + this.resize(); + }); + this.snap.mousedown((event: any, x: number, y: number) => { + mousedownX = x; + }); + this.oEvents.clickEvent$.subscribe((eventData: ITimelineEventSegment) => { + this.onSelectEventStatus$.next(eventData); + }); + this.oTimelineData.onChangeStatusData$.subscribe((statusData: ITimelineStatusSegment[]) => { + this.oStateLine.updateData(statusData); + }); + this.oTimelineData.onChangeEventData$.subscribe((eventData: ITimelineEventSegment[]) => { + this.oEvents.updateData(eventData); + }); + this.oSelectionManager.onChangeTimelineUIEvent$.subscribe((event: TimelineUIEvent) => { + this.onChangeTimelineUIEvent$.next(event); + }); + this.oSelectionManager.onReset$.subscribe(() => { + this.reset(); + }); + + const eventStartPosition = this.options.headerZoneHeight; + const eventEndPosition = this.options.height - this.options.eventZoneHeight; + this.snap.click((event: any, x: number, y: number) => { + if ( mousedownX !== x ) { + return; + } + if ( event.offsetY > eventStartPosition && event.offsetY < eventEndPosition ) { + this.oSelectionManager.onSetPointingByPosition(event.offsetX); + } + }); + } + addData(oNewData: any) { + this.oLoading.show(); + this.oTimelineData.addData( oNewData ); + this.oLoading.hide(); + } + reset() { + this.oXAxis.reset(); + this.oSelectionManager.reset(); + this.oStateLine.reset(); + this.oEvents.reset(); + } + resize() { + this.oPositionManager.setWidth(this.element.getBoundingClientRect().width); + this.oBackground.reset(this.oPositionManager.getTimelineEndPosition()); + this.reset(); + } + zoomIn() { + // 1/2배씩 + this.oPositionManager.zoomIn(); + this.reset(); + this.fireChangedRangeEvent(); + } + zoomOut() { + // 2배씩 + this.oPositionManager.zoomOut(); + this.reset(); + this.fireChangedRangeEvent(); + } + private fireChangedRangeEvent(): void { + const event = new TimelineUIEvent(); + event.setOnRange(); + event.setData( + this.oPositionManager.getPointingTime(), + this.oPositionManager.getSelectionTimeRange(), + this.oPositionManager.getTimelineRange() + ); + this.onChangeTimelineUIEvent$.next(event); + } + resetTimeRangeAndSelectionZone(aSelectionFromTo: number[], aFromTo: number[], selectedTime: number) { + this.oPositionManager.setTimelineRange(aFromTo[0], aFromTo[1]); + this.oPositionManager.setSelectionStartTime(aSelectionFromTo[0]); + this.oPositionManager.setSelectionEndTime(aSelectionFromTo[1]); + this.oPositionManager.setPointingTime(selectedTime || aSelectionFromTo[1]); + this.emptyData(); + this.reset(); + } + movePrev() { + this.oSelectionManager.onSetPointingByTime(this.oPositionManager.getPrevTime()); + } + moveNext() { + this.oSelectionManager.onSetPointingByTime(this.oPositionManager.getNextTime()); + } + moveHead() { + this.oSelectionManager.onSetPointingByTime(Date.now(), true); + } + getTimelineRange() { + return this.oPositionManager.getTimelineRange(); + } + getSelectionTimeRange() { + return this.oPositionManager.getSelectionTimeRange(); + } + emptyData() { + this.oLoading.show(); + this.oTimelineData.emptyData(); + this.oEvents.emptyData(); + this.oStateLine.emptyData(); + this.oLoading.hide(); + } + setPointingTime(time: number): void { + this.oSelectionManager.onSetPointingByTime(time); + } + getPointingTime() { + return this.oPositionManager.getPointingTime(); + } + setTimezone(timezone: string): void { + this.options.timezone = timezone; + this.oPositionManager.setTimezone(timezone); + this.reset(); + } + setDateFormat(dateFormat: string[]): void { + this.options.dateFormat = dateFormat; + this.oPositionManager.setDateFormat(dateFormat); + this.reset(); + } + destroy() { + this.oLoading.destroy(); + this.oBackground.destroy(); + this.oTimelineData.destroy(); + this.oPositionManager.destroy(); + this.oStateLine.destroy(); + this.oSelectionManager.destroy(); + this.oXAxis.destroy(); + this.oEvents.destroy(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/index.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/index.ts new file mode 100644 index 000000000000..4e5d830d3c3a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/index.ts @@ -0,0 +1,28 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { TimelineComponent } from './timeline.component'; +import { TimelineInteractionService } from './timeline-interaction.service'; +import { AgentInspectorTimelineContainerComponent } from './agent-inspector-timeline-container.component'; +import { ApplicationInspectorTimelineContainerComponent } from './application-inspector-timeline-container.component'; +import { AgentTimelineDataService } from './agent-timeline-data.service'; + +@NgModule({ + declarations: [ + TimelineComponent, + AgentInspectorTimelineContainerComponent, + ApplicationInspectorTimelineContainerComponent + ], + imports: [ + CommonModule + ], + exports: [ + AgentInspectorTimelineContainerComponent, + ApplicationInspectorTimelineContainerComponent + ], + providers: [ + TimelineInteractionService, + AgentTimelineDataService + ] +}) +export class TimelineModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/timeline-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/timeline-interaction.service.ts new file mode 100644 index 000000000000..e577b5af2285 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/timeline-interaction.service.ts @@ -0,0 +1,64 @@ +import { Injectable } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { ITimelineEventSegment } from './class/timeline-data.class'; +export enum TimelineCommand { + zoomIn = 'ZOOM_IN', + zoomOut = 'ZOOM_OUT', + prev = 'PREV', + next = 'NEXT', + now = 'NOW' +} + +export interface ITimelineCommandParam { + command: TimelineCommand; + payload?: any; +} + +@Injectable() +export class TimelineInteractionService { + public onSelectPointingTime$: Observable; + public onSelectEventStatus$: Observable; + public onCommand$: Observable; + + private changePointingTimeSource = new Subject(); + private selectEventStatusSource = new Subject(); + private commandSource = new Subject(); + + constructor() { + this.onSelectPointingTime$ = this.changePointingTimeSource.asObservable(); + this.onSelectEventStatus$ = this.selectEventStatusSource.asObservable(); + this.onCommand$ = this.commandSource.asObservable(); + } + sendSelectedPointingTime(pointingTime: number): void { + this.changePointingTimeSource.next(pointingTime); + } + sendSelectedEventStatus(eventSegment: ITimelineEventSegment): void { + this.selectEventStatusSource.next(eventSegment); + } + setZoomIn(): void { + this.commandSource.next({ + command: TimelineCommand.zoomIn + }); + } + setZoomOut(): void { + this.commandSource.next({ + command: TimelineCommand.zoomOut + }); + } + setPrev(): void { + this.commandSource.next({ + command: TimelineCommand.prev + }); + } + setNext(): void { + this.commandSource.next({ + command: TimelineCommand.next + }); + } + setNow(): void { + this.commandSource.next({ + command: TimelineCommand.now + }); + } +} + diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/timeline.component.css b/web/src/main/webapp/v2/src/app/core/components/timeline/timeline.component.css new file mode 100644 index 000000000000..edb330555024 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/timeline.component.css @@ -0,0 +1,91 @@ +:host { + display: block; + user-select: none; +} +svg { + width: 100%; +} +svg text { + user-select: none; +} +.hide { + display: none; +} +.background rect { + fill: #EEE; +} + +.selection-zone rect { + fill: rgba(255, 255, 255, 0.5); +} +.x-axis text { + font-size: 12px; + text-anchor: middle; +} +.x-axis line { + stroke: #FFF; + stroke-width: 0.5; + stroke-linecap: square; +} +.left-handler rect, .right-handler rect { + fill: #FFF; +} +.left-handler line, .right-handler line { + stroke: #000; + stroke-width: 2; +} +.guide line { + stroke: #F00; + stroke-width: .5; + stroke-linecap: square; + stroke-dasharray: 2, 2; +} +.guide circle { + stroke: #F00; + stroke-width: 2; +} +.selection-point line { + stroke: #FF0; + stroke-width: 1; +} +.selection-point circle { + fill: #FF0; + stroke: #000; + stroke-width: 2; +} +.events line { + stroke: #000; + stroke-width: 1; +} +.events circle { + fill: #BDB76B; +} +.events text { + fill: #FFF; + font-size: 11px; +} +image { + cursor: pointer; +} +.event { + cursor: pointer; +} +.loading { + fill: rgba(170, 170, 170, 0.1); +} +.loading rect { + stroke-width: 2px; +} +.loading rect:nth-child(2) { + stroke: rgba(197, 197, 197, .9); +} +.loading rect:nth-child(3) { + stroke: rgba(239, 246, 105, .9); +} +.time-left-signboard text, .time-right-signboard text { + fill: #000; + font-size: 13px; +} +.time-series-signboard text { + fill: #BBB; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/timeline.component.html b/web/src/main/webapp/v2/src/app/core/components/timeline/timeline.component.html new file mode 100644 index 000000000000..e30fc442523d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/timeline.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timeline/timeline.component.ts b/web/src/main/webapp/v2/src/app/core/components/timeline/timeline.component.ts new file mode 100644 index 000000000000..36594afbca7b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timeline/timeline.component.ts @@ -0,0 +1,103 @@ +import { Component, OnInit, ViewEncapsulation, ChangeDetectionStrategy, OnChanges, OnDestroy, SimpleChanges, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core'; +import { Timeline, ITimelineData, ITimelineEventSegment, TimelineUIEvent } from './class'; + +@Component({ + selector: 'pp-timeline', + templateUrl: './timeline.component.html', + styleUrls: ['./timeline.component.css'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TimelineComponent implements OnInit, OnChanges, OnDestroy { + @ViewChild('timeline') el: ElementRef; + + @Input() data: any; + @Input() height: number; + @Input() pointingTime: number; + @Input() timelineStartTime: number; + @Input() timelineEndTime: number; + @Input() selectionStartTime: number; + @Input() selectionEndTime: number; + @Input() timezone: string; + @Input() dateFormat: string[]; + + @Output() outChangeTimelineUIEvent: EventEmitter = new EventEmitter(); + @Output() outSelectEventStatus: EventEmitter = new EventEmitter(); + + timeline: Timeline; + constructor(private hostElRef: ElementRef) {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if (changes['data'] && changes['data'].currentValue) { + this.initTimeline(); + } + if (changes['timezone'] && this.timeline) { + this.timeline.setTimezone(this.timezone); + } + if (changes['dateFormat'] && this.timeline) { + this.timeline.setDateFormat(this.dateFormat); + } + } + // selectionTime : 전체 조회 기간 중 선택 구간 + // start - from : timeline의 전체 조회 구간 + // pointingTime : 포인팅 지점 + initTimeline() { + if ( this.timeline ) { + this.timeline.resetTimeRangeAndSelectionZone( + [this.selectionStartTime, this.selectionEndTime], + [this.timelineStartTime, this.timelineEndTime], + this.pointingTime + ); + this.timeline.addData(this.data); + } else { + this.timeline = new Timeline(this.el.nativeElement, { + 'width': this.hostElRef.nativeElement.offsetWidth, + 'height': this.height, + 'timelineRange': [this.timelineStartTime, this.timelineEndTime], + 'selectionTimeRange': [this.selectionStartTime, this.selectionEndTime], + 'pointingTime': this.pointingTime, + 'timelineData': this.data, + 'timezone': this.timezone, + 'dateFormat': this.dateFormat, + 'statusColor': { + 'BASE': 'rgba(187, 187, 187, .3)', + 'UNKNOWN': 'rgba(220, 214, 214, .8)', + 'RUNNING': 'rgba(0, 158, 0, .4 )', + 'SHUTDOWN': 'rgba(209, 82, 96, .7)', + 'UNSTABLE_RUNNING': 'rgba(255, 102, 0, .4)', + 'EMPTY': 'rgba(165, 219, 245, .7)' + } + }); + this.timeline.onSelectEventStatus$.subscribe((eventSegment: ITimelineEventSegment) => { + this.outSelectEventStatus.emit(eventSegment); + }); + this.timeline.onChangeTimelineUIEvent$.subscribe((event: TimelineUIEvent) => { + this.outChangeTimelineUIEvent.emit(event); + }); + } + } + zoomIn(): void { + this.timeline.zoomIn(); + } + zoomOut(): void { + this.timeline.zoomOut(); + } + movePrev(): void { + this.timeline.movePrev(); + } + moveNext(): void { + this.timeline.moveNext(); + } + moveNow(): void { + this.timeline.moveHead(); + } + getTimelineRange(): number[] { + return this.timeline.getTimelineRange(); + } + updateData(data: any): void { + this.timeline.addData(data); + } + ngOnDestroy() { + // this.timeline.destroy(); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timezone/index.ts b/web/src/main/webapp/v2/src/app/core/components/timezone/index.ts new file mode 100644 index 000000000000..2a66aa18175b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timezone/index.ts @@ -0,0 +1,21 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { TimezoneSelectContainerComponent } from './timezone-select-container.component'; +import { TimezoneSelectComponent } from './timezone-select.component'; + +@NgModule({ + declarations: [ + TimezoneSelectContainerComponent, + TimezoneSelectComponent + ], + imports: [ + SharedModule + ], + exports: [ + TimezoneSelectContainerComponent, + ], + providers: [ + ] +}) +export class TimezoneModule {} diff --git a/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select-container.component.css b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select-container.component.css new file mode 100644 index 000000000000..7f26ddcb5503 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select-container.component.css @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select-container.component.html b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select-container.component.html new file mode 100644 index 000000000000..15cfaa0bf78d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select-container.component.html @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select-container.component.ts new file mode 100644 index 000000000000..fdbe26021570 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select-container.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import * as moment from 'moment-timezone'; +import { Observable, Subject } from 'rxjs'; + +import { Actions } from 'app/shared/store'; +import { StoreHelperService, WebAppSettingDataService, AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; + +@Component({ + selector: 'pp-timezone-select-container', + templateUrl: './timezone-select-container.component.html', + styleUrls: ['./timezone-select-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TimezoneSelectContainerComponent implements OnInit { + private unsubscribe: Subject = new Subject(); + timezoneList: string[]; + currentTimezone$: Observable; + + constructor( + private storeHelperService: StoreHelperService, + private webAppSettingDataService: WebAppSettingDataService, + private analyticsService: AnalyticsService, + ) {} + + ngOnInit() { + this.initTimezoneList(); + this.initCurrentTimezone(); + } + + private initTimezoneList(): void { + this.timezoneList = moment.tz.names(); + } + + private initCurrentTimezone(): void { + this.currentTimezone$ = this.storeHelperService.getTimezone(this.unsubscribe); + } + + onChangeTimezone(timezone: string): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SET_TIMEZONE_IN_CONFIGURATION, timezone); + this.webAppSettingDataService.setTimezone(timezone); + this.storeHelperService.dispatch(new Actions.ChangeTimezone(timezone)); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select.component.css b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select.component.css new file mode 100644 index 000000000000..b2b8789c1cdc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select.component.css @@ -0,0 +1,26 @@ +:host { + display: block; + position: relative; + width: 100%; +} + +.fa-angle-down { + position: absolute; + top: 8px; + right: 8px; + font-size: 15px; +} + +.l-app-select { + width: 100%; + cursor: pointer; + padding: 6px 12px; + background-color: #fff; + border: 1px solid #d7dde4 !important; + border-radius: 0px; + font-size: 13px; + color: #666; + appearance: none; + -webkit-appearance: none; + outline: 0; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select.component.html b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select.component.html new file mode 100644 index 000000000000..47390e84e189 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select.component.html @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select.component.ts b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select.component.ts new file mode 100644 index 000000000000..91a1ea8782be --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/timezone/timezone-select.component.ts @@ -0,0 +1,24 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-timezone-select', + templateUrl: './timezone-select.component.html', + styleUrls: ['./timezone-select.component.css'], +}) +export class TimezoneSelectComponent implements OnInit { + @Input() timezoneList: string[]; + @Input() currentTimezone: string; + @Output() outChangeTimezone = new EventEmitter(); + + constructor() {} + ngOnInit() { + } + + onChangeTimezone(value: string): void { + this.outChangeTimezone.emit(value); + } + + compareFn(o1: string, o2: string): boolean { + return o1 && o2 ? o1 === o2 : false; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/index.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/index.ts new file mode 100644 index 000000000000..864afadbe8f1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/index.ts @@ -0,0 +1,35 @@ + +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { TransactionShortInfoModule } from 'app/core/components/transaction-short-info'; +import { TransactionDetailMenuModule } from 'app/core/components/transaction-detail-menu'; +import { TransactionSearchModule } from 'app/core/components/transaction-search'; +import { CallTreeModule } from 'app/core/components/call-tree'; +import { ServerMapModule } from 'app/core/components/server-map'; +import { TransactionTimelineModule } from 'app/core/components/transaction-timeline'; +import { SyntaxHighlightPopupModule } from 'app/core/components/syntax-highlight-popup'; +import { TransactionDetailContentsContainerComponent } from './transaction-detail-contents-container.component'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + TransactionDetailContentsContainerComponent + ], + imports: [ + SharedModule, + TransactionShortInfoModule, + TransactionDetailMenuModule, + TransactionSearchModule, + CallTreeModule, + ServerMapModule, + TransactionTimelineModule, + SyntaxHighlightPopupModule, + HelpViewerPopupModule + ], + exports: [ + TransactionDetailContentsContainerComponent + ], + providers: [] +}) +export class TransactionDetailContentsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/transaction-detail-contents-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/transaction-detail-contents-container.component.css new file mode 100644 index 000000000000..edfceb22aea7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/transaction-detail-contents-container.component.css @@ -0,0 +1,24 @@ +.l-content-section { + height: 100%; + position: relative; +} +.l-tab-menu-options { + display: flex; + flex-flow: row wrap; +} +.l-component-wrapper { + width: 100%; + height: calc(100% - 84px); + position: relative; +} +.l-middle-tool-box { + height: 54px; + align-items: center; + justify-content: space-between; + padding: 0 25px; + position:relative; +} +.l-middle-tool-box, .l-middle-tool-box-tip { + color:#a8acb5; + font-size: 18px +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/transaction-detail-contents-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/transaction-detail-contents-container.component.html new file mode 100644 index 000000000000..857c3f81ea97 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/transaction-detail-contents-container.component.html @@ -0,0 +1,15 @@ +
    + +
    + + +
    + +
    +
    +
    + + + +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/transaction-detail-contents-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/transaction-detail-contents-container.component.ts new file mode 100644 index 000000000000..a6629f31d8a8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-contents/transaction-detail-contents-container.component.ts @@ -0,0 +1,40 @@ +import { Component, OnInit } from '@angular/core'; + +import { TransactionViewTypeService, VIEW_TYPE, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-transaction-detail-contents-container', + templateUrl: './transaction-detail-contents-container.component.html', + styleUrls: ['./transaction-detail-contents-container.component.css'] +}) +export class TransactionDetailContentsContainerComponent implements OnInit { + private currentViewType: string; + constructor( + private transactionViewTypeService: TransactionViewTypeService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + + ngOnInit() { + this.transactionViewTypeService.onChangeViewType$.subscribe((viewType: string) => { + this.currentViewType = viewType; + }); + } + isHiddenSearchComponent(): boolean { + return this.currentViewType !== VIEW_TYPE.CALL_TREE && this.currentViewType !== VIEW_TYPE.TIMELINE; + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.CALL_TREE); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.CALL_TREE, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/index.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/index.ts new file mode 100644 index 000000000000..bdd1c1b49361 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/index.ts @@ -0,0 +1,26 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { TransactionDetailMenuComponent } from './transaction-detail-menu.component'; +import { TransactionDetailMenuContainerComponent } from './transaction-detail-menu-container.component'; +import { TransactionDetailMenuForDetailContainerComponent } from './transaction-detail-menu-for-detail-container.component'; +import { MessagePopupModule } from 'app/core/components/message-popup'; + +@NgModule({ + declarations: [ + TransactionDetailMenuComponent, + TransactionDetailMenuContainerComponent, + TransactionDetailMenuForDetailContainerComponent + ], + imports: [ + CommonModule, + MessagePopupModule + ], + exports: [ + TransactionDetailMenuContainerComponent, + TransactionDetailMenuForDetailContainerComponent + ], + providers: [] +}) +export class TransactionDetailMenuModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-container.component.html new file mode 100644 index 000000000000..952f08f59823 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-container.component.html @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-container.component.ts new file mode 100644 index 000000000000..29a0e3a33bc8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-container.component.ts @@ -0,0 +1,110 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter, takeUntil } from 'rxjs/operators'; + +import { + StoreHelperService, + NewUrlStateNotificationService, + UrlRouteManagerService, + TransactionViewTypeService, + IViewType, TransactionDetailDataService, + ITransactionDetailPartInfo, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { MessagePopupContainerComponent } from 'app/core/components/message-popup/message-popup-container.component'; + +@Component({ + selector: 'pp-transaction-detail-menu-container', + templateUrl: './transaction-detail-menu-container.component.html', + styleUrls: ['./transaction-detail-menu-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TransactionDetailMenuContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private transactionInfo: ITransactionMetaData; + viewTypeList: IViewType[]; + viewType: string; + partInfo: ITransactionDetailPartInfo; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private transactionViewTypeService: TransactionViewTypeService, + private transactionDetailDataService: TransactionDetailDataService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.viewTypeList = this.transactionViewTypeService.getViewTypeList(); + this.transactionViewTypeService.onChangeViewType$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((viewType: string) => { + this.viewType = viewType; + this.changeDetectorRef.detectChanges(); + }); + this.transactionDetailDataService.partInfo$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((partInfo: ITransactionDetailPartInfo) => { + this.partInfo = partInfo; + this.changeDetectorRef.detectChanges(); + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTransactionData(this.unsubscribe).pipe( + filter((data: ITransactionMetaData) => { + if (data && data.application && data.agentId && data.traceId) { + return true; + } + return false; + }) + ).subscribe((transactionInfo: ITransactionMetaData) => { + this.transactionInfo = transactionInfo; + this.changeDetectorRef.detectChanges(); + }); + } + onSelectViewType(viewType: string): void { + this.analyticsService.trackEvent((TRACKED_EVENT_LIST as any)[`CLICK_${viewType}`]); + this.urlRouteManagerService.moveOnPage({ + url: [ + UrlPath.TRANSACTION_LIST, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.TRANSACTION_INFO), + viewType + ] + }); + } + onOpenDetailView(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_TRANSACTION_VIEW); + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_VIEW, + this.transactionInfo.agentId, + this.transactionInfo.traceId, + this.transactionInfo.collectorAcceptTime + '', + this.transactionInfo.spanId, + ]); + } + onOpenExtraView(param: any): void { + if (param.open) { + this.urlRouteManagerService.openPage(param.url); + } else { + this.dynamicPopupService.openPopup({ + data: { + title: 'Notice', + contents: this.partInfo.disableButtonMessage + }, + component: MessagePopupContainerComponent + }); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-for-detail-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-for-detail-container.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-for-detail-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-for-detail-container.component.html new file mode 100644 index 000000000000..952f08f59823 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-for-detail-container.component.html @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-for-detail-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-for-detail-container.component.ts new file mode 100644 index 000000000000..93fa6b5ad4b2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu-for-detail-container.component.ts @@ -0,0 +1,79 @@ +import { Component, OnInit } from '@angular/core'; + +import { + NewUrlStateNotificationService, + UrlRouteManagerService, + TransactionViewTypeService, + IViewType, + TransactionDetailDataService, + ITransactionDetailPartInfo, + AnalyticsService, + TRACKED_EVENT_LIST, + DynamicPopupService +} from 'app/shared/services'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { MessagePopupContainerComponent } from 'app/core/components/message-popup/message-popup-container.component'; + +@Component({ + selector: 'pp-transaction-detail-menu-for-detail-container', + templateUrl: './transaction-detail-menu-for-detail-container.component.html', + styleUrls: ['./transaction-detail-menu-for-detail-container.component.css'] +}) +export class TransactionDetailMenuForDetailContainerComponent implements OnInit { + viewTypeList: IViewType[]; + viewType: string; + partInfo: ITransactionDetailPartInfo; + constructor( + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private transactionViewTypeService: TransactionViewTypeService, + private transactionDetailDataService: TransactionDetailDataService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.viewTypeList = this.transactionViewTypeService.getViewTypeList(); + this.transactionViewTypeService.onChangeViewType$.subscribe((viewType: string) => { + this.viewType = viewType; + }); + this.transactionDetailDataService.partInfo$.subscribe((partInfo: ITransactionDetailPartInfo) => { + this.partInfo = partInfo; + }); + } + onSelectViewType(viewType: string): void { + this.analyticsService.trackEvent((TRACKED_EVENT_LIST as any)[`CLICK_${viewType}`]); + this.urlRouteManagerService.moveOnPage({ + url: [ + UrlPath.TRANSACTION_DETAIL, + this.newUrlStateNotificationService.getPathValue(UrlPathId.TRACE_ID), + this.newUrlStateNotificationService.getPathValue(UrlPathId.FOCUS_TIMESTAMP), + this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), + this.newUrlStateNotificationService.getPathValue(UrlPathId.SPAN_ID), + viewType + ] + }); + } + onOpenDetailView(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_TRANSACTION_VIEW); + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_VIEW, + this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), + this.newUrlStateNotificationService.getPathValue(UrlPathId.TRACE_ID), + this.newUrlStateNotificationService.getPathValue(UrlPathId.FOCUS_TIMESTAMP), + this.newUrlStateNotificationService.getPathValue(UrlPathId.SPAN_ID) + ]); + } + onOpenExtraView(param: any): void { + if (param.open) { + this.urlRouteManagerService.openPage(param.url); + } else { + this.dynamicPopupService.openPopup({ + data: { + title: 'Notice', + contents: this.partInfo.disableButtonMessage + }, + component: MessagePopupContainerComponent + }); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu.component.css new file mode 100644 index 000000000000..e2eb9160ec67 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu.component.css @@ -0,0 +1,38 @@ +.l-wrapper { + display: flex; + flex-flow: row wrap; +} +.l-btn-group { + border:1px solid #e5e8ea; + height:32px; +} +.l-btn-group button { + background:#fff; + float:left; + padding:0 15px; + height:100%; +} +.l-btn-group button.active, .l-btn-group button:hover { + color:#fff; + font-weight:600; + background:#4a8fd2; +} +.l-transaction-state { + color: #FFF; + height: 32px; + padding: 8px; + font-size: 12px; + margin-left: 10px; +} +.l-transaction-complete { + background-color: #5CB85C; +} +.l-transaction-progress { + background-color: rgb(91, 192, 222); +} +.l-transaction-error { + background-color: #D9534F; +} +.l-log-info.disable { + color: #BBBABA; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu.component.html new file mode 100644 index 000000000000..3bad8e5d42bf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu.component.html @@ -0,0 +1,10 @@ +
    +
    + + + +
    + {{partInfo?.completeState}} +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu.component.ts new file mode 100644 index 000000000000..23e00c742ae5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-detail-menu/transaction-detail-menu.component.ts @@ -0,0 +1,59 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-transaction-detail-menu', + templateUrl: './transaction-detail-menu.component.html', + styleUrls: ['./transaction-detail-menu.component.css'] +}) + +export class TransactionDetailMenuComponent implements OnInit { + @Input() viewTypeList: object[]; + @Input() viewType: string; + @Input() partInfo: any; + @Output() outSelectViewType: EventEmitter = new EventEmitter(); + @Output() outOpenDetailView: EventEmitter = new EventEmitter(); + @Output() outOpenExtraView: EventEmitter = new EventEmitter(); + constructor() {} + ngOnInit() {} + isCurrentView(viewType: string): boolean { + return this.viewType === viewType; + } + onSelectView(viewType: string): void { + if ( this.viewType === viewType ) { + return; + } + this.outSelectViewType.next(viewType); + } + openDetailView(): void { + this.outOpenDetailView.next(); + } + hasLogView(): boolean { + return this.partInfo && this.partInfo.logLinkEnable; + } + openLogView(): void { + if (this.partInfo.loggingTransactionInfo === true ) { + this.outOpenExtraView.next({ + open: true, + url: this.partInfo.logPageUrl + }); + } else { + this.outOpenExtraView.next({ + open: false, + message: this.partInfo.disableButtonMessage + }); + } + } + hasInfo(): boolean { + return this.partInfo && !this.partInfo.loggingTransactionInfo; + } + getStateClass(): string { + if ( this.partInfo ) { + return 'l-transaction-' + this.partInfo.completeState.toLowerCase(); + } else { + return ''; + } + } + hasState(): boolean { + return !!this.partInfo; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/index.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/index.ts new file mode 100644 index 000000000000..c5afafe8738b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/index.ts @@ -0,0 +1,37 @@ + +import { NgModule } from '@angular/core'; + +import { SharedModule } from 'app/shared'; +import { TransactionShortInfoModule } from 'app/core/components/transaction-short-info'; +import { TransactionDetailMenuModule } from 'app/core/components/transaction-detail-menu'; +import { TransactionSearchModule } from 'app/core/components/transaction-search'; +import { CallTreeModule } from 'app/core/components/call-tree'; +import { ServerMapModule } from 'app/core/components/server-map'; +import { TransactionTimelineModule } from 'app/core/components/transaction-timeline'; +import { TransactionTableGridModule } from 'app/core/components/transaction-table-grid'; +import { SyntaxHighlightPopupModule } from 'app/core/components/syntax-highlight-popup'; +import { TransactionListBottomContentsContainerComponent } from './transaction-list-bottom-contents-container.component'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + TransactionListBottomContentsContainerComponent + ], + imports: [ + SharedModule, + TransactionTableGridModule, + TransactionShortInfoModule, + TransactionDetailMenuModule, + TransactionSearchModule, + ServerMapModule, + TransactionTimelineModule, + CallTreeModule, + SyntaxHighlightPopupModule, + HelpViewerPopupModule + ], + exports: [ + TransactionListBottomContentsContainerComponent + ], + providers: [] +}) +export class TransactionListBottomContentsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component.css new file mode 100644 index 000000000000..849ae5c5f46e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component.css @@ -0,0 +1,26 @@ +.l-content-section { + height: 100%; + position: relative; +} +.l-middle-tool-box { + background-color: #edf2f8; +} +.l-component-wrapper { + width: 100%; + height: calc(100% - 84px); + position: relative; +} +.l-middle-tool-box { + display: flex; + flex-flow: row wrap; + height: 54px; + background-color: #edf2f8; + align-items: center; + justify-content: space-between; + padding: 0 25px; + position:relative; +} +.l-middle-tool-box, .l-middle-tool-box-tip { + color:#a8acb5; + font-size: 18px +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component.html new file mode 100644 index 000000000000..c439859621b5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component.html @@ -0,0 +1,21 @@ +
    + +
    + + +
    + +   + +
    +
    +
    + + + +
    + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component.ts new file mode 100644 index 000000000000..46a9a738f9f1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component.ts @@ -0,0 +1,111 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +import { + StoreHelperService, + UrlRouteManagerService, + TransactionViewTypeService, VIEW_TYPE, + TransactionDetailDataService, + AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath } from 'app/shared/models'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; + +@Component({ + selector: 'pp-transaction-list-bottom-contents-container', + templateUrl: './transaction-list-bottom-contents-container.component.html', + styleUrls: ['./transaction-list-bottom-contents-container.component.css'] +}) +export class TransactionListBottomContentsContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + currentViewType: string; + transactionInfo: ITransactionMetaData; + useDisable = false; + showLoading = false; + constructor( + private storeHelperService: StoreHelperService, + private urlRouteManagerService: UrlRouteManagerService, + private transactionDetailDataService: TransactionDetailDataService, + private transactionViewTypeService: TransactionViewTypeService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.transactionViewTypeService.onChangeViewType$.subscribe((viewType: string) => { + this.currentViewType = viewType; + }); + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTransactionData(this.unsubscribe).pipe( + filter((data: ITransactionMetaData) => { + if ( data && data.agentId && data.spanId && data.traceId && data.collectorAcceptTime ) { + return true; + } + return false; + }) + ).subscribe((transactionInfo: ITransactionMetaData) => { + if (this.transactionInfo) { + this.setDisplayGuide(true); + } + this.transactionInfo = transactionInfo; + this.transactionDetailDataService.getData( + transactionInfo.agentId, + transactionInfo.spanId, + transactionInfo.traceId, + transactionInfo.collectorAcceptTime + ).subscribe((transactionDetailInfo: ITransactionDetailData) => { + this.storeHelperService.dispatch(new Actions.UpdateTransactionDetailData(transactionDetailInfo)); + this.setDisplayGuide(false); + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent + }); + }); + }); + } + private setDisplayGuide(state: boolean): void { + this.showLoading = state; + this.useDisable = state; + } + isSameType(type: string): boolean { + return this.currentViewType === type; + } + isCallTreeView(): boolean { + return this.currentViewType === VIEW_TYPE.CALL_TREE || this.currentViewType === VIEW_TYPE.TIMELINE; + } + onOpenTransactionDetailPage(): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_TRANSACTION_DETAIL); + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_DETAIL, + this.transactionInfo.traceId, + this.transactionInfo.collectorAcceptTime + '', + this.transactionInfo.agentId, + this.transactionInfo.spanId + ]); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.CALL_TREE); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.CALL_TREE, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-search/index.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-search/index.ts new file mode 100644 index 000000000000..ad549f27e85f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-search/index.ts @@ -0,0 +1,23 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { TransactionSearchComponent } from './transaction-search.component'; +import { TransactionSearchContainerComponent } from './transaction-search-container.component'; +import { TransactionSearchInteractionService } from './transaction-search-interaction.service'; + +@NgModule({ + declarations: [ + TransactionSearchComponent, + TransactionSearchContainerComponent + ], + imports: [ + SharedModule + ], + exports: [ + TransactionSearchContainerComponent + ], + providers: [ + TransactionSearchInteractionService + ] +}) +export class TransactionSearchModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-container.component.css new file mode 100644 index 000000000000..c3329127e37a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-container.component.css @@ -0,0 +1,3 @@ +:host { + display: flex; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-container.component.html new file mode 100644 index 000000000000..3b114adc6978 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-container.component.html @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-container.component.ts new file mode 100644 index 000000000000..34ce20fafd97 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-container.component.ts @@ -0,0 +1,73 @@ +import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef, OnDestroy } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { combineLatest, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { + TranslateReplaceService, + TransactionViewTypeService, VIEW_TYPE, + AnalyticsService, TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { TransactionSearchInteractionService, ISearchParam } from './transaction-search-interaction.service'; + +@Component({ + selector: 'pp-transaction-search-container', + templateUrl: './transaction-search-container.component.html', + styleUrls: ['./transaction-search-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TransactionSearchContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + private i18nText: { [key: string]: string } = { + HAS_RESULTS: '', + EMPTY_RESULT: '' + }; + currentViewType: string; + useArgument: boolean; + resultMessage: string; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private transactionSearchInteractionService: TransactionSearchInteractionService, + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + private transactionViewTypeService: TransactionViewTypeService, + private analyticsService: AnalyticsService, + ) {} + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + ngOnInit() { + this.getI18NText(); + this.transactionSearchInteractionService.onSearchResult$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((result: any) => { + const resultMessage = result.result === 0 ? this.i18nText.EMPTY_RESULT : this.i18nText.HAS_RESULTS; + this.resultMessage = this.translateReplaceService.replace(resultMessage, result.result); + this.changeDetectorRef.detectChanges(); + }); + this.transactionViewTypeService.onChangeViewType$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((viewType: string) => { + this.currentViewType = viewType; + this.useArgument = viewType === VIEW_TYPE.TIMELINE ? false : true; + this.changeDetectorRef.detectChanges(); + }); + } + private getI18NText(): void { + combineLatest( + this.translateService.get('TRANSACTION.HAS_RESULTS'), + this.translateService.get('TRANSACTION.EMPTY_RESULT') + ).subscribe((i18n: string[]) => { + this.i18nText.HAS_RESULTS = i18n[0]; + this.i18nText.EMPTY_RESULT = i18n[1]; + }); + } + onSearch(params: ISearchParam): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SEARCH_TRANSACTION, `Search Type: ${params.type}`); + this.transactionSearchInteractionService.setSearchParmas({ + type: params.type, + query: params.query === 'self' ? +params.query : params.query + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-interaction.service.ts new file mode 100644 index 000000000000..5ea90f9494ce --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search-interaction.service.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; + +export interface ISearchParam { + type: string; + query: string | number; +} + +@Injectable() +export class TransactionSearchInteractionService { + private search = new Subject(); + private searchResult = new Subject(); + private moveRow = new Subject(); + + onSearch$: Observable; + onSearchResult$: Observable; + onMoveRow$: Observable; + + constructor() { + this.onSearch$ = this.search.asObservable(); + this.onSearchResult$ = this.searchResult.asObservable(); + this.onMoveRow$ = this.moveRow.asObservable(); + } + setSearchParmas(params: ISearchParam): void { + this.search.next(params); + } + setSearchResult(result: any): void { + this.searchResult.next(result); + } + setRow(id: string): void { + this.moveRow.next(id); + } +} + diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search.component.css new file mode 100644 index 000000000000..17de9d4033e7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search.component.css @@ -0,0 +1,60 @@ +:host { + display: flex; +} +.l-search-group-wrap { + display: flex; + flex-flow: row wrap; + padding: 0 10px; + font-size: 13px; + justify-content: flex-end; + position:relative; +} +.l-search-group-wrap .fas { + color:#a8acb5; + font-size:18px; +} +.l-search-group-wrap .l-search-group2 { + height:32px; +} +.l-search-group-wrap .l-search-group2 input { + float: left; + display: inline-block; + height: 100%; + border: 1px solid #4a8fd2; + padding:0 10px; + background:#fff; +} +.l-search-group-wrap button { + margin-left: 10px; +} +.l-search-group-wrap .l-error-message { + width: 300px; + color:#e95459; + margin-left: 10px; +} +select { + appearance: none; + -webkit-appearance: none; + outline: 0; + border-radius: 0px; + color: #FFF; + float: left; + height: 100%; + display: inline-block; + padding: 7px 10px; + font-size: 13px; + font-weight: 600; + background-color: #4A8FD2; + width: 100px; +} +.l-search-group-wrap .l-search-group2 .fa-angle-down { + position: absolute; + color: #FFF; + top: 8px; + left: 94px; + font-size: 15px; +} +.l-error-message { + margin-left: 10px; + margin-top: 8px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search.component.html new file mode 100644 index 000000000000..e8dfa4f79a7e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search.component.html @@ -0,0 +1,13 @@ +
    +
    + + + +
    + + {{resultMessage}} +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search.component.ts new file mode 100644 index 000000000000..47e65fc8ea93 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-search/transaction-search.component.ts @@ -0,0 +1,37 @@ +import { Component, Renderer2, OnInit, OnChanges, SimpleChanges, Output, Input, EventEmitter, ViewChild, ElementRef } from '@angular/core'; + +@Component({ + selector: 'pp-transaction-search', + templateUrl: './transaction-search.component.html', + styleUrls: ['./transaction-search.component.css'] +}) +export class TransactionSearchComponent implements OnInit, OnChanges { + @ViewChild('searchType') searchType: ElementRef; + @Output() outSearch: EventEmitter<{type: string, query: string}> = new EventEmitter(); + @Input() viewType: string; + @Input() useArgument: boolean; + @Input() resultMessage = ''; + inputValue: string; + constructor(private renderer: Renderer2) { } + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if (changes['viewType'] && changes['viewType'].currentValue) { + this.onClear(); + // this.renderer.setAttribute(this.searchType.nativeElement.options[0], 'selected', 'selected'); + this.searchType.nativeElement.options[0].selected = true; + } + } + onSearch(type: string): void { + const query = this.inputValue.trim(); + if (query !== '') { + this.outSearch.emit({ + type: type, + query: query + }); + } + } + onClear() { + this.inputValue = ''; + this.resultMessage = ''; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/index.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/index.ts new file mode 100644 index 000000000000..c61c3250261c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/index.ts @@ -0,0 +1,21 @@ + +import { NgModule } from '@angular/core'; +import { MatTooltipModule } from '@angular/material'; +import { SharedModule } from 'app/shared'; +import { TransactionShortInfoContainerComponent } from './transaction-short-info-container.component'; + +@NgModule({ + declarations: [ + TransactionShortInfoContainerComponent + ], + imports: [ + MatTooltipModule, + SharedModule + ], + exports: [ + TransactionShortInfoContainerComponent, + ], + providers: [ + ] +}) +export class TransactionShortInfoModule {} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/transaction-short-info-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/transaction-short-info-container.component.css new file mode 100644 index 000000000000..66d2c542b316 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/transaction-short-info-container.component.css @@ -0,0 +1,22 @@ +.l-route { + display: flex; + flex-flow: row wrap; + background:#506078; + height: 30px; + align-items: center; + justify-content: space-around; +} +.l-route > div { + width: 25%; + color:#fff; + display: block; + position:relative; + font-size: 12px; + overflow: hidden; + white-space: nowrap; + padding-left: 6px; + text-overflow: ellipsis; +} +.l-route > div:last-child { + padding-right: 6px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/transaction-short-info-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/transaction-short-info-container.component.html new file mode 100644 index 000000000000..c094da947429 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/transaction-short-info-container.component.html @@ -0,0 +1,6 @@ +
    +
    ApplicationName : {{applicationName}}
    +
    AgentId : {{agentId}}
    +
    TransactionId : {{transactionId}}
    +
    Path : {{path}}
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/transaction-short-info-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/transaction-short-info-container.component.ts new file mode 100644 index 000000000000..4ba05fa28947 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-short-info/transaction-short-info-container.component.ts @@ -0,0 +1,41 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter } from 'rxjs/operators'; +import { StoreHelperService } from 'app/shared/services'; + +@Component({ + selector: 'pp-transaction-short-info-container', + templateUrl: './transaction-short-info-container.component.html', + styleUrls: ['./transaction-short-info-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TransactionShortInfoContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + path: string; + agentId: string; + transactionId: string; + applicationName: string; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService) {} + ngOnInit() { + this.connectStore(); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTransactionDetailData(this.unsubscribe).pipe( + filter((transactionDetailInfo: ITransactionDetailData) => { + return transactionDetailInfo ? true : false; + }) + ).subscribe((transactionDetailInfo: ITransactionDetailData) => { + this.path = transactionDetailInfo.applicationName; + this.agentId = transactionDetailInfo.agentId; + this.transactionId = transactionDetailInfo.transactionId; + this.applicationName = transactionDetailInfo.applicationId; + this.changeDetectorRef.detectChanges(); + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/index.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/index.ts new file mode 100644 index 000000000000..04602b816255 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/index.ts @@ -0,0 +1,28 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { AgGridModule } from 'ag-grid-angular/main'; + +import { TransactionTableGridComponent } from './transaction-table-grid.component'; +import { TransactionTableGridContainerComponent } from './transaction-table-grid-container.component'; +import { TransactionMetaDataService } from './transaction-meta-data.service'; +import { MessagePopupModule } from 'app/core/components/message-popup'; + +@NgModule({ + declarations: [ + TransactionTableGridComponent, + TransactionTableGridContainerComponent + ], + imports: [ + CommonModule, + AgGridModule.withComponents([]), + MessagePopupModule + ], + exports: [ + TransactionTableGridContainerComponent + ], + providers: [ + TransactionMetaDataService + ] +}) +export class TransactionTableGridModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-meta-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-meta-data.service.ts new file mode 100644 index 000000000000..6b0118c70425 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-meta-data.service.ts @@ -0,0 +1,199 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Subject, Observable } from 'rxjs'; +import { filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { + UrlRouteManagerService, + NewUrlStateNotificationService, + WindowRefService, + DynamicPopupService +} from 'app/shared/services'; +import { MessagePopupContainerComponent } from 'app/core/components/message-popup/message-popup-container.component'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; + +@Injectable() +export class TransactionMetaDataService { + private requestURL = 'transactionmetadata.pinpoint'; + private retrieveErrorMessage: string; + private lastFetchedIndex = 0; + private maxLoadLength = 100; + private requestSourceData: any[]; + private requestCount = 0; + private countStatus = [0, 0]; + private outTransactionDataLoad: Subject = new Subject(); + private outTransactionDataRange: Subject = new Subject(); + private outTransactionDataCount: Subject = new Subject(); + + onTransactionDataLoad$: Observable; + onTransactionDataRange$: Observable; + onTransactionDataCount$: Observable; + + constructor( + private http: HttpClient, + private windowRefService: WindowRefService, + private translateService: TranslateService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private dynamicPopupService: DynamicPopupService + ) { + this.onTransactionDataLoad$ = this.outTransactionDataLoad.asObservable(); + this.onTransactionDataRange$ = this.outTransactionDataRange.asObservable(); + this.onTransactionDataCount$ = this.outTransactionDataCount.asObservable(); + + this.translateService.get('TRANSACTION_LIST.TRANSACTION_RETRIEVE_ERROR').subscribe((text: string) => { + this.retrieveErrorMessage = text; + }); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + filter((urlService: NewUrlStateNotificationService) => { + return urlService && urlService.hasValue(UrlPathId.APPLICATION, UrlPathId.PERIOD, UrlPathId.END_TIME); + }) + ).subscribe(() => { + this.requestSourceData = this.getInfoFromOpener(); + this.countStatus[1] = this.requestSourceData.length; + }); + } + loadData(): void { + if (this.requestSourceData.length === 0) { + this.dynamicPopupService.openPopup({ + data: { + title: 'Notice', + contents: this.retrieveErrorMessage, + }, + component: MessagePopupContainerComponent, + onCloseCallback: () => { + this.urlRouteManagerService.moveOnPage({ + url: [ + UrlPath.MAIN, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ] + }); + } + }); + } else { + this.http.post<{ metadata: ITransactionMetaData[] }>(this.requestURL, this.makeRequestOptionsArgs(), { + headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded') + }).subscribe((responseData: { metadata: ITransactionMetaData[] }) => { + const responseLength = responseData.metadata.length; + if (this.requestCount !== responseLength) { + if (this.requestCount > responseLength) { + this.countStatus[1] -= (this.requestCount - responseLength); + } else { + this.countStatus[1] += (responseLength - this.requestCount); + } + } + if (responseLength === 0) { + this.outFullRange(); + } else { + this.countStatus[0] += responseLength; + if (this.countStatus[0] === this.countStatus[1]) { + this.outFullRange(); + } else { + this.outTransactionDataRange.next([ + responseData.metadata[responseLength - 1].collectorAcceptTime, + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getDate().valueOf() + ]); + } + this.outTransactionDataLoad.next(responseData.metadata); + } + this.outTransactionDataCount.next(this.countStatus); + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent, + onCloseCallback: () => { + this.urlRouteManagerService.reload(); + } + }); + }); + } + } + moreLoad(): void { + this.loadData(); + } + private outFullRange(): void { + this.outTransactionDataRange.next([ + this.newUrlStateNotificationService.getStartTimeToNumber(), + this.newUrlStateNotificationService.getEndTimeToNumber() + ]); + } + private makeRequestOptionsArgs(): string { + const requestStr = []; + const len = this.requestSourceData.length; + const maxLen = Math.min(len, this.maxLoadLength + this.lastFetchedIndex); + for ( let index = 0, dataIndex = this.lastFetchedIndex ; dataIndex < maxLen ; index++, dataIndex++ ) { + // transactionId, x, y + requestStr.push(`I${index}=${this.requestSourceData[dataIndex][0]}`); + requestStr.push(`T${index}=${this.requestSourceData[dataIndex][1]}`); + requestStr.push(`R${index}=${this.requestSourceData[dataIndex][2]}`); + } + this.requestCount = requestStr.length / 3; + this.lastFetchedIndex = maxLen; + return requestStr.join('&'); + // load from parent window; + // 브라우저 윈도우 이름으로 아래의 정보를 넘김 + // applicationName + // oDragXY.fromX + // oDragXY.toX + // oDragXY.fromY + // oDragXY.toY + // agent + // inclue? + // Success/Failed 정보는 현재 window.opener.htoScatter['applicationName'] 에 저장해 둔 Scatter 객체가 가지고 있음. + // window.htoScatter[''] + // + // transactionList 데이터의 총합은 이전 window에서 가져옴. + // indicator의 range는 + // 가져온 데이터 중 가장 예전의 collectorAcceptTime ~ endTime + // 가져온 데이터의 갯수가 0 이거나 total 보다 커지면 끝 + // 요청 갯수와 응답 갯수가 다른 경우 total 값을 계속 update 해줘야 함. + // 10개 transaction 데이터를 요청했는데 11개 혹은 12개가 오는 케이스가 있음. + // --한번에 요청하는 갯수는 일단 최대 100개 + // const postBody = 'I0=FrontWAS2^1512710981192^11123&T0=1512718752125&R0=2&I1=FrontWAS3^1512711055472^10928&T1=1512718752105&R1=2&I2=FrontWAS2^1512710981192^11122&T2=1512718751113&R2=2&I3=FrontWAS3^1512711055472^10927&T3=1512718751092&R3=2&I4=FrontWAS1^1512711025001^3447&T4=1512718750828&R4=792&I5=FrontWAS4^1512711041898^3430&T5=1512718750448&R5=337&I6=FrontWAS4^1512711041898^3430&T6=1512718750440&R6=8&I7=FrontWAS2^1512710981192^11121&T7=1512718750103&R7=2&I8=FrontWAS3^1512711055472^10926&T8=1512718750081&R8=2&I9=FrontWAS2^1512710981192^11120&T9=1512718749819&R9=9&I10=FrontWAS2^1512710981192^11119&T10=1512718749621&R10=432&I11=FrontWAS2^1512710981192^11119&T11=1512718749617&R11=8&I12=FrontWAS3^1512711055472^10924&T12=1512718749564&R12=933&I13=FrontWAS4^1512711041898^3429&T13=1512718749558&R13=13&I14=FrontWAS2^1512710981192^11118&T14=1512718749091&R14=3&I15=FrontWAS3^1512711055472^10925&T15=1512718749070&R15=2&I16=FrontWAS2^1512710981192^11117&T16=1512718748080&R16=2&I17=FrontWAS3^1512711055472^10923&T17=1512718748059&R17=2&I18=FrontWAS2^1512710981192^11116&T18=1512718747069&R18=2&I19=FrontWAS3^1512711055472^10922&T19=1512718747047&R19=2'; + // return postBody; + } + private getInfoFromOpener(): any[] { + if (this.windowRefService.nativeWindow.opener) { + const paramsInfo = this.windowRefService.nativeWindow.name.split('|'); + if (paramsInfo.length === 7) { + const params = { + application: paramsInfo[0], + fromX: paramsInfo[1], + toX: paramsInfo[2], + fromY: paramsInfo[3], + toY: paramsInfo[4], + agent: paramsInfo[5], + types: paramsInfo[6].split(',') + }; + try { + const scatterChartInstance = this.windowRefService.nativeWindow.opener.scatterChartInstance[params.application]; + if (scatterChartInstance) { + return scatterChartInstance.getDataByRange(params.fromX, params.toX, params.fromY, params.toY, params.agent, params.types); + } + } catch (error) { + return []; + } + } + } + return this.checkUrlInfo(); + } + private checkUrlInfo(): any[] { + if (this.newUrlStateNotificationService.hasValue(UrlPathId.TRANSACTION_INFO)) { + const transactionInfo = this.newUrlStateNotificationService.getPathValue(UrlPathId.TRANSACTION_INFO).split('-'); + const length = transactionInfo.length; + return [[ + transactionInfo.slice(0, length - 2).join('-'), + transactionInfo[length - 2], + transactionInfo[length - 1] + ]]; + } + return []; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid-container.component.css new file mode 100644 index 000000000000..392058fac2cc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid-container.component.css @@ -0,0 +1,8 @@ +:host { + display: flex; + width: 100%; + height: 100%; +} +pp-transaction-table-grid { + width: 100%; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid-container.component.html new file mode 100644 index 000000000000..9ee6a177f6b0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid-container.component.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid-container.component.ts new file mode 100644 index 000000000000..f92ce7eaa258 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid-container.component.ts @@ -0,0 +1,156 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { + UrlRouteManagerService, + NewUrlStateNotificationService, + GutterEventService, + StoreHelperService, + AnalyticsService, TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { IGridData } from './transaction-table-grid.component'; +import { TransactionMetaDataService } from './transaction-meta-data.service'; + + +@Component({ + selector: 'pp-transaction-table-grid-container', + templateUrl: './transaction-table-grid-container.component.html', + styleUrls: ['./transaction-table-grid-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TransactionTableGridContainerComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + areaResized: any; + selectedTraceId: string; + transactionData: ITransactionMetaData[] = []; + transactionDataForAgGrid: IGridData[]; + transactionAddedDataForAgGrid: IGridData[]; + transactionIndex = 1; + timezone: string; + dateFormat: string; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private urlRouteManagerService: UrlRouteManagerService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private transactionMetaDataService: TransactionMetaDataService, + private gutterEventService: GutterEventService, + private analyticsService: AnalyticsService + ) {} + ngOnInit() { + this.connectStore(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.TRANSACTION_INFO)) { + this.selectedTraceId = urlService.getPathValue(UrlPathId.TRANSACTION_INFO).replace(/(.*)-\d*-\d*$/, '$1'); + this.changeDetectorRef.detectChanges(); + this.dispatchTransaction(); + } + if (this.transactionData.length === 0) { + this.transactionMetaDataService.loadData(); + } + }); + this.connectMetaDataService(); + this.gutterEventService.onGutterResized$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((params: any) => { + this.areaResized = params; + this.changeDetectorRef.detectChanges(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTimezone(this.unsubscribe).subscribe((timezone: string) => { + this.timezone = timezone; + this.changeDetectorRef.detectChanges(); + }); + this.storeHelperService.getDateFormat(this.unsubscribe, 2).subscribe((dateFormat: string) => { + this.dateFormat = dateFormat; + this.changeDetectorRef.detectChanges(); + }); + } + private connectMetaDataService(): void { + this.transactionMetaDataService.onTransactionDataLoad$.pipe( + takeUntil(this.unsubscribe), + filter((responseData: any) => { + if ( responseData.length > 0 ) { + return responseData; + } + }) + ).subscribe((responseData: ITransactionMetaData[]) => { + this.transactionData = this.transactionData.concat(responseData || []); + if ( this.transactionDataForAgGrid ) { + this.transactionAddedDataForAgGrid = this.makeGridData(responseData); + this.changeDetectorRef.detectChanges(); + } else { + this.transactionDataForAgGrid = this.makeGridData(responseData); + this.changeDetectorRef.detectChanges(); + this.dispatchTransaction(); + } + }); + } + private makeGridData(transactionData: ITransactionMetaData[]): IGridData[] { + return transactionData.map((data: ITransactionMetaData) => { + return this.makeRow(data); + }); + } + private makeRow(gridData: ITransactionMetaData): IGridData { + return { + id: this.transactionIndex++, + startTime: gridData.startTime, + path: gridData.application, + responseTime: gridData.elapsed, + exception: gridData.exception, + agentId: gridData.agentId, + clientIp: gridData.remoteAddr, + traceId: gridData.traceId, + spanId: gridData.spanId, + collectorAcceptTime: gridData.collectorAcceptTime + } as IGridData; + } + private findTransaction(traceId: string): ITransactionMetaData { + for ( let i = 0 ; i < this.transactionData.length ; i++ ) { + if (this.transactionData[i].traceId === traceId) { + return this.transactionData[i]; + } + } + return null; + } + private dispatchTransaction(): void { + if ( this.selectedTraceId ) { + const transaction = this.findTransaction(this.selectedTraceId); + if ( transaction ) { + this.storeHelperService.dispatch(new Actions.UpdateTransactionData(transaction)); + } + } + } + onSelectTransaction(transactionShortInfo: { traceId: string, collectorAcceptTime: number, elapsed: number }): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_TRANSACTION); + this.urlRouteManagerService.moveOnPage({ + url: [ + UrlPath.TRANSACTION_LIST, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime(), + `${transactionShortInfo.traceId}-${transactionShortInfo.collectorAcceptTime}-${transactionShortInfo.elapsed}` + ] + }); + } + onOpenTransactionView(transactionShortInfo: { agentId: string, traceId: string, collectorAcceptTime: number, spanId: string }): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.OPEN_TRANSACTION_VIEW); + this.urlRouteManagerService.openPage([ + UrlPath.TRANSACTION_VIEW, + transactionShortInfo.agentId, + transactionShortInfo.traceId, + transactionShortInfo.collectorAcceptTime + '', + transactionShortInfo.spanId, + ]); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid.component.css new file mode 100644 index 000000000000..98c57593c8c3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid.component.css @@ -0,0 +1,78 @@ +:host { + width: 100%; + height: 100%; +} +#transaction-table .ag-root { + border: none; + font-size: 12px; + font-family: 'Open Sans', sans-serif; +} +#transaction-table .ag-cell { + padding: 4px; + border-right: 1px solid #e6e8ec; + font-family: 'Open Sans', sans-serif; +} +#transaction-table .ag-column-moving .ag-cell { + transition: left 0.2s; +} +#transaction-table .ag-header-cell-moving .ag-header-cell-label { + opacity: 0; + filter: alpha(opacity=0); +} +#transaction-table .ag-header-cell-moving { + background-color: #bebebe; +} +#transaction-table .ag-header-cell-moving-clone { + border-right: 1px solid #808080; + border-left: 1px solid #808080; + background-color: rgba(220,220,220,0.8); +} +#transaction-table .ag-header { + background: #f6f8fb; + border-bottom: 1px solid #e6e8ec; + line-height: 2; +} +#transaction-table .ag-header-cell { + font-size: 12px; + font-weight: 600; + font-family: 'Open Sans', sans-serif; + border-right: 1px solid #e6e8ec; + padding-left: 2px; + padding-right: 2px; +} +#transaction-table .ag-header-cell-resize:after { + border-right: none; +} +#transaction-table .ag-header-cell-label { + padding: 4px; +} +#transaction-table .ag-group-expanded span { + margin-right: 4px; +} +#transaction-table .ag-row:hover { + background-color: #F5F5F5; +} +#transaction-table .ag-row { + cursor: pointer; + line-height: 2; + border-bottom: 1px solid #e6e8ec; +} +#transaction-table .ag-body { + background-color: #ffffff; +} +#transaction-table .ag-body-viewport { + background-color: #ffffff; +} +#transaction-table .ag-menu { + background-color: #ffffff; + border: 1px solid grey; +} +#transaction-table .fa { + font-size: 14px; +} +#transaction-table .ag-row-exception { + background-color: #fff1f1; +} +#transaction-table .ag-row-selected { + background-color: #e4f5e3; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid.component.html new file mode 100644 index 000000000000..d31fd385a61b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid.component.html @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid.component.ts new file mode 100644 index 000000000000..864a46b1cb1a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-table-grid/transaction-table-grid.component.ts @@ -0,0 +1,190 @@ +import { Component, OnInit, OnChanges, SimpleChanges, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core'; +import * as moment from 'moment-timezone'; +import { GridOptions } from 'ag-grid'; + +export interface IGridData { + id: number; + startTime: number; + path: string; + responseTime: number; + exception: number; + agentId: string; + clientIp: string; + traceId: string; + spanId: string; + collectorAcceptTime: number; +} + +@Component({ + selector: 'pp-transaction-table-grid', + templateUrl: './transaction-table-grid.component.html', + styleUrls: ['./transaction-table-grid.component.css'], + encapsulation: ViewEncapsulation.None +}) +export class TransactionTableGridComponent implements OnInit, OnChanges { + gridOptions: GridOptions; + @Input() rowData: IGridData[]; + @Input() addData: IGridData[]; + @Input() resized: any; + @Input() currentTraceId: string; + @Input() timezone: string; + @Input() dateFormat: string; + @Output() outSelectTransaction: EventEmitter = new EventEmitter(); + @Output() outSelectTransactionView: EventEmitter = new EventEmitter(); + + constructor() {} + ngOnInit() { + this.initGridOptions(); + } + ngOnChanges(changes: SimpleChanges) { + if (changes['addData'] && changes['addData']['currentValue']) { + this.gridOptions.api.updateRowData({ + add: this.addData + }); + } + if (changes['resized'] && !changes['resized']['firstChange'] && changes['resized']['currentValue']) { + this.gridOptions.api.doLayout(); + } + if (changes['timezone'] && changes['timezone'].firstChange === false) { + this.gridOptions.api.refreshCells({ + columns: ['startTime'], + force: true + }); + } + if (changes['dateFormat'] && changes['dateFormat'].firstChange === false) { + this.gridOptions.api.refreshCells({ + columns: ['startTime'], + force: true + }); + } + } + private initGridOptions() { + this.gridOptions = { + rowHeight: 30, + columnDefs: this.makeColumnDefs(), + animateRows: true, + rowSelection: 'single', + headerHeight: 34, + enableSorting: true, + enableColResize: true, + getRowClass: (params: any) => { + return params.data.exception === 1 ? 'ag-row-exception' : ''; + }, + onCellClicked: (params: any) => { + if ( params.colDef.field === 'path' ) { + const tag = params.event.target.tagName.toUpperCase(); + if (tag === 'I' || tag === 'BUTTON' ) { + this.outSelectTransactionView.next({ + agentId: params.data.agentId, + traceId: params.data.traceId, + collectorAcceptTime: params.data.collectorAcceptTime, + spanId: params.data.spanId + }); + return; + } + } + if ( this.currentTraceId === params.data.traceId ) { + return; + } + this.currentTraceId = params.data.traceId; + this.outSelectTransaction.next({ + traceId: params.data.traceId, + collectorAcceptTime: params.data.collectorAcceptTime, + elapsed: params.data.responseTime + }); + } + }; + } + onGridReady(params: GridOptions): void { + this.gridOptions.api.forEachNode((node) => { + if (this.currentTraceId === node.data.traceId) { + node.setSelected(true); + } + }); + } + onGridSizeChanged(params: GridOptions): void { + this.gridOptions.api.sizeColumnsToFit(); + } + private makeColumnDefs(): any { + return [ + { + headerName: '#', + field: 'id', + width: 40, + cellStyle: () => { + return {'text-align': 'center'}; + }, + suppressSizeToFit: true + }, + { + headerName: 'StartTime', + field: 'startTime', + width: 170, + valueFormatter: (params: any) => { + return params.value === 0 ? '' : moment(params.value).tz(this.timezone).format(this.dateFormat); + }, + suppressSizeToFit: true + }, + { + headerName: 'Path', + field: 'path', + width: 370, + cellRenderer: (params: any) => { + return '  ' + params.value; + }, + tooltipField: 'path' + }, + { + headerName: 'Res(ms)', + field: 'responseTime', + width: 75, + cellStyle: this.alignRightCellStyle, + sort: 'desc', + valueFormatter: (params: any) => { + return params.value === '' ? '' : new Intl.NumberFormat().format(params.value); + }, + suppressSizeToFit: true + }, + { + headerName: 'Exception', + field: 'exception', + width: 85, + cellStyle: () => { + return {'text-align': 'center'}; + }, + cellRenderer: (params: any) => { + if ( params.value === 1 ) { + return ''; + } else { + return ''; + } + }, + suppressSizeToFit: true + }, + { + headerName: 'Agent', + field: 'agentId', + width: 170, + tooltipField: 'agentId' + }, + { + headerName: 'Client IP', + field: 'clientIp', + width: 120 + }, + { + headerName: 'Transaction', + field: 'traceId', + width: 270, + suppressSizeToFit: true, + tooltipField: 'traceId' + } + ]; + } + argumentCellStyle(): any { + return {'text-align': 'left'}; + } + alignRightCellStyle(): any { + return {'text-align': 'right'}; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/index.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/index.ts new file mode 100644 index 000000000000..7e06eab6d423 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/index.ts @@ -0,0 +1,22 @@ + +import { NgModule } from '@angular/core'; +import { ScrollingModule } from '@angular/cdk/scrolling'; +import { SharedModule } from 'app/shared'; +import { TransactionTimelineComponent } from './transaction-timeline.component'; +import { TransactionTimelineContainerComponent } from './transaction-timeline-container.component'; + +@NgModule({ + declarations: [ + TransactionTimelineComponent, + TransactionTimelineContainerComponent + ], + imports: [ + SharedModule, + ScrollingModule + ], + exports: [ + TransactionTimelineContainerComponent + ], + providers: [] +}) +export class TransactionTimelineModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline-container.component.css new file mode 100644 index 000000000000..a8962602d61a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline-container.component.css @@ -0,0 +1,6 @@ +:host { + position: relative; + width: 100%; + height: 100%; + background-color: #FFF; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline-container.component.html new file mode 100644 index 000000000000..d12702a43363 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline-container.component.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline-container.component.ts new file mode 100644 index 000000000000..118097111b9c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline-container.component.ts @@ -0,0 +1,125 @@ +import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { + StoreHelperService, + NewUrlStateNotificationService, + UrlRouteManagerService, + TransactionViewTypeService, VIEW_TYPE, + AnalyticsService, TRACKED_EVENT_LIST +} from 'app/shared/services'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { TransactionSearchInteractionService, ISearchParam } from 'app/core/components/transaction-search/transaction-search-interaction.service'; +import { TransactionTimelineComponent } from './transaction-timeline.component'; + +@Component({ + selector: 'pp-transaction-timeline-container', + templateUrl: './transaction-timeline-container.component.html', + styleUrls: ['./transaction-timeline-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) + +export class TransactionTimelineContainerComponent implements OnInit, OnDestroy { + @ViewChild(TransactionTimelineComponent) private transactionTimelineComponent: TransactionTimelineComponent; + private unsubscribe: Subject = new Subject(); + hiddenComponent = true; + keyIndex: any; + startTime: number; + endTime: number; + filteredData: any; + barRatio: number; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private transactionViewTypeService: TransactionViewTypeService, + private transactionSearchInteractionService: TransactionSearchInteractionService, + private analyticsService: AnalyticsService + ) {} + ngOnInit() { + this.connectStore(); + this.transactionViewTypeService.onChangeViewType$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((viewType: string) => { + if ( viewType === VIEW_TYPE.TIMELINE ) { + this.hiddenComponent = false; + } else { + this.hiddenComponent = true; + } + this.changeDetectorRef.detectChanges(); + }); + this.transactionSearchInteractionService.onSearch$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((params: ISearchParam) => { + if (this.hiddenComponent === true) { + return; + } + this.transactionSearchInteractionService.setSearchResult({ + type: params.type, + query: params.query, + result: this.transactionTimelineComponent.searchRow(params) + }); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private connectStore(): void { + this.storeHelperService.getTransactionDetailData(this.unsubscribe).pipe( + filter((transactionDetailInfo: any) => { + return transactionDetailInfo && transactionDetailInfo.transactionId ? true : false; + }) + ).subscribe((transactionDetailInfo: ITransactionDetailData) => { + this.startTime = transactionDetailInfo.callStackStart; + this.endTime = transactionDetailInfo.callStackEnd; + this.keyIndex = transactionDetailInfo.callStackIndex; + this.barRatio = this.getBarRatio(transactionDetailInfo); + this.filteredData = this.filterCallStack(transactionDetailInfo); + this.changeDetectorRef.detectChanges(); + + }); + } + private getBarRatio(tInfo: ITransactionDetailData): number { + return 1000 / (tInfo.callStack[0][tInfo.callStackIndex.end] - tInfo.callStack[0][tInfo.callStackIndex.begin]); + } + private filterCallStack(rowData: ITransactionDetailData): any { + const newCallStacks: any = []; + rowData.callStack.forEach((call: any) => { + if (call[this.keyIndex.isMethod] && !call[this.keyIndex.excludeFromTimeline] && call[this.keyIndex.service] !== '') { + newCallStacks.push(call); + } + }); + return newCallStacks; + } + onSelectTransaction(id: string): void { + if (this.newUrlStateNotificationService.getStartPath() === UrlPath.TRANSACTION_DETAIL) { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_TRANSACTION_IN_TIMELINE); + this.urlRouteManagerService.moveOnPage({ + url: [ + UrlPath.TRANSACTION_DETAIL, + this.newUrlStateNotificationService.getPathValue(UrlPathId.TRACE_ID), + this.newUrlStateNotificationService.getPathValue(UrlPathId.FOCUS_TIMESTAMP), + this.newUrlStateNotificationService.getPathValue(UrlPathId.AGENT_ID), + this.newUrlStateNotificationService.getPathValue(UrlPathId.SPAN_ID), + VIEW_TYPE.CALL_TREE, + id + ] + }); + } else { + this.urlRouteManagerService.moveOnPage({ + url: [ + UrlPath.TRANSACTION_LIST, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME), + this.newUrlStateNotificationService.getPathValue(UrlPathId.TRANSACTION_INFO), + VIEW_TYPE.CALL_TREE, + id + ] + }); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline.component.css new file mode 100644 index 000000000000..c160df1dc113 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline.component.css @@ -0,0 +1,50 @@ +.l-wrapper { + height: 100%; + overflow-y: auto; + background-color: #FFF; +} +.l-timeline-bar { + width: 100%; + height: 20px; + font-size: 11px; + font-family: Verdana; + border-style: dashed !important; + border-bottom: 1px solid #D3D3D3; + text-shadow: 1px 1px 0 #eee, 1px -1px 0 #eee, -1px 1px 0 #eee, -1px -1px 0 #eee, 1px 0px 0 #eee, 0px 1px 0 #eee, -1px 0px 0 #eee, 0px -1px 0 #eee; +} +.l-timeline-bar > div { + color: #000; + cursor: pointer; + margin-top: 1px; + padding-top: 2px; + margin-bottom: 1px; + padding-bottom: 2px; +} +.l-timeline-bar-frame { + width: 100%; + overflow-x: visible; + padding-left: 4px; +} +.l-timeline-bar-frame:hover { + box-shadow: 1px 1px 1px -1px rgba(0, 0, 0, 0.75); + font-weight: bold; +} +.l-timeline-bar-frame > span { + top: 0px; + position: relative; + white-space: nowrap; +} +.l-timeline-bar-frame span.before { + left: -70px; + display: none; + position: absolute; + text-align: right; + white-space: nowrap; +} +.l-timeline-bar-frame span.after { + display: none; + white-space: nowrap; +} +.l-timeline-bar-selected { + background-color: orange !important; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline.component.html new file mode 100644 index 000000000000..b22ea9b69c89 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline.component.html @@ -0,0 +1,16 @@ +
    + +
    +
    +
    + + {{getStartTime(call)}}ms + [{{call[keyIndex.applicationName]}}] / {{call[keyIndex.apiType]}} ({{call[keyIndex.end] - call[keyIndex.begin]}}ms) + / {{call[keyIndex.apiType]}} ({{call[keyIndex.end] - call[keyIndex.begin]}}ms) + ( {{getStartTime(call)}}ms ) + +
    +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline.component.ts new file mode 100644 index 000000000000..d0b616b4300d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-timeline/transaction-timeline.component.ts @@ -0,0 +1,102 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'pp-transaction-timeline', + templateUrl: './transaction-timeline.component.html', + styleUrls: ['./transaction-timeline.component.css'] +}) + +export class TransactionTimelineComponent implements OnInit { + @Input() data: any[]; + @Input() keyIndex: { [key: string]: number}; + @Input() startTime: number; + @Input() endTime: number; + @Input() barRatio: number; + @Output() outSelectTransaction: EventEmitter = new EventEmitter(); + + selectedRow: number[] = []; + colorSet: { [key: string]: string } = {}; + constructor() {} + ngOnInit() {} + private calcColor(str: string): string { + if (!(str in this.colorSet)) { + const color = []; + let hash = 0; + for ( let i = 0 ; i < str.length ; i++ ) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + for ( let i = 0 ; i < 3 ; i++ ) { + color.push(('00' + ((hash >> i * 8) & 0xFF).toString(16)).slice(-2)); + } + this.colorSet[str] = color.map((v: string) => { + return parseInt(v, 16); + }).join(','); + } + return this.colorSet[str]; + } + private getWidth(call: any): number { + return ((call[this.keyIndex.end] - call[this.keyIndex.begin]) * this.barRatio) + 0.9; + } + getLineStyle(call: any): object { + return { + 'background-color': 'rgba(' + this.calcColor(call[this.keyIndex.applicationName]) + ', 0.1)', + }; + } + getStyles(call: any): object { + return { + 'width': this.getWidth(call) + 'px', + 'background-color': 'rgb(' + this.calcColor(call[this.keyIndex.applicationName]) + ')', + 'margin-left': this.getMarginLeft(call) + 'px' + }; + } + getTop(index: number): number { + return index * 21; + } + isSelectedRow(index: number): boolean { + return this.selectedRow.indexOf(index) !== -1; + } + getStartTime(call: any): number { + return call[this.keyIndex.begin] - this.startTime; + } + + getMarginLeft(call: any): number { + return ((call[this.keyIndex.begin] - this.startTime) * this.barRatio) + 0.9; + } + onSelectCall(index: number, call: any): void { + this.outSelectTransaction.emit(call[this.keyIndex.id]); + } + searchRow({type, query}: {type: string, query: string | number}): number { + let resultCount = 0; + this.selectedRow = []; + const fnCompare = { + 'self': (data: any, value: string): boolean => { + return data[this.keyIndex.executionMilliseconds] >= value; + }, + 'argument': (data: any, value: number): boolean => { + return data[this.keyIndex.arguments].indexOf(value) !== -1; + } + }; + this.data.forEach((call: any, index: number) => { + if (fnCompare[type](call, query)) { + resultCount++; + this.selectedRow.push(index); + } + }); + if (resultCount > 0) { + // move row + } + return resultCount; + } + showApplicationName(call: any, index: number): boolean { + if (index === 0 || index >= this.data.length) { + return true; + } else { + if (this.data[index - 1][this.keyIndex.applicationName] === call[this.keyIndex.applicationName]) { + return false; + } else { + return true; + } + } + } + onScrollDown() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/index.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/index.ts new file mode 100644 index 000000000000..58df3c301061 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/index.ts @@ -0,0 +1,32 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { TransactionShortInfoModule } from 'app/core/components/transaction-short-info'; +import { TransactionDetailMenuModule } from 'app/core/components/transaction-detail-menu'; +import { TransactionSearchModule } from 'app/core/components/transaction-search'; +import { CallTreeModule } from 'app/core/components/call-tree'; +import { ServerMapModule } from 'app/core/components/server-map'; +import { TransactionTimelineModule } from 'app/core/components/transaction-timeline'; +import { SyntaxHighlightPopupModule } from 'app/core/components/syntax-highlight-popup'; +import { TransactionViewBottomContentsContainerComponent } from './transaction-view-bottom-contents-container.component'; + +@NgModule({ + declarations: [ + TransactionViewBottomContentsContainerComponent + ], + imports: [ + SharedModule, + TransactionShortInfoModule, + TransactionDetailMenuModule, + TransactionSearchModule, + ServerMapModule, + TransactionTimelineModule, + CallTreeModule, + SyntaxHighlightPopupModule + ], + exports: [ + TransactionViewBottomContentsContainerComponent + ], + providers: [] +}) +export class TransactionViewBottomContentsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/transaction-view-bottom-contents-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/transaction-view-bottom-contents-container.component.css new file mode 100644 index 000000000000..57778b22a899 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/transaction-view-bottom-contents-container.component.css @@ -0,0 +1,5 @@ +.l-wrapper { + width: 100%; + height: calc(100% - 30px); + position: relative; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/transaction-view-bottom-contents-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/transaction-view-bottom-contents-container.component.html new file mode 100644 index 000000000000..716743ea91ec --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/transaction-view-bottom-contents-container.component.html @@ -0,0 +1,5 @@ +
    + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/transaction-view-bottom-contents-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/transaction-view-bottom-contents-container.component.ts new file mode 100644 index 000000000000..1bb50aa04e27 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-view-bottom-contents/transaction-view-bottom-contents-container.component.ts @@ -0,0 +1,11 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'pp-transaction-view-bottom-contents-container', + templateUrl: './transaction-view-bottom-contents-container.component.html', + styleUrls: ['./transaction-view-bottom-contents-container.component.css'] +}) +export class TransactionViewBottomContentsContainerComponent implements OnInit { + constructor() {} + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/index.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/index.ts new file mode 100644 index 000000000000..4118d5a531b8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/index.ts @@ -0,0 +1,22 @@ + +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { InspectorChartModule } from 'app/core/components/inspector-chart'; +import { ServerMapModule } from 'app/core/components/server-map'; +import { TransactionViewTopContentsContainerComponent } from './transaction-view-top-contents-container.component'; + +@NgModule({ + declarations: [ + TransactionViewTopContentsContainerComponent + ], + imports: [ + SharedModule, + InspectorChartModule, + ServerMapModule + ], + exports: [ + TransactionViewTopContentsContainerComponent + ], + providers: [] +}) +export class TransactionViewTopContentsModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component.css b/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component.css new file mode 100644 index 000000000000..a43561ac9715 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component.css @@ -0,0 +1,55 @@ +:host { + display: block; + width: 100%; + height: 100%; +} +.l-transaction-view-top { + height: 100%; + display: flex; +} +.l-left-section, .l-right-section { + width: 50%; + height: 100%; + padding: 5px 25px +} +.l-left-section { + background-color: #fff; +} +.l-tab-menu-list { + border-bottom: 1px solid #e6e8ec; +} +.l-tab-menu-list:after { + content: ""; + display: block; + width: 100%; + height: 0; + visibility: hidden; + clear: both; +} +.l-tab-menu-list-item { + float: left; +} +.l-tab-menu-list-item a { + cursor: pointer; + display:inline-block; + font-size: 13px; + color: #666; + padding: 14px 15px; + border: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + line-height: 1em; +} +.l-tab-menu-list-item:hover a { + border-color: #e6e8ec #e6e8ec #fff; +} +.active a { + color: #fff; + background: #4a8fd2; +} +.active a:hover { + border-color: transparent; +} +.l-right-section { + position: relative; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component.html b/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component.html new file mode 100644 index 000000000000..3473a8ce1d5c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component.html @@ -0,0 +1,11 @@ +
    + +
    + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component.ts new file mode 100644 index 000000000000..d50192d0957c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component.ts @@ -0,0 +1,79 @@ +import { Component, OnInit, OnDestroy, ComponentFactoryResolver, ViewChild, ViewContainerRef, ComponentRef, ChangeDetectionStrategy } from '@angular/core'; + +import { TransactionViewJVMHeapChartContainerComponent } from 'app/core/components/inspector-chart/transaction-view-jvm-heap-chart-container.component'; +import { TransactionViewJVMNonHeapChartContainerComponent } from 'app/core/components/inspector-chart/transaction-view-jvm-non-heap-chart-container.component'; +import { TransactionViewCPUChartContainerComponent } from 'app/core/components/inspector-chart/transaction-view-cpu-chart-container.component'; +import { AnalyticsService, TRACKED_EVENT_LIST } from 'app/shared/services'; + +@Component({ + selector: 'pp-transaction-view-top-contents-container', + templateUrl: './transaction-view-top-contents-container.component.html', + styleUrls: ['./transaction-view-top-contents-container.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TransactionViewTopContentsContainerComponent implements OnInit, OnDestroy { + @ViewChild('chartContainer', { read: ViewContainerRef }) chartContainer: ViewContainerRef; + + tabList: any[]; + private componentMap = new Map(); + private chartComponentList = [TransactionViewJVMHeapChartContainerComponent, TransactionViewJVMNonHeapChartContainerComponent, TransactionViewCPUChartContainerComponent]; + private aliveComponentRef: ComponentRef; + + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + private analyticsService: AnalyticsService + ) {} + + ngOnInit() { + this.initTabList(); + this.initComponentMap(); + this.loadComponent(this.tabList.find((tab) => tab.isActive).id); + } + + ngOnDestroy() { + this.aliveComponentRef.destroy(); + } + + onTabClick(tabName: string): void { + this.setActiveTab(tabName); + this.clearContainer(); + this.loadComponent(tabName); + } + + private clearContainer(): void { + this.chartContainer.clear(); + } + + private initTabList(): void { + this.tabList = [{ + id: 'heap', + displayText: 'Heap', + isActive: true + }, + { + id: 'nonHeap', + displayText: 'Non Heap', + isActive: false + }, + { + id: 'cpu', + displayText: 'CPU Load', + isActive: false + }]; + } + + private initComponentMap(): void { + this.tabList.forEach((value, i) => this.componentMap.set(value.id, this.chartComponentList[i])); + } + + private loadComponent(key: string): void { + this.analyticsService.trackEvent((TRACKED_EVENT_LIST as any)[`CLICK_${key}`]); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.componentMap.get(key)); + + this.aliveComponentRef = this.chartContainer.createComponent(componentFactory); + } + + private setActiveTab(tabName: string): void { + this.tabList.forEach((tab) => tab.isActive = tabName === tab.id); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/index.ts b/web/src/main/webapp/v2/src/app/core/components/user-group/index.ts new file mode 100644 index 000000000000..8f6f9408d990 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/index.ts @@ -0,0 +1,34 @@ + +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { SharedModule } from 'app/shared'; +import { UserGroupComponent } from './user-group.component'; +import { UserGroupCreateAndUpdateComponent } from './user-group-create-and-update.component'; +import { UserGroupContainerComponent } from './user-group-container.component'; +import { UserGroupInteractionService } from './user-group-interaction.service'; +import { UserGroupDataService } from './user-group-data.service'; + +@NgModule({ + declarations: [ + UserGroupComponent, + UserGroupCreateAndUpdateComponent, + UserGroupContainerComponent + ], + imports: [ + FormsModule, + ReactiveFormsModule, + SharedModule + ], + exports: [ + UserGroupContainerComponent + ], + entryComponents: [ + UserGroupComponent, + UserGroupContainerComponent + ], + providers: [ + UserGroupInteractionService, + UserGroupDataService + ] +}) +export class UserGroupModule { } diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-container.component.css b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-container.component.css new file mode 100644 index 000000000000..46f321379891 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-container.component.css @@ -0,0 +1,60 @@ +:host { + position: relative; +} +.l-user-group-wrapper { + color: #333; + border: 1px solid #e5e8f0; + height: 100%; + display: grid; + position: relative; + font-size: 13px; + font-family: 'Open Sans', sans-serif; + font-weight: 600; + grid-template-columns: auto; + grid-template-rows: 48px 53px 416px; + +} +.l-user-group-title { + display: flex; + padding: 0px 15px; + align-items: center; + justify-content: space-between; + background-color: #f6f8fb; + border-bottom: 1px solid #e5e8f0; +} +.l-user-group-title button:last-child { + margin-left: 2px; +} +.l-user-group-search { + padding: 10px 15px; + border-bottom: 1px solid #e5e8f0; +} +.l-user-group-list { + overflow-y: auto; +} +.l-message { + width: 100%; + height: 100%; + z-index: 15; + display: flex; + position: absolute; + align-items: center; + justify-content: center; + background-color: rgba(226, 226, 226, 0.8); +} +.l-message span { + color: #ff8c00; + text-align: center; +} +.l-message button { + top: 0px; + right: 0px; + position: absolute; +} +.l-search-input { + width: 100%; + color: #b3b3b4; + border: 1px solid #469ae4; + padding: 6px 11px; + font-size: 13px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-container.component.html b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-container.component.html new file mode 100644 index 000000000000..b299091743c0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-container.component.html @@ -0,0 +1,38 @@ +
    +
    + User Group ({{userGroupList.length}}) +
    + + +
    +
    + +
    + +
    +
    + + {{message}} +
    + + + +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-container.component.ts b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-container.component.ts new file mode 100644 index 000000000000..b540a5639485 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-container.component.ts @@ -0,0 +1,146 @@ +import { Component, OnInit } from '@angular/core'; +import { combineLatest } from 'rxjs'; +import { TranslateService } from '@ngx-translate/core'; +import { WebAppSettingDataService, TranslateReplaceService } from 'app/shared/services'; +import { UserGroupInteractionService } from './user-group-interaction.service'; +import { UserGroupDataService, IUserGroup, IUserGroupCreated, IUserGroupDeleted } from './user-group-data.service'; + +@Component({ + selector: 'pp-user-group-container', + templateUrl: './user-group-container.component.html', + styleUrls: ['./user-group-container.component.css'] +}) +export class UserGroupContainerComponent implements OnInit { + private searchQuery = ''; + private userId = ''; + i18nText: { [key: string]: string } = { + NAME_LABEL: '', + USER_GROUP_NAME_REQUIRED: '', + USER_GROUP_NAME_MIN_LENGTH: '', + USER_GROUP_SERACH_MIN_LENGTH: '' + }; + USER_GROUP_NAME_MIN_LENGTH = 3; + SEARCH_MIN_LENGTH = 2; + searchUseEnter = false; + userGroupList: IUserGroup[] = []; + useDisable = true; + showLoading = true; + showCreate = false; + message = ''; + selectedUserGroupId = ''; + constructor( + private webAppSettingDataService: WebAppSettingDataService, + private userGroupDataService: UserGroupDataService, + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + private userGroupInteractionService: UserGroupInteractionService + ) {} + ngOnInit() { + this.getI18NText(); + this.webAppSettingDataService.getUserId().subscribe((userId: string = '') => { + this.userId = userId; + this.getUserGroupList({ userId: this.userId}); + }); + } + private getI18NText(): void { + combineLatest( + this.translateService.get('COMMON.MIN_LENGTH'), + this.translateService.get('COMMON.REQUIRED'), + this.translateService.get('CONFIGURATION.COMMON.NAME') + ).subscribe((i18n: string[]) => { + this.i18nText.USER_GROUP_NAME_MIN_LENGTH = this.translateReplaceService.replace(i18n[0], this.USER_GROUP_NAME_MIN_LENGTH); + this.i18nText.USER_GROUP_SEARCH_MIN_LENGTH = this.translateReplaceService.replace(i18n[0], this.SEARCH_MIN_LENGTH); + this.i18nText.USER_GROUP_NAME_REQUIRED = this.translateReplaceService.replace(i18n[1], i18n[2]); + this.i18nText.NAME_LABEL = i18n[2]; + }); + } + private getUserGroupList(params: any): void { + this.userGroupDataService.retrieve(params).subscribe((userGroupData: IUserGroup[] | IServerErrorShortFormat) => { + if ((userGroupData as IServerErrorShortFormat).errorCode) { + this.message = (userGroupData as IServerErrorShortFormat).errorMessage; + } else { + this.userGroupList = userGroupData as IUserGroup[]; + } + this.hideProcessing(); + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + }); + } + private makeUserGroupQuery(): any { + return this.searchQuery === '' ? { + userId: this.userId + } : { + userGroupId: this.searchQuery + }; + } + onRemoveUserGroup(id: string): void { + this.showProcessing(); + this.userGroupDataService.remove(id, this.userId).subscribe((response: IUserGroupDeleted | IServerErrorShortFormat) => { + if ((response as IServerErrorShortFormat).errorCode) { + this.message = (response as IServerErrorShortFormat).errorMessage; + this.hideProcessing(); + } else { + if ((response as IUserGroupDeleted).result === 'SUCCESS') { + this.userGroupInteractionService.setSelectedUserGroup(''); + this.getUserGroupList(this.makeUserGroupQuery()); + } else { + this.hideProcessing(); + } + } + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + }); + } + onCreateUserGroup(newUserGroupName: string): void { + this.showProcessing(); + this.userGroupDataService.create(newUserGroupName, this.userId).subscribe((userGroupData: IUserGroupCreated | IServerErrorShortFormat) => { + if ((userGroupData as IServerErrorShortFormat).errorCode) { + this.message = (userGroupData as IServerErrorShortFormat).errorMessage; + } else { + this.userGroupList.push({ + id: newUserGroupName, + number: (userGroupData as IUserGroupCreated).number + }); + } + this.hideProcessing(); + }, (error: IServerErrorFormat) => { + this.hideProcessing(); + this.message = error.exception.message; + }); + } + onCloseCreateUserPopup(): void { + this.showCreate = false; + } + onShowCreateUserPopup(): void { + this.showCreate = true; + } + hasMessage(): boolean { + return this.message !== ''; + } + onSelectUserGroup(userGroupId: string): void { + this.selectedUserGroupId = userGroupId; + this.userGroupInteractionService.setSelectedUserGroup(userGroupId); + } + onCloseMessage(): void { + this.message = ''; + } + onReload(): void { + this.showProcessing(); + this.getUserGroupList(this.makeUserGroupQuery()); + } + onSearch(query: string): void { + this.showProcessing(); + this.searchQuery = query; + this.getUserGroupList(this.makeUserGroupQuery()); + } + private showProcessing(): void { + this.useDisable = true; + this.showLoading = true; + } + private hideProcessing(): void { + this.useDisable = false; + this.showLoading = false; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-create-and-update.component.css b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-create-and-update.component.css new file mode 100644 index 000000000000..7cfb2acc6531 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-create-and-update.component.css @@ -0,0 +1,50 @@ +.l-wrapper { + top: 0px; + left: 0px; + width: 100%; + height: 100%; + z-index: 15; + display: flex; + padding: 0px 20px; + position: absolute; + align-items: center; + flex-direction: column; + justify-content: center; + background-color: rgba(226, 226, 226, 0.9); +} +.l-wrapper h1 { + margin-bottom: 6px; +} +.l-wrapper form { + width: 100%; +} +.l-wrapper input { + width: 100%; + border: 1px solid #469ae4; + padding: 6px 11px; + font-size: 13px; + margin-bottom: 2px; + background-color: #FFF; +} +.l-wrapper .l-create { + width: 100%; + margin-top: 6px; +} +.l-wrapper .l-close { + top: 0px; + right: 0px; + position: absolute; +} +.l-wrapper .l-alert { + color: #FFF; + padding: 4px; + margin-bottom: 4px; + background-color: #000; +} +.ng-valid[required], .ng-valid.required { + border-left: 5px solid #42A948 !important; +} + +.ng-invalid:not(form) { + border-left: 5px solid #a94442 !important; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-create-and-update.component.html b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-create-and-update.component.html new file mode 100644 index 000000000000..ca4fb51ada9a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-create-and-update.component.html @@ -0,0 +1,15 @@ +
    + +

    {{title}}

    +
    +
    + + +
    +
    {{nameGuide}}
    +
    {{nameLengthGuide}}
    +
    +
    + +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-create-and-update.component.ts b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-create-and-update.component.ts new file mode 100644 index 000000000000..3d58be7d835c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-create-and-update.component.ts @@ -0,0 +1,41 @@ +import { Component, OnInit, AfterViewChecked, Input, Output, EventEmitter } from '@angular/core'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; + +@Component({ + selector: 'pp-user-group-create-and-update', + templateUrl: './user-group-create-and-update.component.html', + styleUrls: ['./user-group-create-and-update.component.css'] +}) +export class UserGroupCreateAndUpdateComponent implements OnInit, AfterViewChecked { + @Input() showCreate = false; + @Input() minLength: number; + @Input() nameLabel: string; + @Input() nameGuide: string; + @Input() nameLengthGuide: string; + @Output() outCreateUserGroup: EventEmitter = new EventEmitter(); + @Output() outClose: EventEmitter = new EventEmitter(); + newUserGroupModel = ''; + userGroupForm: FormGroup; + title = 'User Group'; + constructor() {} + ngOnInit() { + this.userGroupForm = new FormGroup({ + 'userGroupName': new FormControl(this.newUserGroupModel, [ + Validators.required, + Validators.minLength(3) + ]) + }); + } + ngAfterViewChecked() {} + onCreateOrUpdate(): void { + this.outCreateUserGroup.emit(this.userGroupForm.get('userGroupName').value); + this.onClose(); + } + onClose(): void { + this.outClose.emit(); + this.userGroupForm.reset(); + } + get userGroupName() { + return this.userGroupForm.get('userGroupName'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-data.service.ts b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-data.service.ts new file mode 100644 index 000000000000..9e3adbf6f202 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-data.service.ts @@ -0,0 +1,57 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { retry } from 'rxjs/operators'; + +export interface IUserGroup { + id: string; + number: string; +} +export interface IUserGroupCreated { + number: string; +} +export interface IUserGroupDeleted { + result: string; +} + +@Injectable() +export class UserGroupDataService { + private url = 'userGroup.pinpoint'; + constructor(private http: HttpClient) { } + retrieve(param?: any): Observable { + return this.http.get(this.url, this.makeRequestOptionsArgs(param)).pipe( + retry(3) + ); + } + create(id: string, userId: string): Observable { + return this.http.post(this.url, this.makeCreateRemoveOptionsArgs(id, userId)).pipe( + retry(3) + ); + } + remove(id: string, userId: string): Observable { + return this.http.request('delete', this.url, { + body: this.makeCreateRemoveOptionsArgs(id, userId) + }).pipe( + retry(3) + ); + } + private makeRequestOptionsArgs(param?: any): object { + if (param) { + const httpParams = new HttpParams(); + Object.keys(param).forEach((key: string) => { + httpParams.set(key, param[key]); + }); + return { + params: httpParams + }; + } else { + return {}; + } + } + private makeCreateRemoveOptionsArgs(id: string, userId: string): object { + return { + id: id, + userId: userId + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-interaction.service.ts b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-interaction.service.ts new file mode 100644 index 000000000000..0b3269a50bb9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group-interaction.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; + +@Injectable() +export class UserGroupInteractionService { + private outSelect = new Subject(); + onSelect$: Observable; + + constructor() { + this.onSelect$ = this.outSelect.asObservable(); + } + setSelectedUserGroup(id: string): void { + this.outSelect.next(id); + } +} + diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group.component.css b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group.component.css new file mode 100644 index 000000000000..3d5b434688a4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group.component.css @@ -0,0 +1,31 @@ +li { + color: #333; + height: 28px; + margin: 0; + cursor: pointer; + padding: 6px 15px 0px 15px; + font-size: 13px; +} +li:hover { + background:#fff0f0; +} +li.selected { + background:#fff0f0; +} +.l-item-wrapper { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.l-item-wrapper > div { + float: right; +} +.l-item-wrapper .fa-trash-alt { + color: #b3b6bf; + font-size: 14px; +} +.l-item-wrapper .fa-check { + color: #F00; + margin-left: 10px; +} diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group.component.html b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group.component.html new file mode 100644 index 000000000000..712b23f8bb0a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group.component.html @@ -0,0 +1,12 @@ +
      +
    • +
      +
      + + + +
      + {{group.id}} +
      +
    • +
    diff --git a/web/src/main/webapp/v2/src/app/core/components/user-group/user-group.component.ts b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group.component.ts new file mode 100644 index 000000000000..930e8188ab19 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/components/user-group/user-group.component.ts @@ -0,0 +1,42 @@ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { IUserGroup } from './user-group-data.service'; + +@Component({ + selector: 'pp-user-group', + templateUrl: './user-group.component.html', + styleUrls: ['./user-group.component.css'] +}) +export class UserGroupComponent implements OnInit { + @Input() groupList: IUserGroup[]; + @Output() outRemove: EventEmitter = new EventEmitter(); + @Output() outSelected: EventEmitter = new EventEmitter(); + private removeConformId = ''; + private selectedUserGroup: string; + constructor() {} + ngOnInit() {} + onRemove(id: string): void { + this.removeConformId = id; + } + onSelect($event: MouseEvent, userGroup: IUserGroup): void { + if ($event.target['tagName'].toLowerCase() === 'button') { + return; + } + if (this.selectedUserGroup !== userGroup.id) { + this.selectedUserGroup = userGroup.id; + this.outSelected.emit(this.selectedUserGroup); + } + } + onCancelRemove(): void { + this.removeConformId = ''; + } + onConfirmRemove(): void { + this.outRemove.emit(this.removeConformId); + this.removeConformId = ''; + } + isRemoveTarget(id: string): boolean { + return this.removeConformId === id; + } + isSelected(id: string): boolean { + return this.selectedUserGroup === id; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/httpInterceptor/index.ts b/web/src/main/webapp/v2/src/app/core/httpInterceptor/index.ts new file mode 100644 index 000000000000..200ca4b3c85d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/httpInterceptor/index.ts @@ -0,0 +1,7 @@ +import { HTTP_INTERCEPTORS } from '@angular/common/http'; + +import { MarkingInterceptor } from './marking-interceptor'; + +export const httpInterceptorProviders = [ + { provide: HTTP_INTERCEPTORS, useClass: MarkingInterceptor, multi: true } +]; diff --git a/web/src/main/webapp/v2/src/app/core/httpInterceptor/marking-interceptor.ts b/web/src/main/webapp/v2/src/app/core/httpInterceptor/marking-interceptor.ts new file mode 100644 index 000000000000..31439d6b2551 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/httpInterceptor/marking-interceptor.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@angular/core'; +import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse, HttpErrorResponse } from '@angular/common/http'; + +import { Observable, throwError } from 'rxjs'; +import { map, catchError } from 'rxjs/operators'; + +const validUrlList: string[] = []; +const urlPrefix = '/'; + +@Injectable() +export class MarkingInterceptor implements HttpInterceptor { + intercept(req: HttpRequest, next: HttpHandler): Observable> { + let patchedReq = req; + if (/.*\.pinpoint(ws)?$/.test(req.url)) { + patchedReq = req.clone({ + url: urlPrefix + req.url + }); + } + return next.handle(patchedReq).pipe( + map((event => { + if (event instanceof HttpResponse) { + if (!(event.body instanceof Array)) { + if (this.isValidUrl(event.url)) { + event = event.clone({ + body: { ...event.body, 'pinpointPageBaseApi': true } + }); + } + } + } + return event; + })), + catchError((error: HttpErrorResponse) => { + if (error.status < 500) { + return throwError({ + exception: { + request: { + url: error.url + }, + message: error.message + } + }); + } else { + return throwError(error.error); + } + }) + ); + } + private isValidUrl(url: string): boolean { + const index = validUrlList.findIndex((validUrl: string) => { + return validUrl.indexOf(url) !== -1; + }); + return index >= 0 ? true : false; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/models/application.ts b/web/src/main/webapp/v2/src/app/core/models/application.ts new file mode 100644 index 000000000000..d261d9f43a32 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/models/application.ts @@ -0,0 +1,30 @@ +export class Application implements IApplication { + constructor( + public applicationName: string, + public serviceType: string, + public code: number, + public key?: string + ) {} + equals(target: IApplication): boolean { + if ( target ) { + return this.applicationName === target.applicationName && this.serviceType === target.serviceType; + } else { + return false; + } + } + getApplicationName(): string { + return this.applicationName; + } + getServiceType(): string { + return this.serviceType; + } + getCode(): number { + return this.code; + } + getUrlStr(): string { + return `${this.applicationName}@${this.serviceType}`; + } + getKeyStr(): string { + return this.key ? this.key : `${this.applicationName}^${this.serviceType}`; + } +} diff --git a/web/src/main/webapp/v2/src/app/core/models/end-time.ts b/web/src/main/webapp/v2/src/app/core/models/end-time.ts new file mode 100644 index 000000000000..03adc925e056 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/models/end-time.ts @@ -0,0 +1,34 @@ +import * as moment from 'moment'; + +const DATE_TIME_FORMAT = 'YYYY-MM-DD-HH-mm-ss'; +export class EndTime { + public static formatDate(time: number): string { + return moment(time).format(DATE_TIME_FORMAT); + } + public static newByNumber(time: number): EndTime { + return new EndTime(EndTime.formatDate(time)); + } + constructor(private endTimeStr: string) {} + getEndTime(): string { + return this.endTimeStr; + } + getDate(): Date { + return moment(this.endTimeStr, DATE_TIME_FORMAT).toDate(); + } + getMilliSecond(): number { + return this.getDate().valueOf(); + } + calcuStartTime(minute: number): EndTime { + return new EndTime(moment(this.endTimeStr, DATE_TIME_FORMAT).subtract(minute, 'minutes').format(DATE_TIME_FORMAT)); + } + calcuNextTime(minute: number): EndTime { + return new EndTime(moment(this.endTimeStr, DATE_TIME_FORMAT).add(minute, 'minutes').format(DATE_TIME_FORMAT)); + } + equals(target: EndTime) { + if ( target ) { + return this.endTimeStr === target.getEndTime(); + } else { + return false; + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/models/filter.ts b/web/src/main/webapp/v2/src/app/core/models/filter.ts new file mode 100644 index 000000000000..406c37788388 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/models/filter.ts @@ -0,0 +1,129 @@ +export class Filter { + // paramName = fa + fromApplication = ''; + // paramName = fst + fromServiceType = ''; + // paramName = ta + toApplication = ''; + // paramName = tst + toServiceType = ''; + // paramName = ie + transactionResult: null | boolean = null; + // paramName = rf + responseFrom?: number; + // paramName = rt + responseTo?: number; + // paramName = url + urlPattern?: string; + // paramName = fan + fromAgentName?: string; + // paramName = tan + toAgentName?: string; + static instanceFromString(str: string): Filter[] { + const returnFilter: Filter[] = []; + let aFilterFromStr: any; + try { + aFilterFromStr = JSON.parse(str); + } catch (exception) { + return returnFilter; + } + + for ( let i = 0 ; i < aFilterFromStr.length ; i++ ) { + const filterFromStr = aFilterFromStr[i]; + const newFilter = new Filter( + filterFromStr.fa, + filterFromStr.fst, + filterFromStr.ta, + filterFromStr.tst, + filterFromStr.ie, + ); + if (filterFromStr.rf || filterFromStr.rf === 0) { + newFilter.setResponseFrom(filterFromStr.rf); + } + if (filterFromStr.rt) { + newFilter.setResponseTo(filterFromStr.rt); + } + if (filterFromStr.url) { + newFilter.setUrlPattern(filterFromStr.url); + } + if (filterFromStr.fan) { + newFilter.setFromAgentName(filterFromStr.fan); + } + if (filterFromStr.tan) { + newFilter.setToAgentName(filterFromStr.tan); + } + returnFilter.push(newFilter); + } + return returnFilter; + } + constructor(fa: string, fst: string, ta: string, tst: string, ie: null | boolean = null) { + this.fromApplication = fa; + this.fromServiceType = fst; + this.toApplication = ta; + this.toServiceType = tst; + this.transactionResult = ie; + } + equal(filter: Filter): boolean { + return ( + this.fromApplication === filter.fromApplication && + this.fromServiceType === filter.fromServiceType && + this.toApplication === filter.toApplication && + this.toServiceType === filter.toServiceType + ); + } + setResponseFrom(rf: number): void { + this.responseFrom = rf; + } + setResponseTo(rt: number): void { + this.responseTo = rt; + } + setUrlPattern(url: string): void { + this.urlPattern = url; + } + setFromAgentName(fan: string): void { + this.fromAgentName = fan; + } + setToAgentName(tan: string): void { + this.toAgentName = tan; + } + getToKey(): string { + return `${this.toApplication}^${this.toServiceType}`; + } + getFromKey(): string { + return `${this.fromApplication}^${this.fromServiceType}`; + } + getTransactionResultStr(): string { + if (this.transactionResult === true) { + return 'Success Only'; + } else if (this.transactionResult === false) { + return 'Failed Only'; + } + return 'Success + Failed'; + } + toString(): string { + + const param: { [key: string]: any } = { + fa: this.fromApplication, + fst: this.fromServiceType, + ta: this.toApplication, + tst: this.toServiceType, + ie: this.transactionResult + }; + if (this.responseFrom || this.responseFrom === 0) { + param['rf'] = this.responseFrom; + } + if (this.responseTo) { + param['rt'] = this.responseTo; + } + if (this.urlPattern) { + param['url'] = this.urlPattern; + } + if (this.fromAgentName) { + param['fan'] = this.fromAgentName; + } + if (this.toAgentName) { + param['tan'] = this.toAgentName; + } + return JSON.stringify(param); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/models/index.ts b/web/src/main/webapp/v2/src/app/core/models/index.ts new file mode 100644 index 000000000000..7e1400e6faa2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/models/index.ts @@ -0,0 +1,4 @@ +export * from './application'; +export * from './end-time'; +export * from './filter'; +export * from './period'; diff --git a/web/src/main/webapp/v2/src/app/core/models/period.ts b/web/src/main/webapp/v2/src/app/core/models/period.ts new file mode 100644 index 000000000000..c5a922c7df86 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/models/period.ts @@ -0,0 +1,68 @@ +const ONE_HOUR = 60; +const ONE_DAY = 1440; +const MINUTE = 'm'; +const HOUR = 'h'; +const DAY = 'd'; + +export class Period { + private viewValue: string; + public static parseToMinute(time: string): number { + const timeChar = time.substr(-1).toLowerCase(); + const yourTime = parseInt(time, 10); + switch ( timeChar ) { + case MINUTE: + return yourTime; + case HOUR: + return yourTime * ONE_HOUR; + case DAY: + return yourTime * ONE_DAY; + default: + return yourTime; + } + } + constructor(private minute: number, private prefix?: string, private postfix?: string) { + this.calcuDisplay(); + } + private calcuDisplay() { + if (this.minute < ONE_HOUR ) { + this.viewValue = this.minute + MINUTE; + } else if (this.minute < ONE_DAY) { + if ( this.minute % ONE_HOUR === 0 ) { + this.viewValue = (this.minute / ONE_HOUR) + HOUR; + } else { + this.viewValue = this.minute + MINUTE; + } + } else { + if ( this.minute % ONE_DAY === 0 ) { + this.viewValue = (this.minute / ONE_DAY) + DAY; + } else { + this.viewValue = this.minute + MINUTE; + } + } + } + + getValueWithTime(): string { + return this.viewValue; + } + getValueWithAddedWords(): string { + const prefix = this.prefix ? this.prefix + ' ' : ''; + const postfix = this.postfix ? this.postfix + ' ' : ''; + return prefix + this.getValueWithTime() + postfix; + } + getValue(): number { + return this.minute; + } + getMiliSeconds(): number { + return this.minute * 60 * 1000; + } + equalValue(target: number): boolean { + return this.minute === target; + } + equals(target: Period): boolean { + if ( target ) { + return this.getValue() === target.getValue(); + } else { + return false; + } + } +} diff --git a/web/src/main/webapp/v2/src/app/core/utils/chart-data-param-maker.ts b/web/src/main/webapp/v2/src/app/core/utils/chart-data-param-maker.ts new file mode 100644 index 000000000000..f6eaa56fce4d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/utils/chart-data-param-maker.ts @@ -0,0 +1,21 @@ +export function getParamForAgentChartData(agentId: string, [from, to]: number[]): object { + return { + params: { + agentId, + from, + to, + sampleRate: 1 + } + }; +} + +export function getParamForApplicationChartData(applicationId: string, [from, to]: number[]): object { + return { + params: { + applicationId, + from, + to, + sampleRate: 1 + } + }; +} diff --git a/web/src/main/webapp/v2/src/app/core/utils/filter-param-maker.ts b/web/src/main/webapp/v2/src/app/core/utils/filter-param-maker.ts new file mode 100644 index 000000000000..c9407e492f5d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/utils/filter-param-maker.ts @@ -0,0 +1,23 @@ +import { Filter } from '../models/filter'; + +export class FilterParamMaker { + static makeParam(currentFilter: string, filter: Filter): string { + const aCurrentFilter: Filter[] = Filter.instanceFromString(currentFilter || '[]'); + if (aCurrentFilter.length === 0) { + aCurrentFilter.push(filter); + } else { + let searchIndex = -1; + for ( let i = 0 ; i < aCurrentFilter.length ; i++ ) { + if ( aCurrentFilter[i].equal(filter) ) { + searchIndex = i; + aCurrentFilter[i] = filter; // replace previous param object + break; + } + } + if (searchIndex === -1) { + aCurrentFilter.push(filter); + } + } + return '/' + encodeURIComponent('[' + aCurrentFilter.map(f => f.toString()).join(',') + ']'); + } +} diff --git a/web/src/main/webapp/v2/src/app/core/utils/hint-param-maker.ts b/web/src/main/webapp/v2/src/app/core/utils/hint-param-maker.ts new file mode 100644 index 000000000000..d6bbf2638c95 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/core/utils/hint-param-maker.ts @@ -0,0 +1,93 @@ +/* + from server + filterTargetRpcList : [{ + rpc: string, + rpcServiceTypeCode: number + }, ...] + > URL string size를 줄이기 위해 다음과 같이 변경 함. + url + { + [toNode.applicationName] : [ rpc, rpcServiceTypeCode, rpc, rpcServiceTypeCode ... ], + ... + } +*/ +interface IUrlFormat { + [key: string]: any[]; +} +interface IServerFormat { + [key: string]: { + rpc: string, + rpcServiceTypeCode: number + }[]; +} +export class HintParamMaker { + static makeParam(currentHint: string, addedHint: IServerFormat): string { + if (addedHint) { + const parsedCurrntHint = JSON.parse(currentHint || '{}'); + const currentHintKeys = Object.keys(parsedCurrntHint); + + if (currentHintKeys.length === 0) { + return '/' + encodeURIComponent(JSON.stringify(HintParamMaker.makeToUrlFormatFromServerFormat(addedHint))); + } else { + const urlFormatOfCurrentHint = HintParamMaker.makeToServerFormatFromUrlFormat(parsedCurrntHint); + const mergedFormat = HintParamMaker.mergeFormat(urlFormatOfCurrentHint, addedHint); + return '/' + encodeURIComponent(JSON.stringify(HintParamMaker.makeToUrlFormatFromServerFormat(mergedFormat))); + } + } else { + return '/' + currentHint; + } + } + static makeToUrlFormatFromServerFormat(addedHint: IServerFormat): IUrlFormat { + const addedHintKeys = Object.keys(addedHint); + const urlFormat: IUrlFormat = {}; + addedHintKeys.forEach((key: string) => { + urlFormat[key] = addedHint[key].reduce((acc: any, data: any) => { + acc.push(data.rpc, data.rpcServiceTypeCode); + return acc; + }, []); + }); + return urlFormat; + } + static makeToServerFormatFromUrlFormat(urlHint: IUrlFormat): IServerFormat { + const newFormat: IServerFormat = {}; + const urlHintKeys = Object.keys(urlHint); + urlHintKeys.forEach((key: string) => { + const urlHintValue = urlHint[key]; + const value = []; + for (let i = 0 ; i < urlHintValue.length ; i = i + 2) { + value.push({ + rpc: urlHintValue[i], + rpcServiceTypeCode: urlHintValue[i + 1] + }); + } + newFormat[key] = value; + }); + return newFormat; + } + static mergeFormat(urlFormat: IServerFormat, addedFormat: IServerFormat): IServerFormat { + const mergedFormat: IServerFormat = {}; + const urlFormatKeys = Object.keys(urlFormat); + const addedFormatKeys = Object.keys(addedFormat); + + urlFormatKeys.forEach((key: string) => { + mergedFormat[key] = urlFormat[key]; + }); + addedFormatKeys.forEach((key: string) => { + if (mergedFormat[key]) { + mergedFormat[key] = mergedFormat[key].concat(addedFormat[key]); + const m = mergedFormat[key]; + for (let i = 0 ; i < m.length ; i++) { + for (let j = i + 1 ; j < m.length ; j++ ) { + if (m[i].rpc === m[j].rpc && m[i].rpcServiceTypeCode === m[j].rpcServiceTypeCode) { + m.splice(j, 1); + j--; + } + } + } + } else { + mergedFormat[key] = addedFormat[key]; + } + }); + return mergedFormat; + } +} diff --git a/web/src/main/webapp/v2/src/app/index.ts b/web/src/main/webapp/v2/src/app/index.ts new file mode 100644 index 000000000000..875bdb2f254f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/index.ts @@ -0,0 +1,2 @@ +export * from './app.component'; +export * from './app.module'; diff --git a/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.component.css b/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.component.css new file mode 100644 index 000000000000..9b58cf19b304 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.component.css @@ -0,0 +1,28 @@ +header { + background-color:#000; +} +.l-widget-group { + flex: 1; + color: #FFF; + height: 100%; + padding: 0 15px; + display: flex; + flex-flow: row; + font-size: 14px; + font-family: monospace; + align-items: flex-end; + justify-content: start; +} +.l-widget-group a { + padding: 6px 20px; +} +.active { + background-color: #408dd4; + box-shadow: 1px -1px 0px 1px rgba(255, 255, 255, 1); +} +.l-main-container { + display: flex; + flex-flow: column nowrap; + overflow-y: hidden; + height: calc(100vh - 50px); +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.component.html b/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.component.html new file mode 100644 index 000000000000..b558afff6704 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.component.html @@ -0,0 +1,11 @@ +
    + + +
    +
    + +
    + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.component.ts b/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.component.ts new file mode 100644 index 000000000000..3444d704619f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.component.ts @@ -0,0 +1,14 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; + +import { RouteInfoCollectorService } from 'app/shared/services'; + +@Component({ + selector: 'pp-admin-page', + templateUrl: './admin-page.component.html', + styleUrls: ['./admin-page.component.css'] +}) +export class AdminPageComponent implements OnInit, OnDestroy { + constructor(private routeInfoCollectorService: RouteInfoCollectorService) {} + ngOnInit() {} + ngOnDestroy() {} +} diff --git a/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.routing.ts new file mode 100644 index 000000000000..746c05a8b52b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/admin-page/admin-page.routing.ts @@ -0,0 +1,29 @@ + +import { Routes } from '@angular/router'; + +import { UrlPathId } from 'app/shared/models'; +import { SystemConfigurationResolverService, ServerTimeResolverService } from 'app/shared/services'; +import { AgentStatContentsContainerComponent } from 'app/core/components/agent-stat-contents/agent-stat-contents-container.component'; +import { AgentManagementContentsContainerComponent } from 'app/core/components/agent-management-contents/agent-management-contents-container.component'; +import { AdminPageComponent } from './admin-page.component'; + +export const routing: Routes = [ + { + path: '', + component: AdminPageComponent, + resolve: { + configuration: SystemConfigurationResolverService, + serverTime: ServerTimeResolverService + }, + children: [ + { + path: UrlPathId.AGENT, + component: AgentManagementContentsContainerComponent + }, + { + path: UrlPathId.STAT, + component: AgentStatContentsContainerComponent + } + ] + } +]; diff --git a/web/src/main/webapp/v2/src/app/routes/admin-page/index.ts b/web/src/main/webapp/v2/src/app/routes/admin-page/index.ts new file mode 100644 index 000000000000..b78989e691e4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/admin-page/index.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { SharedModule } from 'app/shared'; +import { AdminPageComponent } from './admin-page.component'; +import { routing } from './admin-page.routing'; + +import { AgentManagementContentsModule } from 'app/core/components/agent-management-contents'; +import { AgentStatContentsModule } from 'app/core/components/agent-stat-contents'; + +@NgModule({ + declarations: [ + AdminPageComponent + ], + imports: [ + RouterModule.forChild(routing), + SharedModule, + AgentStatContentsModule, + AgentManagementContentsModule + ], + exports: [], + providers: [] +}) +export class AdminPageModule { } diff --git a/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.component.css b/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.component.css new file mode 100644 index 000000000000..9f8680bc63ce --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.component.css @@ -0,0 +1,60 @@ +:host { + display: block; + height: 100%; + background-color: #edf2f8; +} + +.l-support-page-logo { + display: flex; + justify-content: center; + align-items: center; +} + +.l-info-text { + text-align: center; + margin-bottom: 40px; + font-size: 17px; + color: #757575; +} + +.l-support-page-contents { + position: relative; + top: 50px; +} + +.l-browser-list { + width: 420px; + margin: auto; +} + +.l-browser-list-item { + background-color: #fff; + border-radius: 5px; + border: 1px solid #e5e8f0; + margin-bottom: 3px; +} + +.l-browser-list-item:hover { + background-color: #e5e8f0; +} + +.l-browser-link { + display: inline-block; + width: 100%; + padding: 20px 30px; +} + +.l-browser-img { + display: inline-block; + vertical-align: middle; + width: 42px; + height: 42px; +} + +.l-browser-name { + display: inline-block; + vertical-align: middle; + margin-left: 13px; + font-size: 17p; + color: #757575; +} diff --git a/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.component.html b/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.component.html new file mode 100644 index 000000000000..3dfffb16e77c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.component.html @@ -0,0 +1,14 @@ +
    + +
    +
    +

    {{i18nText$ | async}}

    + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.component.ts b/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.component.ts new file mode 100644 index 000000000000..0f2f1240aafc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.component.ts @@ -0,0 +1,66 @@ +import { Component, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; +import * as bowser from 'bowser'; + +import { WebAppSettingDataService } from 'app/shared/services'; + +interface IBrowserInfo { + downloadLink: string; + name: string; + displayName: string; +} + +@Component({ + templateUrl: './browser-support-page.component.html', + styleUrls: ['./browser-support-page.component.css'] +}) +export class BrowserSupportPageComponent implements OnInit { + private browserInfoList: IBrowserInfo[]; + funcImagePath: Function; + i18nText$: Observable; + + constructor( + private webAppSettingDataService: WebAppSettingDataService, + private translateService: TranslateService + ) {} + + ngOnInit() { + this.funcImagePath = this.webAppSettingDataService.getImagePathMakeFunc(); + this.browserInfoList = [ + { + downloadLink: 'https://www.google.com/chrome', + name: 'chrome', + displayName: 'Google Chrome' + }, { + downloadLink: 'https://www.mozilla.org/en/firefox/new', + name: 'firefox', + displayName: 'Mozilla Firefox' + }, { + downloadLink: 'https://support.apple.com/en-us/HT204416', + name: 'safari', + displayName: 'Apple Safari' + }, { + downloadLink: 'https://www.microsoft.com/en-us/windows/microsoft-edge', + name: 'edge', + displayName: 'Microsoft Edge' + } + ]; + this.i18nText$ = this.translateService.get('SUPPORT.INSTALL_GUIDE'); + } + + getFilteredBrowserInfoList(): IBrowserInfo[] { + const userOSName = bowser.osname; + + return this.browserInfoList.filter((browserInfo: IBrowserInfo) => { + switch (userOSName) { + case 'Windows': + return browserInfo.name !== 'safari'; + case 'macOS': + return browserInfo.name !== 'edge'; + default: + return browserInfo.name === 'chrome' || browserInfo.name === 'firefox'; + } + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.routing.ts new file mode 100644 index 000000000000..ced6cebf3501 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/browser-support-page/browser-support-page.routing.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { BrowserSupportPageComponent } from './browser-support-page.component'; + +const routes: Routes = [ + { + path: '', + component: BrowserSupportPageComponent + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes) + ], + exports: [ + RouterModule + ] +}) +export class BrowserSupportPageRoutingModule {} diff --git a/web/src/main/webapp/v2/src/app/routes/browser-support-page/index.ts b/web/src/main/webapp/v2/src/app/routes/browser-support-page/index.ts new file mode 100644 index 000000000000..61979ce8a07e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/browser-support-page/index.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { BrowserSupportPageRoutingModule } from './browser-support-page.routing'; +import { BrowserSupportPageComponent } from './browser-support-page.component'; + +@NgModule({ + declarations: [ + BrowserSupportPageComponent + ], + imports: [ + SharedModule, + BrowserSupportPageRoutingModule + ], + exports: [], + providers: [] +}) +export class BrowserSupportPageModule {} diff --git a/web/src/main/webapp/v2/src/app/routes/error-page/error-page.component.css b/web/src/main/webapp/v2/src/app/routes/error-page/error-page.component.css new file mode 100644 index 000000000000..1c26d6e778cc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/error-page/error-page.component.css @@ -0,0 +1,50 @@ +.l-title { + display: flex; + flex: 1; + color: #FFF; + font-size: 20px; + align-items: center; + padding-left: 20px; +} +.l-api-check { + width: 100%; + height: calc(100% - 50px); + padding-top: 5%; + display: flex; + position: absolute; + align-items: center; + flex-direction: column; + align-items: center; +} +.l-api-check .l-apis { + width: 700px; + display: flex; + font-size: 30px; + flex-direction: column; +} +.l-api-check .l-api { + display: flex; + padding: 0px 20px; + align-items: center; + flex-direction: row; +} +.l-api-check .l-api i { + margin: 10px 10px 0px 0px; +} +.l-api-check button { + width: 100px; + height: 100px; + margin: 20px 0px; + font-size: 40px; + border-radius: 50px; +} +.l-success { + color: #03a203; +} +.l-fail { + color: #c10404; +} +.l-error { + padding: 20px; + font-size: 14px; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/routes/error-page/error-page.component.html b/web/src/main/webapp/v2/src/app/routes/error-page/error-page.component.html new file mode 100644 index 000000000000..28b89a1c9760 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/error-page/error-page.component.html @@ -0,0 +1,17 @@ +
    + +
    API Check
    +
    +
    +
    + + + +
    +
    + {{getUrl(stateName)}} +
    +
    {{getErrorMessage(stateName)}}
    +
    +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/routes/error-page/error-page.component.ts b/web/src/main/webapp/v2/src/app/routes/error-page/error-page.component.ts new file mode 100644 index 000000000000..aab6c4a1d7bf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/error-page/error-page.component.ts @@ -0,0 +1,101 @@ +import { Component, OnInit } from '@angular/core'; + +import { SystemConfigurationDataService, ServerTimeDataService, UrlRouteManagerService } from 'app/shared/services'; +import { ApplicationListDataService } from 'app/core/components/application-list/application-list-data.service'; +@Component({ + templateUrl: './error-page.component.html', + styleUrls: ['./error-page.component.css'] +}) +export class ErrorPageComponent implements OnInit { + stateList = ['serverTime', 'configuration', 'applicationList']; + state: any = { + serverTime: { + url: 'serverTime.pinpoint', + loading: true, + success: false, + message: '' + }, + configuration: { + url: 'configuration.pinpoint', + loading: true, + success: false, + message: '' + }, + applicationList: { + url: 'applicationList.pinpoint', + loading: true, + success: false, + message: '' + } + }; + constructor( + private urlRouteManagerService: UrlRouteManagerService, + private systemConfigurationDataService: SystemConfigurationDataService, + private applicationListDataService: ApplicationListDataService, + private serverTimeDataService: ServerTimeDataService + ) {} + + ngOnInit() { + this.checkServerTime(this.stateList[0]); + this.checkSystemConfiguration(this.stateList[1]); + this.checkApplicationList(this.stateList[2]); + } + private setState(type: string, result: boolean, loading: boolean, message: string = ''): void { + this.state[type].success = result; + this.state[type].loading = loading; + this.state[type].message = message; + } + private checkServerTime(type: string): void { + this.serverTimeDataService.getServerTime().subscribe((time: number) => { + this.setState(type, true, false); + }, (error: IServerErrorFormat) => { + this.setState(type, false, false, error.exception.message); + }); + } + private checkSystemConfiguration(type: string): void { + this.systemConfigurationDataService.getConfiguration().subscribe((configuration: ISystemConfiguration) => { + this.setState(type, true, false); + }, (error: IServerErrorFormat) => { + this.setState(type, false, false, error.exception.message); + }); + } + private checkApplicationList(type: string): void { + this.applicationListDataService.getApplicationList().subscribe((applicationList: IApplication[]) => { + this.setState(type, true, false); + }, (error: IServerErrorFormat) => { + this.setState(type, false, false, error.exception.message); + }); + } + getErrorMessage(type: string): string { + return this.state[type].message; + } + showErrorMessage(type: string): boolean { + return !(this.state[type].loading === false && this.state[type].success); + } + getStateClass(type: string): string { + const spin = 'fas fa-spinner fa-spin'; + const success = 'far fa-check-square l-success'; + const fail = 'far fa-times-circle l-fail'; + const typeState = this.state[type]; + + if (typeState.loading) { + return spin; + } else { + return typeState.success ? success : fail; + } + } + getUrl(type: string): string { + return this.state[type].url; + } + onMoveBack(): void { + this.urlRouteManagerService.back(); + } + onReload(): void { + this.urlRouteManagerService.reload(); + } + hasError(): boolean { + return this.stateList.reduce((prevState: boolean, stateName: string) => { + return prevState && (this.state[stateName].loading === false && !this.state[stateName].success); + }, true); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/error-page/error-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/error-page/error-page.routing.ts new file mode 100644 index 000000000000..f12dd0532f48 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/error-page/error-page.routing.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { ErrorPageComponent } from './error-page.component'; + +const routes: Routes = [ + { + path: '', + component: ErrorPageComponent + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes) + ], + exports: [ + RouterModule + ] +}) +export class ErrorPageRoutingModule {} diff --git a/web/src/main/webapp/v2/src/app/routes/error-page/index.ts b/web/src/main/webapp/v2/src/app/routes/error-page/index.ts new file mode 100644 index 000000000000..288fcf134530 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/error-page/index.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { SharedModule } from 'app/shared'; +import { ErrorPageRoutingModule } from './error-page.routing'; +import { ErrorPageComponent } from './error-page.component'; +import { ApplicationListModule } from 'app/core/components/application-list'; + +@NgModule({ + declarations: [ + ErrorPageComponent + ], + imports: [ + SharedModule, + ErrorPageRoutingModule, + ApplicationListModule + ], + exports: [], + providers: [] +}) +export class ErrorPageModule {} diff --git a/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.component.css b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.component.css new file mode 100644 index 000000000000..affb06f4e3a9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.component.css @@ -0,0 +1,29 @@ +.l-widget-group { + display: flex; + flex-flow: row wrap; + flex: 1; + padding: 0 15px; + height: 100%; + align-items: center; +} +.l-main-container { + display: flex; + flex-flow: row wrap; + height: calc(100vh - 50px); + overflow-y: hidden; +} +.l-main-section { + display: flex; + flex-flow: column nowrap; + flex: 1; + background: #edf2f8; + position: relative; + height: 100%; +} +.l-main-contents { + height: 100%; + position: relative; +} +button { + outline: none; +} diff --git a/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.component.html b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.component.html new file mode 100644 index 000000000000..30788b2e2df6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.component.html @@ -0,0 +1,17 @@ + +
    + +
    + +
    + + +
    +
    +
    +
    + +
    +
    + +
    diff --git a/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.component.ts b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.component.ts new file mode 100644 index 000000000000..95234dfd4a03 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.component.ts @@ -0,0 +1,13 @@ +import { Component, OnInit } from '@angular/core'; + +import { RouteInfoCollectorService } from 'app/shared/services'; + +@Component({ + selector: 'pp-filtered-map-page', + templateUrl: './filtered-map-page.component.html', + styleUrls: ['./filtered-map-page.component.css'] +}) +export class FilteredMapPageComponent implements OnInit { + constructor(private routeInfoCollectorService: RouteInfoCollectorService) {} + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.routing.ts new file mode 100644 index 000000000000..a35cfbb37a16 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/filtered-map-page.routing.ts @@ -0,0 +1,137 @@ +import { Routes } from '@angular/router'; + +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { FilteredMapContentsContainerComponent } from 'app/core/components/filtered-map-contents/filtered-map-contents-container.component'; +// import { NoneComponent } from 'app/shared/components/empty-contents'; +import { SystemConfigurationResolverService, ApplicationListResolverService } from 'app/shared/services'; +// import { UrlValidateGuard } from 'app/shared/services'; +import { UrlRedirectorComponent } from 'app/shared/components/url-redirector/url-redirector.component'; +import { FilteredMapPageComponent } from './filtered-map-page.component'; + +export const routing: Routes = [ + { + path: '', + component: FilteredMapPageComponent, + resolve: { + configuration: SystemConfigurationResolverService, + applicationList: ApplicationListResolverService + }, + children: [ + { + path: '', + redirectTo: '/' + UrlPath.MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.APPLICATION, + data: { + path: UrlPath.MAIN + }, + component: UrlRedirectorComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD, + data: { + path: UrlPath.MAIN + }, + component: UrlRedirectorComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME, + children: [ + { + path: '', + component: FilteredMapContentsContainerComponent + }, + { + path: ':' + UrlPathId.FILTER, + children: [ + { + path: '', + component: FilteredMapContentsContainerComponent + }, + { + path: ':' + UrlPathId.HINT, + children: [ + { + path: '', + component: FilteredMapContentsContainerComponent + } + ] + } + ] + } + ] + } + ] + } +]; + +// export const routing: Routes = [ +// { +// path: UrlPath.FILTERED_MAP, +// component: FilteredMapPageComponent, +// canActivate: [ UrlValidateGuard ], +// resolve: { +// configuration: SystemConfigurationResolverService, +// applicationList: ApplicationListResolverService +// }, +// children: [ +// { +// path: '', +// component: NoneComponent +// }, +// { +// path: ':' + UrlPathId.APPLICATION, +// component: NoneComponent +// }, +// { +// path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD, +// component: NoneComponent +// }, +// { +// path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME, +// children: [ +// { +// path: '', +// component: FilteredMapContentsContainerComponent +// }, +// { +// path: '', +// component: SideBarForFilteredMapContainerComponent, +// outlet: 'sidebar' +// } +// ] +// }, +// { +// path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME + '/:' + UrlPathId.FILTER, +// children: [ +// { +// path: '', +// component: FilteredMapContentsContainerComponent +// }, +// { +// path: '', +// component: SideBarForFilteredMapContainerComponent, +// outlet: 'sidebar' +// } +// ] +// }, +// { +// path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME + '/:' + UrlPathId.FILTER + '/:' + UrlPathId.HINT, +// children: [ +// { +// path: '', +// component: FilteredMapContentsContainerComponent +// }, +// { +// path: '', +// component: SideBarForFilteredMapContainerComponent, +// outlet: 'sidebar' +// } +// ] +// } + +// ] +// } +// ]; diff --git a/web/src/main/webapp/v2/src/app/routes/filtered-map-page/index.ts b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/index.ts new file mode 100644 index 000000000000..39f83b93adb5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/filtered-map-page/index.ts @@ -0,0 +1,34 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { routing } from './filtered-map-page.routing'; +import { SharedModule } from 'app/shared'; +import { NoticeModule } from 'app/core/components/notice'; +import { DataLoadIndicatorModule } from 'app/core/components/data-load-indicator'; +import { StateButtonModule } from 'app/core/components/state-button'; +import { CommandGroupModule } from 'app/core/components/command-group'; +import { FilteredMapContentsModule } from 'app/core/components/filtered-map-contents'; +import { SideBarModule } from 'app/core/components/side-bar'; + +import { FilteredMapPageComponent } from './filtered-map-page.component'; + +@NgModule({ + declarations: [ + FilteredMapPageComponent + ], + imports: [ + SharedModule, + NoticeModule, + DataLoadIndicatorModule, + StateButtonModule, + CommandGroupModule, + FilteredMapContentsModule, + SideBarModule, + RouterModule.forChild(routing) + ], + exports: [ + RouterModule + ], + providers: [] +}) +export class FilteredMapPageModule { } diff --git a/web/src/main/webapp/v2/src/app/routes/inspector-page/index.ts b/web/src/main/webapp/v2/src/app/routes/inspector-page/index.ts new file mode 100644 index 000000000000..462570bb6a8a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/inspector-page/index.ts @@ -0,0 +1,43 @@ +import { NgModule } from '@angular/core'; +import { MatTooltipModule } from '@angular/material'; +import { RouterModule } from '@angular/router'; + +import { routing } from './inspector-page.routing'; +import { SharedModule } from 'app/shared'; +import { NoticeModule } from 'app/core/components/notice'; +import { ApplicationListModule } from 'app/core/components/application-list'; +import { PeriodSelectorModule } from 'app/core/components/period-selector'; +import { CommandGroupModule } from 'app/core/components/command-group'; +import { ApplicationInspectorTitleModule } from 'app/core/components/application-inspector-title'; +import { ServerAndAgentListModule } from 'app/core/components/server-and-agent-list'; +import { AgentSearchInputModule } from 'app/core/components/agent-search-input'; +import { ApplicationInspectorContentsModule } from 'app/core/components/application-inspector-contents'; +import { AgentInspectorContentsModule } from 'app/core/components/agent-inspector-contents'; +import { EmptyInspectorContentsModule } from 'app/core/components/empty-inspector-contents'; +import { InspectorPageComponent } from './inspector-page.component'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + InspectorPageComponent + ], + imports: [ + MatTooltipModule, + SharedModule, + NoticeModule, + ApplicationListModule, + PeriodSelectorModule, + CommandGroupModule, + ApplicationInspectorTitleModule, + ServerAndAgentListModule, + ApplicationInspectorContentsModule, + AgentInspectorContentsModule, + AgentSearchInputModule, + EmptyInspectorContentsModule, + HelpViewerPopupModule, + RouterModule.forChild(routing) + ], + exports: [], + providers: [] +}) +export class InspectorPageModule {} diff --git a/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.component.css b/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.component.css new file mode 100644 index 000000000000..c7b3647a1cf5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.component.css @@ -0,0 +1,42 @@ +.l-widget-group { + display: flex; + flex-flow: row wrap; + flex: 1; + padding: 0 15px; + height: 100%; + align-items: center; +} +.l-main-container { + display: flex; + flex-flow: row wrap; + height: calc(100vh - 50px); + overflow-y: hidden; +} +.l-sidemenu-wrap { + display: flex; + flex-flow: column nowrap; + position: relative; + height: 100%; +} +.l-sidemenu-left { + width: 260px; + overflow: visible; + border-right: 1px solid #E5E8F0; + background: #FFF; + height: 100%; +} +.l-main-section { + display: flex; + flex-flow: column nowrap; + flex: 1; + background: #edf2f8; + position: relative; + height: 100%; +} +.fa-question-circle { + color: white; + font-size: 18px; +} +button { + outline: none; +} diff --git a/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.component.html b/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.component.html new file mode 100644 index 000000000000..3ef10ff84e7b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.component.html @@ -0,0 +1,22 @@ + +
    + +
    + + +
    + + +
    +
    +
    +
    + + + +
    +
    +
    + +
    +
    diff --git a/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.component.ts b/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.component.ts new file mode 100644 index 000000000000..031e1ba83683 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.component.ts @@ -0,0 +1,63 @@ +import { Component, OnInit } from '@angular/core'; +import { state, style, animate, transition, trigger } from '@angular/animations'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { RouteInfoCollectorService, NewUrlStateNotificationService, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { EndTime } from 'app/core/models'; +import { UrlPathId } from 'app/shared/models'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-inspector-page', + animations: [ + trigger('fadeInOut', [ + state('in', style({transform: 'translateX(0)', opacity: 1})), + transition(':leave', [ // is alias to '* => void' + animate('1.5s 0.1s ease-in', style({ + transform: 'translateX(-100%)', + opacity: 0 + })) + ]), + transition(':enter', [ // is alias to 'void => *' + style({ + transform: 'translateX(-100%)', + opacity: 0 + }), + animate('2s ease-out') + ]) + ]) + ], + templateUrl: './inspector-page.component.html', + styleUrls: ['./inspector-page.component.css'] +}) +export class InspectorPageComponent implements OnInit { + endTime$: Observable; + + constructor( + private routeInfoCollectorService: RouteInfoCollectorService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.endTime$ = this.newUrlStateNotificationService.onUrlStateChange$.pipe( + map((urlService: NewUrlStateNotificationService) => { + return urlService.getPathValue(UrlPathId.END_TIME); + }) + ); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.NAVBAR); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.NAVBAR, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.routing.ts new file mode 100644 index 000000000000..2b02daaf2f80 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/inspector-page/inspector-page.routing.ts @@ -0,0 +1,55 @@ +import { Routes } from '@angular/router'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ApplicationInspectorContentsContainerComponent } from 'app/core/components/application-inspector-contents/application-inspector-contents-container.component'; +import { AgentInspectorContentsContainerComponent } from 'app/core/components/agent-inspector-contents/agent-inspector-contents-container.component'; +import { EmptyInspectorContentsContainerComponent } from 'app/core/components/empty-inspector-contents/empty-inspector-contents-container.component'; +import { UrlRedirectorComponent } from 'app/shared/components/url-redirector/url-redirector.component'; +import { SystemConfigurationResolverService, ApplicationListResolverService } from 'app/shared/services'; +import { InspectorPageComponent } from './inspector-page.component'; + +export const routing: Routes = [ + { + path: '', + component: InspectorPageComponent, + resolve: { + configuration: SystemConfigurationResolverService, + applicationList: ApplicationListResolverService + }, + children: [ + { + path: '', + component: EmptyInspectorContentsContainerComponent + }, + { + path: ':' + UrlPathId.APPLICATION, + data: { + path: UrlPath.INSPECTOR + }, + component: UrlRedirectorComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD, + data: { + path: UrlPath.INSPECTOR + }, + component: UrlRedirectorComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME, + component: ApplicationInspectorContentsContainerComponent, + data: { + showRealTimeButton: false, + enableRealTimeMode: false + } + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME + '/:' + UrlPathId.AGENT_ID, + component: AgentInspectorContentsContainerComponent, + data: { + showRealTimeButton: false, + enableRealTimeMode: false + } + } + ] + } +]; diff --git a/web/src/main/webapp/v2/src/app/routes/main-page/index.ts b/web/src/main/webapp/v2/src/app/routes/main-page/index.ts new file mode 100644 index 000000000000..5f588977268b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/main-page/index.ts @@ -0,0 +1,41 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { SharedModule } from 'app/shared'; +import { NoticeModule } from 'app/core/components/notice'; +import { ApplicationListModule } from 'app/core/components/application-list'; +import { ServerMapOptionsModule } from 'app/core/components/server-map-options'; +import { PeriodSelectorModule } from 'app/core/components/period-selector'; +import { CommandGroupModule } from 'app/core/components/command-group'; +import { MainContentsModule } from 'app/core/components/main-contents'; +import { RealTimeModule } from 'app/core/components/real-time'; +import { NewRealTimeModule } from 'app/core/components/real-time-new'; +import { SideBarModule } from 'app/core/components/side-bar'; +import { MainPageComponent } from './main-page.component'; +import { routing } from './main-page.routing'; +import { HelpViewerPopupModule } from 'app/core/components/help-viewer-popup'; + +@NgModule({ + declarations: [ + MainPageComponent + ], + imports: [ + SharedModule, + NoticeModule, + ApplicationListModule, + ServerMapOptionsModule, + PeriodSelectorModule, + CommandGroupModule, + MainContentsModule, + RealTimeModule, + NewRealTimeModule, + SideBarModule, + HelpViewerPopupModule, + RouterModule.forChild(routing) + ], + exports: [ + + ], + providers: [] +}) +export class MainPageModule { } diff --git a/web/src/main/webapp/v2/src/app/routes/main-page/main-page.component.css b/web/src/main/webapp/v2/src/app/routes/main-page/main-page.component.css new file mode 100644 index 000000000000..1b9767653bc6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/main-page/main-page.component.css @@ -0,0 +1,37 @@ +:host { + display: block; +} +.l-widget-group { + display: flex; + flex-flow: row wrap; + flex: 1; + padding: 0 15px; + height: 100%; + align-items: center; +} +.l-main-container { + display: flex; + flex-flow: row wrap; + height: calc(100vh - 50px); /* 50px: header 높이 */ + overflow-y: hidden; +} +.l-main-section { + display: flex; + flex-flow: column nowrap; + flex: 1; + background: #edf2f8; + position: relative; + height: 100%; +} +.l-main-contents { + height: 100%; + position: relative; +} +.fa-question-circle { + color: white; + font-size: 18px; +} + +button { + outline: none; +} diff --git a/web/src/main/webapp/v2/src/app/routes/main-page/main-page.component.html b/web/src/main/webapp/v2/src/app/routes/main-page/main-page.component.html new file mode 100644 index 000000000000..2627c9fc5329 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/main-page/main-page.component.html @@ -0,0 +1,20 @@ + +
    + +
    + + + +
    + + +
    +
    +
    +
    + +
    + +
    + +
    diff --git a/web/src/main/webapp/v2/src/app/routes/main-page/main-page.component.ts b/web/src/main/webapp/v2/src/app/routes/main-page/main-page.component.ts new file mode 100644 index 000000000000..8574a57f941e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/main-page/main-page.component.ts @@ -0,0 +1,48 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable, combineLatest } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { RouteInfoCollectorService, WebAppSettingDataService, NewUrlStateNotificationService, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services'; +import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component'; + +@Component({ + selector: 'pp-main-page', + templateUrl: './main-page.component.html', + styleUrls: ['./main-page.component.css'] +}) +export class MainPageComponent implements OnInit { + enableRealTime$: Observable; + constructor( + private routeInfoCollectorService: RouteInfoCollectorService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private webAppSettingDataService: WebAppSettingDataService, + private analyticsService: AnalyticsService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.enableRealTime$ = combineLatest( + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + map((urlService: NewUrlStateNotificationService) => urlService.isRealTimeMode()) + ), + this.webAppSettingDataService.useActiveThreadChart() + ).pipe( + map(([isRealTimeMode, useActiveThreadChart]: boolean[]) => isRealTimeMode && useActiveThreadChart) + ); + this.webAppSettingDataService.getVersion().subscribe((version: string) => { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.VERSION, version); + }); + } + onShowHelp($event: MouseEvent): void { + this.analyticsService.trackEvent(TRACKED_EVENT_LIST.TOGGLE_HELP_VIEWER, HELP_VIEWER_LIST.NAVBAR); + const {left, top, width, height} = ($event.target as HTMLElement).getBoundingClientRect(); + + this.dynamicPopupService.openPopup({ + data: HELP_VIEWER_LIST.NAVBAR, + coord: { + coordX: left + width / 2, + coordY: top + height / 2 + }, + component: HelpViewerPopupContainerComponent + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/main-page/main-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/main-page/main-page.routing.ts new file mode 100644 index 000000000000..42718fa6edcc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/main-page/main-page.routing.ts @@ -0,0 +1,159 @@ + +import { Routes } from '@angular/router'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { MainContentsContainerComponent } from 'app/core/components/main-contents/main-contents-container.component'; +import { EmptyContentsComponent, NoneComponent } from 'app/shared/components/empty-contents'; +import { UrlRedirectorComponent } from 'app/shared/components/url-redirector'; +// import { UrlValidateGuard } from 'app/shared/services'; +import { SystemConfigurationResolverService, ApplicationListResolverService, ServerTimeResolverService } from 'app/shared/services'; + +import { MainPageComponent } from './main-page.component'; +import { NewRealTimeContainerComponent } from 'app/core/components/real-time-new/new-real-time-container.component'; + +export const routing: Routes = [ + { + path: '', + component: MainPageComponent, + resolve: { + configuration: SystemConfigurationResolverService, + applicationList: ApplicationListResolverService + }, + children: [ + { + path: '', + component: EmptyContentsComponent, + data: { + showRealTimeButton: false, + enableRealTimeMode: false + }, + }, + { + path: ':' + UrlPathId.APPLICATION, + children: [ + { + path: '', + data: { + path: UrlPath.MAIN + }, + component: UrlRedirectorComponent + }, + { + path: UrlPath.REAL_TIME, + resolve: { + serverTime: ServerTimeResolverService + }, + children: [ + { + path: '', + component: MainContentsContainerComponent, + data: { + showRealTimeButton: true, + enableRealTimeMode: true + } + } + ] + }, + { + path: ':' + UrlPathId.PERIOD, + children: [ + { + path: '', + data: { + path: UrlPath.MAIN + }, + component: UrlRedirectorComponent + }, + { + path: ':' + UrlPathId.END_TIME, + children: [ + { + path: '', + component: MainContentsContainerComponent, + data: { + showRealTimeButton: true, + enableRealTimeMode: false + } + } + ] + } + ] + } + ] + } + ] + } +]; + +// export const routing: Routes = [ +// { +// path: UrlPath.MAIN, +// component: MainPageComponent, +// canActivate: [ UrlValidateGuard ], +// resolve: { +// configuration: SystemConfigurationResolverService, +// applicationList: ApplicationListResolverService +// }, +// children: [ +// { +// path: '', +// component: EmptyContentsComponent, +// data: { +// showRealTimeButton: false, +// enableRealTimeMode: false +// }, +// }, +// { +// path: ':' + UrlPathId.APPLICATION + '/' + UrlPath.REAL_TIME, +// resolve: { +// serverTime: ServerTimeResolverService +// }, +// children: [ +// { +// path: '', +// component: MainContentsContainerComponent, +// data: { +// showRealTimeButton: true, +// enableRealTimeMode: true +// } +// }, +// { +// path: '', +// component: SideBarContainerComponent, +// outlet: 'sidebar' +// }, +// { +// path: '', +// component: RealTimeContainerComponent, +// outlet: 'realtime' +// } +// ] +// }, +// { +// path: ':' + UrlPathId.APPLICATION, +// component: NoneComponent +// }, +// { +// path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD, +// component: NoneComponent +// }, +// { +// path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME, +// children: [ +// { +// path: '', +// component: MainContentsContainerComponent, +// data: { +// showRealTimeButton: true, +// enableRealTimeMode: false +// } +// }, +// { +// path: '', +// component: SideBarContainerComponent, +// outlet: 'sidebar' +// } +// ] +// } +// ] +// } +// ]; diff --git a/web/src/main/webapp/v2/src/app/routes/real-time-page/index.ts b/web/src/main/webapp/v2/src/app/routes/real-time-page/index.ts new file mode 100644 index 000000000000..ecada919dc8d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/real-time-page/index.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { SharedModule } from 'app/shared'; +import { RealTimeModule } from 'app/core/components/real-time'; +import { NewRealTimeModule } from 'app/core/components/real-time-new'; +import { RealTimePageComponent } from './real-time-page.component'; +import { routing } from './real-time-page.routing'; + +@NgModule({ + declarations: [ + RealTimePageComponent + ], + imports: [ + SharedModule, + RealTimeModule, + NewRealTimeModule, + RouterModule.forChild(routing) + ], + exports: [], + providers: [] +}) +export class RealTimePageModule { } diff --git a/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.component.css b/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.component.css new file mode 100644 index 000000000000..332fa2063ca6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.component.css @@ -0,0 +1,32 @@ +.realtime-application { + color: #FFF; +} +.realtime-application span { + margin-left: 10px; +} +.realtime-application span:last-child { + margin-left: 20px; + font-size: 12px; +} +.l-widget-group { + display: flex; + flex-flow: row wrap; + flex: 1; + padding: 0 15px; + height: 100%; + align-items: center; +} +.l-main-container { + display: flex; + flex-flow: row wrap; + height: calc(100vh - 50px); /* 50px: header 높이 */ + overflow-y: hidden; +} +.l-main-section { + display: flex; + flex-flow: column nowrap; + flex: 1; + background: #edf2f8; + position: relative; + height: 100%; +} diff --git a/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.component.html b/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.component.html new file mode 100644 index 000000000000..9961baa5203d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.component.html @@ -0,0 +1,15 @@ +
    + +
    + + {{applicationName}} + RealTime Active Thread Chart +
    +
    +
    +
    + + + +
    +
    diff --git a/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.component.ts b/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.component.ts new file mode 100644 index 000000000000..6ca669ebaa0b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.component.ts @@ -0,0 +1,36 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject, Observable } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { RouteInfoCollectorService, WebAppSettingDataService, NewUrlStateNotificationService } from 'app/shared/services'; + +@Component({ + selector: 'pp-real-time', + templateUrl: './real-time-page.component.html', + styleUrls: ['./real-time-page.component.css'] +}) +export class RealTimePageComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + applicationImgPath: string; + applicationName: string; + enableRealTime$: Observable; + constructor( + private routeInfoCollectorService: RouteInfoCollectorService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private webAppSettingDataService: WebAppSettingDataService + ) {} + ngOnInit() { + this.enableRealTime$ = this.webAppSettingDataService.useActiveThreadChart(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.applicationName = urlService.getPathValue(UrlPathId.APPLICATION).getApplicationName(); + this.applicationImgPath = this.webAppSettingDataService.getIconImagePath() + urlService.getPathValue(UrlPathId.APPLICATION).getServiceType() + this.webAppSettingDataService.getImageExt(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.routing.ts new file mode 100644 index 000000000000..73625a0d2908 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/real-time-page/real-time-page.routing.ts @@ -0,0 +1,40 @@ + +import { Routes } from '@angular/router'; + +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { RealTimePagingContainerComponent } from 'app/core/components/real-time/real-time-paging-container.component'; +import { SystemConfigurationResolverService, ServerTimeResolverService } from 'app/shared/services'; +import { RealTimePageComponent } from './real-time-page.component'; +import { NewRealTimePagingContainerComponent } from 'app/core/components/real-time-new/new-real-time-paging-container.component'; + +const TO_MAIN = '/' + UrlPath.MAIN; + +export const routing: Routes = [ + { + path: '', + component: RealTimePageComponent, + resolve: { + configuration: SystemConfigurationResolverService + }, + children: [ + { + path: '', + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.APPLICATION, + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PAGE, + resolve: { + serverTime: ServerTimeResolverService + }, + // component: RealTimePagingContainerComponent + component: NewRealTimePagingContainerComponent + } + ] + } +]; diff --git a/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/index.ts b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/index.ts new file mode 100644 index 000000000000..79efc9979979 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/index.ts @@ -0,0 +1,28 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { SharedModule } from 'app/shared'; +import { ScatterChartModule } from 'app/core/components/scatter-chart'; +import { ApplicationListModule } from 'app/core/components/application-list'; +import { PeriodSelectorModule } from 'app/core/components/period-selector'; +import { NoticeModule } from 'app/core/components/notice'; +import { ScatterFullScreenModePageComponent } from './scatter-full-screen-mode-page.component'; +import { routing } from './scatter-full-screen-mode-page.routing'; + +@NgModule({ + declarations: [ + ScatterFullScreenModePageComponent + ], + imports: [ + RouterModule.forChild(routing), + SharedModule, + ApplicationListModule, + PeriodSelectorModule, + ScatterChartModule, + NoticeModule, + ], + exports: [ + ], + providers: [] +}) +export class ScatterFullScreenModePageModule {} diff --git a/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.component.css b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.component.css new file mode 100644 index 000000000000..757fa691b81d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.component.css @@ -0,0 +1,31 @@ +.l-widget-group { + flex:1; + padding: 0 15px; + height: 100%; + align-items: center; + color: #FFF; + display: flex; + flex-flow: row wrap; +} +.l-widget-group img { + margin-right: 10px; +} +.l-widget-group .l-title { + margin-right: 10px; +} +.l-main-container { + display: flex; + flex-flow: row wrap; + justify-content: center; + width: 100%; + height: calc(100vh - 50px); +} +.l-sidemenu-wrap { + display: flex; + position:relative; + height: 100%; +} +.l-sidemenu { + margin-top: 50px; + width: 691px; +} diff --git a/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.component.html b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.component.html new file mode 100644 index 000000000000..dca195ab64a9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.component.html @@ -0,0 +1,15 @@ + +
    + +
    + {{applicationName}} - {{selectedAgent}} + +
    +
    +
    +
    +
    + +
    +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.component.ts b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.component.ts new file mode 100644 index 000000000000..752e07ed34cc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.component.ts @@ -0,0 +1,40 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { RouteInfoCollectorService, NewUrlStateNotificationService, WebAppSettingDataService } from 'app/shared/services'; + +@Component({ + selector: 'pp-scatter-full-screen-mode-page', + templateUrl: './scatter-full-screen-mode-page.component.html', + styleUrls: ['./scatter-full-screen-mode-page.component.css'] +}) +export class ScatterFullScreenModePageComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + applicationImgPath: string; + applicationName: string; + selectedAgent: string; + constructor( + private routeInfoCollectorService: RouteInfoCollectorService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private webAppSettingDataService: WebAppSettingDataService, + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.applicationName = urlService.getPathValue(UrlPathId.APPLICATION).getApplicationName(); + if (urlService.hasValue(UrlPathId.AGENT_ID)) { + this.selectedAgent = urlService.getPathValue(UrlPathId.AGENT_ID); + } else { + this.selectedAgent = 'All'; + } + this.applicationImgPath = this.webAppSettingDataService.getIconImagePath() + urlService.getPathValue(UrlPathId.APPLICATION).getServiceType() + this.webAppSettingDataService.getImageExt(); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.routing.ts new file mode 100644 index 000000000000..779f041b4c3c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/scatter-full-screen-mode-page/scatter-full-screen-mode-page.routing.ts @@ -0,0 +1,65 @@ +import { Routes } from '@angular/router'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ScatterChartForFullScreenModeContainerComponent } from 'app/core/components/scatter-chart/scatter-chart-for-full-screen-mode-container.component'; +import { UrlRedirectorComponent } from 'app/shared/components/url-redirector/url-redirector.component'; +import { SystemConfigurationResolverService, ApplicationListResolverService, ServerTimeResolverService } from 'app/shared/services'; +import { ScatterFullScreenModePageComponent } from './scatter-full-screen-mode-page.component'; + +export const routing: Routes = [ + { + path: '', + component: ScatterFullScreenModePageComponent, + resolve: { + configuration: SystemConfigurationResolverService, + applicationList: ApplicationListResolverService + }, + children: [ + { + path: '', + redirectTo: '/' + UrlPath.MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.APPLICATION, + data: { + path: UrlPath.MAIN + }, + component: UrlRedirectorComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/' + UrlPathId.REAL_TIME, + resolve: { + serverTime: ServerTimeResolverService + }, + data: { + showRealTimeButton: true, + enableRealTimeMode: true + }, + component: ScatterChartForFullScreenModeContainerComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD, + data: { + path: UrlPath.MAIN + }, + component: UrlRedirectorComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME, + data: { + showRealTimeButton: true, + enableRealTimeMode: false + }, + component: ScatterChartForFullScreenModeContainerComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME + '/:' + UrlPathId.AGENT_ID, + data: { + showRealTimeButton: true, + enableRealTimeMode: false + }, + component: ScatterChartForFullScreenModeContainerComponent + } + ] + } +]; diff --git a/web/src/main/webapp/v2/src/app/routes/thread-dump-page/index.ts b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/index.ts new file mode 100644 index 000000000000..a42c47a80918 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/index.ts @@ -0,0 +1,25 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { SharedModule } from 'app/shared'; +import { NoticeModule } from 'app/core/components/notice'; +import { ThreadDumpListModule } from 'app/core/components/thread-dump-list'; +import { ThreadDumpLogModule } from 'app/core/components/thread-dump-log'; +import { ThreadDumpPageComponent } from './thread-dump-page.component'; +import { routing } from './thread-dump-page.routing'; + +@NgModule({ + declarations: [ + ThreadDumpPageComponent + ], + imports: [ + SharedModule, + NoticeModule, + ThreadDumpListModule, + ThreadDumpLogModule, + RouterModule.forChild(routing) + ], + exports: [], + providers: [] +}) +export class ThreadDumpPageModule { } diff --git a/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.component.css b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.component.css new file mode 100644 index 000000000000..ac38fa98b833 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.component.css @@ -0,0 +1,43 @@ +.l-widget-group { + display: flex; + flex-flow: row wrap; + flex: 1; + padding: 0 15px; + height: 100%; + align-items: center; +} +.l-widget-group span { + color: #FFF; +} +.l-main-container { + display: flex; + flex-flow: column nowrap; + padding-top: 20px; + overflow-y: hidden; + height: calc(100vh - 50px); +} +.l-main-container h3 { + color: #00ccff; + padding-left: 20px; + font-weight: 200; + border-bottom: 1px solid #D0D7E1; + padding-bottom: 20px; +} +.l-main-section { + display: flex; + flex-flow: column nowrap; + background-color: #FFF; + flex: 1; + position: relative; + height: 100%; +} +.l-thread-dump-list { + height: 40%; + margin: 20px; + position: relative; +} +.l-thread-dump-log { + height: 60%; + position: relative; + background-color: #edf2f8; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.component.html b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.component.html new file mode 100644 index 000000000000..82c9e1a82bee --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.component.html @@ -0,0 +1,18 @@ + +
    + +
    + {{applicationName}} / {{agentId}} +
    +
    +
    +

    Thread Dump

    +
    +
    + +
    +
    + +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.component.ts b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.component.ts new file mode 100644 index 000000000000..360884985c39 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.component.ts @@ -0,0 +1,39 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter, takeUntil } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { RouteInfoCollectorService, NewUrlStateNotificationService } from 'app/shared/services'; + +@Component({ + selector: 'pp-thread-dump-page', + templateUrl: './thread-dump-page.component.html', + styleUrls: ['./thread-dump-page.component.css'] +}) +export class ThreadDumpPageComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + applicationName: string; + agentId: string; + constructor( + private routeInfoCollectorService: RouteInfoCollectorService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.APPLICATION, UrlPathId.AGENT_ID)) { + return true; + } + return false; + }) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.applicationName = urlService.getPathValue(UrlPathId.APPLICATION).getApplicationName(); + this.agentId = urlService.getPathValue(UrlPathId.AGENT_ID); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.routing.ts new file mode 100644 index 000000000000..d392dd8e42eb --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/thread-dump-page/thread-dump-page.routing.ts @@ -0,0 +1,45 @@ + +import { Routes } from '@angular/router'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { ThreadDumpListContainerComponent } from 'app/core/components/thread-dump-list/thread-dump-list-container.component'; +import { UrlRedirectorComponent } from 'app/shared/components/url-redirector'; +import { SystemConfigurationResolverService, ServerTimeResolverService } from 'app/shared/services'; +import { ThreadDumpPageComponent } from './thread-dump-page.component'; + +export const routing: Routes = [ + { + path: '', + component: ThreadDumpPageComponent, + resolve: { + configuration: SystemConfigurationResolverService + }, + children: [ + { + path: '', + redirectTo: '/' + UrlPath.MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.APPLICATION, + data: { + path: UrlPath.MAIN + }, + component: UrlRedirectorComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.AGENT_ID, + data: { + path: UrlPath.MAIN + }, + component: UrlRedirectorComponent + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.AGENT_ID + '/:' + UrlPathId.FOCUS_TIMESTAMP, + resolve: { + serverTime: ServerTimeResolverService + }, + component: ThreadDumpListContainerComponent + } + ] + } +]; diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/index.ts b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/index.ts new file mode 100644 index 000000000000..a0a842f8e4e5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/index.ts @@ -0,0 +1,27 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { SharedModule } from 'app/shared'; +import { NoticeModule } from 'app/core/components/notice'; +import { ApplicationListModule } from 'app/core/components/application-list'; +import { CommandGroupModule } from 'app/core/components/command-group'; +import { TransactionDetailContentsModule } from 'app/core/components/transaction-detail-contents'; +import { TransactionDetailPageComponent } from './transaction-detail-page.component'; +import { routing } from './transaction-detail-page.routing'; + +@NgModule({ + declarations: [ + TransactionDetailPageComponent + ], + imports: [ + SharedModule, + NoticeModule, + ApplicationListModule, + CommandGroupModule, + TransactionDetailContentsModule, + RouterModule.forChild(routing) + ], + exports: [], + providers: [] +}) +export class TransactionDetailPageModule {} diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.component.css b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.component.css new file mode 100644 index 000000000000..edb5a625303d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.component.css @@ -0,0 +1,34 @@ +.l-transaction-content { + height:100%; +} +.l-main-container { + display: flex; + flex-flow: row wrap; + overflow-y: hidden; + height: calc(100vh - 50px); +} +.l-main-section { + display: flex; + flex-flow: column nowrap; + flex:1; + background:#edf2f8; + position: relative; + height: 100%; +} +.l-main-section .l-main-contents { + height: 100%; + position: relative; + overflow: auto; +} +.l-main-section .l-main-contents.l-main-contents-transaction { + overflow: hidden; +} +.l-main-contents .l-content-item { + margin:10px; +} +.l-main-contents .l-content-item.l-margin-none { + margin:0; +} +.l-main-contents .l-content-item.l-border-none { + border:none; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.component.html b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.component.html new file mode 100644 index 000000000000..3707f8d2ee6e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.component.html @@ -0,0 +1,14 @@ + +
    + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.component.ts b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.component.ts new file mode 100644 index 000000000000..11abb6fcd86b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.component.ts @@ -0,0 +1,64 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +import { + StoreHelperService, + RouteInfoCollectorService, + UrlRouteManagerService, + NewUrlStateNotificationService, + DynamicPopupService, + TransactionDetailDataService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPathId } from 'app/shared/models'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; + +@Component({ + selector: 'pp-transaction-detail-page', + templateUrl: './transaction-detail-page.component.html', + styleUrls: ['./transaction-detail-page.component.css'] +}) +export class TransactionDetailPageComponent implements OnInit, OnDestroy { + private unsubscribe: Subject = new Subject(); + constructor( + private routeInfoCollectorService: RouteInfoCollectorService, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private transactionDetailDataService: TransactionDetailDataService, + private dynamicPopupService: DynamicPopupService + ) {} + ngOnInit() { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + filter((urlService: NewUrlStateNotificationService) => { + return urlService.hasValue(UrlPathId.AGENT_ID, UrlPathId.SPAN_ID, UrlPathId.TRACE_ID, UrlPathId.FOCUS_TIMESTAMP); + }) + ).subscribe((urlService: NewUrlStateNotificationService) => { + this.transactionDetailDataService.getData( + urlService.getPathValue(UrlPathId.AGENT_ID), + urlService.getPathValue(UrlPathId.SPAN_ID), + urlService.getPathValue(UrlPathId.TRACE_ID), + urlService.getPathValue(UrlPathId.FOCUS_TIMESTAMP) + ).subscribe((transactionDetailInfo: ITransactionDetailData) => { + this.storeHelperService.dispatch(new Actions.UpdateTransactionDetailData(transactionDetailInfo)); + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent, + onCloseCallback: () => { + this.urlRouteManagerService.reload(); + } + }); + }); + }); + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.routing.ts new file mode 100644 index 000000000000..3ec2c8c9740b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-detail-page/transaction-detail-page.routing.ts @@ -0,0 +1,68 @@ +import { Routes } from '@angular/router'; + +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { TransactionDetailContentsContainerComponent } from 'app/core/components/transaction-detail-contents/transaction-detail-contents-container.component'; +import { SystemConfigurationResolverService, ApplicationListResolverService } from 'app/shared/services'; +import { TransactionDetailPageComponent } from './transaction-detail-page.component'; + +const TO_MAIN = '/' + UrlPath.MAIN; + +export const routing: Routes = [ + { + path: '', + component: TransactionDetailPageComponent, + resolve: { + configuration: SystemConfigurationResolverService, + applicationList: ApplicationListResolverService + }, + children: [ + { + path: '', + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.TRACE_ID, + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.TRACE_ID + '/:' + UrlPathId.FOCUS_TIMESTAMP, + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.TRACE_ID + '/:' + UrlPathId.FOCUS_TIMESTAMP + '/:' + UrlPathId.AGENT_ID, + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.TRACE_ID + '/:' + UrlPathId.FOCUS_TIMESTAMP + '/:' + UrlPathId.AGENT_ID + '/:' + UrlPathId.SPAN_ID, + children: [ + { + path: '', + component: TransactionDetailContentsContainerComponent + }, + { + path: ':' + UrlPathId.VIEW_TYPE, + children: [ + { + path: '', + component: TransactionDetailContentsContainerComponent, + }, + { + path: ':' + UrlPathId.SEARCH_ID, + children: [ + { + path: '', + component: TransactionDetailContentsContainerComponent, + } + ] + } + ] + } + ] + } + ] + } +]; diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-list-page/index.ts b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/index.ts new file mode 100644 index 000000000000..86fc552fa3ee --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/index.ts @@ -0,0 +1,38 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { SharedModule } from 'app/shared'; +import { AngularSplitModule } from 'app/core/components/angular-split/angular-split'; +import { NoticeModule } from 'app/core/components/notice'; +import { ApplicationListModule } from 'app/core/components/application-list'; +import { DataLoadIndicatorModule } from 'app/core/components/data-load-indicator'; +import { StateButtonModule } from 'app/core/components/state-button'; +import { CommandGroupModule } from 'app/core/components/command-group'; +import { TransactionTableGridModule } from 'app/core/components/transaction-table-grid'; +import { TransactionListBottomContentsModule } from 'app/core/components/transaction-list-bottom-contents'; + +import { TransactionListEmptyComponent } from './transaction-list-empty.component'; +import { TransactionListPageComponent } from './transaction-list-page.component'; +import { routing } from './transaction-list-page.routing'; + +@NgModule({ + declarations: [ + TransactionListEmptyComponent, + TransactionListPageComponent + ], + imports: [ + AngularSplitModule, + SharedModule, + NoticeModule, + ApplicationListModule, + DataLoadIndicatorModule, + StateButtonModule, + CommandGroupModule, + TransactionTableGridModule, + TransactionListBottomContentsModule, + RouterModule.forChild(routing) + ], + exports: [], + providers: [] +}) +export class TransactionListPageModule {} diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-empty.component.ts b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-empty.component.ts new file mode 100644 index 000000000000..534964ab3546 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-empty.component.ts @@ -0,0 +1,32 @@ +import { Component, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + +@Component({ + selector: 'pp-transaction-list-empty', + template: ` +
    + {{message}} +
    + `, + styles: [` + div { + width: 100%; + height: 100%; + display: flex; + font-size: 20px; + font-weight: 600; + align-items: center; + justify-content: center; + background-color: rgba(30, 87, 153, 0.3); + } + `] +}) +export class TransactionListEmptyComponent implements OnInit { + message: string; + constructor(private translateService: TranslateService) {} + ngOnInit() { + this.translateService.get('TRANSACTION_LIST.SELECT_TRANSACTION').subscribe((text: string) => { + this.message = text; + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.component.css b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.component.css new file mode 100644 index 000000000000..5ecc00916670 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.component.css @@ -0,0 +1,17 @@ +.l-widget-group { + display: flex; + flex-flow: row wrap; + flex: 1; + padding: 0 15px; + height: 100%; + align-items: center; +} +.l-main-container { + display: flex; + flex-flow: row wrap; + height: calc(100vh - 50px); + overflow-y: hidden; +} +split-area:first-child { + overflow: hidden !important; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.component.html b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.component.html new file mode 100644 index 000000000000..fce979573022 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.component.html @@ -0,0 +1,19 @@ + +
    + +
    + +
    + + +
    +
    + + + + + + + + +
    diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.component.ts b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.component.ts new file mode 100644 index 000000000000..d69d58b652d5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.component.ts @@ -0,0 +1,27 @@ +import { Component, OnInit } from '@angular/core'; + +import { WebAppSettingDataService, RouteInfoCollectorService, GutterEventService } from 'app/shared/services'; + +@Component({ + selector: 'pp-transaction-list-page', + templateUrl: './transaction-list-page.component.html', + styleUrls: ['./transaction-list-page.component.css'] +}) +export class TransactionListPageComponent implements OnInit { + direction = 'vertical'; + handlePosition: number[]; + constructor( + private routeInfoCollectorService: RouteInfoCollectorService, + private webAppSettingDataService: WebAppSettingDataService, + private gutterEventService: GutterEventService, + ) {} + ngOnInit() { + this.handlePosition = this.webAppSettingDataService.getListHandlePosition(); + } + onGutterResized({sizes}: {sizes: number[]}): void { + this.webAppSettingDataService.setListHandlePosition(sizes.map((size: number): number => { + return Number.parseFloat(size.toFixed(2)); + })); + this.gutterEventService.resizedGutter(sizes); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.routing.ts new file mode 100644 index 000000000000..2616eecbd2fb --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-list-page/transaction-list-page.routing.ts @@ -0,0 +1,64 @@ +import { Routes } from '@angular/router'; + +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { TransactionListEmptyComponent } from './transaction-list-empty.component'; +import { TransactionListBottomContentsContainerComponent } from 'app/core/components/transaction-list-bottom-contents/transaction-list-bottom-contents-container.component'; +import { SystemConfigurationResolverService, ApplicationListResolverService } from 'app/shared/services'; +import { TransactionListPageComponent } from './transaction-list-page.component'; + +const TO_MAIN = '/' + UrlPath.MAIN; + +export const routing: Routes = [ + { + path: '', + component: TransactionListPageComponent, + resolve: { + configuration: SystemConfigurationResolverService, + applicationList: ApplicationListResolverService + }, + children: [ + { + path: '', + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.APPLICATION, + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD, + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME, + children: [ + { + path: '', + component: TransactionListEmptyComponent + }, + { + path: ':' + UrlPathId.TRANSACTION_INFO, + children: [ + { + path: '', + component: TransactionListBottomContentsContainerComponent, + }, + { + path: ':' + UrlPathId.VIEW_TYPE, + children: [ + { + path: '', + component: TransactionListBottomContentsContainerComponent, + } + ] + } + ] + } + ] + } + ] + } +]; diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-view-page/index.ts b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/index.ts new file mode 100644 index 000000000000..024bae77e9cc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/index.ts @@ -0,0 +1,35 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { SharedModule } from 'app/shared'; +import { ApplicationListModule } from 'app/core/components/application-list'; +import { NoticeModule } from 'app/core/components/notice'; +import { CommandGroupModule } from 'app/core/components/command-group'; +import { TransactionShortInfoModule } from 'app/core/components/transaction-short-info'; +import { TransactionViewTopContentsModule } from 'app/core/components/transaction-view-top-contents'; +import { TransactionViewBottomContentsModule } from 'app/core/components/transaction-view-bottom-contents'; + +import { AngularSplitModule } from 'app/core/components/angular-split/angular-split'; +import { TransactionViewPageComponent } from './transaction-view-page.component'; +import { routing } from './transaction-view-page.routing'; + +@NgModule({ + declarations: [ + TransactionViewPageComponent + ], + imports: [ + AngularSplitModule, + SharedModule, + ApplicationListModule, + NoticeModule, + CommandGroupModule, + TransactionShortInfoModule, + TransactionViewTopContentsModule, + TransactionViewBottomContentsModule, + RouterModule.forChild(routing) + ], + exports: [ + ], + providers: [] +}) +export class TransactionViewPageModule {} diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.component.css b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.component.css new file mode 100644 index 000000000000..69c5b0cdace4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.component.css @@ -0,0 +1,10 @@ +.l-main-container { + display: flex; + flex-flow: row wrap; + overflow-y: hidden; + height: calc(100vh - 50px); +} +.l-component-wrapper { + position: relative; + width: 100%; +} diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.component.html b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.component.html new file mode 100644 index 000000000000..e621cd2c6309 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.component.html @@ -0,0 +1,18 @@ + +
    + + +
    +
    +
    + +
    + + + + + + + + +
    diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.component.ts b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.component.ts new file mode 100644 index 000000000000..8a57ed82640d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.component.ts @@ -0,0 +1,76 @@ +import { Component, OnInit } from '@angular/core'; +import { Subject, Observable, of } from 'rxjs'; +import { take, takeUntil, switchMap } from 'rxjs/operators'; + +import { + StoreHelperService, + RouteInfoCollectorService, + UrlRouteManagerService, + NewUrlStateNotificationService, + TransactionDetailDataService, + DynamicPopupService, + GutterEventService +} from 'app/shared/services'; +import { Actions } from 'app/shared/store'; +import { UrlPathId } from 'app/shared/models'; +import { ServerErrorPopupContainerComponent } from 'app/core/components/server-error-popup'; + +@Component({ + selector: 'pp-transaction-view-page', + templateUrl: './transaction-view-page.component.html', + styleUrls: ['./transaction-view-page.component.css'] +}) +export class TransactionViewPageComponent implements OnInit { + private unsubscribe: Subject = new Subject(); + splitSize: number[]; + + constructor( + private routeInfoCollectorService: RouteInfoCollectorService, + private storeHelperService: StoreHelperService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private urlRouteManagerService: UrlRouteManagerService, + private transactionDetailDataService: TransactionDetailDataService, + private gutterEventService: GutterEventService, + private dynamicPopupService: DynamicPopupService + ) { } + + ngOnInit() { + this.initSplitRatio(); + this.initTransactionViewInfo(); + } + private initSplitRatio(): void { + this.gutterEventService.onGutterResized$.pipe( + take(1) + ).subscribe((splitSize: number[]) => this.splitSize = splitSize); + } + private initTransactionViewInfo(): void { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + takeUntil(this.unsubscribe), + switchMap((urlService: NewUrlStateNotificationService) => { + return this.transactionDetailDataService.getData( + urlService.getPathValue(UrlPathId.AGENT_ID), + urlService.getPathValue(UrlPathId.SPAN_ID), + urlService.getPathValue(UrlPathId.TRACE_ID), + urlService.getPathValue(UrlPathId.FOCUS_TIMESTAMP) + ); + }) + ).subscribe((transactionDetailInfo: ITransactionDetailData) => { + this.storeHelperService.dispatch(new Actions.UpdateTransactionDetailData(transactionDetailInfo)); + }, (error: IServerErrorFormat) => { + this.dynamicPopupService.openPopup({ + data: { + title: 'Error', + contents: error + }, + component: ServerErrorPopupContainerComponent, + onCloseCallback: () => { + this.urlRouteManagerService.reload(); + } + }); + }); + } + onAjaxError(err: Error): Observable { + // TODO: Error발생시 띄워줄 팝업 컴포넌트 Call - issue#170 + return of({}); + } +} diff --git a/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.routing.ts b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.routing.ts new file mode 100644 index 000000000000..11f9e870bd61 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/routes/transaction-view-page/transaction-view-page.routing.ts @@ -0,0 +1,49 @@ +import { Routes } from '@angular/router'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { TransactionViewTopContentsContainerComponent } from 'app/core/components/transaction-view-top-contents/transaction-view-top-contents-container.component'; +import { SystemConfigurationResolverService, ApplicationListResolverService } from 'app/shared/services'; +import { TransactionViewPageComponent } from './transaction-view-page.component'; + +const TO_MAIN = '/' + UrlPath.MAIN; + +export const routing: Routes = [ + { + path: '', + component: TransactionViewPageComponent, + resolve: { + configuration: SystemConfigurationResolverService, + applicationList: ApplicationListResolverService + }, + children: [ + { + path: '', + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.AGENT_ID, + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.AGENT_ID + '/:' + UrlPathId.TRACE_ID, + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.AGENT_ID + '/:' + UrlPathId.TRACE_ID + '/:' + UrlPathId.FOCUS_TIMESTAMP, + redirectTo: TO_MAIN, + pathMatch: 'full' + }, + { + path: ':' + UrlPathId.AGENT_ID + '/:' + UrlPathId.TRACE_ID + '/:' + UrlPathId.FOCUS_TIMESTAMP + '/:' + UrlPathId.SPAN_ID, + children: [ + { + path: '', + component: TransactionViewTopContentsContainerComponent + } + ] + } + ] + } +]; diff --git a/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.css b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.css new file mode 100644 index 000000000000..924588cb7673 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.css @@ -0,0 +1,11 @@ +div { + text-align: center; + padding: 10% 20px 20px 20px; + vertical-align: middle; + height: 100%; +} +img { + width: 80%; + filter: grayscale(90%); + opacity: .5; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.html b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.html new file mode 100644 index 000000000000..8b92dedb9dec --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.html @@ -0,0 +1,3 @@ +
    + +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.spec.ts b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.spec.ts new file mode 100644 index 000000000000..436daa628444 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EmptyContentsComponent } from './empty-contents.component'; + +describe('EmptyContentsComponent', () => { + let component: EmptyContentsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [EmptyContentsComponent] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(EmptyContentsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.ts b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.ts new file mode 100644 index 000000000000..75d207214166 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/empty-contents.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService } from 'app/shared/services'; + +@Component({ + selector: 'pp-empty-contents', + templateUrl: './empty-contents.component.html', + styleUrls: ['./empty-contents.component.css'] +}) +export class EmptyContentsComponent implements OnInit { + hiddenComponent$: Observable; + constructor( + private newUrlStateNotificationService: NewUrlStateNotificationService + ) {} + ngOnInit() { + this.hiddenComponent$ = this.newUrlStateNotificationService.onUrlStateChange$.pipe( + map((urlService: NewUrlStateNotificationService) => { + return !urlService.hasValue(UrlPathId.PERIOD, UrlPathId.END_TIME); + }) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/components/empty-contents/index.ts b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/index.ts new file mode 100644 index 000000000000..3dd9c774a2fe --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/index.ts @@ -0,0 +1,2 @@ +export { EmptyContentsComponent } from './empty-contents.component'; +export { NoneComponent } from './none.component'; diff --git a/web/src/main/webapp/v2/src/app/shared/components/empty-contents/none.component.ts b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/none.component.ts new file mode 100644 index 000000000000..ee1f6360e957 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/empty-contents/none.component.ts @@ -0,0 +1,10 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'pp-none', + template: '' +}) +export class NoneComponent implements OnInit { + constructor() {} + ngOnInit() {} +} diff --git a/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/film-for-disable.component.css b/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/film-for-disable.component.css new file mode 100644 index 000000000000..1eca87e53427 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/film-for-disable.component.css @@ -0,0 +1,7 @@ +.l-disabled { + top: 0px; + left: 0px; + height: 100%; + position: absolute; + background: linear-gradient(135deg, rgba(226,226,226,0.7) 0%, rgba(219,219,219,0.7) 43%, rgba(209,209,209,0.7) 51%, rgba(254,254,254,0.7) 100%); +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/film-for-disable.component.html b/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/film-for-disable.component.html new file mode 100644 index 000000000000..1ea029adc822 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/film-for-disable.component.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/film-for-disable.component.ts b/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/film-for-disable.component.ts new file mode 100644 index 000000000000..a2daac5c8094 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/film-for-disable.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit, Input, ElementRef, Renderer2 } from '@angular/core'; + +@Component({ + selector: 'pp-film-for-disable', + templateUrl: './film-for-disable.component.html', + styleUrls: ['./film-for-disable.component.css'] +}) +export class FilmForDisableComponent implements OnInit { + @Input() zIndex: number; + @Input() marginWidth: number; + constructor( + private el: ElementRef, + private renderer: Renderer2 + ) {} + + ngOnInit() { + const el = this.el.nativeElement.querySelector('.l-disabled'); + this.renderer.setStyle(el, 'z-index', this.zIndex); + this.renderer.setStyle(el, 'width', `calc(100% - ${this.marginWidth}px)`); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/index.ts b/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/index.ts new file mode 100644 index 000000000000..f929c3b993b9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/film-for-disable/index.ts @@ -0,0 +1 @@ +export { FilmForDisableComponent } from './film-for-disable.component'; diff --git a/web/src/main/webapp/v2/src/app/shared/components/header-logo/header-logo.component.css b/web/src/main/webapp/v2/src/app/shared/components/header-logo/header-logo.component.css new file mode 100644 index 000000000000..c402b32623e5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/header-logo/header-logo.component.css @@ -0,0 +1,14 @@ +.logo { + width: 165px; + height: 100%; + box-shadow: 1px 0 0 #55a2e6; + background: #408dd4; + border-right: 1px solid #3881c4; +} +.logo a { + width:100%; + height:100%; + display: flex; + align-items: center; + justify-content: center; +} diff --git a/web/src/main/webapp/v2/src/app/shared/components/header-logo/header-logo.component.html b/web/src/main/webapp/v2/src/app/shared/components/header-logo/header-logo.component.html new file mode 100644 index 000000000000..4b3cb2522238 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/header-logo/header-logo.component.html @@ -0,0 +1,5 @@ +

    + + PINPOINT LOGO + +

    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/shared/components/header-logo/header-logo.component.ts b/web/src/main/webapp/v2/src/app/shared/components/header-logo/header-logo.component.ts new file mode 100644 index 000000000000..85a998adcea3 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/header-logo/header-logo.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; +import { WebAppSettingDataService } from 'app/shared/services'; + +@Component({ + selector: 'pp-header-logo', + templateUrl: './header-logo.component.html', + styleUrls: ['./header-logo.component.css'] +}) +export class HeaderLogoComponent implements OnInit { + logoPath: string; + constructor( + private webAppSettingDataService: WebAppSettingDataService + ) { } + + ngOnInit() { + this.logoPath = this.webAppSettingDataService.getLogoPath(); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/components/header-logo/index.ts b/web/src/main/webapp/v2/src/app/shared/components/header-logo/index.ts new file mode 100644 index 000000000000..f14db7e5060e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/header-logo/index.ts @@ -0,0 +1 @@ +export { HeaderLogoComponent } from './header-logo.component'; diff --git a/web/src/main/webapp/v2/src/app/shared/components/index.ts b/web/src/main/webapp/v2/src/app/shared/components/index.ts new file mode 100644 index 000000000000..61b8de77f0b1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/index.ts @@ -0,0 +1,5 @@ +import { EmptyContentsComponent } from './empty-contents'; + +export const SHARED_COMPONENTS = [ + EmptyContentsComponent +]; diff --git a/web/src/main/webapp/v2/src/app/shared/components/loading/index.ts b/web/src/main/webapp/v2/src/app/shared/components/loading/index.ts new file mode 100644 index 000000000000..5d28caaf62c9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/loading/index.ts @@ -0,0 +1 @@ +export { LoadingComponent } from './loading.component'; diff --git a/web/src/main/webapp/v2/src/app/shared/components/loading/loading.component.css b/web/src/main/webapp/v2/src/app/shared/components/loading/loading.component.css new file mode 100644 index 000000000000..c196e42aabb8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/loading/loading.component.css @@ -0,0 +1,5 @@ +:host { + position: absolute; + top: 40%; + left: 47%; +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/shared/components/loading/loading.component.html b/web/src/main/webapp/v2/src/app/shared/components/loading/loading.component.html new file mode 100644 index 000000000000..3c612393afce --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/loading/loading.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/shared/components/loading/loading.component.ts b/web/src/main/webapp/v2/src/app/shared/components/loading/loading.component.ts new file mode 100644 index 000000000000..0cf5be37bdaa --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/loading/loading.component.ts @@ -0,0 +1,30 @@ +import { Component, OnInit, Input, ElementRef, Renderer2 } from '@angular/core'; +import { style, animate, transition, trigger } from '@angular/animations'; + +@Component({ + selector: 'pp-loading', + animations: [ + trigger('fadeOut', [ + transition(':leave', [ // is alias to '* => void' + animate(1000, style({ + opacity: 0 + })) + ]) + ]) + ], + templateUrl: './loading.component.html', + styleUrls: ['./loading.component.css'] +}) +export class LoadingComponent implements OnInit { + @Input() showLoading: boolean; + @Input() zIndex: number; + + constructor( + private el: ElementRef, + private renderer: Renderer2 + ) {} + + ngOnInit() { + this.renderer.setStyle(this.el.nativeElement, 'z-index', this.zIndex); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/components/page-not-found/index.ts b/web/src/main/webapp/v2/src/app/shared/components/page-not-found/index.ts new file mode 100644 index 000000000000..59f9c154443e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/page-not-found/index.ts @@ -0,0 +1 @@ +export * from './page-not-found.component'; diff --git a/web/src/main/webapp/v2/src/app/shared/components/page-not-found/page-not-found.component.css b/web/src/main/webapp/v2/src/app/shared/components/page-not-found/page-not-found.component.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/app/shared/components/page-not-found/page-not-found.component.html b/web/src/main/webapp/v2/src/app/shared/components/page-not-found/page-not-found.component.html new file mode 100644 index 000000000000..61ed4e6a016d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/page-not-found/page-not-found.component.html @@ -0,0 +1,5 @@ +
    +
    + Page Not Found 사공사 +
    +
    \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/shared/components/page-not-found/page-not-found.component.ts b/web/src/main/webapp/v2/src/app/shared/components/page-not-found/page-not-found.component.ts new file mode 100644 index 000000000000..6d7496a76210 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/page-not-found/page-not-found.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'pp-page-not-found', + templateUrl: './page-not-found.component.html', + styleUrls: ['./page-not-found.component.css'] +}) +export class PageNotFoundComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/index.ts b/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/index.ts new file mode 100644 index 000000000000..f1bc08c2e1b6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/index.ts @@ -0,0 +1 @@ +export * from './simple-progress-slider.component'; diff --git a/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/simple-progress-slider.component.css b/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/simple-progress-slider.component.css new file mode 100644 index 000000000000..bba669ac8b77 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/simple-progress-slider.component.css @@ -0,0 +1,132 @@ + :host { + width: 100%; + } + .slider-for-progress { + width: 100%; + padding-top: 10px; + } + .slider-for-progress .sfp-line { + width: 100%; + height: 14px; + position: relative; + } + .slider-for-progress .sfp-line div, .slider-for-progress .sfp-line span { + position: absolute; + } + .slider-for-progress .sfp-handle { + top: -4px; + width: 14px; + height: 14px; + border-radius: 50%; + background-color: #FFF; + box-shadow: 1px 1px 3px 1px rgba(0,0,0,0.4); + } + .slider-for-progress .sfp-handle span { + top: 3px; + left: 3px; + width: 8px; + height: 8px; + border-radius: 50%; + background-color: #4b8ed4; + } + .slider-for-progress .sfp-left-handler { + left: 100%; /* @script position reset */ + margin-left: -7px; + } + .slider-for-progress .sfp-right-handler { + right: 0px; /* @script position reset */ + margin-right: -7px; + } + .slider-for-progress .sfp-label { + top: -2px; + position: absolute; + font-size: 10px; + } + .slider-for-progress .sfp-label span { + border: 1px solid #3e83c6; + padding: 2px 4px 1px 4px; + position: relative; + background-color: #FFF; + box-shadow: 1px 1px 3px 1px rgba(0,0,0,0.4); + } + .slider-for-progress .sfp-label span:before, .slider-for-progress .sfp-label span:after { + top: 50%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + } + .slider-for-progress .sfp-label span:before { + border-color: rgba(62, 131, 198, 0); + border-width: 5px; + margin-top: -5px; + } + .slider-for-progress .sfp-label span:after { + border-color: rgba(255, 255, 255, 0); + border-width: 4px; + margin-top: -4px; + } + .slider-for-progress .sfp-label-right-arrow span:before, .slider-for-progress .sfp-label-right-arrow span:after { + left: 100%; + } + .slider-for-progress .sfp-label-right-arrow span:before { + border-left-color: #3e83c6; + } + .slider-for-progress .sfp-label-right-arrow span:after { + border-left-color: #ffffff; + } + .slider-for-progress .sfp-label-left-arrow span:before, .slider-for-progress .sfp-label-left-arrow span:after { + right: 100%; + } + .slider-for-progress .sfp-label-left-arrow span:before { + border-right-color: #3e83c6; + } + .slider-for-progress .sfp-label-left-arrow span:after { + border-right-color: #ffffff; + } + + .slider-for-progress .sfp-label-right-arrow { + margin-left: -50px; + left: 0%;/* @script position reset */ + } + .slider-for-progress .sfp-label-left-arrow { + margin-left: 13px; + left: 0%; /* @script position reset */ + } + .slider-for-progress .sfp-value { + width: 100%; + height: 20px; + } + .slider-for-progress .sfp-background { + top: 0px; + left: 0px; + width: 100%; + height: 7px; + background-color: #c9def3; + } + .slider-for-progress .sfp-foreground { + top: 0px; + right: 0px; + width: 0px; /* @script position reset */ + height: 7px; + background-color: #3dcfa8; + } + .slider-for-progress .sfp-value { + color: #FFF; + width: 100%; + position: relative; + font-size: 10px; + } + .slider-for-progress .sfp-value span { + position: absolute; + } + .slider-for-progress .sfp-value .first { + left: 0px; + margin-left: -15px; + } + .slider-for-progress .sfp-value .last { + right: 0px; + margin-right: -15px; + } \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/simple-progress-slider.component.html b/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/simple-progress-slider.component.html new file mode 100644 index 000000000000..f47b5a4c61f9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/simple-progress-slider.component.html @@ -0,0 +1,19 @@ +
    +
    +
    +
    +
    +
    +
    + {{selectedStartValue}} +
    +
    + {{selectedStartValue}} +
    +
    +
    + {{rangeStartValue}} + {{d.value}} + {{rangeEndValue}} +
    +
    diff --git a/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/simple-progress-slider.component.ts b/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/simple-progress-slider.component.ts new file mode 100644 index 000000000000..982a95bd819b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/simple-progress-slider/simple-progress-slider.component.ts @@ -0,0 +1,145 @@ +import { Component, OnInit, OnChanges, SimpleChanges, Input } from '@angular/core'; +import { trigger, state, style, animate, transition } from '@angular/animations'; +import * as moment from 'moment-timezone'; + +interface IRangePosition { + value: string; + position: number; +} + +@Component({ + selector: 'pp-simple-progress-slider', + templateUrl: './simple-progress-slider.component.html', + styleUrls: ['./simple-progress-slider.component.css'], + animations: [ + trigger('handlerTrigger', [ + state('start', style({ + left: '100%' + })), + state(':enter', style({ + left: '100%' + })), + state('next', style({ + left: '{{value}}' + }), {params: {value: '100%'}}), + state('andNext', style({ + left: '{{value}}' + }), {params: {value: '100%'}}), + transition('* => *', [ + animate('0.3s 0.3s ease-out') + ]) + ]), + trigger('barTrigger', [ + state('start', style({ + width: '0%' + })), + state(':enter', style({ + width: '0%' + })), + state('next', style({ + width: '{{value}}' + }), {params: {value: '0%'}}), + state('andNext', style({ + width: '{{value}}' + }), {params: {value: '0%'}}), + transition('* => *', [ + animate('0.3s 0.3s ease-out') + ]) + ]), + ] +}) +export class SimpleProgressSliderComponent implements OnInit, OnChanges { + @Input() timezone: string; + @Input() dateFormat: string; + @Input() rangeValue: number[] = [0, 100]; + @Input() selectedRangeValue: number[] = [100, 100]; + @Input() type = 'date'; // count + @Input() gradationCount = 6; + private triggerStep: { [key: string]: string } = { + start: 'next', + next: 'andNext', + andNext: 'next' + }; + barTrigger = 'start'; + handlerTrigger = 'start'; + showLabel = false; + rangeStartValue = ''; + rangeEndValue = ''; + selectedStartValue = ''; + gradationValue: IRangePosition[] = []; + selectedStartPosition = 100; + constructor() {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if (changes['rangeValue'] && changes['rangeValue']['currentValue']) { + this.initXAxis(); + } + if (changes['selectedRangeValue'] && changes['selectedRangeValue']['currentValue']) { + this.selectedStartValue = this.convertToType(this.selectedRangeValue[0]); + this.calcuSelectedStartPosition(); + this.setAnimationNextStep(); + } + if (changes['timezone'] && changes['timezone'].firstChange === false) { + this.changeTimeDisplay(); + } + if (changes['dateFormat'] && changes['dateFormat'].firstChange === false) { + this.changeTimeDisplay(); + } + } + private setAnimationNextStep(): void { + this.barTrigger = this.triggerStep[this.barTrigger]; + this.handlerTrigger = this.triggerStep[this.handlerTrigger]; + } + private initXAxis(): void { + this.rangeStartValue = this.convertToType(this.rangeValue[0]); + this.rangeEndValue = this.convertToType(this.rangeValue[1]); + this.calcuGradationValue(); + } + private changeTimeDisplay(): void { + this.initXAxis(); + this.selectedStartValue = this.convertToType(this.selectedRangeValue[0]); + } + animationStart($event: any): void { + this.showLabel = false; + } + animationDone($event: any): void { + if ($event.fromState !== 'void') { + this.showLabel = true; + } + } + hiddenRightArrowLabel(): boolean { + return this.selectedStartPosition < 50 || this.showLabel === false; + } + hiddenLeftArrowLabel(): boolean { + return this.selectedStartPosition >= 50 || this.showLabel === false; + } + convertToType(value: number): string { + switch (this.type) { + case 'count': + return value.toString(); + case 'date': + return moment(value).tz(this.timezone).format(this.dateFormat); + default: + return value.toString(); + } + } + calcuGradationValue(): void { + const gradationCount = this.gradationCount - 1; + const gap = this.rangeValue[1] - this.rangeValue[0]; + const gapPosition = 100 / gradationCount; + const gapValue = gap / gradationCount; + this.gradationValue.length = 0; + for (let i = 1; i <= gradationCount - 1; i++) { + this.gradationValue.push({ + value: this.convertToType(this.rangeValue[0] + (gapValue * i)), + position: (gapPosition * i), + }); + } + } + calcuSelectedStartPosition(): void { + const gap = this.rangeValue[1] - this.rangeValue[0]; + const selectedGap = this.selectedRangeValue[1] - this.selectedRangeValue[0]; + const tempStartPosition = 100 - (selectedGap * 100) / gap; + this.selectedStartPosition = Math.min(100, Math.max(0, tempStartPosition)); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/components/url-redirector/index.ts b/web/src/main/webapp/v2/src/app/shared/components/url-redirector/index.ts new file mode 100644 index 000000000000..4182656f6fb7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/url-redirector/index.ts @@ -0,0 +1 @@ +export * from './url-redirector.component'; diff --git a/web/src/main/webapp/v2/src/app/shared/components/url-redirector/url-redirector.component.ts b/web/src/main/webapp/v2/src/app/shared/components/url-redirector/url-redirector.component.ts new file mode 100644 index 000000000000..4683d5bab98f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/components/url-redirector/url-redirector.component.ts @@ -0,0 +1,59 @@ +import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { WebAppSettingDataService, UrlRouteManagerService } from 'app/shared/services'; + +@Component({ + selector: 'pp-url-redirector', + template: '' +}) +export class UrlRedirectorComponent { + + constructor( + private activatedRoute: ActivatedRoute, + private webAppSettingDataService: WebAppSettingDataService, + private urlRouteManagerService: UrlRouteManagerService, + ) { + // @ALERT + // URL Redirector가 호출되는 상황은 RouteInfoCollectorService가 호출되지 않는 상황이기 때문에 + // RouteInfoCollectorService를 통해 초기화 되는 UrlStateNotifactionService 의 URL 초기화 정보를 사용하면 안됨. + this.activatedRoute.data.subscribe((urlData: any) => { + const params = this.getUrlParams(); + if (params.period) { + this.urlRouteManagerService.move({ + url: [ + urlData['path'] || params.startPath, + params.application, + params.period + ], + needServerTimeRequest: true + }); + } else { + this.urlRouteManagerService.move({ + url: [ + urlData['path'] || params.startPath, + params.application, + this.webAppSettingDataService.getUserDefaultPeriod().getValueWithTime() + ], + needServerTimeRequest: true + }); + } + }); + } + private getUrlParams(): any { + const params: { [key: string]: string } = {}; + let activatedRoute: ActivatedRoute | null = this.activatedRoute; + while ( activatedRoute ) { + activatedRoute.snapshot.paramMap.keys.forEach((key: string) => { + params[key] = activatedRoute.snapshot.paramMap.get(key); + }); + if ( activatedRoute.parent === null ) { + break; + } else { + activatedRoute = activatedRoute.parent; + } + } + params['startPath'] = activatedRoute.snapshot.root.firstChild.url[0].path; + return params; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/directives/context-popup.directive.ts b/web/src/main/webapp/v2/src/app/shared/directives/context-popup.directive.ts new file mode 100644 index 000000000000..ef30574d50f9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/directives/context-popup.directive.ts @@ -0,0 +1,8 @@ +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[ppContextPopup]', +}) +export class ContextPopupDirective { + constructor(public viewContainerRef: ViewContainerRef) {} +} diff --git a/web/src/main/webapp/v2/src/app/shared/directives/index.ts b/web/src/main/webapp/v2/src/app/shared/directives/index.ts new file mode 100644 index 000000000000..4e3066282c30 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/directives/index.ts @@ -0,0 +1,9 @@ +import { SettingHeightDirective } from './setting-height.directive'; +import { ContextPopupDirective } from './context-popup.directive'; +import { SplitterDirective } from './splitter.directive'; + +export const DIRECTIVES = [ + SettingHeightDirective, + ContextPopupDirective, + SplitterDirective +]; diff --git a/web/src/main/webapp/v2/src/app/shared/directives/search-input.directive.ts b/web/src/main/webapp/v2/src/app/shared/directives/search-input.directive.ts new file mode 100644 index 000000000000..bcdaa6c2bdcf --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/directives/search-input.directive.ts @@ -0,0 +1,83 @@ +import { Directive, OnInit, OnChanges, OnDestroy, SimpleChanges, EventEmitter, HostListener, Input, Output } from '@angular/core'; +import { Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, filter, takeUntil } from 'rxjs/operators'; + +@Directive({ + selector: '[ppSearchInput]' +}) +export class SearchInputDirective implements OnInit, OnChanges, OnDestroy { + @Input() searchMinLength = 0; + @Input() searchMaxLength = Number.MAX_SAFE_INTEGER; + @Input() useEnter: boolean; + @Input() debounceTime = 100; + @Output() outSearch: EventEmitter = new EventEmitter(); + @Output() outArrowKey: EventEmitter = new EventEmitter(); + private unsubscribe: Subject = new Subject(); + private userInput: Subject = new Subject(); + + @HostListener('keydown', ['$event']) onKeyDown($event: KeyboardEvent): void { + const keyCode = $event.keyCode; + if (this.isArrowKey(keyCode)) { + this.outArrowKey.emit(keyCode); + return; + } + } + @HostListener('keyup', ['$event']) onKeyUp($event: KeyboardEvent): void { + const keyCode = $event.keyCode; + const element = ($event.srcElement as HTMLInputElement); + const value = element.value.trim(); + if (this.isArrowKey(keyCode)) { + return; + } + if (this.isESC(keyCode)) { + element.value = ''; + return; + } + if (this.useEnter) { + if (this.isEnter(keyCode) && this.isValidLength(value)) { + this.outSearch.next(value); + } + } else { + this.userInput.next(value); + } + } + constructor() {} + ngOnInit() {} + ngOnChanges(changes: SimpleChanges) { + if (changes['useEnter']) { + if (this.useEnter) { + this.unsubscribe.next(); + } else { + this.setObservable(); + } + } + } + ngOnDestroy() { + this.unsubscribe.next(); + this.unsubscribe.complete(); + } + private setObservable(): void { + this.userInput.pipe( + takeUntil(this.unsubscribe), + debounceTime(this.debounceTime), + distinctUntilChanged(), + filter((query: string) => { + return this.isValidLength(query); + }) + ).subscribe((query: string) => { + this.outSearch.next(query); + }); + } + private isValidLength(value: string): boolean { + return value.length === 0 || (value.length >= this.searchMinLength && value.length < this.searchMaxLength); + } + private isESC(key: number): boolean { + return key === 27; + } + private isEnter(key: number): boolean { + return key === 13; + } + private isArrowKey(key: number): boolean { + return key >= 37 && key <= 40; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/directives/setting-height.directive.ts b/web/src/main/webapp/v2/src/app/shared/directives/setting-height.directive.ts new file mode 100644 index 000000000000..92d173051cfc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/directives/setting-height.directive.ts @@ -0,0 +1,38 @@ +import { Directive, ElementRef, OnInit, OnChanges, SimpleChanges, Renderer2, Input } from '@angular/core'; +import { WindowRefService } from 'app/shared/services'; + +@Directive({ + selector: '[ppSettingHeight]' +}) +export class SettingHeightDirective implements OnInit, OnChanges { + // tslint:disable-next-line:no-input-rename + @Input('ppSettingHeight') heightConfig: {[key: string]: any}; + + constructor( + private elementRef: ElementRef, + private renderer: Renderer2, + private windowRefService: WindowRefService + ) { } + + ngOnChanges(changes: SimpleChanges) { + this.setHeight(this.getHeightValue()); + } + + ngOnInit() { + } + + private getHeightValue(): string { + return this.heightConfig.height || (this.heightConfig.setHeightAuto ? 'auto' : this.getComputedHeight()); + } + + private getComputedHeight(): string { + const width = this.windowRefService.nativeWindow.getComputedStyle(this.elementRef.nativeElement).getPropertyValue('width'); + const height = Number(width.replace(/px/, '')) / this.heightConfig.ratio; + + return height + 'px'; + } + + private setHeight(height: string): void { + this.renderer.setStyle(this.elementRef.nativeElement, 'height', height); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/directives/splitter.directive.ts b/web/src/main/webapp/v2/src/app/shared/directives/splitter.directive.ts new file mode 100644 index 000000000000..0997ad82515c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/directives/splitter.directive.ts @@ -0,0 +1,20 @@ +import { Directive, OnInit, HostListener } from '@angular/core'; +import { GutterEventService } from 'app/shared/services'; + +@Directive({ + selector: '[ppSplitter]' +}) +export class SplitterDirective implements OnInit { + constructor( + private gutterEventService: GutterEventService + ) { } + + ngOnInit() { + } + + @HostListener('dragEnd', ['$event']) + @HostListener('dragProgress', ['$event']) + onDragEndProgress({sizes}: {sizes: number[]}) { + this.gutterEventService.resizedGutter(sizes); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/index.ts b/web/src/main/webapp/v2/src/app/shared/index.ts new file mode 100644 index 000000000000..f1499d1a1708 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/index.ts @@ -0,0 +1,107 @@ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { ClipboardModule } from 'ngx-clipboard'; + +import { ClickOutsideModule } from 'ng-click-outside'; +import { TranslateReplaceService } from './services/translate-replace.service'; +import { ServerTimeDataService } from './services/server-time-data.service'; +import { WebAppSettingDataService } from './services/web-app-setting-data.service'; +import { ComponentDefaultSettingDataService } from './services/component-default-setting-data.service'; +import { RouteInfoCollectorService } from './services/route-info-collector.service'; +import { ServerTimeResolverService } from './services/server-time-resolver.service'; +import { NewUrlStateNotificationService } from './services/new-url-state-notification.service'; +import { UrlRouteManagerService } from './services/url-route-manager.service'; +import { SystemConfigurationDataService } from './services/system-configuration-data.service'; +import { SystemConfigurationResolverService } from './services/system-configuration-resolver.service'; +import { SplitRatioService } from './services/split-ratio.service'; +import { GutterEventService } from './services/gutter-event.service'; +import { AjaxExceptionCheckerService } from './services/ajax-exception-checker.service'; +import { ApplicationListResolverService } from './services/application-list-resolver.service'; +import { AnalyticsService } from './services/analytics.service'; +import { BrowserSupportCheckService } from './services/browser-support-check.service'; +import { AgentHistogramDataService } from './services/agent-histogram-data.service'; +import { TransactionDetailDataService } from './services/transaction-detail-data.service'; +import { TransactionViewTypeService } from './services/transaction-view-type.service'; +import { StoreHelperService } from './services/store-helper.service'; +import { UrlValidateGuard } from './services/url-validate.guard'; + +import { HeaderLogoComponent } from './components/header-logo'; +import { EmptyContentsComponent, NoneComponent } from './components/empty-contents'; +import { UrlRedirectorComponent } from './components/url-redirector'; +import { LoadingComponent } from './components/loading'; +import { FilmForDisableComponent } from './components/film-for-disable'; +import { SimpleProgressSliderComponent } from './components/simple-progress-slider'; +import { SettingHeightDirective } from './directives/setting-height.directive'; +import { ContextPopupDirective } from './directives/context-popup.directive'; +import { SplitterDirective } from './directives/splitter.directive'; +import { SearchInputDirective } from './directives/search-input.directive'; +import { SafeHtmlPipe } from './pipes/safe-html.pipe'; +import { JSONTextParserPipe } from './pipes/json-text-parser.pipe'; +import { DynamicPopupService } from 'app/shared/services/dynamic-popup.service'; + +@NgModule({ + declarations: [ + NoneComponent, + HeaderLogoComponent, + EmptyContentsComponent, + UrlRedirectorComponent, + LoadingComponent, + FilmForDisableComponent, + SimpleProgressSliderComponent, + SafeHtmlPipe, + JSONTextParserPipe, + SettingHeightDirective, + ContextPopupDirective, + SplitterDirective, + SearchInputDirective + ], + imports: [ + CommonModule, + ClickOutsideModule + ], + exports: [ + CommonModule, + FormsModule, + ClipboardModule, + ClickOutsideModule, + HeaderLogoComponent, + EmptyContentsComponent, + UrlRedirectorComponent, + LoadingComponent, + FilmForDisableComponent, + SimpleProgressSliderComponent, + SafeHtmlPipe, + JSONTextParserPipe, + SettingHeightDirective, + ContextPopupDirective, + SplitterDirective, + SearchInputDirective + ], + providers: [ + TranslateReplaceService, + ServerTimeDataService, + ServerTimeResolverService, + ComponentDefaultSettingDataService, + RouteInfoCollectorService, + WebAppSettingDataService, + NewUrlStateNotificationService, + UrlRouteManagerService, + SystemConfigurationDataService, + SystemConfigurationResolverService, + SplitRatioService, + GutterEventService, + AjaxExceptionCheckerService, + ApplicationListResolverService, + AnalyticsService, + BrowserSupportCheckService, + AgentHistogramDataService, + TransactionDetailDataService, + TransactionViewTypeService, + StoreHelperService, + UrlValidateGuard, + DynamicPopupService + ] +}) +export class SharedModule { } diff --git a/web/src/main/webapp/v2/src/app/shared/models/app-state.ts b/web/src/main/webapp/v2/src/app/shared/models/app-state.ts new file mode 100644 index 000000000000..6ba6b8b5fcb7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/models/app-state.ts @@ -0,0 +1,4 @@ +export interface AppState { + timezone: string; + [key: string]: any; +} diff --git a/web/src/main/webapp/v2/src/app/shared/models/index.ts b/web/src/main/webapp/v2/src/app/shared/models/index.ts new file mode 100644 index 000000000000..2c10bf1a61e2 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/models/index.ts @@ -0,0 +1,3 @@ +export * from './url-path'; +export * from './url-path-id'; +export * from './url-query'; diff --git a/web/src/main/webapp/v2/src/app/shared/models/url-path-id.ts b/web/src/main/webapp/v2/src/app/shared/models/url-path-id.ts new file mode 100644 index 000000000000..08ed675936be --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/models/url-path-id.ts @@ -0,0 +1,142 @@ +import { Application, Period, EndTime } from 'app/core/models'; + +export interface IUrlPathId { + get(): T; + equals(value: IUrlPathId): boolean; + toString(): string; +} + +export class UrlApplication implements IUrlPathId { + constructor(private application: IApplication) {} + equals(value: IUrlPathId): boolean { + if (value === null) { + return false; + } + return this.application.equals(value.get()); + } + get(): IApplication { + return this.application; + } + toString(): string { + return this.application.toString(); + } +} +export class UrlPeriod implements IUrlPathId { + constructor(private period: Period) {} + equals(value: IUrlPathId): boolean { + if (value === null) { + return false; + } + return this.period.equals(value.get()); + } + get(): Period { + return this.period; + } + toString(): string { + return this.period.toString(); + } +} +export class UrlEndTime implements IUrlPathId { + constructor(private endTime: EndTime) {} + equals(value: IUrlPathId): boolean { + if (value === null) { + return false; + } + return this.endTime.equals(value.get()); + } + get(): EndTime { + return this.endTime; + } + toString(): string { + return this.endTime.toString(); + } +} +export class UrlGeneral implements IUrlPathId { + constructor(private value: T) {} + equals(target: IUrlPathId): boolean { + if (target === null) { + return false; + } + return this.value.toString() === target.toString(); + } + get(): T { + return this.value; + } + toString(): string { + return this.value.toString(); + } +} + +export class UrlPathId { + static APPLICATION = 'application'; + static PERIOD = 'period'; + static END_TIME = 'endTime'; + static FILTER = 'filter'; + static HINT = 'hint'; + static REAL_TIME = 'realtime'; + static AGENT_ID = 'agentId'; + static TRANSACTION_INFO = 'transactionInfo'; + static TRACE_ID = 'traceId'; + static FOCUS_TIMESTAMP = 'focusTimestamp'; + static SPAN_ID = 'spanId'; + static VIEW_TYPE = 'viewType'; + static AGENT_LIST = 'agentList'; + static PAGE = 'page'; + static SEARCH_ID = 'searchId'; + static STAT = 'stat'; + static AGENT = 'agent'; + + constructor() {} + static getPathIdList(): string[] { + return [ + UrlPathId.AGENT_LIST, + UrlPathId.AGENT_ID, + UrlPathId.APPLICATION, + UrlPathId.END_TIME, + UrlPathId.FILTER, + UrlPathId.FOCUS_TIMESTAMP, + UrlPathId.HINT, + UrlPathId.PAGE, + UrlPathId.PERIOD, + UrlPathId.REAL_TIME, + UrlPathId.SEARCH_ID, + UrlPathId.SPAN_ID, + UrlPathId.TRACE_ID, + UrlPathId.TRANSACTION_INFO, + UrlPathId.VIEW_TYPE, + UrlPathId.STAT, + UrlPathId.AGENT + ]; + } +} + +export class UrlPathIdFactory { + constructor() {} + static createPath(paramName: string, paramValue: string): IUrlPathId { + switch (paramName) { + case UrlPathId.APPLICATION: + const params = paramValue.split('@'); + return new UrlApplication(new Application(params[0], params[1], 0)) as IUrlPathId; + case UrlPathId.PERIOD: + return new UrlPeriod(new Period(Period.parseToMinute(paramValue))) as IUrlPathId; + case UrlPathId.END_TIME: + return new UrlEndTime(new EndTime(paramValue)) as IUrlPathId; + case UrlPathId.PAGE: + return new UrlGeneral(paramValue || '2') as IUrlPathId; + case UrlPathId.FILTER: + case UrlPathId.HINT: + case UrlPathId.REAL_TIME: + case UrlPathId.AGENT_ID: + case UrlPathId.TRANSACTION_INFO: + case UrlPathId.TRACE_ID: + case UrlPathId.FOCUS_TIMESTAMP: + case UrlPathId.SPAN_ID: + case UrlPathId.VIEW_TYPE: + case UrlPathId.AGENT_LIST: + case UrlPathId.SEARCH_ID: + return new UrlGeneral(paramValue) as IUrlPathId; + default: + return new UrlGeneral(paramValue) as IUrlPathId; + } + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/models/url-path.ts b/web/src/main/webapp/v2/src/app/shared/models/url-path.ts new file mode 100644 index 000000000000..14eeb673c801 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/models/url-path.ts @@ -0,0 +1,33 @@ +export class UrlPath { + static ADMIN = 'admin'; + static FILTERED_MAP = 'filteredMap'; + static INSPECTOR = 'inspector'; + static MAIN = 'main'; + static REAL_TIME = 'realtime'; + static SCATTER_FULL_SCREEN_MODE = 'scatterFullScreenMode'; + static THREAD_DUMP = 'threadDump'; + static TRANSACTION_DETAIL = 'transactionDetail'; + static TRANSACTION_LIST = 'transactionList'; + static TRANSACTION_VIEW = 'transactionView'; + static BROWSER_NOT_SUPPORT = 'browserNotSupported'; + static ERROR = 'error'; + + constructor() {} + static getParamList(): string[] { + return [ + UrlPath.ADMIN, + UrlPath.ERROR, + UrlPath.FILTERED_MAP, + UrlPath.INSPECTOR, + UrlPath.MAIN, + UrlPath.REAL_TIME, + UrlPath.SCATTER_FULL_SCREEN_MODE, + UrlPath.THREAD_DUMP, + UrlPath.TRANSACTION_DETAIL, + UrlPath.TRANSACTION_LIST, + UrlPath.TRANSACTION_VIEW + ]; + } +} + +export default UrlPath; diff --git a/web/src/main/webapp/v2/src/app/shared/models/url-query.ts b/web/src/main/webapp/v2/src/app/shared/models/url-query.ts new file mode 100644 index 000000000000..510de9a2819c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/models/url-query.ts @@ -0,0 +1,54 @@ +export interface IUrlQuery { + get(): T; + equals(value: IUrlQuery): boolean; + toString(): string; +} + +export class UrlQueryClass implements IUrlQuery { + constructor(private value: T) {} + equals(target: IUrlQuery): boolean { + if (target === null) { + return false; + } + return this.value.toString() === target.toString(); + } + get(): T { + return this.value; + } + toString(): string { + return this.value.toString(); + } +} + +export class UrlQuery { + static BIDIRECTIONAL = 'bidirectional'; + static INBOUND = 'inbound'; + static OUTBOUND = 'outbound'; + static WAS_ONLY = 'wasOnly'; + + constructor() {} + static getQueryList(): string[] { + return [ + UrlQuery.BIDIRECTIONAL, + UrlQuery.INBOUND, + UrlQuery.OUTBOUND, + UrlQuery.WAS_ONLY, + ]; + } +} + +export class UrlQueryFactory { + constructor() {} + static createQuery(queryName: string, queryValue?: T): IUrlQuery { + switch (queryName) { + case UrlQuery.INBOUND: + case UrlQuery.OUTBOUND: + return new UrlQueryClass(queryValue) as IUrlQuery; + case UrlQuery.BIDIRECTIONAL: + case UrlQuery.WAS_ONLY: + return new UrlQueryClass(queryValue) as IUrlQuery; + default: + return new UrlQueryClass(queryValue) as IUrlQuery; + } + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/pipes/index.ts b/web/src/main/webapp/v2/src/app/shared/pipes/index.ts new file mode 100644 index 000000000000..19c411774261 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/pipes/index.ts @@ -0,0 +1,7 @@ +import { JSONTextParserPipe } from './json-text-parser.pipe'; +import { SafeHtmlPipe } from './safe-html.pipe'; + +export const PIPES = [ + SafeHtmlPipe, + JSONTextParserPipe +]; diff --git a/web/src/main/webapp/v2/src/app/shared/pipes/json-text-parser.pipe.ts b/web/src/main/webapp/v2/src/app/shared/pipes/json-text-parser.pipe.ts new file mode 100644 index 000000000000..e8521cfc8fb6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/pipes/json-text-parser.pipe.ts @@ -0,0 +1,45 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { WebAppSettingDataService } from 'app/shared/services'; +/** + * sson에서 icon, image등의 키워드를 캐치해서 + * 맞는 icon, image로 해당 텍스트를 대체 또는 추가. + * [Type]:{property=value} + * Chaining with '|' + * ex: [ICON]:{className=fa-clock-o\\style=font-size:17px}|[TEXT]:{value=X-Axis} + */ +@Pipe({ name: 'jsonTextParser' }) +export class JSONTextParserPipe implements PipeTransform { + constructor( + private webAppSettingDataService: WebAppSettingDataService + ) {} + + transform(text: string): string { + if (text) { + return text.split('|').map((textElem: string) => { + const i = textElem.indexOf(':'); + const textType = textElem.substr(0, i).replace(/\[|\]/g, ''); + const textInfoArr = textElem.substr(i + 1).replace(/\{|\}/g, '').split('\\').map((textInfo: string) => { + return textInfo.split('=')[1]; + }); + + switch (textType) { + case 'ICON': + return ``; + case 'TEXT': + return textInfoArr[0]; + case 'IMAGE': + const path = this.webAppSettingDataService.getImagePath(); + const extension = this.webAppSettingDataService.getImageExt(); + + return ``; + case 'LINK': + return `${textInfoArr[3]}`; + default: + return text; + } + }).join(' '); + } else { + return ''; + } + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/pipes/safe-html.pipe.ts b/web/src/main/webapp/v2/src/app/shared/pipes/safe-html.pipe.ts new file mode 100644 index 000000000000..f147803879fc --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/pipes/safe-html.pipe.ts @@ -0,0 +1,13 @@ +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ name: 'safeHtml' }) +export class SafeHtmlPipe implements PipeTransform { + constructor( + private sanitized: DomSanitizer + ) {} + + transform(value: string): SafeHtml { + return this.sanitized.bypassSecurityTrustHtml(value); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/agent-histogram-data.service.ts b/web/src/main/webapp/v2/src/app/shared/services/agent-histogram-data.service.ts new file mode 100644 index 000000000000..baa4ff678c1d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/agent-histogram-data.service.ts @@ -0,0 +1,128 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import * as moment from 'moment-timezone'; +import { Observable, of } from 'rxjs'; +import { shareReplay } from 'rxjs/operators'; +import { NewUrlStateNotificationService } from 'app/shared/services/new-url-state-notification.service'; + +@Injectable() +export class AgentHistogramDataService { + readonly url = 'getResponseTimeHistogramDataV2.pinpoint'; + + private previousFrom: number; + private previousTo: number; + private previousName: string; + private previousCode: string; + private previousKey: string; + private previousObservable: any; + constructor( + private http: HttpClient, + private newUrlStateNotificationService: NewUrlStateNotificationService + ) {} + getData(key: string, applicationName: string, serviceTypeCode: string, serverMapData: any, from?: number, to?: number): Observable { + if (this.isCached(key, applicationName, serviceTypeCode, from, to) === false) { + this.previousObservable = this.http.post(this.url, this.makeBodyData(key, serverMapData), this.makeRequestOptionsArgs(applicationName, serviceTypeCode, from, to)).pipe( + shareReplay(1) + ); + this.previousFrom = from || this.newUrlStateNotificationService.getStartTimeToNumber(); + this.previousTo = to || this.newUrlStateNotificationService.getEndTimeToNumber(); + this.previousName = applicationName; + this.previousCode = serviceTypeCode; + this.previousKey = key; + } + return this.previousObservable; + } + isCached(key: string, applicationName: string, serviceTypeCode: string, from?: number, to?: number): boolean { + return this.previousCode === serviceTypeCode && + this.previousKey === key && + this.previousName === applicationName && + this.previousFrom === (from || this.newUrlStateNotificationService.getStartTimeToNumber()) && + this.previousTo === (to || this.newUrlStateNotificationService.getEndTimeToNumber()); + } + private makeRequestOptionsArgs(applicationName: string, serviceTypeCode: string, from?: number, to?: number): object { + return { + params: { + applicationName: applicationName, + serviceTypeCode: serviceTypeCode, + from: from || this.newUrlStateNotificationService.getStartTimeToNumber(), + to: to || this.newUrlStateNotificationService.getEndTimeToNumber() + } + }; + } + private makeBodyData(nodeKey: string, serverMapData: any): any { + const linkedNodeData: { [key: string]: any } = { + from: [], + to: [] + }; + serverMapData.linkList.forEach((link: ILinkInfo) => { + if ( link.from === nodeKey ) { + if ( link.targetInfo instanceof Array ) { + link.targetInfo.forEach((targetLinkInfo: ILinkInfo) => { + linkedNodeData.to.push([targetLinkInfo.targetInfo.applicationName, targetLinkInfo.targetInfo.serviceTypeCode]); + }); + } else { + linkedNodeData.to.push([link.targetInfo.applicationName, link.targetInfo.serviceTypeCode]); + } + } else if ( link.to === nodeKey ) { + linkedNodeData.from.push([link.sourceInfo.applicationName, link.sourceInfo.serviceTypeCode]); + } + }); + return linkedNodeData; + } + makeChartDataForResponseSummary(histogramData: IResponseTime | IResponseMilliSecondTime, yMax?: number): any { + let newData: { + keys: string[], + values: number[], + max?: number + }; + if (histogramData) { + newData = { + keys: Object.keys(histogramData), + values: [] + }; + newData.keys.forEach((key: string, index: number) => { + newData['values'][index] = histogramData[key]; + }); + } else { + return newData; + } + if (yMax) { + newData['max'] = yMax; + } + return newData; + } + makeChartDataForLoad(histogramData: IHistogram[], timezone: string, dateFormat: string[], yMax?: number): any { + let newData: { + keyValues: { + key: string; + values: number[]; + }[]; + labels: string[]; + max?: number; + }; + if (histogramData) { + newData = { + labels: [], + keyValues: [] + }; + histogramData.forEach((histogram: IHistogram, index: number) => { + newData.keyValues[index] = { + key: histogram.key, + values: [] + }; + histogram.values.forEach((aValue: number[]) => { + newData.keyValues[index].values.push(aValue[1]); + if (index === 0) { + newData.labels.push(moment(aValue[0]).tz(timezone).format(dateFormat[0]) + '#' + moment(aValue[0]).tz(timezone).format(dateFormat[1])); + } + }); + }); + } else { + return newData; + } + if (yMax) { + newData['max'] = yMax; + } + return newData; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/ajax-exception-checker.service.ts b/web/src/main/webapp/v2/src/app/shared/services/ajax-exception-checker.service.ts new file mode 100644 index 000000000000..a54d6fd602e1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/ajax-exception-checker.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class AjaxExceptionCheckerService { + constructor() { + } + + isAjaxException(data: AjaxException | any): data is AjaxException { + return (data).exception !== undefined; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/analytics.service.ts b/web/src/main/webapp/v2/src/app/shared/services/analytics.service.ts new file mode 100644 index 000000000000..6a2369f58ae7 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/analytics.service.ts @@ -0,0 +1,110 @@ +import { Injectable } from '@angular/core'; + +import { WindowRefService } from 'app/shared/services/window-ref.service'; +import { WebAppSettingDataService } from 'app/shared/services/web-app-setting-data.service'; + +export enum TRACKED_EVENT_LIST { + TOGGLE_HELP_VIEWER = 'Toggle HelpViewer', + VERSION = 'Version', + SELECT_APPLICATION = 'Select Application', + SELECT_PERIOD = 'Select Period', + SEARCH_NODE = 'Search Node', + SELECT_APPLICATION_IN_SEARCH_RESULT = 'Select Application in Search Result', + CLICK_NODE = 'Click Node', + CLICK_NODE_IN_GROUPED_VIEW = 'Click Node in Grouped View', + SHOW_GROUPED_NODE_VIEW = 'Show Grouped Node View', + CLICK_LINK = 'Click Link', + CLICK_LINK_IN_GROUPED_VIEW = 'Click Link in GROUPED View', + SHOW_GROUPED_LINK_VIEW = 'Show Grouped Link View', + CLICK_SCATTER_SETTING = 'Click Scatter Setting', + DOWNLOAD_SCATTER = 'Download Scatter', + GO_TO_FULL_SCREEN_SCATTER = 'Go to FullScreen Scatter', + CLICK_RESPONSE_GRAPH = 'Click Response Graph', + CLICK_LOAD_GRAPH = 'Click Load Graph', + SHOW_SERVER_LIST = 'Show Server List', + OPEN_INSPECTOR = 'Open Inspector', + CLICK_FILTER_TRANSACTION = 'Click Filter Transaction', + OPEN_FILTER_TRANSACTION_WIZARD = 'Open Filter Transaction Wizard', + CLICK_callTree = 'Click CallTree Tab', + CLICK_serverMap = 'Click ServerMap Tab', + CLICK_timeline = 'Click Timeline Tab', + SELECT_TRANSACTION = 'Select Transaction', + OPEN_TRANSACTION_VIEW = 'Open Transaction View', + CLICK_heap = 'Click Heap in Transaction View', + CLICK_nonHeap = 'Click Non Heap in Transaction View', + CLICK_cpu = 'Click CPU Load in Transaction View', + REFRESH_SERVER_MAP = 'Refresh Server Map', + SET_SERVER_MAP_OPTION = 'Set ServerMap Option', + PIN_UP_REAL_TIME_CHART = 'Pin up RealTime Chart', + REMOVE_PIN_ON_REAL_TIME_CHART = 'Remove Pin on RealTime Chart', + TOGGLE_SERVER_TYPE_DETAIL = 'Toggle Server Type Detail', + SELECT_AGENT = 'Select Agent', + SET_PERIOD_AS_REAL_TIME = 'Set Period as RealTime', + OPEN_THREAD_DUMP = 'Open Thread Dump', + OPEN_CONFIGURATION_POPUP = 'Open Configuration Popup', + SET_BOUND_IN_CONFIGURATION = 'Set Bound in Configuration', + SET_SEARCH_PERIOD_IN_CONFIGURATION = 'Set Search Period in Configuration', + SET_FAVORITE_APPLICATION_IN_CONFIGURATION = 'Set Favorite Application in Configuration', + SET_TIMEZONE_IN_CONFIGURATION = 'Set Timezone in Configuration', + SET_DATE_FORMAT_IN_CONFIGURATION = 'Set Date Format in Configuration', + TOGGLE_PERIOD_SELECT_TYPE = 'Toggle Period Select Type', + CLICK_MORE_STATE_BUTTON = 'Click MORE State Button', + CLICK_RELOAD_APPLICATION_LIST_BUTTON = 'Click Reload Application List Button', + CLICK_FIXED_PERIOD_MOVE_BUTTON = 'Click Fixed Period Move Button', + OPEN_INSPECTOR_WITH_AGENT = 'Open Inspector with Agent', + OPEN_TRANSACTION_LIST = 'Open Transaction List', + GO_TO_APPLICATION_INSPECTOR = 'Go to Application Inspector', + GO_TO_AGENT_INSPECTOR = 'Go To Agent Inspector', + ZOOM_IN_TIMELINE = 'Zoom in Timeline', + ZOOM_OUT_TIMELINE = 'Zoom out Timeline', + MOVE_TO_PREV_ON_TIMELINE = 'Move to Prev on Timeline', + MOVE_TO_NEXT_ON_TIMELINE = 'Move to Next on Timeline', + MOVE_TO_NOW_ON_TIMELINE = 'Move to Now on Timeline', + CHANGE_POINTING_TIME_ON_TIMELINE = 'Change Pointing Time on Timeline', + CHANGE_SELECTION_RANGE_ON_TIMELINE = 'Change Selection Range on Timeline', + SEARCH_AGENT = 'Search Agent', + SEARCH_TRANSACTION = 'Search Transaction', + SELECT_SQL = 'Select SQL', + OPEN_TRANSACTION_DETAIL = 'Open Transaction Detail', + CHANGE_SCATTER_CHART_STATE = 'Change Scatter Chart State', + TOGGLE_SERVER_MAP_MERGE_STATE = 'Toggle ServerMap Merge State', + SELECT_TRANSACTION_IN_TIMELINE = 'Select Transaction in Timeline', +} + +@Injectable() +export class AnalyticsService { + private sendUsage: boolean; + private currentPage: string; + + constructor( + private windowRefService: WindowRefService, + private webAppSettingDataService: WebAppSettingDataService + ) { + this.webAppSettingDataService.isDataUsageAllowed().subscribe((result: boolean) => { + this.sendUsage = result; + }); + } + + trackPage(pageName: string): void { + if (this.sendUsage) { + if (this.windowRefService.nativeWindow.ga && typeof ga === 'function') { + this.currentPage = pageName; + ga('set', 'page', `/${pageName}`); + ga('send', 'pageview'); + } + } + } + /** + * eventCategory: 각 페이지 별 라우팅 주소 + * eventAction: 액션 정보 ex. 동영상 다운로드 + * eventLabel: 액션에 대한 추가 정보(Optional) ex. 동영상 이름 + * eventValue: 액션에 대한 추가 정보2(Optional) 단, 수치로 제공 ex. 동영상 다운로드 액션 이벤트 발생 시, 다운로드 시간. + */ + trackEvent(eventAction: string, eventLabel?: string, eventValue?: number): void { + if (this.sendUsage) { + if (this.windowRefService.nativeWindow.ga && typeof ga === 'function') { + ga('send', 'event', { eventCategory: this.currentPage, eventAction, eventLabel, eventValue }); + } + } + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/application-list-resolver.service.ts b/web/src/main/webapp/v2/src/app/shared/services/application-list-resolver.service.ts new file mode 100644 index 000000000000..219348bde75b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/application-list-resolver.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router'; +import { Observable, EMPTY } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { ApplicationListDataService } from 'app/core/components/application-list/application-list-data.service'; + +@Injectable() +export class ApplicationListResolverService implements Resolve { + constructor( + private router: Router, + private applicationListDataService: ApplicationListDataService) { } + resolve(reoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.applicationListDataService.getApplicationList().pipe( + catchError((error: any) => { + this.router.navigate(['/error']); + return EMPTY; + }) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/browser-support-check.service.ts b/web/src/main/webapp/v2/src/app/shared/services/browser-support-check.service.ts new file mode 100644 index 000000000000..32c81df1bec4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/browser-support-check.service.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@angular/core'; +import * as bowser from 'bowser'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable, of } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { TranslateReplaceService } from 'app/shared/services/translate-replace.service'; + +@Injectable() +export class BrowserSupportCheckService { + // 2018.06.01 기준 지원하는 브라우저 최신버전 + private latestBrowserList = [ + { + name: 'Chrome', + version: 66 + }, { + name: 'Firefox', + version: 60 + }, { + name: 'Safari', + version: 11 + }, { + name: 'Microsoft Edge', + version: 42 + } + ]; + + constructor( + private translateService: TranslateService, + private translateReplaceService: TranslateReplaceService, + ) {} + + private isBrowserSupported(): boolean { + const userBrowserInfo = { + name: bowser.name, + version: Math.trunc(Number(bowser.version)) + }; + + return this.latestBrowserList.findIndex((browserInfo) => { + return browserInfo.name === userBrowserInfo.name && browserInfo.version <= userBrowserInfo.version; + }) !== -1; + } + + getMessage(): Observable { + if (this.isBrowserSupported()) { + return of(''); + } else { + return this.translateService.get('SUPPORT.RESTRICT_USAGE').pipe( + map(((message: string) => { + return this.translateReplaceService.replace(message, bowser.name + ' ' + Math.trunc(Number(bowser.version))); + })) + ); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/component-default-setting-data.service.ts b/web/src/main/webapp/v2/src/app/shared/services/component-default-setting-data.service.ts new file mode 100644 index 000000000000..c6ccb1017c43 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/component-default-setting-data.service.ts @@ -0,0 +1,96 @@ +import { Injectable } from '@angular/core'; +import { Period } from 'app/core/models/period'; +import { UrlPath } from 'app/shared/models'; +@Injectable() +export class ComponentDefaultSettingDataService { + + private inboundList = ['1', '2', '3', '4']; + private outboundList = ['1', '2', '3', '4']; + private periodList = { + [UrlPath.MAIN]: [ + new Period(5, 'Last'), + new Period(20), + new Period(60), + new Period(180), + new Period(360), + new Period(720), + new Period(1440), + new Period(2880) + ], + [UrlPath.SCATTER_FULL_SCREEN_MODE]: [ + new Period(5, 'Last'), + new Period(20), + new Period(60), + new Period(180), + new Period(360), + new Period(720), + new Period(1440), + new Period(2880) + ], + [UrlPath.INSPECTOR]: [ + new Period(5, 'Last'), + new Period(20), + new Period(60), + new Period(180), + new Period(360), + new Period(720), + new Period(1440), + new Period(2880), + new Period(10080) + ], + [UrlPath.TRANSACTION_VIEW]: [ + new Period(20), + ] + }; + private maxPeriodTime = 60 * 24 * 2; // 2day + private colorByRequest: string[] = [ + 'rgba(52, 185, 148, 0.5)', // #34b994 + 'rgba(81, 175, 223, 0.5)', // #51afdf + 'rgba(255, 186, 0, 0.5)', // #ffba00 + 'rgba(230, 127, 34, 0.5)', // #e67f22 + 'rgba(233, 84, 89, 0.5)' // #e95459 + ]; + private dateFormatList = [ + // [default, default + timezone, default + millisecond, year+month+day, time, variation1, variation2] + ['YYYY.MM.DD HH:mm:ss', 'YYYY.MM.DD HH:mm:ss Z', 'YYYY.MM.DD HH:mm:ss SSS', 'YYYY.MM.DD', 'HH:mm:ss', 'MM.DD', 'HH:mm'], + ['YYYY.MM.DD h:mm:ss a', 'YYYY.MM.DD h:mm:ss a Z', 'YYYY.MM.DD h:mm:ss SSS a ', 'YYYY.MM.DD', 'h:mm:ss a', 'MM.DD', 'h:mm a'], + ['MMM D, YYYY HH:mm:ss', 'MMM D, YYYY HH:mm:ss Z', 'MMM D, YYYY HH:mm:ss SSS', 'MMM D, YYYY', 'HH:mm:ss', 'MMM D', 'HH:mm'], + ['MMM D, YYYY h:mm:ss a', 'MMM D, YYYY h:mm:ss a Z', 'MMM D, YYYY h:mm:ss SSS a', 'MMM D, YYYY', 'h:mm:ss a', 'MMM D', 'h:mm a'], + ['D MMM YYYY HH:mm:ss', 'D MMM YYYY HH:mm:ss Z', 'D MMM YYYY HH:mm:ss SSS', 'D MMM YYYY', 'HH:mm:ss', 'D MMM', 'HH:mm'], + ['D MMM YYYY h:mm:ss a', 'D MMM YYYY h:mm:ss a Z', 'D MMM YYYY h:mm:ss SSS a', 'D MMM YYYY', 'h:mm:ss a', 'D MMM', 'h:mm a'] + ]; + constructor() {} + getInboundList(): string[] { + return this.inboundList; + } + getOutboundList(): string[] { + return this.outboundList; + } + getPeriodList(path: string): Period[] { + return this.periodList[path] || this.periodList[UrlPath.MAIN] ; + } + getSystemDefaultPeriod(): Period { + return this.periodList[UrlPath.MAIN][0]; + } + getSystemDefaultTransactionViewPeriod(): Period { + return this.periodList[UrlPath.TRANSACTION_VIEW][0]; + } + getSystemDefaultInbound(): string { + return this.inboundList[0]; + } + getSystemDefaultOutbound(): string { + return this.outboundList[0]; + } + getMaxPeriodTime(): number { + return this.maxPeriodTime; + } + getColorByRequest(): string[] { + return this.colorByRequest; + } + getDateFormatList(): string[][] { + return this.dateFormatList; + } + getDefaultDateFormat(): string[] { + return this.dateFormatList[4]; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/dynamic-popup.service.ts b/web/src/main/webapp/v2/src/app/shared/services/dynamic-popup.service.ts new file mode 100644 index 000000000000..a0d67e25a6af --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/dynamic-popup.service.ts @@ -0,0 +1,118 @@ +import { + Injectable, + ComponentFactoryResolver, + ComponentRef, + ApplicationRef, + Injector, + EmbeddedViewRef, + Renderer2, + RendererFactory2, + EventEmitter +} from '@angular/core'; + +export interface DynamicPopup { + data?: any; + coord?: ICoordinate; + outCreated?: EventEmitter; + outClose?: EventEmitter; + outReInit?: EventEmitter<{[key: string]: any}>; // HelpViewer처럼 컴포넌트를 아예 destroy하고 새로 init해야 하는 경우 + onInputChange?: Function; +} + +interface IPopupParam { + data?: any; + coord?: ICoordinate; + component: any; + onCloseCallback?: Function; +} + +@Injectable() +export class DynamicPopupService { + private renderer: Renderer2; + private componentRef: ComponentRef; + + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + private appRef: ApplicationRef, + private injector: Injector, + rendererFactory: RendererFactory2, + ) { + this.renderer = rendererFactory.createRenderer(null, null); + } + + openPopup($param: IPopupParam): void { + const {data, coord, component} = $param; + + if (!this.componentRef) { + // The very first + this.initPopup($param); + } else if (this.componentRef && this.componentRef.instance instanceof component) { + // Update input binding + this.bindInputProps(this.componentRef.instance, data, coord); + } else { + // Close the current popup and create a new one + this.closePopup(); + this.initPopup($param); + } + } + + closePopup(): void { + this.appRef.detachView(this.componentRef.hostView); + this.componentRef.destroy(); + this.componentRef = null; + } + + private initPopup({data, coord, component, onCloseCallback}: IPopupParam): void { + this.componentRef = this.componentFactoryResolver.resolveComponentFactory(component).create(this.injector); + const popupComponent = this.componentRef.instance; + const domElem = (this.componentRef.hostView as EmbeddedViewRef).rootNodes[0] as HTMLElement; + + this.bindInputProps(popupComponent, data, coord); + this.bindOutputProps(popupComponent, domElem, onCloseCallback); + this.renderer.addClass(domElem, 'popup'); + this.renderer.appendChild((this.appRef.components[0].location).nativeElement, domElem); + this.appRef.attachView(this.componentRef.hostView); + } + + private bindInputProps(popupComponent: DynamicPopup, data: any, coord: ICoordinate): void { + if (popupComponent.onInputChange) { + popupComponent.onInputChange({data, coord}); + } + if (data) { + popupComponent.data = data; + } + if (coord) { + popupComponent.coord = coord; + } + } + + private bindOutputProps(popupComponent: DynamicPopup, domElem: HTMLElement, onCloseCallback: Function): void { + if (popupComponent.outCreated) { + popupComponent.outCreated.subscribe(({coordX, coordY}: {coordX: number, coordY: number}) => { + this.renderer.setStyle(domElem, 'left', coordX < 0 ? 0 : coordX + 'px'); + this.renderer.setStyle(domElem, 'top', coordY < 0 ? 0 : coordY + 'px'); + }); + } + if (popupComponent.outClose) { + popupComponent.outClose.subscribe(() => { + if (onCloseCallback) { + onCloseCallback(); + } + + this.closePopup(); + }); + } + if (popupComponent.outReInit) { + popupComponent.outReInit.subscribe(({data, coord}: {data: any, coord: ICoordinate}) => { + const component = this.componentRef.componentType; + + this.closePopup(); + this.openPopup({ + data, + coord, + component + }); + }); + } + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/gutter-event.service.ts b/web/src/main/webapp/v2/src/app/shared/services/gutter-event.service.ts new file mode 100644 index 000000000000..42ad42b90844 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/gutter-event.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +import { NewUrlStateNotificationService } from 'app/shared/services/new-url-state-notification.service'; +import { SplitRatioService } from './split-ratio.service'; + +@Injectable() +export class GutterEventService { + private outGutterResized: BehaviorSubject; + onGutterResized$: Observable; + + constructor( + private newUrlStateNotificationService: NewUrlStateNotificationService, + private splitRatioService: SplitRatioService + ) { + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + filter((urlService: NewUrlStateNotificationService) => !!urlService), + ).subscribe((urlService: NewUrlStateNotificationService) => { + const view = urlService.getStartPath(); + + this.outGutterResized = new BehaviorSubject(this.splitRatioService.getSplitRatio(view)); + this.onGutterResized$ = this.outGutterResized.asObservable(); + }); + } + + resizedGutter(sizes: number[]): void { + this.outGutterResized.next(sizes); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/index.ts b/web/src/main/webapp/v2/src/app/shared/services/index.ts new file mode 100644 index 000000000000..77c59487cf97 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/index.ts @@ -0,0 +1,23 @@ +export * from './agent-histogram-data.service'; +export * from './ajax-exception-checker.service'; +export * from './analytics.service'; +export * from './application-list-resolver.service'; +export * from './browser-support-check.service'; +export * from './component-default-setting-data.service'; +export * from './gutter-event.service'; +export * from './new-url-state-notification.service'; +export * from './route-info-collector.service'; +export * from './server-time-data.service'; +export * from './server-time-resolver.service'; +export * from './split-ratio.service'; +export * from './store-helper.service'; +export * from './system-configuration-data.service'; +export * from './system-configuration-resolver.service'; +export * from './transaction-detail-data.service'; +export * from './transaction-view-type.service'; +export * from './translate-replace.service'; +export * from './url-route-manager.service'; +export * from './url-validate.guard'; +export * from './web-app-setting-data.service'; +export * from './window-ref.service'; +export * from './dynamic-popup.service'; diff --git a/web/src/main/webapp/v2/src/app/shared/services/new-url-state-notification.service.ts b/web/src/main/webapp/v2/src/app/shared/services/new-url-state-notification.service.ts new file mode 100644 index 000000000000..902896bc8d17 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/new-url-state-notification.service.ts @@ -0,0 +1,182 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { WebAppSettingDataService } from 'app/shared/services/web-app-setting-data.service'; +import { EndTime } from 'app/core/models/end-time'; +import { UrlPath, UrlPathIdFactory, UrlPathId, IUrlPathId, UrlQueryFactory, UrlQuery, IUrlQuery } from 'app/shared/models'; + +interface IGeneral { + [key: string]: any; +} +interface IUrlState { + [key: string]: { + prev: IUrlPathId | IUrlQuery; + curr: IUrlPathId | IUrlQuery; + }; +} + +@Injectable() +export class NewUrlStateNotificationService { + private startPath: string; + private urlState: IUrlState = {}; + private innerRouteData: IGeneral = {}; + private onUrlStateChange: BehaviorSubject = new BehaviorSubject(null); + + onUrlStateChange$: Observable; + constructor(private webAppSettingDataService: WebAppSettingDataService) { + this.onUrlStateChange$ = this.onUrlStateChange.asObservable(); + this.initState(); + } + private initState(): void { + UrlPathId.getPathIdList().forEach((path: string) => { + this.urlState[path] = { + prev: null, + curr: null + }; + }); + UrlQuery.getQueryList().forEach((query: string) => { + this.urlState[query] = { + prev: null, + curr: null + }; + }); + } + updateUrl(startPath: string, pathParams: IGeneral, queryParams: IGeneral, routeData: IGeneral): void { + const bStartPathChanged = this.updateStartPath(startPath); + const bPathChanged = this.updatePathId(pathParams); + const bQueryChanged = this.updateQuery(queryParams); + this.updateRouteData(routeData); + + if (bStartPathChanged || bPathChanged || bQueryChanged) { + // this.onUrlStateChange.next(this.urlState); + this.onUrlStateChange.next(this); + } + } + private updateStartPath(path: string): boolean { + if ( this.startPath === path ) { + return false; + } else { + this.startPath = path; + return true; + } + } + private updatePathId(pathParams: IGeneral): boolean { + let updated = false; + const hasValuePathIdList: string[] = []; + UrlPathId.getPathIdList().forEach((path: string) => { + if (this.changedPathId(path, pathParams[path])) { + this.changePathIdState(path, pathParams[path] ? UrlPathIdFactory.createPath(path, pathParams[path]) : null); + hasValuePathIdList.push(path); + updated = true; + } + }); + this.setConnectedPath(hasValuePathIdList, pathParams); + return updated; + } + private changedPathId(path: string, pathValue: any): boolean { + if (pathValue === null || pathValue === undefined) { + return this.urlState[path].curr !== null; + } else { + if (this.urlState[path].curr === null) { + return true; + } else { + return !UrlPathIdFactory.createPath(path, pathValue).equals(this.urlState[path].curr); + } + } + } + private changePathIdState(path: string, newPathIdObject: IUrlPathId): void { + this.urlState[path].prev = this.urlState[path].curr; + this.urlState[path].curr = newPathIdObject; + } + private setConnectedPath(hasValuePathIdList: string[], pathParams: IGeneral): void { + if (hasValuePathIdList.indexOf(UrlPathId.FOCUS_TIMESTAMP) !== -1) { + this.urlState[UrlPathId.END_TIME].prev = this.urlState[UrlPathId.END_TIME].curr; + this.urlState[UrlPathId.END_TIME].curr = UrlPathIdFactory.createPath(UrlPathId.END_TIME, EndTime.formatDate((Number(pathParams[UrlPathId.FOCUS_TIMESTAMP]) + (1000 * 60 * 10)))); + this.urlState[UrlPathId.PERIOD].prev = this.urlState[UrlPathId.PERIOD].curr; + this.urlState[UrlPathId.PERIOD].curr = UrlPathIdFactory.createPath(UrlPathId.PERIOD, this.webAppSettingDataService.getSystemDefaultTransactionViewPeriod().getValueWithTime()); + } + } + private updateQuery(queryParams: IGeneral): boolean { + let updated = false; + UrlQuery.getQueryList().forEach((query: string) => { + if (this.changedQuery(query, queryParams[query])) { + this.changeQueryState(query, queryParams[query] ? UrlQueryFactory.createQuery(query, queryParams[query]) : null); + updated = true; + } + }); + return updated; + } + private changedQuery(query: string, queryValue: any): boolean { + if (queryValue === null || queryValue === undefined) { + return this.urlState[query].curr !== null; + } else { + if (this.urlState[query].curr === null) { + return true; + } else { + return !(this.urlState[query].curr as IUrlQuery).equals(UrlQueryFactory.createQuery(query, queryValue)); + } + } + } + private changeQueryState(query: string, newQueryObject: IUrlQuery): void { + this.urlState[query].prev = this.urlState[query].curr; + this.urlState[query].curr = newQueryObject; + } + private updateRouteData(routeData: IGeneral) { + this.innerRouteData = routeData; + } + isRealTimeMode(type?: string): boolean { + if (typeof type === 'string') { + return type === UrlPath.REAL_TIME; + } else { + return this.innerRouteData['enableRealTimeMode'] || false; + } + } + showRealTimeButton(): boolean { + return this.innerRouteData['showRealTimeButton'] || false; + } + getUrlServerTimeData(): number { + return this.innerRouteData['serverTime']; + } + hasValue(...names: string[]): boolean { + return names.reduce((previous: boolean, name: string) => { + return previous && (this.urlState[name].curr === null ? false : true); + }, true); + } + getStartPath(): string { + return this.startPath || UrlPath.MAIN; + } + getPathValue(path: string): any { + return this.urlState[path].curr.get(); + } + getQueryValue(query: string): any { + return this.urlState[query].curr.get(); + } + getStartTimeToNumber(): number { + if (this.isRealTimeMode()) { + return this.getUrlServerTimeData() - (this.webAppSettingDataService.getSystemDefaultPeriod().getMiliSeconds()); + } else { + return this.getPathValue(UrlPathId.END_TIME).calcuStartTime(this.getPathValue(UrlPathId.PERIOD).getValue()).getDate().valueOf(); + } + } + getEndTimeToNumber(): number { + if (this.isRealTimeMode()) { + return this.getUrlServerTimeData(); + } else { + return this.getPathValue(UrlPathId.END_TIME).getDate().valueOf(); + } + } + isChanged(path: string): boolean { + if (this.urlState[path]) { + const { prev: prev, curr: curr } = this.urlState[path]; + if ( + (prev === null && curr !== null) || + (prev !== null && curr === null) || + (prev === null && curr === null) + ) { + return false; + } else { + return true; + } + } + return false; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/route-info-collector.service.ts b/web/src/main/webapp/v2/src/app/shared/services/route-info-collector.service.ts new file mode 100644 index 000000000000..16aa9334383d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/route-info-collector.service.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRoute, ActivatedRouteSnapshot, Router, NavigationEnd, ParamMap } from '@angular/router'; +import { filter } from 'rxjs/operators'; +import { NewUrlStateNotificationService } from './new-url-state-notification.service'; +import { AnalyticsService } from 'app/shared/services/analytics.service'; + +@Injectable() +export class RouteInfoCollectorService { + constructor( + private router: Router, + private activatedRoute: ActivatedRoute, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private analyticsService: AnalyticsService + ) { + this.router.events.pipe( + filter(event => event instanceof NavigationEnd) + ).subscribe((event: NavigationEnd) => { + const startPath = this.activatedRoute.snapshot.root.firstChild.url[0].path; + const innerData = {}; + const pathIds = {}; + const queryParams = {}; + this.collectUrlInfo(this.activatedRoute.snapshot.children, pathIds, queryParams, innerData); + this.newUrlStateNotificationService.updateUrl(startPath, pathIds, queryParams, innerData); + this.analyticsService.trackPage(startPath); + }); + } + private collectUrlInfo(activatedChildRouteSnapshot: ActivatedRouteSnapshot[], pathIds: any, queryParams: any, innerData: any): void { + if (activatedChildRouteSnapshot.length !== 0) { + for ( let i = 0 ; i < activatedChildRouteSnapshot.length ; i++ ) { + this.assign(pathIds, activatedChildRouteSnapshot[i].paramMap); + this.assign(queryParams, activatedChildRouteSnapshot[i].queryParamMap); + Object.assign(innerData, activatedChildRouteSnapshot[i].data); + this.collectUrlInfo(activatedChildRouteSnapshot[i].children, pathIds, queryParams, innerData); + } + } + } + private assign(data: any, mapData: ParamMap): void { + mapData.keys.forEach((key: string) => { + data[key] = mapData.get(key); + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/server-time-data.service.ts b/web/src/main/webapp/v2/src/app/shared/services/server-time-data.service.ts new file mode 100644 index 000000000000..b2974b8ac37f --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/server-time-data.service.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +interface IServerTime { + currentServerTime: number; +} + +@Injectable() +export class ServerTimeDataService { + + constructor(private http: HttpClient) { } + getServerTime(): Observable { + return this.http.get('serverTime.pinpoint').pipe( + map(res => { + return res.currentServerTime; + }) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/server-time-resolver.service.ts b/web/src/main/webapp/v2/src/app/shared/services/server-time-resolver.service.ts new file mode 100644 index 000000000000..bd8870fd9774 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/server-time-resolver.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router'; +import { Observable, of } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { ServerTimeDataService } from 'app/shared/services/server-time-data.service'; + +@Injectable() +export class ServerTimeResolverService implements Resolve { + + constructor(private serverTimeService: ServerTimeDataService) { } + resolve(reoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.serverTimeService.getServerTime().pipe( + catchError((error: IServerErrorFormat) => { + return of(Date.now()); + }) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/split-ratio.service.ts b/web/src/main/webapp/v2/src/app/shared/services/split-ratio.service.ts new file mode 100644 index 000000000000..88165d6ab784 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/split-ratio.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { UrlPath } from 'app/shared/models'; + +@Injectable() +export class SplitRatioService { + private splitRatioMap = new Map(); + + constructor() { + this.initSplitRatioMap(); + } + + private initSplitRatioMap(): void { + this.splitRatioMap.set(UrlPath.TRANSACTION_LIST, [30, 70]); + this.splitRatioMap.set(UrlPath.TRANSACTION_VIEW, [40, 60]); + } + + getSplitRatio(view: string): number[] { + return this.splitRatioMap.get(view); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/store-helper.service.ts b/web/src/main/webapp/v2/src/app/shared/services/store-helper.service.ts new file mode 100644 index 000000000000..897a559f8af5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/store-helper.service.ts @@ -0,0 +1,178 @@ +import { Injectable } from '@angular/core'; +import { Store, Action, select } from '@ngrx/store'; +import { Observable, Subject, iif } from 'rxjs'; +import { takeUntil, map, filter, debounceTime, distinctUntilChanged } from 'rxjs/operators'; + +import { + AppState, + STORE_KEY, + selectServerMapDisableState, + selectInfoPerServerVisibleState, + selectTimelineRange, + selectTimelineSelectedTime, + selectTimelineSelectionRange +} from 'app/shared/store'; +import { WebAppSettingDataService } from './web-app-setting-data.service'; + +@Injectable() +export class StoreHelperService { + private dateFormatList: string[][]; + constructor( + private store: Store, + private webAppSettingDataService: WebAppSettingDataService + ) { + this.dateFormatList = this.webAppSettingDataService.getDateFormatList(); + } + getApplicationList(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.APPLICATION_LIST, unsubscribe); + } + getFavoriteApplicationList(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.FAVORITE_APPLICATION_LIST, unsubscribe); + } + getTimezone(unsubscribe?: Subject): Observable { + return this.getObservable(STORE_KEY.TIMEZONE, unsubscribe); + } + getDateFormatIndex(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.DATE_FORMAT, unsubscribe); + } + getDateFormat(unsubscribe: Subject, index: number): Observable { + return this.getObservable(STORE_KEY.DATE_FORMAT, unsubscribe).pipe( + map((format: number) => { + return this.dateFormatList[format][index]; + }) + ); + } + getDateFormatArray(unsubscribe: Subject, ...index: number[]): Observable { + return this.getObservable(STORE_KEY.DATE_FORMAT, unsubscribe).pipe( + map((format: number) => { + return index.map((i: number) => { + return this.dateFormatList[format][i]; + }); + }) + ); + } + getAgentList(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.ADMIN_AGENT_LIST, unsubscribe).pipe( + filter((data: T) => { + return data ? true : false; + }) + ); + } + getServerAndAgentQuery(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.SERVER_AND_AGENT, unsubscribe).pipe( + debounceTime(100), + distinctUntilChanged() + ); + } + getHoverInfo(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.HOVER_ON_INSPECTOR_CHARTS, unsubscribe); + } + getServerMapTargetSelectedByList(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.SERVER_MAP_TARGET_SELECTED_BY_LIST, unsubscribe).pipe( + filter((target: any) => { + return (target && target.key) ? true : false; + }) + ); + } + getAgentSelection(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.AGENT_SELECTION, unsubscribe); + } + getAgentSelectionForServerList(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.AGENT_SELECTION_FOR_SERVER_LIST, unsubscribe); + } + getRealTimeScatterChartRange(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.REAL_TIME_SCATTER_CHART, unsubscribe).pipe( + filter((range: IScatterXRange) => { + if (range && range.from && range.to && range.from !== -1 && range.to !== -1) { + return true; + } + return false; + }) + ); + } + getScatterChartData(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.SCATTER_CHART, unsubscribe); + } + getServerMapData(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.SERVER_MAP_DATA, unsubscribe); + } + getServerMapLoadingState(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.SERVER_MAP_LOADING_STATE, unsubscribe); + } + getServerMapTargetSelected(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.SERVER_MAP_TARGET_SELECTED, unsubscribe); + } + getTransactionData(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.TRANSACTION_DATA, unsubscribe); + } + getTransactionDetailData(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.TRANSACTION_DETAIL_DATA, unsubscribe); + } + getServerListData(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.SERVER_LIST, unsubscribe); + } + getAgentInfo(unsubscribe?: Subject): Observable { + return this.getObservable(STORE_KEY.AGENT_INFO, unsubscribe); + } + getLoadChartYMax(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.LOAD_CHART_Y_MAX, unsubscribe); + } + getResponseSummaryChartYMax(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.RESPONSE_SUMMARY_CHART_Y_MAX, unsubscribe); + } + getServerMapDisableState(unsubscribe: Subject): Observable { + return this.store.pipe( + select(selectServerMapDisableState), + takeUntil(unsubscribe) + ); + } + getInfoPerServerState(unsubscribe: Subject): Observable { + return this.store.pipe( + select(selectInfoPerServerVisibleState), + takeUntil(unsubscribe) + ); + } + getInspectorTimelineData(unsubscribe: Subject): Observable { + return this.getObservable(STORE_KEY.TIMELINE, unsubscribe); + } + getInspectorTimelineRange(unsubscribe: Subject): Observable { + return this.store.pipe( + takeUntil(unsubscribe), + select(selectTimelineRange), + filter(([from, to]: number[]) => { + return (from === 0 && to === 0) ? false : true; + }) + ); + } + getInspectorTimelineSelectionRange(unsubscribe: Subject): Observable { + return this.store.pipe( + takeUntil(unsubscribe), + select(selectTimelineSelectionRange), + filter(([from, to]: number[]) => { + return (from === 0 && to === 0) ? false : true; + }) + ); + } + getInspectorTimelineSelectedTime(unsubscribe: Subject): Observable { + return this.store.pipe( + takeUntil(unsubscribe), + select(selectTimelineSelectedTime), + filter((time: number) => { + return time === 0 ? false : true; + }) + ); + } + private getObservable(key: string, unsubscribe?: Subject): Observable { + return iif( + () => !!unsubscribe, + this.store.pipe( + select(key), + takeUntil(unsubscribe) + ), + this.store.pipe(select(key)) + ); + } + dispatch(action: Action): void { + this.store.dispatch(action); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/system-configuration-data.service.ts b/web/src/main/webapp/v2/src/app/shared/services/system-configuration-data.service.ts new file mode 100644 index 000000000000..3ff1b91d6bfa --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/system-configuration-data.service.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +@Injectable() +export class SystemConfigurationDataService { + private url = 'configuration.pinpoint'; + private defaultConfiguration: ISystemConfiguration = { + editUserInfo: false, + enableServerMapRealTime: false, + openSource: true, + sendUsage: true, + showActiveThread: false, + showActiveThreadDump: false, + showApplicationStat: false, + version: '', + userId: '', + userName: '', + userDepartment: '' + }; + constructor(private http: HttpClient) {} + getConfiguration(): Observable { + return this.http.get(this.url).pipe( + map(res => { + if (res) { + return res; + } else { + return this.defaultConfiguration; + } + }) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/system-configuration-resolver.service.ts b/web/src/main/webapp/v2/src/app/shared/services/system-configuration-resolver.service.ts new file mode 100644 index 000000000000..0e632ffbd362 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/system-configuration-resolver.service.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@angular/core'; +import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router'; +import { Observable, EMPTY } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { SystemConfigurationDataService } from './system-configuration-data.service'; + +@Injectable() +export class SystemConfigurationResolverService implements Resolve { + constructor( + private router: Router, + private systemConfigurationDataService: SystemConfigurationDataService + ) {} + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.systemConfigurationDataService.getConfiguration().pipe( + catchError((error: any) => { + this.router.navigate(['/error']); + return EMPTY; + }) + ); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/transaction-detail-data.service.ts b/web/src/main/webapp/v2/src/app/shared/services/transaction-detail-data.service.ts new file mode 100644 index 000000000000..b883ffd2f08d --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/transaction-detail-data.service.ts @@ -0,0 +1,60 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; + +import { Observable, Subject } from 'rxjs'; +import { tap, shareReplay, retry } from 'rxjs/operators'; + +export interface ITransactionDetailPartInfo { + completeState: string; + logPageUrl: string; + logButtonName: string; + logLinkEnable: boolean; + disableButtonMessage: string; + loggingTransactionInfo: boolean; +} + +@Injectable() +export class TransactionDetailDataService { + private requestURL = 'transactionInfo.pinpoint'; + private partInfo: Subject = new Subject(); + private lastKey: string; + cachedData: { [key: string]: Observable } = {}; + partInfo$: Observable; + constructor(private http: HttpClient) { + this.partInfo$ = this.partInfo.asObservable(); + } + getData(agentId: string, spanId: string, traceId: string, focusTimestamp: number): Observable { + this.lastKey = agentId + spanId + traceId + focusTimestamp; + if ( this.hasData() ) { + return this.cachedData[this.lastKey]; + } else { + const httpRequest$ = this.http.get(this.requestURL, this.makeRequestOptionsArgs(agentId, spanId, traceId, focusTimestamp)); + this.cachedData[this.lastKey] = httpRequest$.pipe( + tap((transactionInfo: any) => { + this.partInfo.next({ + logButtonName: transactionInfo.logButtonName, + logLinkEnable: transactionInfo.logLinkEnable, + logPageUrl: transactionInfo.logPageUrl, + loggingTransactionInfo: transactionInfo.loggingTransactionInfo, + disableButtonMessage: transactionInfo.disableButtonMessage, + completeState: transactionInfo.completeState, + }); + }), + shareReplay(3) + ); + return this.cachedData[this.lastKey]; + } + } + private hasData(): boolean { + return !!this.cachedData[this.lastKey]; + } + private makeRequestOptionsArgs(agentId: string, spanId: string, traceId: string, focusTimestamp: number): object { + return { + params: new HttpParams() + .set('agentId', agentId) + .set('spanId', spanId) + .set('traceId', traceId) + .set('focusTimestamp', focusTimestamp + '') + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/transaction-view-type.service.ts b/web/src/main/webapp/v2/src/app/shared/services/transaction-view-type.service.ts new file mode 100644 index 000000000000..c3c3f0562ed8 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/transaction-view-type.service.ts @@ -0,0 +1,70 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +import { UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService } from 'app/shared/services/new-url-state-notification.service'; + +export interface IViewType { + key: string; + display: string; +} +export const VIEW_TYPE = { + CALL_TREE: 'callTree', + SERVER_MAP: 'serverMap', + TIMELINE: 'timeline' +}; + +@Injectable() +export class TransactionViewTypeService { + private outChangeViewType: BehaviorSubject = new BehaviorSubject(VIEW_TYPE.CALL_TREE); + private viewTypeList = [ + { + key: VIEW_TYPE.CALL_TREE, + display: 'Call Tree' + }, { + key: VIEW_TYPE.SERVER_MAP, + display: 'Server Map' + }, { + key: VIEW_TYPE.TIMELINE, + display: 'Timeline' + } + ]; + private currentViewType = ''; + private defaultViewType = this.viewTypeList[0].key; + onChangeViewType$: Observable; + constructor( + private newUrlStateNotificationService: NewUrlStateNotificationService + ) { + this.onChangeViewType$ = this.outChangeViewType.asObservable(); + this.newUrlStateNotificationService.onUrlStateChange$.pipe( + filter((urlService: NewUrlStateNotificationService) => !!urlService) + ).subscribe((urlService: NewUrlStateNotificationService) => { + if (urlService.hasValue(UrlPathId.VIEW_TYPE)) { + this.setCurrentViewType(urlService.getPathValue(UrlPathId.VIEW_TYPE)); + } else { + this.setCurrentViewType(''); + } + }); + } + private setCurrentViewType(viewType: string): void { + if ( viewType === '' ) { + this.currentViewType = this.defaultViewType; + } else { + if ( this.currentViewType === viewType ) { + return; + } + let hasMatchedKey = false; + this.viewTypeList.forEach((obj: IViewType) => { + if ( obj.key === viewType ) { + hasMatchedKey = true; + } + }); + this.currentViewType = hasMatchedKey ? viewType : this.defaultViewType; + } + this.outChangeViewType.next(this.currentViewType); + } + getViewTypeList(): IViewType[] { + return this.viewTypeList; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/translate-replace.service.ts b/web/src/main/webapp/v2/src/app/shared/services/translate-replace.service.ts new file mode 100644 index 000000000000..ec8283d28728 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/translate-replace.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class TranslateReplaceService { + constructor() { } + replace(template: string, ...argu: any[]): string { + let replacedTemplate = template; + argu.forEach((value: string, index: number) => { + replacedTemplate = replacedTemplate.replace( new RegExp('\\!\\{' + index + '\\}'), '' + value); + }); + return replacedTemplate; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/url-route-manager.service.ts b/web/src/main/webapp/v2/src/app/shared/services/url-route-manager.service.ts new file mode 100644 index 000000000000..e7e0ae9ec1f9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/url-route-manager.service.ts @@ -0,0 +1,145 @@ +import { Injectable, Inject } from '@angular/core'; +import { Router } from '@angular/router'; +import { WindowRefService } from 'app/shared/services/window-ref.service'; +import { ServerTimeDataService } from 'app/shared/services/server-time-data.service'; +import { FilterParamMaker } from 'app/core/utils/filter-param-maker'; +import { HintParamMaker } from 'app/core/utils/hint-param-maker'; +import { EndTime } from 'app/core/models/end-time'; +import { Filter } from 'app/core/models/filter'; +import { UrlPath, UrlPathId } from 'app/shared/models'; +import { NewUrlStateNotificationService } from 'app/shared/services/new-url-state-notification.service'; +import { WebAppSettingDataService } from 'app/shared/services/web-app-setting-data.service'; +import { APP_BASE_HREF } from '@angular/common'; + +@Injectable() +export class UrlRouteManagerService { + + constructor( + private windowRef: WindowRefService, + private router: Router, + private webAppSettingDataService: WebAppSettingDataService, + private newUrlStateNotificationService: NewUrlStateNotificationService, + private serverTimeDataService: ServerTimeDataService, + @Inject(APP_BASE_HREF) private baseHref: string + ) {} + changeApplication(applicationUrlStr: string): void { + const startPath = this.newUrlStateNotificationService.getStartPath(); + if (this.newUrlStateNotificationService.isRealTimeMode()) { + this.moveToRealTime(applicationUrlStr); + } else { + this.serverTimeDataService.getServerTime().subscribe(time => { + const url = [ + startPath, + applicationUrlStr, + this.webAppSettingDataService.getUserDefaultPeriod().getValueWithTime(), + EndTime.formatDate(time) + ]; + this.router.navigate(url, { + queryParamsHandling: 'preserve' + }); + }); + } + } + moveToRealTime(applicationUrlStr?: string): void { + this.router.navigate([ + this.newUrlStateNotificationService.getStartPath(), + (applicationUrlStr || this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr()), + UrlPath.REAL_TIME + ]); + } + move({ url, needServerTimeRequest, nextUrl = [], queryParam }: { url: string[], needServerTimeRequest: boolean, nextUrl?: string[], queryParam?: any} ): void { + if (needServerTimeRequest) { + this.serverTimeDataService.getServerTime().subscribe(time => { + const newUrl = url.concat([EndTime.formatDate(time)]).concat(nextUrl).filter((v: string) => { + return v !== ''; + }); + if (queryParam) { + this.router.navigate(newUrl, { + queryParams: queryParam, + queryParamsHandling: 'merge' + }); + } else { + this.router.navigate(newUrl, { + queryParamsHandling: 'preserve' + }); + } + }); + } else { + const newUrl = [...url, ...nextUrl]; + + if (queryParam) { + this.router.navigate(newUrl, { + queryParams: queryParam, + queryParamsHandling: 'merge' + }); + } else { + this.router.navigate(newUrl, { + queryParamsHandling: 'preserve' + }); + } + } + } + moveOnPage({ url, queryParam }: { url: string[], queryParam?: any }): void { + this.move({ + url: url, + needServerTimeRequest: false, + nextUrl: [], + queryParam: queryParam + }); + } + openPage(path: string | string[], title?: string): void { + this.windowRef.nativeWindow.open(this.getBaseHref() + (path instanceof Array ? path.join('/') : path), title || ''); + } + makeFilterMapUrl( + { applicationName, serviceType, periodStr, timeStr, filterStr, hintStr, addedFilter, addedHint }: + { applicationName: string, serviceType: string, periodStr: string, timeStr: string, filterStr: string, hintStr: string, addedFilter: Filter, addedHint?: any } + ): string { + return `filteredMap/${applicationName}@${serviceType}/${periodStr}/${timeStr}` + + FilterParamMaker.makeParam(filterStr, addedFilter) + + HintParamMaker.makeParam(hintStr, addedHint); + } + openInspectorPage(realTimeMode: boolean): void { + if (realTimeMode) { + this.serverTimeDataService.getServerTime().subscribe(time => { + this.windowRef.nativeWindow.open([ + this.getBaseHref() + UrlPath.INSPECTOR, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.webAppSettingDataService.getSystemDefaultPeriod().getValueWithTime(), + EndTime.newByNumber(time).getEndTime() + ].join('/')); + }); + } else { + this.windowRef.nativeWindow.open([ + this.getBaseHref() + UrlPath.INSPECTOR, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ].join('/')); + } + } + openMainPage(): void { + this.windowRef.nativeWindow.open([ + this.getBaseHref() + UrlPath.MAIN, + this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(), + this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime() + ].join('/')); + } + reload(): void { + this.windowRef.nativeWindow.location.reload(); + } + back(): void { + this.windowRef.nativeWindow.history.back(); + } + private getBaseHref(): string { + if (this.baseHref === '/') { + return ''; + } else { + if (/.*\/$/.test(this.baseHref)) { + return this.baseHref; + } else { + return this.baseHref + '/'; + } + } + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/url-validate.guard.ts b/web/src/main/webapp/v2/src/app/shared/services/url-validate.guard.ts new file mode 100644 index 000000000000..6b4dfa00a5e9 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/url-validate.guard.ts @@ -0,0 +1,90 @@ +import { Injectable } from '@angular/core'; +import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, ParamMap } from '@angular/router'; + +import { UrlRouteManagerService } from 'app/shared/services/url-route-manager.service'; +import { WebAppSettingDataService } from 'app/shared/services/web-app-setting-data.service'; +import { UrlPath, UrlPathId } from 'app/shared/models'; + +interface IPathParam { + [key: string]: string; +} + +@Injectable() +export class UrlValidateGuard implements CanActivate { + constructor( + private webAppSettingDataService: WebAppSettingDataService, + private urlRouteManagerService: UrlRouteManagerService + ) {} + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + const hasPaths: IPathParam = {}; + this.collectUrlInfo(route.children, hasPaths); + switch (route.routeConfig.path) { + case UrlPath.MAIN: + return this.checkMainRoute(route, hasPaths); + case UrlPath.FILTERED_MAP: + return this.checkFilteredMapRoute(route, hasPaths); + } + return false; + } + private checkMainRoute(route: ActivatedRouteSnapshot, hasPaths: IPathParam): boolean { + const subPath = route.children[0].routeConfig.path; + switch (subPath) { + case ':' + UrlPathId.APPLICATION: + this.urlRouteManagerService.move({ + url: [ + UrlPath.MAIN, + hasPaths.application, + this.webAppSettingDataService.getUserDefaultPeriod().getValueWithTime() + ], + needServerTimeRequest: true + }); + return false; + case ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD: + this.urlRouteManagerService.move({ + url: [ + UrlPath.MAIN, + hasPaths.application, + hasPaths.period + ], + needServerTimeRequest: true + }); + return false; + case ':' + UrlPathId.APPLICATION + '/' + UrlPath.REAL_TIME: + case ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME: + default: + return true; + } + } + private checkFilteredMapRoute(route: ActivatedRouteSnapshot, hasPaths: IPathParam): boolean { + const subPath = route.children[0].routeConfig.path; + switch (subPath) { + case ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME: + case ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME + '/:' + UrlPathId.FILTER: + case ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD + '/:' + UrlPathId.END_TIME + '/:' + UrlPathId.FILTER + '/:' + UrlPathId.HINT: + return true; + case ':' + UrlPathId.APPLICATION: + case ':' + UrlPathId.APPLICATION + '/:' + UrlPathId.PERIOD: + default: + this.urlRouteManagerService.move({ + url: [ + UrlPath.MAIN + ], + needServerTimeRequest: false + }); + return false; + } + } + private collectUrlInfo(activatedChildRouteSnapshot: ActivatedRouteSnapshot[], hasPaths: any): void { + if (activatedChildRouteSnapshot.length !== 0) { + for ( let i = 0 ; i < activatedChildRouteSnapshot.length ; i++ ) { + this.assign(hasPaths, activatedChildRouteSnapshot[i].paramMap); + this.collectUrlInfo(activatedChildRouteSnapshot[i].children, hasPaths); + } + } + } + private assign(data: any, mapData: ParamMap): void { + mapData.keys.forEach((key: string) => { + data[key] = mapData.get(key); + }); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/web-app-setting-data.service.ts b/web/src/main/webapp/v2/src/app/shared/services/web-app-setting-data.service.ts new file mode 100644 index 000000000000..afc3b8f60762 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/web-app-setting-data.service.ts @@ -0,0 +1,227 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs'; +import { Store } from '@ngrx/store'; +import { LocalStorageService } from 'angular-2-local-storage'; +import 'moment-timezone'; +import * as moment from 'moment-timezone'; +import { pluck } from 'rxjs/operators'; + +import { AppState, Actions } from 'app/shared/store'; +import { ComponentDefaultSettingDataService } from 'app/shared/services/component-default-setting-data.service'; +import { Application, Period } from 'app/core/models'; + +interface IMinMax { + min: number; + max: number; +} + +@Injectable() +export class WebAppSettingDataService { + static KEYS = { + FAVORLIITE_APPLICATION_LIST: 'favoriteApplicationList', + TIMEZONE: 'timezone', + DATE_FORMAT: 'dateFormat', + LIST_HANDLE_POSITION: 'listHandlePosition', + LAYER_HEIGHT: 'layerHeight', + USER_DEFAULT_INBOUND: 'userDefaultInbound', + USER_DEFAULT_OUTBOUND: 'userDefaultOutbound', + USER_DEFAULT_PERIOD: 'userDefaultPeriod', + TRANSACTION_LIST_GUTTER_POSITION: 'transactionListGutterPosition' + }; + private IMAGE_PATH = './assets/img/'; + private IMAGE_EXT = '.png'; + private SERVER_MAP_PATH = 'servermap/'; + private ICON_PATH = 'icons/'; + private LOGO_IMG_NAME = 'logo.png'; + constructor( + private store: Store, + private activatedRoute: ActivatedRoute, + private localStorageService: LocalStorageService, + private componentDefaultSettingDataService: ComponentDefaultSettingDataService + ) { + this.store.dispatch(new Actions.AddFavoriteApplication(this.getFavoriteApplicationList())); + this.store.dispatch(new Actions.ChangeTimezone(this.getTimezone())); + this.store.dispatch(new Actions.ChangeDateFormat(this.getDateFormat())); + } + private getConfigurationData(): Observable { + return this.activatedRoute.children[0].children[0].data; + } + useActiveThreadChart(): Observable { + return this.getConfigurationData().pipe( + pluck('configuration', 'showActiveThread') + ); + } + getUserId(): Observable { + return this.getConfigurationData().pipe( + pluck('configuration', 'userId') + ); + } + getUserDepartment(): Observable { + return this.getConfigurationData().pipe( + pluck('configuration', 'userDepartment') + ); + } + useUserEdit(): Observable { + return this.getConfigurationData().pipe( + pluck('configuration', 'editUserInfo') + ); + } + isDataUsageAllowed(): Observable { + return this.getConfigurationData().pipe( + pluck('configuration', 'sendUsage') + ); + } + getVersion(): Observable { + return this.getConfigurationData().pipe( + pluck('configuration', 'version') + ); + } + isApplicationInspectorActivated(): Observable { + return this.getConfigurationData().pipe( + pluck('configuration', 'showApplicationStat') + ); + } + getImagePath(): string { + return this.IMAGE_PATH; + } + getServerMapImagePath(): string { + return this.getImagePath() + this.SERVER_MAP_PATH; + } + getIconImagePath(): string { + return this.getImagePath() + this.ICON_PATH; + } + getImageExt(): string { + return this.IMAGE_EXT; + } + getLogoPath(): string { + return this.getImagePath() + this.LOGO_IMG_NAME; + } + getSystemDefaultInbound(): string { + return this.componentDefaultSettingDataService.getSystemDefaultInbound(); + } + getSystemDefaultOutbound(): string { + return this.componentDefaultSettingDataService.getSystemDefaultOutbound(); + } + getSystemDefaultPeriod(): Period { + return this.componentDefaultSettingDataService.getSystemDefaultPeriod(); + } + getSystemDefaultTransactionViewPeriod(): Period { + return this.componentDefaultSettingDataService.getSystemDefaultTransactionViewPeriod(); + } + getInboundList(): string[] { + return this.componentDefaultSettingDataService.getInboundList(); + } + getOutboundList(): string[] { + return this.componentDefaultSettingDataService.getOutboundList(); + } + getPeriodList(path: string): Period[] { + return this.componentDefaultSettingDataService.getPeriodList(path); + } + getMaxPeriodTime(): number { + return this.componentDefaultSettingDataService.getMaxPeriodTime(); + } + getColorByRequest(): string[] { + return this.componentDefaultSettingDataService.getColorByRequest(); + } + private loadFavoriteList(): any[] { + return JSON.parse(this.localStorageService.get(WebAppSettingDataService.KEYS.FAVORLIITE_APPLICATION_LIST)) || []; + } + private saveFavoriteList(data: any[]): void { + this.localStorageService.set(WebAppSettingDataService.KEYS.FAVORLIITE_APPLICATION_LIST, JSON.stringify(data)); + } + addFavoriteApplication(application: IApplication): void { + this.saveFavoriteList([...this.loadFavoriteList(), { + applicationName: application.getApplicationName(), + serviceType: application.getServiceType(), + code: application.getCode() + }]); + this.store.dispatch(new Actions.AddFavoriteApplication([application])); + } + removeFavoriteApplication(application: IApplication): void { + const removedList = this.getFavoriteApplicationList().filter((app: IApplication) => { + return !app.equals(application); + }); + this.saveFavoriteList(removedList); + this.store.dispatch(new Actions.RemoveFavoriteApplication([application])); + } + private getFavoriteApplicationList(): IApplication[] { + return this.loadFavoriteList().map(({applicationName, serviceType, code}) => { + return new Application(applicationName, serviceType, code); + }); + } + getScatterY(key: string): IMinMax { + return this.localStorageService.get(key) || { min: 0, max: 10000 }; + } + setScatterY(key: string, value: IMinMax): void { + this.localStorageService.set(key, value); + } + setTimezone(value: string): void { + this.localStorageService.set(WebAppSettingDataService.KEYS.TIMEZONE, value); + } + private getTimezone(): string { + return this.localStorageService.get(WebAppSettingDataService.KEYS.TIMEZONE) || this.getDefaultTimezone(); + } + getDefaultTimezone(): string { + return moment.tz.guess(); + } + setDateFormat(value: number): void { + this.localStorageService.set(WebAppSettingDataService.KEYS.DATE_FORMAT, value); + } + private getDateFormat(): number { + return this.localStorageService.get(WebAppSettingDataService.KEYS.DATE_FORMAT) || 0; + } + getDefaultDateFormat(): string[] { + return this.componentDefaultSettingDataService.getDefaultDateFormat(); + } + getDateFormatList(): string[][] { + return this.componentDefaultSettingDataService.getDateFormatList(); + } + setListHandlePosition(value: number[]): void { + this.localStorageService.set(WebAppSettingDataService.KEYS.LIST_HANDLE_POSITION, value); + } + getListHandlePosition(): number[] { + return this.localStorageService.get(WebAppSettingDataService.KEYS.LIST_HANDLE_POSITION) || [30, 70]; + } + setLayerHeight(value: number): void { + this.localStorageService.set(WebAppSettingDataService.KEYS.LAYER_HEIGHT, value); + } + getLayerHeight(): number { + return Number.parseInt(this.localStorageService.get(WebAppSettingDataService.KEYS.LAYER_HEIGHT), 10); + } + setUserDefaultInbound(value: string): void { + this.localStorageService.set(WebAppSettingDataService.KEYS.USER_DEFAULT_INBOUND, value); + } + getUserDefaultInbound(): string { + return this.localStorageService.get(WebAppSettingDataService.KEYS.USER_DEFAULT_INBOUND) || this.getSystemDefaultInbound(); + } + setUserDefaultOutbound(value: string): void { + this.localStorageService.set(WebAppSettingDataService.KEYS.USER_DEFAULT_OUTBOUND, value); + } + getUserDefaultOutbound(): string { + return this.localStorageService.get(WebAppSettingDataService.KEYS.USER_DEFAULT_OUTBOUND) || this.getSystemDefaultOutbound(); + } + setUserDefaultPeriod(value: Period): void { + this.localStorageService.set(WebAppSettingDataService.KEYS.USER_DEFAULT_PERIOD, value.getValue()); + } + getUserDefaultPeriod(): Period { + const userDefaultPeriodInMinute = this.localStorageService.get(WebAppSettingDataService.KEYS.USER_DEFAULT_PERIOD); + + return userDefaultPeriodInMinute ? new Period(userDefaultPeriodInMinute) : this.getSystemDefaultPeriod(); + } + getServerMapIconPathMakeFunc(): Function { + return (name: string) => { + return this.IMAGE_PATH + this.SERVER_MAP_PATH + name + this.IMAGE_EXT; + }; + } + getIconPathMakeFunc(): Function { + return (name: string) => { + return this.IMAGE_PATH + this.ICON_PATH + name + this.IMAGE_EXT; + }; + } + getImagePathMakeFunc(): Function { + return (name: string) => { + return this.IMAGE_PATH + name + this.IMAGE_EXT; + }; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/services/window-ref.service.ts b/web/src/main/webapp/v2/src/app/shared/services/window-ref.service.ts new file mode 100644 index 000000000000..1548c2ec742e --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/services/window-ref.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@angular/core'; + +function getWindow(): any { + return window; +} + +@Injectable() +export class WindowRefService { + get nativeWindow(): any { + return getWindow(); + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/admin.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/admin.reducer.ts new file mode 100644 index 000000000000..c451bc9bd5f4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/admin.reducer.ts @@ -0,0 +1,16 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_ADMIN_AGENT_LIST = 'UPDATE_ADMIN_AGENT_LIST'; +export class UpdateAdminAgentList implements Action { + readonly type = UPDATE_ADMIN_AGENT_LIST; + constructor(public payload: IAgentList) {} +} + +export function Reducer(state: IAgentList, action: UpdateAdminAgentList): IAgentList { + switch (action.type) { + case UPDATE_ADMIN_AGENT_LIST: + return action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/agent-info.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/agent-info.reducer.ts new file mode 100644 index 000000000000..2faf50d4b203 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/agent-info.reducer.ts @@ -0,0 +1,17 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_AGENT_INFO = 'UPDATE_AGENT_INFO'; + +export class UpdateAgentInfo implements Action { + readonly type = UPDATE_AGENT_INFO; + constructor(public payload: IServerAndAgentData) {} +} + +export function Reducer(state: IServerAndAgentData, action: UpdateAgentInfo): IServerAndAgentData { + switch (action.type) { + case UPDATE_AGENT_INFO: + return action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/agent-selection-for-info-per-server.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/agent-selection-for-info-per-server.reducer.ts new file mode 100644 index 000000000000..059ef31ccce0 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/agent-selection-for-info-per-server.reducer.ts @@ -0,0 +1,17 @@ +import { Action } from '@ngrx/store'; + +const CHANGE_AGENT_FOR_SERVER_LIST = 'CHANGE_AGENT_FOR_SERVER_LIST'; + +export class ChangeAgentForServerList implements Action { + readonly type = CHANGE_AGENT_FOR_SERVER_LIST; + constructor(public payload: IAgentSelection) {} +} + +export function Reducer(state: IAgentSelection, action: ChangeAgentForServerList): IAgentSelection { + switch ( action.type ) { + case CHANGE_AGENT_FOR_SERVER_LIST: + return (state && state.agent === action.payload.agent) ? state : action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/agent-selection-for-side-bar.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/agent-selection-for-side-bar.reducer.ts new file mode 100644 index 000000000000..d0f2a7353c31 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/agent-selection-for-side-bar.reducer.ts @@ -0,0 +1,17 @@ +import { Action } from '@ngrx/store'; + +const CHANGE_AGENT = 'CHANGE_AGENT'; + +export class ChangeAgent implements Action { + readonly type = CHANGE_AGENT; + constructor(public payload: string) {} +} + +export function Reducer(state = '', action: ChangeAgent): string { + switch ( action.type ) { + case CHANGE_AGENT: + return (state === action.payload) ? state : action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/application-list.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/application-list.reducer.ts new file mode 100644 index 000000000000..4cfcdb198931 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/application-list.reducer.ts @@ -0,0 +1,17 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_APPLICATION_LIST = 'UPDATE_APPLICATION_LIST'; + +export class UpdateApplicationList implements Action { + readonly type = UPDATE_APPLICATION_LIST; + constructor(public payload: IApplication[]) {} +} + +export function Reducer(state: IApplication[] = [], action: UpdateApplicationList): IApplication[] { + switch (action.type) { + case UPDATE_APPLICATION_LIST: + return action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/date-format.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/date-format.reducer.ts new file mode 100644 index 000000000000..de12929dbdb6 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/date-format.reducer.ts @@ -0,0 +1,16 @@ +import { Action } from '@ngrx/store'; + +const CHANGE_DATE_FORMAT = 'CHANGE_DATE_FORMAT'; +export class ChangeDateFormat implements Action { + readonly type = CHANGE_DATE_FORMAT; + constructor(public payload: number) {} +} + +export function Reducer(state = 0, action: ChangeDateFormat) { + switch (action.type) { + case CHANGE_DATE_FORMAT: + return (state === action.payload) ? state : action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/favorite-application-list.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/favorite-application-list.reducer.ts new file mode 100644 index 000000000000..4aaac3d76f15 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/favorite-application-list.reducer.ts @@ -0,0 +1,31 @@ +import { Action } from '@ngrx/store'; + +const ADD_FAVORITE_APPLICATION = 'ADD_FAVORITE_APPLICATION'; +const REMOVE_FAVORITE_APPLICATION = 'REMOVE_FAVORITE_APPLICATION'; + +export class AddFavoriteApplication implements Action { + readonly type = ADD_FAVORITE_APPLICATION; + constructor(public payload: IApplication[]) {} +} +export class RemoveFavoriteApplication implements Action { + readonly type = REMOVE_FAVORITE_APPLICATION; + constructor(public payload: IApplication[]) {} +} + +export function Reducer(state: IApplication[] = [], action: AddFavoriteApplication | RemoveFavoriteApplication): IApplication[] { + switch (action.type) { + case ADD_FAVORITE_APPLICATION: + return [...state, ...action.payload]; + case REMOVE_FAVORITE_APPLICATION: + return state.filter((application: IApplication) => { + for (let i = 0 ; i < action.payload.length ; i++) { + if (application.equals(action.payload[i])) { + return false; + } + } + return true; + }); + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/index.ts b/web/src/main/webapp/v2/src/app/shared/store/index.ts new file mode 100644 index 000000000000..c6be81fbd092 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/index.ts @@ -0,0 +1,163 @@ +import { ActionReducerMap, createSelector, createFeatureSelector } from '@ngrx/store'; + +import * as admin from './admin.reducer'; +import * as agentInfo from './agent-info.reducer'; +import * as agentSelectionForInfoPerServer from './agent-selection-for-info-per-server.reducer'; +import * as agentSelectionForSideBar from './agent-selection-for-side-bar.reducer'; +import * as applicationList from './application-list.reducer'; +import * as dateFormat from './date-format.reducer'; +import * as favoriteApplicationList from './favorite-application-list.reducer'; +import * as inspectorChartHover from './inspector-chart-hover.reducer'; +import * as loadChart from './load-chart.reducer'; +import * as responseSummaryChart from './response-summary-chart.reducer'; +import * as scatterChartRealTime from './scatter-chart-real-time.reducer'; +import * as scatterChart from './scatter-chart.reducer'; +import * as serverAndAgent from './server-and-agent.reducer'; +import * as serverList from './server-list.reducer'; +import * as timeline from './timeline.reducer'; +import * as timezone from './timezone.reducer'; +import * as transactionDetailData from './transaction-detail-data.reducer'; +import * as transactionData from './transaction-info.reducer'; +import * as targetList from './target-list.reducer'; +import * as serverMap from './server-map.reducer'; +import * as serverMapSelectedTarget from './server-map-selected-target.reducer'; +import * as serverMapLoadingState from './server-map-loading-state.reducer'; +import * as uiState from './ui-state.reducer'; + + +export interface AppState { + timeline: ITimelineInfo; + timezone: string; + dateFormat: number; + loadChartYMax: number; + responseSummaryChartYMax: number; + agentSelection: string; + agentSelectionForServerList: IAgentSelection; + transactionData: ITransactionMetaData; + transactionDetailData: ITransactionDetailData; + hoverOnInspectorCharts: number; + agentInfo: IServerAndAgentData; + applicationList: IApplication[]; + favoriteApplicationList: IApplication[]; + serverList: any; + scatterChart: IScatterData; + realTimeScatterChart: IScatterXRange; + serverMapData: any; + serverMapLoadingState: string; + serverMapTargetSelected: ISelectedTarget; + serverMapTargetSelectByList: any; + updateFilterOfServerAndAgentList: string; + adminAgentList: { [key: string]: IAgent[] }; + uiState: IUIState; +} + +export const STORE_KEY = { + TIMELINE: 'timeline', + TIMEZONE: 'timezone', + DATE_FORMAT: 'dateFormat', + LOAD_CHART_Y_MAX: 'loadChartYMax', + RESPONSE_SUMMARY_CHART_Y_MAX: 'responseSummaryChartYMax', + AGENT_SELECTION: 'agentSelection', + AGENT_SELECTION_FOR_SERVER_LIST: 'agentSelectionForServerList', + TIMELINE_SELECTION_RANGE: 'timelineSelectionRange', + TRANSACTION_DATA: 'transactionData', + TRANSACTION_DETAIL_DATA: 'transactionDetailData', + HOVER_ON_INSPECTOR_CHARTS: 'hoverOnInspectorCharts', + AGENT_INFO: 'agentInfo', + APPLICATION_LIST: 'applicationList', + FAVORITE_APPLICATION_LIST: 'favoriteApplicationList', + SERVER_LIST: 'serverList', + SCATTER_CHART: 'scatterChart', + REAL_TIME_SCATTER_CHART: 'realTimeScatterChart', + SERVER_MAP_DATA: 'serverMapData', + SERVER_MAP_LOADING_STATE: 'serverMapLoadingState', + SERVER_MAP_TARGET_SELECTED: 'serverMapTargetSelected', + SERVER_MAP_TARGET_SELECTED_BY_LIST: 'serverMapTargetSelectByList', + ADMIN_AGENT_LIST: 'adminAgentList', + SERVER_AND_AGENT: 'serverAndAgent', + UI_STATE: 'uiState' +}; + + +export const reducers: ActionReducerMap = { + // [STORE_KEY.AGENT_INFo]: agentInfoReducer 방식은 빌드시 에러가 발생 함. + agentInfo: agentInfo.Reducer, + agentSelection: agentSelectionForSideBar.Reducer, + agentSelectionForServerList: agentSelectionForInfoPerServer.Reducer, + applicationList: applicationList.Reducer, + favoriteApplicationList: favoriteApplicationList.Reducer, + dateFormat: dateFormat.Reducer, + hoverOnInspectorCharts: inspectorChartHover.Reducer, + loadChartYMax: loadChart.Reducer, + responseSummaryChartYMax: responseSummaryChart.Reducer, + realTimeScatterChart: scatterChartRealTime.Reducer, + scatterChart: scatterChart.Reducer, + serverList: serverList.Reducer, + serverMapLoadingState: serverMapLoadingState.Reducer, + serverMapData: serverMap.Reducer, + serverMapTargetSelected: serverMapSelectedTarget.Reducer, + serverMapTargetSelectByList: targetList.Reducer, + timezone: timezone.Reducer, + transactionData: transactionData.Reducer, + transactionDetailData: transactionDetailData.Reducer, + adminAgentList: admin.Reducer, + serverAndAgent: serverAndAgent.Reducer, + uiState: uiState.Reducer, + timeline: timeline.Reducer +}; + +export const Actions = { + 'ChangeTimezone': timezone.ChangeTimezone, + 'ChangeDateFormat': dateFormat.ChangeDateFormat, + 'ChangeResponseSummaryChartYMax': responseSummaryChart.ChangeResponseSummaryChartYMax, + 'ChangeLoadChartYMax': loadChart.ChangeLoadChartYMax, + 'ChangeAgent': agentSelectionForSideBar.ChangeAgent, + 'ChangeAgentForServerList': agentSelectionForInfoPerServer.ChangeAgentForServerList, + 'UpdateTransactionData': transactionData.UpdateTransactionData, + 'UpdateTransactionDetailData': transactionDetailData.UpdateTransactionDetailData, + 'ChangeHoverOnInspectorCharts': inspectorChartHover.ChangeHoverOnInspectorCharts, + 'UpdateApplicationList': applicationList.UpdateApplicationList, + 'AddFavoriteApplication': favoriteApplicationList.AddFavoriteApplication, + 'RemoveFavoriteApplication': favoriteApplicationList.RemoveFavoriteApplication, + 'UpdateServerList': serverList.UpdateServerList, + 'AddScatterChartData': scatterChart.AddScatterChartData, + 'UpdateRealTimeScatterChartXRange': scatterChartRealTime.UpdateRealTimeScatterChartXRange, + 'UpdateServerMapData': serverMap.UpdateServerMapData, + 'UpdateServerMapLoadingState': serverMapLoadingState.UpdateServerMapLoadingState, + 'UpdateServerMapTargetSelected': serverMapSelectedTarget.UpdateServerMapTargetSelected, + 'UpdateServerMapSelectedTargetByList': targetList.UpdateServerMapSelectedTargetByList, + 'UpdateFilterOfServerAndAgentList': serverAndAgent.UpdateFilterOfServerAndAgentList, + 'UpdateAgentInfo': agentInfo.UpdateAgentInfo, + 'UpdateAdminAgentList': admin.UpdateAdminAgentList, + 'ChangeServerMapDisableState': uiState.ChangeServerMapDisableState, + 'ChangeInfoPerServerVisibleState': uiState.ChangeInfoPerServerVisibleState, + 'UpdateTimelineSelectionRange': timeline.UpdateTimelineSelectionRange, + 'UpdateTimelineRange': timeline.UpdateTimelineRange, + 'UpdateTimelineSelectedTime': timeline.UpdateTimelineSelectedTime, + 'UpdateTimelineData': timeline.UpdateTimelineData +}; + +const getUI = createFeatureSelector('uiState'); +export const selectServerMapDisableState = createSelector( + getUI, + (state: IUIState) => state['serverMap'] +); +export const selectInfoPerServerVisibleState = createSelector( + getUI, + (state: IUIState) => state['infoPerServer'] +); + +const getTimeline = createFeatureSelector('timeline'); +export const selectTimelineRange = createSelector( + getTimeline, + (state: ITimelineInfo) => state['range'] +); +export const selectTimelineSelectionRange = createSelector( + getTimeline, + (state: ITimelineInfo) => state['selectionRange'] +); +export const selectTimelineSelectedTime = createSelector( + getTimeline, + (state: ITimelineInfo) => state['selectedTime'] +); + diff --git a/web/src/main/webapp/v2/src/app/shared/store/inspector-chart-hover.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/inspector-chart-hover.reducer.ts new file mode 100644 index 000000000000..985372c10031 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/inspector-chart-hover.reducer.ts @@ -0,0 +1,16 @@ +import { Action } from '@ngrx/store'; + +const SYNC_HOVER_ON_INSPECTOR_CHARTS = 'SYNC_HOVER_ON_INSPECTOR_CHARTS'; +export class ChangeHoverOnInspectorCharts implements Action { + readonly type = SYNC_HOVER_ON_INSPECTOR_CHARTS; + constructor(public payload: IHoveredInfo) {} +} + +export function Reducer(state: IHoveredInfo, action: ChangeHoverOnInspectorCharts): IHoveredInfo { + switch ( action.type ) { + case SYNC_HOVER_ON_INSPECTOR_CHARTS: + return action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/load-chart.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/load-chart.reducer.ts new file mode 100644 index 000000000000..a9354ebc7349 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/load-chart.reducer.ts @@ -0,0 +1,18 @@ +import { Action } from '@ngrx/store'; + +const CHANGE_LOAD_CHART_Y_MAX = 'CHANGE_LOAD_Y_MAX'; + +export class ChangeLoadChartYMax implements Action { + readonly type = CHANGE_LOAD_CHART_Y_MAX; + constructor(public payload: number) {} +} + +export function Reducer(state = 0, action: ChangeLoadChartYMax) { + switch (action.type) { + case CHANGE_LOAD_CHART_Y_MAX: + return action.payload; + default: + return state; + } +} + diff --git a/web/src/main/webapp/v2/src/app/shared/store/response-summary-chart.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/response-summary-chart.reducer.ts new file mode 100644 index 000000000000..b26f2d16186c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/response-summary-chart.reducer.ts @@ -0,0 +1,18 @@ +import { Action } from '@ngrx/store'; + +const CHANGE_RESPONSE_SUMMARY_CHART_Y_MAX = 'CHANGE_RESPONSE_SUMMARY_Y_MAX'; + +export class ChangeResponseSummaryChartYMax implements Action { + readonly type = CHANGE_RESPONSE_SUMMARY_CHART_Y_MAX; + constructor(public payload: number) {} +} + +export function Reducer(state = 0, action: ChangeResponseSummaryChartYMax) { + switch (action.type) { + case CHANGE_RESPONSE_SUMMARY_CHART_Y_MAX: + return action.payload; + default: + return state; + } +} + diff --git a/web/src/main/webapp/v2/src/app/shared/store/scatter-chart-real-time.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/scatter-chart-real-time.reducer.ts new file mode 100644 index 000000000000..3542197ef038 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/scatter-chart-real-time.reducer.ts @@ -0,0 +1,20 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_REAL_TIME_SCATTER_CHART_X_RANGE = 'UPDATE_REAL_TIME_SCATTER_CHART_X_RANGE'; + +export class UpdateRealTimeScatterChartXRange implements Action { + readonly type = UPDATE_REAL_TIME_SCATTER_CHART_X_RANGE; + constructor(public payload: IScatterXRange) {} +} + +export function Reducer(state: IScatterXRange = {from: -1, to: -1}, action: UpdateRealTimeScatterChartXRange): IScatterXRange { + switch (action.type) { + case UPDATE_REAL_TIME_SCATTER_CHART_X_RANGE: + if (state.from === action.payload.from && state.to === action.payload.to) { + return state; + } + return action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/scatter-chart.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/scatter-chart.reducer.ts new file mode 100644 index 000000000000..e3d26d31682c --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/scatter-chart.reducer.ts @@ -0,0 +1,17 @@ +import { Action } from '@ngrx/store'; + +const ADD_SCATTER_CHART_DATA = 'UPDATE_SCATTER_CHART_DATA'; + +export class AddScatterChartData implements Action { + readonly type = ADD_SCATTER_CHART_DATA; + constructor(public payload: IScatterData) {} +} + +export function Reducer(state: IScatterData[] = [], action: AddScatterChartData): IScatterData[] { + switch (action.type) { + case ADD_SCATTER_CHART_DATA: + return state.concat(action.payload); + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/server-and-agent.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/server-and-agent.reducer.ts new file mode 100644 index 000000000000..554730a98789 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/server-and-agent.reducer.ts @@ -0,0 +1,16 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_FILTER_OF_SERVER_AND_AGENT_LIST = 'UPDATE_FILTER_OF_SERVER_AND_AGENT_LIST'; +export class UpdateFilterOfServerAndAgentList implements Action { + readonly type = UPDATE_FILTER_OF_SERVER_AND_AGENT_LIST; + constructor(public payload: string) {} +} + +export function Reducer(state = '', action: UpdateFilterOfServerAndAgentList): string { + switch (action.type) { + case UPDATE_FILTER_OF_SERVER_AND_AGENT_LIST: + return state === action.payload ? state : action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/server-list.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/server-list.reducer.ts new file mode 100644 index 000000000000..aa6ae2ea8dc4 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/server-list.reducer.ts @@ -0,0 +1,17 @@ +import { Action } from '@ngrx/store'; + +export const UPDATE_SERVER_LIST = 'UPDATE_SERVER_LIST'; + +export class UpdateServerList implements Action { + readonly type = UPDATE_SERVER_LIST; + constructor(public payload: any) {} +} + +export function Reducer(state = {}, action: UpdateServerList): any { + switch (action.type) { + case UPDATE_SERVER_LIST: + return action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/server-map-loading-state.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/server-map-loading-state.reducer.ts new file mode 100644 index 000000000000..dda4707d6999 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/server-map-loading-state.reducer.ts @@ -0,0 +1,16 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_SERVER_MAP_LOADING_STATE = 'UPDATE_LOADING_STATE'; + +export class UpdateServerMapLoadingState implements Action { + readonly type = UPDATE_SERVER_MAP_LOADING_STATE; + constructor(public payload: string) {} +} +export function Reducer(state = 'LOADING', action: UpdateServerMapLoadingState): string { + switch (action.type) { + case UPDATE_SERVER_MAP_LOADING_STATE: + return action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/server-map-selected-target.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/server-map-selected-target.reducer.ts new file mode 100644 index 000000000000..11d1db7e0826 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/server-map-selected-target.reducer.ts @@ -0,0 +1,32 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_SERVER_MAP_TARGET_SELECTED = 'UPDATE_SERVER_MAP_TARGET_SELECTED'; + +export class UpdateServerMapTargetSelected implements Action { + readonly type = UPDATE_SERVER_MAP_TARGET_SELECTED; + constructor(public payload: ISelectedTarget) {} +} + +export function Reducer(state: ISelectedTarget, action: UpdateServerMapTargetSelected): ISelectedTarget { + switch (action.type) { + case UPDATE_SERVER_MAP_TARGET_SELECTED: + if (action.payload === null) { + return {} as ISelectedTarget; + } else if ( + state && + state.endTime === action.payload.endTime && + state.period === action.payload.period && + state.isWAS === action.payload.isWAS && + (state.isNode === action.payload.isNode + ? (state.isNode ? state.node[0] === action.payload.node[0] : state.link[0] === action.payload.link[0]) + : false + ) + ) { + return state; + } else { + return action.payload; + } + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/server-map.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/server-map.reducer.ts new file mode 100644 index 000000000000..7f8464858118 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/server-map.reducer.ts @@ -0,0 +1,17 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_SERVER_MAP_DATA = 'UPDATE_SERVER_MAP_DATA'; + +export class UpdateServerMapData implements Action { + readonly type = UPDATE_SERVER_MAP_DATA; + constructor(public payload: any) {} +} + +export function Reducer(state = {}, action: UpdateServerMapData): any { + switch (action.type) { + case UPDATE_SERVER_MAP_DATA: + return action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/target-list.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/target-list.reducer.ts new file mode 100644 index 000000000000..2d0ed134fc8b --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/target-list.reducer.ts @@ -0,0 +1,20 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_SERVER_MAP_SELECTED_TARGET_BY_LIST = 'UPDATE_SERVER_MAP_SELECTED_TARGET_BY_LIST'; + +export class UpdateServerMapSelectedTargetByList implements Action { + readonly type = UPDATE_SERVER_MAP_SELECTED_TARGET_BY_LIST; + constructor(public payload: any) {} +} +export function Reducer(state: any, action: UpdateServerMapSelectedTargetByList): any { + switch (action.type) { + case UPDATE_SERVER_MAP_SELECTED_TARGET_BY_LIST: + if (state && state.key === action.payload.key) { + return state; + } else { + return action.payload; + } + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/timeline.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/timeline.reducer.ts new file mode 100644 index 000000000000..7beb90856ee1 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/timeline.reducer.ts @@ -0,0 +1,74 @@ +import { Action } from '@ngrx/store'; + +const initState: ITimelineInfo = { + range: [0, 0], + selectedTime: 0, + selectionRange: [0, 0], +}; + +const UPDATE_TIMELINE_INFO = 'UPDATE_TIMELINE_INFO'; +const UPDATE_TIMELINE_SELECTED_TIME = 'UPDATE_TIMELINE_SELECTED_TIME'; +const UPDATE_TIMELINE_SELECTION_RANGE = 'UPDATE_TIMELINE_SELECTION_RANGE'; +const UPDATE_TIMELINE_RANGE = 'UPDATE_TIMELINE_RANGE'; + +export class UpdateTimelineData implements Action { + readonly type = UPDATE_TIMELINE_INFO; + constructor(public payload: ITimelineInfo) {} +} +export class UpdateTimelineSelectedTime implements Action { + readonly type = UPDATE_TIMELINE_SELECTED_TIME; + constructor(public payload: number) {} +} +export class UpdateTimelineSelectionRange implements Action { + readonly type = UPDATE_TIMELINE_SELECTION_RANGE; + constructor(public payload: number[]) {} +} +export class UpdateTimelineRange implements Action { + readonly type = UPDATE_TIMELINE_RANGE; + constructor(public payload: number[]) {} +} +export function Reducer(state = initState, action: UpdateTimelineData | UpdateTimelineSelectedTime | UpdateTimelineSelectionRange | UpdateTimelineRange): ITimelineInfo { + switch (action.type) { + case UPDATE_TIMELINE_INFO: + if ( + state.range[0] !== action.payload.range[0] || + state.range[1] !== action.payload.range[1] || + state.selectedTime !== action.payload.selectedTime || + state.selectionRange[0] !== action.payload.selectionRange[0] || + state.selectionRange[1] !== action.payload.selectionRange[1] + ) { + return action.payload; + } else { + return state; + } + case UPDATE_TIMELINE_SELECTED_TIME: + if (state.selectedTime === action.payload) { + return state; + } else { + return { + ...state, + selectedTime : action.payload + }; + } + case UPDATE_TIMELINE_SELECTION_RANGE: + if (state.selectionRange[0] === action.payload[0] && state.selectionRange[1] === action.payload[1]) { + return state; + } else { + return { + ...state, + selectionRange: action.payload + }; + } + case UPDATE_TIMELINE_RANGE: + if (state.range[0] === action.payload[0] && state.range[1] === action.payload[1]) { + return state; + } else { + return { + ...state, + range: action.payload + }; + } + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/timezone.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/timezone.reducer.ts new file mode 100644 index 000000000000..d49657b361b5 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/timezone.reducer.ts @@ -0,0 +1,16 @@ +import { Action } from '@ngrx/store'; + +const CHANGE_TIMEZONE = 'CHANGE_TIMEZONE'; +export class ChangeTimezone implements Action { + readonly type = CHANGE_TIMEZONE; + constructor(public payload: string) {} +} + +export function Reducer(state = 'Asia/Seoul', action: ChangeTimezone): string { + switch (action.type) { + case CHANGE_TIMEZONE: + return (state === action.payload) ? state : action.payload; + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/transaction-detail-data.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/transaction-detail-data.reducer.ts new file mode 100644 index 000000000000..43e0dcd18a82 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/transaction-detail-data.reducer.ts @@ -0,0 +1,21 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_TRANSACTION_DETAIL_DATA = 'UPDATE_TRANSACTION_DETAIL_DATA'; + +export class UpdateTransactionDetailData implements Action { + readonly type = UPDATE_TRANSACTION_DETAIL_DATA; + constructor(public payload: ITransactionDetailData) {} +} + +export function Reducer(state: ITransactionDetailData, action: UpdateTransactionDetailData): ITransactionDetailData { + switch ( action.type ) { + case UPDATE_TRANSACTION_DETAIL_DATA: + if (state && (state.agentId === action.payload.agentId && state.applicationId === action.payload['applicationId'] && state.transactionId === action.payload.transactionId)) { + return state; + } else { + return action.payload; + } + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/app/shared/store/transaction-info.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/transaction-info.reducer.ts new file mode 100644 index 000000000000..446b94ffac84 --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/transaction-info.reducer.ts @@ -0,0 +1,22 @@ +import { Action } from '@ngrx/store'; + +const UPDATE_TRANSACTION_DATA = 'UPDATE_TRANSACTION_DATA'; + +export class UpdateTransactionData implements Action { + readonly type = UPDATE_TRANSACTION_DATA; + constructor(public payload: ITransactionMetaData) {} +} + +export function Reducer(state: ITransactionMetaData, action: UpdateTransactionData): ITransactionMetaData { + switch ( action.type ) { + case UPDATE_TRANSACTION_DATA: + if (state && (state.traceId === action.payload.traceId && state.collectorAcceptTime === action.payload.collectorAcceptTime && state.elapsed === action.payload.elapsed)) { + return state; + } else { + return action.payload; + } + default: + return state; + } +} + diff --git a/web/src/main/webapp/v2/src/app/shared/store/ui-state.reducer.ts b/web/src/main/webapp/v2/src/app/shared/store/ui-state.reducer.ts new file mode 100644 index 000000000000..333e63d97e5a --- /dev/null +++ b/web/src/main/webapp/v2/src/app/shared/store/ui-state.reducer.ts @@ -0,0 +1,43 @@ +import { Action } from '@ngrx/store'; + +const CHANGE_INFO_PER_SERVER_VISIBLE_STATE = 'CHANGE_INFO_PER_SERVER_VISIBLE_STATE'; +const CHANGE_SERVER_MAP_DISABLE_STATE = 'CHANGE_SERVER_MAP_DISABLE_STATE'; + +const initState = { + infoPerServer: false, + serverMap: false +}; + +export class ChangeInfoPerServerVisibleState implements Action { + readonly type = CHANGE_INFO_PER_SERVER_VISIBLE_STATE; + constructor(public payload: boolean) {} +} +export class ChangeServerMapDisableState implements Action { + readonly type = CHANGE_SERVER_MAP_DISABLE_STATE; + constructor(public payload: boolean) {} +} + +export function Reducer(state: IUIState = initState, action: ChangeInfoPerServerVisibleState | ChangeServerMapDisableState): IUIState { + switch (action.type) { + case CHANGE_INFO_PER_SERVER_VISIBLE_STATE: + if (action.payload === state['infoPerServer']) { + return state; + } else { + return { + ...state, + 'infoPerServer': action.payload + }; + } + case CHANGE_SERVER_MAP_DISABLE_STATE: + if (action.payload === state['serverMap']) { + return state; + } else { + return { + ...state, + 'serverMap': action.payload + }; + } + default: + return state; + } +} diff --git a/web/src/main/webapp/v2/src/assets/.gitkeep b/web/src/main/webapp/v2/src/assets/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/css/fontawesome-all.css b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/css/fontawesome-all.css new file mode 100644 index 000000000000..ec052ff5bd51 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/css/fontawesome-all.css @@ -0,0 +1,2861 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa, +.fas, +.far, +.fal, +.fab { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; } + +.fa-lg { + font-size: 1.33333em; + line-height: 0.75em; + vertical-align: -.0667em; } + +.fa-xs { + font-size: .75em; } + +.fa-sm { + font-size: .875em; } + +.fa-1x { + font-size: 1em; } + +.fa-2x { + font-size: 2em; } + +.fa-3x { + font-size: 3em; } + +.fa-4x { + font-size: 4em; } + +.fa-5x { + font-size: 5em; } + +.fa-6x { + font-size: 6em; } + +.fa-7x { + font-size: 7em; } + +.fa-8x { + font-size: 8em; } + +.fa-9x { + font-size: 9em; } + +.fa-10x { + font-size: 10em; } + +.fa-fw { + text-align: center; + width: 1.25em; } + +.fa-ul { + list-style-type: none; + margin-left: 2.5em; + padding-left: 0; } + .fa-ul > li { + position: relative; } + +.fa-li { + left: -2em; + position: absolute; + text-align: center; + width: 2em; + line-height: inherit; } + +.fa-border { + border: solid 0.08em #eee; + border-radius: .1em; + padding: .2em .25em .15em; } + +.fa-pull-left { + float: left; } + +.fa-pull-right { + float: right; } + +.fa.fa-pull-left, +.fas.fa-pull-left, +.far.fa-pull-left, +.fal.fa-pull-left, +.fab.fa-pull-left { + margin-right: .3em; } + +.fa.fa-pull-right, +.fas.fa-pull-right, +.far.fa-pull-right, +.fal.fa-pull-right, +.fab.fa-pull-right { + margin-left: .3em; } + +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; } + +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); } + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); } + +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); } + +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + transform: rotate(270deg); } + +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1); } + +.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-transform: scale(1, -1); + transform: scale(1, -1); } + +.fa-flip-horizontal.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-transform: scale(-1, -1); + transform: scale(-1, -1); } + +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + -webkit-filter: none; + filter: none; } + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2em; } + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; } + +.fa-stack-1x { + line-height: inherit; } + +.fa-stack-2x { + font-size: 2em; } + +.fa-inverse { + color: #fff; } + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ +.fa-500px:before { + content: "\f26e"; } + +.fa-accessible-icon:before { + content: "\f368"; } + +.fa-accusoft:before { + content: "\f369"; } + +.fa-address-book:before { + content: "\f2b9"; } + +.fa-address-card:before { + content: "\f2bb"; } + +.fa-adjust:before { + content: "\f042"; } + +.fa-adn:before { + content: "\f170"; } + +.fa-adversal:before { + content: "\f36a"; } + +.fa-affiliatetheme:before { + content: "\f36b"; } + +.fa-algolia:before { + content: "\f36c"; } + +.fa-align-center:before { + content: "\f037"; } + +.fa-align-justify:before { + content: "\f039"; } + +.fa-align-left:before { + content: "\f036"; } + +.fa-align-right:before { + content: "\f038"; } + +.fa-allergies:before { + content: "\f461"; } + +.fa-amazon:before { + content: "\f270"; } + +.fa-amazon-pay:before { + content: "\f42c"; } + +.fa-ambulance:before { + content: "\f0f9"; } + +.fa-american-sign-language-interpreting:before { + content: "\f2a3"; } + +.fa-amilia:before { + content: "\f36d"; } + +.fa-anchor:before { + content: "\f13d"; } + +.fa-android:before { + content: "\f17b"; } + +.fa-angellist:before { + content: "\f209"; } + +.fa-angle-double-down:before { + content: "\f103"; } + +.fa-angle-double-left:before { + content: "\f100"; } + +.fa-angle-double-right:before { + content: "\f101"; } + +.fa-angle-double-up:before { + content: "\f102"; } + +.fa-angle-down:before { + content: "\f107"; } + +.fa-angle-left:before { + content: "\f104"; } + +.fa-angle-right:before { + content: "\f105"; } + +.fa-angle-up:before { + content: "\f106"; } + +.fa-angrycreative:before { + content: "\f36e"; } + +.fa-angular:before { + content: "\f420"; } + +.fa-app-store:before { + content: "\f36f"; } + +.fa-app-store-ios:before { + content: "\f370"; } + +.fa-apper:before { + content: "\f371"; } + +.fa-apple:before { + content: "\f179"; } + +.fa-apple-pay:before { + content: "\f415"; } + +.fa-archive:before { + content: "\f187"; } + +.fa-arrow-alt-circle-down:before { + content: "\f358"; } + +.fa-arrow-alt-circle-left:before { + content: "\f359"; } + +.fa-arrow-alt-circle-right:before { + content: "\f35a"; } + +.fa-arrow-alt-circle-up:before { + content: "\f35b"; } + +.fa-arrow-circle-down:before { + content: "\f0ab"; } + +.fa-arrow-circle-left:before { + content: "\f0a8"; } + +.fa-arrow-circle-right:before { + content: "\f0a9"; } + +.fa-arrow-circle-up:before { + content: "\f0aa"; } + +.fa-arrow-down:before { + content: "\f063"; } + +.fa-arrow-left:before { + content: "\f060"; } + +.fa-arrow-right:before { + content: "\f061"; } + +.fa-arrow-up:before { + content: "\f062"; } + +.fa-arrows-alt:before { + content: "\f0b2"; } + +.fa-arrows-alt-h:before { + content: "\f337"; } + +.fa-arrows-alt-v:before { + content: "\f338"; } + +.fa-assistive-listening-systems:before { + content: "\f2a2"; } + +.fa-asterisk:before { + content: "\f069"; } + +.fa-asymmetrik:before { + content: "\f372"; } + +.fa-at:before { + content: "\f1fa"; } + +.fa-audible:before { + content: "\f373"; } + +.fa-audio-description:before { + content: "\f29e"; } + +.fa-autoprefixer:before { + content: "\f41c"; } + +.fa-avianex:before { + content: "\f374"; } + +.fa-aviato:before { + content: "\f421"; } + +.fa-aws:before { + content: "\f375"; } + +.fa-backward:before { + content: "\f04a"; } + +.fa-balance-scale:before { + content: "\f24e"; } + +.fa-ban:before { + content: "\f05e"; } + +.fa-band-aid:before { + content: "\f462"; } + +.fa-bandcamp:before { + content: "\f2d5"; } + +.fa-barcode:before { + content: "\f02a"; } + +.fa-bars:before { + content: "\f0c9"; } + +.fa-baseball-ball:before { + content: "\f433"; } + +.fa-basketball-ball:before { + content: "\f434"; } + +.fa-bath:before { + content: "\f2cd"; } + +.fa-battery-empty:before { + content: "\f244"; } + +.fa-battery-full:before { + content: "\f240"; } + +.fa-battery-half:before { + content: "\f242"; } + +.fa-battery-quarter:before { + content: "\f243"; } + +.fa-battery-three-quarters:before { + content: "\f241"; } + +.fa-bed:before { + content: "\f236"; } + +.fa-beer:before { + content: "\f0fc"; } + +.fa-behance:before { + content: "\f1b4"; } + +.fa-behance-square:before { + content: "\f1b5"; } + +.fa-bell:before { + content: "\f0f3"; } + +.fa-bell-slash:before { + content: "\f1f6"; } + +.fa-bicycle:before { + content: "\f206"; } + +.fa-bimobject:before { + content: "\f378"; } + +.fa-binoculars:before { + content: "\f1e5"; } + +.fa-birthday-cake:before { + content: "\f1fd"; } + +.fa-bitbucket:before { + content: "\f171"; } + +.fa-bitcoin:before { + content: "\f379"; } + +.fa-bity:before { + content: "\f37a"; } + +.fa-black-tie:before { + content: "\f27e"; } + +.fa-blackberry:before { + content: "\f37b"; } + +.fa-blind:before { + content: "\f29d"; } + +.fa-blogger:before { + content: "\f37c"; } + +.fa-blogger-b:before { + content: "\f37d"; } + +.fa-bluetooth:before { + content: "\f293"; } + +.fa-bluetooth-b:before { + content: "\f294"; } + +.fa-bold:before { + content: "\f032"; } + +.fa-bolt:before { + content: "\f0e7"; } + +.fa-bomb:before { + content: "\f1e2"; } + +.fa-book:before { + content: "\f02d"; } + +.fa-bookmark:before { + content: "\f02e"; } + +.fa-bowling-ball:before { + content: "\f436"; } + +.fa-box:before { + content: "\f466"; } + +.fa-box-open:before { + content: "\f49e"; } + +.fa-boxes:before { + content: "\f468"; } + +.fa-braille:before { + content: "\f2a1"; } + +.fa-briefcase:before { + content: "\f0b1"; } + +.fa-briefcase-medical:before { + content: "\f469"; } + +.fa-btc:before { + content: "\f15a"; } + +.fa-bug:before { + content: "\f188"; } + +.fa-building:before { + content: "\f1ad"; } + +.fa-bullhorn:before { + content: "\f0a1"; } + +.fa-bullseye:before { + content: "\f140"; } + +.fa-burn:before { + content: "\f46a"; } + +.fa-buromobelexperte:before { + content: "\f37f"; } + +.fa-bus:before { + content: "\f207"; } + +.fa-buysellads:before { + content: "\f20d"; } + +.fa-calculator:before { + content: "\f1ec"; } + +.fa-calendar:before { + content: "\f133"; } + +.fa-calendar-alt:before { + content: "\f073"; } + +.fa-calendar-check:before { + content: "\f274"; } + +.fa-calendar-minus:before { + content: "\f272"; } + +.fa-calendar-plus:before { + content: "\f271"; } + +.fa-calendar-times:before { + content: "\f273"; } + +.fa-camera:before { + content: "\f030"; } + +.fa-camera-retro:before { + content: "\f083"; } + +.fa-capsules:before { + content: "\f46b"; } + +.fa-car:before { + content: "\f1b9"; } + +.fa-caret-down:before { + content: "\f0d7"; } + +.fa-caret-left:before { + content: "\f0d9"; } + +.fa-caret-right:before { + content: "\f0da"; } + +.fa-caret-square-down:before { + content: "\f150"; } + +.fa-caret-square-left:before { + content: "\f191"; } + +.fa-caret-square-right:before { + content: "\f152"; } + +.fa-caret-square-up:before { + content: "\f151"; } + +.fa-caret-up:before { + content: "\f0d8"; } + +.fa-cart-arrow-down:before { + content: "\f218"; } + +.fa-cart-plus:before { + content: "\f217"; } + +.fa-cc-amazon-pay:before { + content: "\f42d"; } + +.fa-cc-amex:before { + content: "\f1f3"; } + +.fa-cc-apple-pay:before { + content: "\f416"; } + +.fa-cc-diners-club:before { + content: "\f24c"; } + +.fa-cc-discover:before { + content: "\f1f2"; } + +.fa-cc-jcb:before { + content: "\f24b"; } + +.fa-cc-mastercard:before { + content: "\f1f1"; } + +.fa-cc-paypal:before { + content: "\f1f4"; } + +.fa-cc-stripe:before { + content: "\f1f5"; } + +.fa-cc-visa:before { + content: "\f1f0"; } + +.fa-centercode:before { + content: "\f380"; } + +.fa-certificate:before { + content: "\f0a3"; } + +.fa-chart-area:before { + content: "\f1fe"; } + +.fa-chart-bar:before { + content: "\f080"; } + +.fa-chart-line:before { + content: "\f201"; } + +.fa-chart-pie:before { + content: "\f200"; } + +.fa-check:before { + content: "\f00c"; } + +.fa-check-circle:before { + content: "\f058"; } + +.fa-check-square:before { + content: "\f14a"; } + +.fa-chess:before { + content: "\f439"; } + +.fa-chess-bishop:before { + content: "\f43a"; } + +.fa-chess-board:before { + content: "\f43c"; } + +.fa-chess-king:before { + content: "\f43f"; } + +.fa-chess-knight:before { + content: "\f441"; } + +.fa-chess-pawn:before { + content: "\f443"; } + +.fa-chess-queen:before { + content: "\f445"; } + +.fa-chess-rook:before { + content: "\f447"; } + +.fa-chevron-circle-down:before { + content: "\f13a"; } + +.fa-chevron-circle-left:before { + content: "\f137"; } + +.fa-chevron-circle-right:before { + content: "\f138"; } + +.fa-chevron-circle-up:before { + content: "\f139"; } + +.fa-chevron-down:before { + content: "\f078"; } + +.fa-chevron-left:before { + content: "\f053"; } + +.fa-chevron-right:before { + content: "\f054"; } + +.fa-chevron-up:before { + content: "\f077"; } + +.fa-child:before { + content: "\f1ae"; } + +.fa-chrome:before { + content: "\f268"; } + +.fa-circle:before { + content: "\f111"; } + +.fa-circle-notch:before { + content: "\f1ce"; } + +.fa-clipboard:before { + content: "\f328"; } + +.fa-clipboard-check:before { + content: "\f46c"; } + +.fa-clipboard-list:before { + content: "\f46d"; } + +.fa-clock:before { + content: "\f017"; } + +.fa-clone:before { + content: "\f24d"; } + +.fa-closed-captioning:before { + content: "\f20a"; } + +.fa-cloud:before { + content: "\f0c2"; } + +.fa-cloud-download-alt:before { + content: "\f381"; } + +.fa-cloud-upload-alt:before { + content: "\f382"; } + +.fa-cloudscale:before { + content: "\f383"; } + +.fa-cloudsmith:before { + content: "\f384"; } + +.fa-cloudversify:before { + content: "\f385"; } + +.fa-code:before { + content: "\f121"; } + +.fa-code-branch:before { + content: "\f126"; } + +.fa-codepen:before { + content: "\f1cb"; } + +.fa-codiepie:before { + content: "\f284"; } + +.fa-coffee:before { + content: "\f0f4"; } + +.fa-cog:before { + content: "\f013"; } + +.fa-cogs:before { + content: "\f085"; } + +.fa-columns:before { + content: "\f0db"; } + +.fa-comment:before { + content: "\f075"; } + +.fa-comment-alt:before { + content: "\f27a"; } + +.fa-comment-dots:before { + content: "\f4ad"; } + +.fa-comment-slash:before { + content: "\f4b3"; } + +.fa-comments:before { + content: "\f086"; } + +.fa-compass:before { + content: "\f14e"; } + +.fa-compress:before { + content: "\f066"; } + +.fa-connectdevelop:before { + content: "\f20e"; } + +.fa-contao:before { + content: "\f26d"; } + +.fa-copy:before { + content: "\f0c5"; } + +.fa-copyright:before { + content: "\f1f9"; } + +.fa-couch:before { + content: "\f4b8"; } + +.fa-cpanel:before { + content: "\f388"; } + +.fa-creative-commons:before { + content: "\f25e"; } + +.fa-credit-card:before { + content: "\f09d"; } + +.fa-crop:before { + content: "\f125"; } + +.fa-crosshairs:before { + content: "\f05b"; } + +.fa-css3:before { + content: "\f13c"; } + +.fa-css3-alt:before { + content: "\f38b"; } + +.fa-cube:before { + content: "\f1b2"; } + +.fa-cubes:before { + content: "\f1b3"; } + +.fa-cut:before { + content: "\f0c4"; } + +.fa-cuttlefish:before { + content: "\f38c"; } + +.fa-d-and-d:before { + content: "\f38d"; } + +.fa-dashcube:before { + content: "\f210"; } + +.fa-database:before { + content: "\f1c0"; } + +.fa-deaf:before { + content: "\f2a4"; } + +.fa-delicious:before { + content: "\f1a5"; } + +.fa-deploydog:before { + content: "\f38e"; } + +.fa-deskpro:before { + content: "\f38f"; } + +.fa-desktop:before { + content: "\f108"; } + +.fa-deviantart:before { + content: "\f1bd"; } + +.fa-diagnoses:before { + content: "\f470"; } + +.fa-digg:before { + content: "\f1a6"; } + +.fa-digital-ocean:before { + content: "\f391"; } + +.fa-discord:before { + content: "\f392"; } + +.fa-discourse:before { + content: "\f393"; } + +.fa-dna:before { + content: "\f471"; } + +.fa-dochub:before { + content: "\f394"; } + +.fa-docker:before { + content: "\f395"; } + +.fa-dollar-sign:before { + content: "\f155"; } + +.fa-dolly:before { + content: "\f472"; } + +.fa-dolly-flatbed:before { + content: "\f474"; } + +.fa-donate:before { + content: "\f4b9"; } + +.fa-dot-circle:before { + content: "\f192"; } + +.fa-dove:before { + content: "\f4ba"; } + +.fa-download:before { + content: "\f019"; } + +.fa-draft2digital:before { + content: "\f396"; } + +.fa-dribbble:before { + content: "\f17d"; } + +.fa-dribbble-square:before { + content: "\f397"; } + +.fa-dropbox:before { + content: "\f16b"; } + +.fa-drupal:before { + content: "\f1a9"; } + +.fa-dyalog:before { + content: "\f399"; } + +.fa-earlybirds:before { + content: "\f39a"; } + +.fa-edge:before { + content: "\f282"; } + +.fa-edit:before { + content: "\f044"; } + +.fa-eject:before { + content: "\f052"; } + +.fa-elementor:before { + content: "\f430"; } + +.fa-ellipsis-h:before { + content: "\f141"; } + +.fa-ellipsis-v:before { + content: "\f142"; } + +.fa-ember:before { + content: "\f423"; } + +.fa-empire:before { + content: "\f1d1"; } + +.fa-envelope:before { + content: "\f0e0"; } + +.fa-envelope-open:before { + content: "\f2b6"; } + +.fa-envelope-square:before { + content: "\f199"; } + +.fa-envira:before { + content: "\f299"; } + +.fa-eraser:before { + content: "\f12d"; } + +.fa-erlang:before { + content: "\f39d"; } + +.fa-ethereum:before { + content: "\f42e"; } + +.fa-etsy:before { + content: "\f2d7"; } + +.fa-euro-sign:before { + content: "\f153"; } + +.fa-exchange-alt:before { + content: "\f362"; } + +.fa-exclamation:before { + content: "\f12a"; } + +.fa-exclamation-circle:before { + content: "\f06a"; } + +.fa-exclamation-triangle:before { + content: "\f071"; } + +.fa-expand:before { + content: "\f065"; } + +.fa-expand-arrows-alt:before { + content: "\f31e"; } + +.fa-expeditedssl:before { + content: "\f23e"; } + +.fa-external-link-alt:before { + content: "\f35d"; } + +.fa-external-link-square-alt:before { + content: "\f360"; } + +.fa-eye:before { + content: "\f06e"; } + +.fa-eye-dropper:before { + content: "\f1fb"; } + +.fa-eye-slash:before { + content: "\f070"; } + +.fa-facebook:before { + content: "\f09a"; } + +.fa-facebook-f:before { + content: "\f39e"; } + +.fa-facebook-messenger:before { + content: "\f39f"; } + +.fa-facebook-square:before { + content: "\f082"; } + +.fa-fast-backward:before { + content: "\f049"; } + +.fa-fast-forward:before { + content: "\f050"; } + +.fa-fax:before { + content: "\f1ac"; } + +.fa-female:before { + content: "\f182"; } + +.fa-fighter-jet:before { + content: "\f0fb"; } + +.fa-file:before { + content: "\f15b"; } + +.fa-file-alt:before { + content: "\f15c"; } + +.fa-file-archive:before { + content: "\f1c6"; } + +.fa-file-audio:before { + content: "\f1c7"; } + +.fa-file-code:before { + content: "\f1c9"; } + +.fa-file-excel:before { + content: "\f1c3"; } + +.fa-file-image:before { + content: "\f1c5"; } + +.fa-file-medical:before { + content: "\f477"; } + +.fa-file-medical-alt:before { + content: "\f478"; } + +.fa-file-pdf:before { + content: "\f1c1"; } + +.fa-file-powerpoint:before { + content: "\f1c4"; } + +.fa-file-video:before { + content: "\f1c8"; } + +.fa-file-word:before { + content: "\f1c2"; } + +.fa-film:before { + content: "\f008"; } + +.fa-filter:before { + content: "\f0b0"; } + +.fa-fire:before { + content: "\f06d"; } + +.fa-fire-extinguisher:before { + content: "\f134"; } + +.fa-firefox:before { + content: "\f269"; } + +.fa-first-aid:before { + content: "\f479"; } + +.fa-first-order:before { + content: "\f2b0"; } + +.fa-firstdraft:before { + content: "\f3a1"; } + +.fa-flag:before { + content: "\f024"; } + +.fa-flag-checkered:before { + content: "\f11e"; } + +.fa-flask:before { + content: "\f0c3"; } + +.fa-flickr:before { + content: "\f16e"; } + +.fa-flipboard:before { + content: "\f44d"; } + +.fa-fly:before { + content: "\f417"; } + +.fa-folder:before { + content: "\f07b"; } + +.fa-folder-open:before { + content: "\f07c"; } + +.fa-font:before { + content: "\f031"; } + +.fa-font-awesome:before { + content: "\f2b4"; } + +.fa-font-awesome-alt:before { + content: "\f35c"; } + +.fa-font-awesome-flag:before { + content: "\f425"; } + +.fa-fonticons:before { + content: "\f280"; } + +.fa-fonticons-fi:before { + content: "\f3a2"; } + +.fa-football-ball:before { + content: "\f44e"; } + +.fa-fort-awesome:before { + content: "\f286"; } + +.fa-fort-awesome-alt:before { + content: "\f3a3"; } + +.fa-forumbee:before { + content: "\f211"; } + +.fa-forward:before { + content: "\f04e"; } + +.fa-foursquare:before { + content: "\f180"; } + +.fa-free-code-camp:before { + content: "\f2c5"; } + +.fa-freebsd:before { + content: "\f3a4"; } + +.fa-frown:before { + content: "\f119"; } + +.fa-futbol:before { + content: "\f1e3"; } + +.fa-gamepad:before { + content: "\f11b"; } + +.fa-gavel:before { + content: "\f0e3"; } + +.fa-gem:before { + content: "\f3a5"; } + +.fa-genderless:before { + content: "\f22d"; } + +.fa-get-pocket:before { + content: "\f265"; } + +.fa-gg:before { + content: "\f260"; } + +.fa-gg-circle:before { + content: "\f261"; } + +.fa-gift:before { + content: "\f06b"; } + +.fa-git:before { + content: "\f1d3"; } + +.fa-git-square:before { + content: "\f1d2"; } + +.fa-github:before { + content: "\f09b"; } + +.fa-github-alt:before { + content: "\f113"; } + +.fa-github-square:before { + content: "\f092"; } + +.fa-gitkraken:before { + content: "\f3a6"; } + +.fa-gitlab:before { + content: "\f296"; } + +.fa-gitter:before { + content: "\f426"; } + +.fa-glass-martini:before { + content: "\f000"; } + +.fa-glide:before { + content: "\f2a5"; } + +.fa-glide-g:before { + content: "\f2a6"; } + +.fa-globe:before { + content: "\f0ac"; } + +.fa-gofore:before { + content: "\f3a7"; } + +.fa-golf-ball:before { + content: "\f450"; } + +.fa-goodreads:before { + content: "\f3a8"; } + +.fa-goodreads-g:before { + content: "\f3a9"; } + +.fa-google:before { + content: "\f1a0"; } + +.fa-google-drive:before { + content: "\f3aa"; } + +.fa-google-play:before { + content: "\f3ab"; } + +.fa-google-plus:before { + content: "\f2b3"; } + +.fa-google-plus-g:before { + content: "\f0d5"; } + +.fa-google-plus-square:before { + content: "\f0d4"; } + +.fa-google-wallet:before { + content: "\f1ee"; } + +.fa-graduation-cap:before { + content: "\f19d"; } + +.fa-gratipay:before { + content: "\f184"; } + +.fa-grav:before { + content: "\f2d6"; } + +.fa-gripfire:before { + content: "\f3ac"; } + +.fa-grunt:before { + content: "\f3ad"; } + +.fa-gulp:before { + content: "\f3ae"; } + +.fa-h-square:before { + content: "\f0fd"; } + +.fa-hacker-news:before { + content: "\f1d4"; } + +.fa-hacker-news-square:before { + content: "\f3af"; } + +.fa-hand-holding:before { + content: "\f4bd"; } + +.fa-hand-holding-heart:before { + content: "\f4be"; } + +.fa-hand-holding-usd:before { + content: "\f4c0"; } + +.fa-hand-lizard:before { + content: "\f258"; } + +.fa-hand-paper:before { + content: "\f256"; } + +.fa-hand-peace:before { + content: "\f25b"; } + +.fa-hand-point-down:before { + content: "\f0a7"; } + +.fa-hand-point-left:before { + content: "\f0a5"; } + +.fa-hand-point-right:before { + content: "\f0a4"; } + +.fa-hand-point-up:before { + content: "\f0a6"; } + +.fa-hand-pointer:before { + content: "\f25a"; } + +.fa-hand-rock:before { + content: "\f255"; } + +.fa-hand-scissors:before { + content: "\f257"; } + +.fa-hand-spock:before { + content: "\f259"; } + +.fa-hands:before { + content: "\f4c2"; } + +.fa-hands-helping:before { + content: "\f4c4"; } + +.fa-handshake:before { + content: "\f2b5"; } + +.fa-hashtag:before { + content: "\f292"; } + +.fa-hdd:before { + content: "\f0a0"; } + +.fa-heading:before { + content: "\f1dc"; } + +.fa-headphones:before { + content: "\f025"; } + +.fa-heart:before { + content: "\f004"; } + +.fa-heartbeat:before { + content: "\f21e"; } + +.fa-hips:before { + content: "\f452"; } + +.fa-hire-a-helper:before { + content: "\f3b0"; } + +.fa-history:before { + content: "\f1da"; } + +.fa-hockey-puck:before { + content: "\f453"; } + +.fa-home:before { + content: "\f015"; } + +.fa-hooli:before { + content: "\f427"; } + +.fa-hospital:before { + content: "\f0f8"; } + +.fa-hospital-alt:before { + content: "\f47d"; } + +.fa-hospital-symbol:before { + content: "\f47e"; } + +.fa-hotjar:before { + content: "\f3b1"; } + +.fa-hourglass:before { + content: "\f254"; } + +.fa-hourglass-end:before { + content: "\f253"; } + +.fa-hourglass-half:before { + content: "\f252"; } + +.fa-hourglass-start:before { + content: "\f251"; } + +.fa-houzz:before { + content: "\f27c"; } + +.fa-html5:before { + content: "\f13b"; } + +.fa-hubspot:before { + content: "\f3b2"; } + +.fa-i-cursor:before { + content: "\f246"; } + +.fa-id-badge:before { + content: "\f2c1"; } + +.fa-id-card:before { + content: "\f2c2"; } + +.fa-id-card-alt:before { + content: "\f47f"; } + +.fa-image:before { + content: "\f03e"; } + +.fa-images:before { + content: "\f302"; } + +.fa-imdb:before { + content: "\f2d8"; } + +.fa-inbox:before { + content: "\f01c"; } + +.fa-indent:before { + content: "\f03c"; } + +.fa-industry:before { + content: "\f275"; } + +.fa-info:before { + content: "\f129"; } + +.fa-info-circle:before { + content: "\f05a"; } + +.fa-instagram:before { + content: "\f16d"; } + +.fa-internet-explorer:before { + content: "\f26b"; } + +.fa-ioxhost:before { + content: "\f208"; } + +.fa-italic:before { + content: "\f033"; } + +.fa-itunes:before { + content: "\f3b4"; } + +.fa-itunes-note:before { + content: "\f3b5"; } + +.fa-java:before { + content: "\f4e4"; } + +.fa-jenkins:before { + content: "\f3b6"; } + +.fa-joget:before { + content: "\f3b7"; } + +.fa-joomla:before { + content: "\f1aa"; } + +.fa-js:before { + content: "\f3b8"; } + +.fa-js-square:before { + content: "\f3b9"; } + +.fa-jsfiddle:before { + content: "\f1cc"; } + +.fa-key:before { + content: "\f084"; } + +.fa-keyboard:before { + content: "\f11c"; } + +.fa-keycdn:before { + content: "\f3ba"; } + +.fa-kickstarter:before { + content: "\f3bb"; } + +.fa-kickstarter-k:before { + content: "\f3bc"; } + +.fa-korvue:before { + content: "\f42f"; } + +.fa-language:before { + content: "\f1ab"; } + +.fa-laptop:before { + content: "\f109"; } + +.fa-laravel:before { + content: "\f3bd"; } + +.fa-lastfm:before { + content: "\f202"; } + +.fa-lastfm-square:before { + content: "\f203"; } + +.fa-leaf:before { + content: "\f06c"; } + +.fa-leanpub:before { + content: "\f212"; } + +.fa-lemon:before { + content: "\f094"; } + +.fa-less:before { + content: "\f41d"; } + +.fa-level-down-alt:before { + content: "\f3be"; } + +.fa-level-up-alt:before { + content: "\f3bf"; } + +.fa-life-ring:before { + content: "\f1cd"; } + +.fa-lightbulb:before { + content: "\f0eb"; } + +.fa-line:before { + content: "\f3c0"; } + +.fa-link:before { + content: "\f0c1"; } + +.fa-linkedin:before { + content: "\f08c"; } + +.fa-linkedin-in:before { + content: "\f0e1"; } + +.fa-linode:before { + content: "\f2b8"; } + +.fa-linux:before { + content: "\f17c"; } + +.fa-lira-sign:before { + content: "\f195"; } + +.fa-list:before { + content: "\f03a"; } + +.fa-list-alt:before { + content: "\f022"; } + +.fa-list-ol:before { + content: "\f0cb"; } + +.fa-list-ul:before { + content: "\f0ca"; } + +.fa-location-arrow:before { + content: "\f124"; } + +.fa-lock:before { + content: "\f023"; } + +.fa-lock-open:before { + content: "\f3c1"; } + +.fa-long-arrow-alt-down:before { + content: "\f309"; } + +.fa-long-arrow-alt-left:before { + content: "\f30a"; } + +.fa-long-arrow-alt-right:before { + content: "\f30b"; } + +.fa-long-arrow-alt-up:before { + content: "\f30c"; } + +.fa-low-vision:before { + content: "\f2a8"; } + +.fa-lyft:before { + content: "\f3c3"; } + +.fa-magento:before { + content: "\f3c4"; } + +.fa-magic:before { + content: "\f0d0"; } + +.fa-magnet:before { + content: "\f076"; } + +.fa-male:before { + content: "\f183"; } + +.fa-map:before { + content: "\f279"; } + +.fa-map-marker:before { + content: "\f041"; } + +.fa-map-marker-alt:before { + content: "\f3c5"; } + +.fa-map-pin:before { + content: "\f276"; } + +.fa-map-signs:before { + content: "\f277"; } + +.fa-mars:before { + content: "\f222"; } + +.fa-mars-double:before { + content: "\f227"; } + +.fa-mars-stroke:before { + content: "\f229"; } + +.fa-mars-stroke-h:before { + content: "\f22b"; } + +.fa-mars-stroke-v:before { + content: "\f22a"; } + +.fa-maxcdn:before { + content: "\f136"; } + +.fa-medapps:before { + content: "\f3c6"; } + +.fa-medium:before { + content: "\f23a"; } + +.fa-medium-m:before { + content: "\f3c7"; } + +.fa-medkit:before { + content: "\f0fa"; } + +.fa-medrt:before { + content: "\f3c8"; } + +.fa-meetup:before { + content: "\f2e0"; } + +.fa-meh:before { + content: "\f11a"; } + +.fa-mercury:before { + content: "\f223"; } + +.fa-microchip:before { + content: "\f2db"; } + +.fa-microphone:before { + content: "\f130"; } + +.fa-microphone-slash:before { + content: "\f131"; } + +.fa-microsoft:before { + content: "\f3ca"; } + +.fa-minus:before { + content: "\f068"; } + +.fa-minus-circle:before { + content: "\f056"; } + +.fa-minus-square:before { + content: "\f146"; } + +.fa-mix:before { + content: "\f3cb"; } + +.fa-mixcloud:before { + content: "\f289"; } + +.fa-mizuni:before { + content: "\f3cc"; } + +.fa-mobile:before { + content: "\f10b"; } + +.fa-mobile-alt:before { + content: "\f3cd"; } + +.fa-modx:before { + content: "\f285"; } + +.fa-monero:before { + content: "\f3d0"; } + +.fa-money-bill-alt:before { + content: "\f3d1"; } + +.fa-moon:before { + content: "\f186"; } + +.fa-motorcycle:before { + content: "\f21c"; } + +.fa-mouse-pointer:before { + content: "\f245"; } + +.fa-music:before { + content: "\f001"; } + +.fa-napster:before { + content: "\f3d2"; } + +.fa-neuter:before { + content: "\f22c"; } + +.fa-newspaper:before { + content: "\f1ea"; } + +.fa-nintendo-switch:before { + content: "\f418"; } + +.fa-node:before { + content: "\f419"; } + +.fa-node-js:before { + content: "\f3d3"; } + +.fa-notes-medical:before { + content: "\f481"; } + +.fa-npm:before { + content: "\f3d4"; } + +.fa-ns8:before { + content: "\f3d5"; } + +.fa-nutritionix:before { + content: "\f3d6"; } + +.fa-object-group:before { + content: "\f247"; } + +.fa-object-ungroup:before { + content: "\f248"; } + +.fa-odnoklassniki:before { + content: "\f263"; } + +.fa-odnoklassniki-square:before { + content: "\f264"; } + +.fa-opencart:before { + content: "\f23d"; } + +.fa-openid:before { + content: "\f19b"; } + +.fa-opera:before { + content: "\f26a"; } + +.fa-optin-monster:before { + content: "\f23c"; } + +.fa-osi:before { + content: "\f41a"; } + +.fa-outdent:before { + content: "\f03b"; } + +.fa-page4:before { + content: "\f3d7"; } + +.fa-pagelines:before { + content: "\f18c"; } + +.fa-paint-brush:before { + content: "\f1fc"; } + +.fa-palfed:before { + content: "\f3d8"; } + +.fa-pallet:before { + content: "\f482"; } + +.fa-paper-plane:before { + content: "\f1d8"; } + +.fa-paperclip:before { + content: "\f0c6"; } + +.fa-parachute-box:before { + content: "\f4cd"; } + +.fa-paragraph:before { + content: "\f1dd"; } + +.fa-paste:before { + content: "\f0ea"; } + +.fa-patreon:before { + content: "\f3d9"; } + +.fa-pause:before { + content: "\f04c"; } + +.fa-pause-circle:before { + content: "\f28b"; } + +.fa-paw:before { + content: "\f1b0"; } + +.fa-paypal:before { + content: "\f1ed"; } + +.fa-pen-square:before { + content: "\f14b"; } + +.fa-pencil-alt:before { + content: "\f303"; } + +.fa-people-carry:before { + content: "\f4ce"; } + +.fa-percent:before { + content: "\f295"; } + +.fa-periscope:before { + content: "\f3da"; } + +.fa-phabricator:before { + content: "\f3db"; } + +.fa-phoenix-framework:before { + content: "\f3dc"; } + +.fa-phone:before { + content: "\f095"; } + +.fa-phone-slash:before { + content: "\f3dd"; } + +.fa-phone-square:before { + content: "\f098"; } + +.fa-phone-volume:before { + content: "\f2a0"; } + +.fa-php:before { + content: "\f457"; } + +.fa-pied-piper:before { + content: "\f2ae"; } + +.fa-pied-piper-alt:before { + content: "\f1a8"; } + +.fa-pied-piper-hat:before { + content: "\f4e5"; } + +.fa-pied-piper-pp:before { + content: "\f1a7"; } + +.fa-piggy-bank:before { + content: "\f4d3"; } + +.fa-pills:before { + content: "\f484"; } + +.fa-pinterest:before { + content: "\f0d2"; } + +.fa-pinterest-p:before { + content: "\f231"; } + +.fa-pinterest-square:before { + content: "\f0d3"; } + +.fa-plane:before { + content: "\f072"; } + +.fa-play:before { + content: "\f04b"; } + +.fa-play-circle:before { + content: "\f144"; } + +.fa-playstation:before { + content: "\f3df"; } + +.fa-plug:before { + content: "\f1e6"; } + +.fa-plus:before { + content: "\f067"; } + +.fa-plus-circle:before { + content: "\f055"; } + +.fa-plus-square:before { + content: "\f0fe"; } + +.fa-podcast:before { + content: "\f2ce"; } + +.fa-poo:before { + content: "\f2fe"; } + +.fa-pound-sign:before { + content: "\f154"; } + +.fa-power-off:before { + content: "\f011"; } + +.fa-prescription-bottle:before { + content: "\f485"; } + +.fa-prescription-bottle-alt:before { + content: "\f486"; } + +.fa-print:before { + content: "\f02f"; } + +.fa-procedures:before { + content: "\f487"; } + +.fa-product-hunt:before { + content: "\f288"; } + +.fa-pushed:before { + content: "\f3e1"; } + +.fa-puzzle-piece:before { + content: "\f12e"; } + +.fa-python:before { + content: "\f3e2"; } + +.fa-qq:before { + content: "\f1d6"; } + +.fa-qrcode:before { + content: "\f029"; } + +.fa-question:before { + content: "\f128"; } + +.fa-question-circle:before { + content: "\f059"; } + +.fa-quidditch:before { + content: "\f458"; } + +.fa-quinscape:before { + content: "\f459"; } + +.fa-quora:before { + content: "\f2c4"; } + +.fa-quote-left:before { + content: "\f10d"; } + +.fa-quote-right:before { + content: "\f10e"; } + +.fa-random:before { + content: "\f074"; } + +.fa-ravelry:before { + content: "\f2d9"; } + +.fa-react:before { + content: "\f41b"; } + +.fa-readme:before { + content: "\f4d5"; } + +.fa-rebel:before { + content: "\f1d0"; } + +.fa-recycle:before { + content: "\f1b8"; } + +.fa-red-river:before { + content: "\f3e3"; } + +.fa-reddit:before { + content: "\f1a1"; } + +.fa-reddit-alien:before { + content: "\f281"; } + +.fa-reddit-square:before { + content: "\f1a2"; } + +.fa-redo:before { + content: "\f01e"; } + +.fa-redo-alt:before { + content: "\f2f9"; } + +.fa-registered:before { + content: "\f25d"; } + +.fa-rendact:before { + content: "\f3e4"; } + +.fa-renren:before { + content: "\f18b"; } + +.fa-reply:before { + content: "\f3e5"; } + +.fa-reply-all:before { + content: "\f122"; } + +.fa-replyd:before { + content: "\f3e6"; } + +.fa-resolving:before { + content: "\f3e7"; } + +.fa-retweet:before { + content: "\f079"; } + +.fa-ribbon:before { + content: "\f4d6"; } + +.fa-road:before { + content: "\f018"; } + +.fa-rocket:before { + content: "\f135"; } + +.fa-rocketchat:before { + content: "\f3e8"; } + +.fa-rockrms:before { + content: "\f3e9"; } + +.fa-rss:before { + content: "\f09e"; } + +.fa-rss-square:before { + content: "\f143"; } + +.fa-ruble-sign:before { + content: "\f158"; } + +.fa-rupee-sign:before { + content: "\f156"; } + +.fa-safari:before { + content: "\f267"; } + +.fa-sass:before { + content: "\f41e"; } + +.fa-save:before { + content: "\f0c7"; } + +.fa-schlix:before { + content: "\f3ea"; } + +.fa-scribd:before { + content: "\f28a"; } + +.fa-search:before { + content: "\f002"; } + +.fa-search-minus:before { + content: "\f010"; } + +.fa-search-plus:before { + content: "\f00e"; } + +.fa-searchengin:before { + content: "\f3eb"; } + +.fa-seedling:before { + content: "\f4d8"; } + +.fa-sellcast:before { + content: "\f2da"; } + +.fa-sellsy:before { + content: "\f213"; } + +.fa-server:before { + content: "\f233"; } + +.fa-servicestack:before { + content: "\f3ec"; } + +.fa-share:before { + content: "\f064"; } + +.fa-share-alt:before { + content: "\f1e0"; } + +.fa-share-alt-square:before { + content: "\f1e1"; } + +.fa-share-square:before { + content: "\f14d"; } + +.fa-shekel-sign:before { + content: "\f20b"; } + +.fa-shield-alt:before { + content: "\f3ed"; } + +.fa-ship:before { + content: "\f21a"; } + +.fa-shipping-fast:before { + content: "\f48b"; } + +.fa-shirtsinbulk:before { + content: "\f214"; } + +.fa-shopping-bag:before { + content: "\f290"; } + +.fa-shopping-basket:before { + content: "\f291"; } + +.fa-shopping-cart:before { + content: "\f07a"; } + +.fa-shower:before { + content: "\f2cc"; } + +.fa-sign:before { + content: "\f4d9"; } + +.fa-sign-in-alt:before { + content: "\f2f6"; } + +.fa-sign-language:before { + content: "\f2a7"; } + +.fa-sign-out-alt:before { + content: "\f2f5"; } + +.fa-signal:before { + content: "\f012"; } + +.fa-simplybuilt:before { + content: "\f215"; } + +.fa-sistrix:before { + content: "\f3ee"; } + +.fa-sitemap:before { + content: "\f0e8"; } + +.fa-skyatlas:before { + content: "\f216"; } + +.fa-skype:before { + content: "\f17e"; } + +.fa-slack:before { + content: "\f198"; } + +.fa-slack-hash:before { + content: "\f3ef"; } + +.fa-sliders-h:before { + content: "\f1de"; } + +.fa-slideshare:before { + content: "\f1e7"; } + +.fa-smile:before { + content: "\f118"; } + +.fa-smoking:before { + content: "\f48d"; } + +.fa-snapchat:before { + content: "\f2ab"; } + +.fa-snapchat-ghost:before { + content: "\f2ac"; } + +.fa-snapchat-square:before { + content: "\f2ad"; } + +.fa-snowflake:before { + content: "\f2dc"; } + +.fa-sort:before { + content: "\f0dc"; } + +.fa-sort-alpha-down:before { + content: "\f15d"; } + +.fa-sort-alpha-up:before { + content: "\f15e"; } + +.fa-sort-amount-down:before { + content: "\f160"; } + +.fa-sort-amount-up:before { + content: "\f161"; } + +.fa-sort-down:before { + content: "\f0dd"; } + +.fa-sort-numeric-down:before { + content: "\f162"; } + +.fa-sort-numeric-up:before { + content: "\f163"; } + +.fa-sort-up:before { + content: "\f0de"; } + +.fa-soundcloud:before { + content: "\f1be"; } + +.fa-space-shuttle:before { + content: "\f197"; } + +.fa-speakap:before { + content: "\f3f3"; } + +.fa-spinner:before { + content: "\f110"; } + +.fa-spotify:before { + content: "\f1bc"; } + +.fa-square:before { + content: "\f0c8"; } + +.fa-square-full:before { + content: "\f45c"; } + +.fa-stack-exchange:before { + content: "\f18d"; } + +.fa-stack-overflow:before { + content: "\f16c"; } + +.fa-star:before { + content: "\f005"; } + +.fa-star-half:before { + content: "\f089"; } + +.fa-staylinked:before { + content: "\f3f5"; } + +.fa-steam:before { + content: "\f1b6"; } + +.fa-steam-square:before { + content: "\f1b7"; } + +.fa-steam-symbol:before { + content: "\f3f6"; } + +.fa-step-backward:before { + content: "\f048"; } + +.fa-step-forward:before { + content: "\f051"; } + +.fa-stethoscope:before { + content: "\f0f1"; } + +.fa-sticker-mule:before { + content: "\f3f7"; } + +.fa-sticky-note:before { + content: "\f249"; } + +.fa-stop:before { + content: "\f04d"; } + +.fa-stop-circle:before { + content: "\f28d"; } + +.fa-stopwatch:before { + content: "\f2f2"; } + +.fa-strava:before { + content: "\f428"; } + +.fa-street-view:before { + content: "\f21d"; } + +.fa-strikethrough:before { + content: "\f0cc"; } + +.fa-stripe:before { + content: "\f429"; } + +.fa-stripe-s:before { + content: "\f42a"; } + +.fa-studiovinari:before { + content: "\f3f8"; } + +.fa-stumbleupon:before { + content: "\f1a4"; } + +.fa-stumbleupon-circle:before { + content: "\f1a3"; } + +.fa-subscript:before { + content: "\f12c"; } + +.fa-subway:before { + content: "\f239"; } + +.fa-suitcase:before { + content: "\f0f2"; } + +.fa-sun:before { + content: "\f185"; } + +.fa-superpowers:before { + content: "\f2dd"; } + +.fa-superscript:before { + content: "\f12b"; } + +.fa-supple:before { + content: "\f3f9"; } + +.fa-sync:before { + content: "\f021"; } + +.fa-sync-alt:before { + content: "\f2f1"; } + +.fa-syringe:before { + content: "\f48e"; } + +.fa-table:before { + content: "\f0ce"; } + +.fa-table-tennis:before { + content: "\f45d"; } + +.fa-tablet:before { + content: "\f10a"; } + +.fa-tablet-alt:before { + content: "\f3fa"; } + +.fa-tablets:before { + content: "\f490"; } + +.fa-tachometer-alt:before { + content: "\f3fd"; } + +.fa-tag:before { + content: "\f02b"; } + +.fa-tags:before { + content: "\f02c"; } + +.fa-tape:before { + content: "\f4db"; } + +.fa-tasks:before { + content: "\f0ae"; } + +.fa-taxi:before { + content: "\f1ba"; } + +.fa-telegram:before { + content: "\f2c6"; } + +.fa-telegram-plane:before { + content: "\f3fe"; } + +.fa-tencent-weibo:before { + content: "\f1d5"; } + +.fa-terminal:before { + content: "\f120"; } + +.fa-text-height:before { + content: "\f034"; } + +.fa-text-width:before { + content: "\f035"; } + +.fa-th:before { + content: "\f00a"; } + +.fa-th-large:before { + content: "\f009"; } + +.fa-th-list:before { + content: "\f00b"; } + +.fa-themeisle:before { + content: "\f2b2"; } + +.fa-thermometer:before { + content: "\f491"; } + +.fa-thermometer-empty:before { + content: "\f2cb"; } + +.fa-thermometer-full:before { + content: "\f2c7"; } + +.fa-thermometer-half:before { + content: "\f2c9"; } + +.fa-thermometer-quarter:before { + content: "\f2ca"; } + +.fa-thermometer-three-quarters:before { + content: "\f2c8"; } + +.fa-thumbs-down:before { + content: "\f165"; } + +.fa-thumbs-up:before { + content: "\f164"; } + +.fa-thumbtack:before { + content: "\f08d"; } + +.fa-ticket-alt:before { + content: "\f3ff"; } + +.fa-times:before { + content: "\f00d"; } + +.fa-times-circle:before { + content: "\f057"; } + +.fa-tint:before { + content: "\f043"; } + +.fa-toggle-off:before { + content: "\f204"; } + +.fa-toggle-on:before { + content: "\f205"; } + +.fa-trademark:before { + content: "\f25c"; } + +.fa-train:before { + content: "\f238"; } + +.fa-transgender:before { + content: "\f224"; } + +.fa-transgender-alt:before { + content: "\f225"; } + +.fa-trash:before { + content: "\f1f8"; } + +.fa-trash-alt:before { + content: "\f2ed"; } + +.fa-tree:before { + content: "\f1bb"; } + +.fa-trello:before { + content: "\f181"; } + +.fa-tripadvisor:before { + content: "\f262"; } + +.fa-trophy:before { + content: "\f091"; } + +.fa-truck:before { + content: "\f0d1"; } + +.fa-truck-loading:before { + content: "\f4de"; } + +.fa-truck-moving:before { + content: "\f4df"; } + +.fa-tty:before { + content: "\f1e4"; } + +.fa-tumblr:before { + content: "\f173"; } + +.fa-tumblr-square:before { + content: "\f174"; } + +.fa-tv:before { + content: "\f26c"; } + +.fa-twitch:before { + content: "\f1e8"; } + +.fa-twitter:before { + content: "\f099"; } + +.fa-twitter-square:before { + content: "\f081"; } + +.fa-typo3:before { + content: "\f42b"; } + +.fa-uber:before { + content: "\f402"; } + +.fa-uikit:before { + content: "\f403"; } + +.fa-umbrella:before { + content: "\f0e9"; } + +.fa-underline:before { + content: "\f0cd"; } + +.fa-undo:before { + content: "\f0e2"; } + +.fa-undo-alt:before { + content: "\f2ea"; } + +.fa-uniregistry:before { + content: "\f404"; } + +.fa-universal-access:before { + content: "\f29a"; } + +.fa-university:before { + content: "\f19c"; } + +.fa-unlink:before { + content: "\f127"; } + +.fa-unlock:before { + content: "\f09c"; } + +.fa-unlock-alt:before { + content: "\f13e"; } + +.fa-untappd:before { + content: "\f405"; } + +.fa-upload:before { + content: "\f093"; } + +.fa-usb:before { + content: "\f287"; } + +.fa-user:before { + content: "\f007"; } + +.fa-user-circle:before { + content: "\f2bd"; } + +.fa-user-md:before { + content: "\f0f0"; } + +.fa-user-plus:before { + content: "\f234"; } + +.fa-user-secret:before { + content: "\f21b"; } + +.fa-user-times:before { + content: "\f235"; } + +.fa-users:before { + content: "\f0c0"; } + +.fa-ussunnah:before { + content: "\f407"; } + +.fa-utensil-spoon:before { + content: "\f2e5"; } + +.fa-utensils:before { + content: "\f2e7"; } + +.fa-vaadin:before { + content: "\f408"; } + +.fa-venus:before { + content: "\f221"; } + +.fa-venus-double:before { + content: "\f226"; } + +.fa-venus-mars:before { + content: "\f228"; } + +.fa-viacoin:before { + content: "\f237"; } + +.fa-viadeo:before { + content: "\f2a9"; } + +.fa-viadeo-square:before { + content: "\f2aa"; } + +.fa-vial:before { + content: "\f492"; } + +.fa-vials:before { + content: "\f493"; } + +.fa-viber:before { + content: "\f409"; } + +.fa-video:before { + content: "\f03d"; } + +.fa-video-slash:before { + content: "\f4e2"; } + +.fa-vimeo:before { + content: "\f40a"; } + +.fa-vimeo-square:before { + content: "\f194"; } + +.fa-vimeo-v:before { + content: "\f27d"; } + +.fa-vine:before { + content: "\f1ca"; } + +.fa-vk:before { + content: "\f189"; } + +.fa-vnv:before { + content: "\f40b"; } + +.fa-volleyball-ball:before { + content: "\f45f"; } + +.fa-volume-down:before { + content: "\f027"; } + +.fa-volume-off:before { + content: "\f026"; } + +.fa-volume-up:before { + content: "\f028"; } + +.fa-vuejs:before { + content: "\f41f"; } + +.fa-warehouse:before { + content: "\f494"; } + +.fa-weibo:before { + content: "\f18a"; } + +.fa-weight:before { + content: "\f496"; } + +.fa-weixin:before { + content: "\f1d7"; } + +.fa-whatsapp:before { + content: "\f232"; } + +.fa-whatsapp-square:before { + content: "\f40c"; } + +.fa-wheelchair:before { + content: "\f193"; } + +.fa-whmcs:before { + content: "\f40d"; } + +.fa-wifi:before { + content: "\f1eb"; } + +.fa-wikipedia-w:before { + content: "\f266"; } + +.fa-window-close:before { + content: "\f410"; } + +.fa-window-maximize:before { + content: "\f2d0"; } + +.fa-window-minimize:before { + content: "\f2d1"; } + +.fa-window-restore:before { + content: "\f2d2"; } + +.fa-windows:before { + content: "\f17a"; } + +.fa-wine-glass:before { + content: "\f4e3"; } + +.fa-won-sign:before { + content: "\f159"; } + +.fa-wordpress:before { + content: "\f19a"; } + +.fa-wordpress-simple:before { + content: "\f411"; } + +.fa-wpbeginner:before { + content: "\f297"; } + +.fa-wpexplorer:before { + content: "\f2de"; } + +.fa-wpforms:before { + content: "\f298"; } + +.fa-wrench:before { + content: "\f0ad"; } + +.fa-x-ray:before { + content: "\f497"; } + +.fa-xbox:before { + content: "\f412"; } + +.fa-xing:before { + content: "\f168"; } + +.fa-xing-square:before { + content: "\f169"; } + +.fa-y-combinator:before { + content: "\f23b"; } + +.fa-yahoo:before { + content: "\f19e"; } + +.fa-yandex:before { + content: "\f413"; } + +.fa-yandex-international:before { + content: "\f414"; } + +.fa-yelp:before { + content: "\f1e9"; } + +.fa-yen-sign:before { + content: "\f157"; } + +.fa-yoast:before { + content: "\f2b1"; } + +.fa-youtube:before { + content: "\f167"; } + +.fa-youtube-square:before { + content: "\f431"; } + +.sr-only { + border: 0; + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; } + +.sr-only-focusable:active, .sr-only-focusable:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; } +@font-face { + font-family: 'Font Awesome 5 Brands'; + font-style: normal; + font-weight: normal; + src: url("../webfonts/fa-brands-400.eot"); + src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); } + +.fab { + font-family: 'Font Awesome 5 Brands'; } +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 400; + src: url("../webfonts/fa-regular-400.eot"); + src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); } + +.far { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; } +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 900; + src: url("../webfonts/fa-solid-900.eot"); + src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); } + +.fa, +.fas { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; } diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/css/fontawesome-all.min.css b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/css/fontawesome-all.min.css new file mode 100644 index 000000000000..0c0e4e00d5dc --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/css/fontawesome-all.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:a 2s infinite linear}.fa-pulse{animation:a 1s infinite steps(8)}@keyframes a{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-aws:before{content:"\f375"}.fa-backward:before{content:"\f04a"}.fa-balance-scale:before{content:"\f24e"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bicycle:before{content:"\f206"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blind:before{content:"\f29d"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-btc:before{content:"\f15a"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-certificate:before{content:"\f0a3"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-square:before{content:"\f14a"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-credit-card:before{content:"\f09d"}.fa-crop:before{content:"\f125"}.fa-crosshairs:before{content:"\f05b"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-deviantart:before{content:"\f1bd"}.fa-diagnoses:before{content:"\f470"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drupal:before{content:"\f1a9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-excel:before{content:"\f1c3"}.fa-file-image:before{content:"\f1c5"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fire:before{content:"\f06d"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-firstdraft:before{content:"\f3a1"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frown:before{content:"\f119"}.fa-futbol:before{content:"\f1e3"}.fa-gamepad:before{content:"\f11b"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-gift:before{content:"\f06b"}.fa-git:before{content:"\f1d3"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-martini:before{content:"\f000"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hashtag:before{content:"\f292"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-heart:before{content:"\f004"}.fa-heartbeat:before{content:"\f21e"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-houzz:before{content:"\f27c"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-internet-explorer:before{content:"\f26b"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jenkins:before{content:"\f3b6"}.fa-joget:before{content:"\f3b7"}.fa-joomla:before{content:"\f1aa"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-key:before{content:"\f084"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-korvue:before{content:"\f42f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-male:before{content:"\f183"}.fa-map:before{content:"\f279"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-maxcdn:before{content:"\f136"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-meh:before{content:"\f11a"}.fa-mercury:before{content:"\f223"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-moon:before{content:"\f186"}.fa-motorcycle:before{content:"\f21c"}.fa-mouse-pointer:before{content:"\f245"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nintendo-switch:before{content:"\f418"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-paint-brush:before{content:"\f1fc"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-people-carry:before{content:"\f4ce"}.fa-percent:before{content:"\f295"}.fa-periscope:before{content:"\f3da"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phone:before{content:"\f095"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-volume:before{content:"\f2a0"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-plane:before{content:"\f072"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poo:before{content:"\f2fe"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-random:before{content:"\f074"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-rendact:before{content:"\f3e4"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-resolving:before{content:"\f3e7"}.fa-retweet:before{content:"\f079"}.fa-ribbon:before{content:"\f4d6"}.fa-road:before{content:"\f018"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-rupee-sign:before{content:"\f156"}.fa-safari:before{content:"\f267"}.fa-sass:before{content:"\f41e"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-scribd:before{content:"\f28a"}.fa-search:before{content:"\f002"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shower:before{content:"\f2cc"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smoking:before{content:"\f48d"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowflake:before{content:"\f2dc"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-spinner:before{content:"\f110"}.fa-spotify:before{content:"\f1bc"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-star:before{content:"\f005"}.fa-star-half:before{content:"\f089"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-strava:before{content:"\f428"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-trademark:before{content:"\f25c"}.fa-train:before{content:"\f238"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-moving:before{content:"\f4df"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-circle:before{content:"\f2bd"}.fa-user-md:before{content:"\f0f0"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vuejs:before{content:"\f41f"}.fa-warehouse:before{content:"\f494"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-glass:before{content:"\f4e3"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:Font Awesome\ 5 Brands;font-style:normal;font-weight:400;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:Font Awesome\ 5 Brands}@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:Font Awesome\ 5 Free}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_animated.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_animated.less new file mode 100644 index 000000000000..704ec9510374 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_animated.less @@ -0,0 +1,19 @@ +// Animated Icons +// -------------------------- + +.@{fa-css-prefix}-spin { + animation: fa-spin 2s infinite linear; +} + +.@{fa-css-prefix}-pulse { + animation: fa-spin 1s infinite steps(8); +} + +@keyframes fa-spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_bordered-pulled.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_bordered-pulled.less new file mode 100644 index 000000000000..29a356b423de --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_bordered-pulled.less @@ -0,0 +1,16 @@ +// Bordered & Pulled +// ------------------------- + +.@{fa-css-prefix}-border { + border-radius: .1em; + border: solid .08em @fa-border-color; + padding: .2em .25em .15em; +} + +.@{fa-css-prefix}-pull-left { float: left; } +.@{fa-css-prefix}-pull-right { float: right; } + +.@{fa-css-prefix}, .fas, .far, .fal, .fab { + &.@{fa-css-prefix}-pull-left { margin-right: .3em; } + &.@{fa-css-prefix}-pull-right { margin-left: .3em; } +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_core.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_core.less new file mode 100644 index 000000000000..82031d65235d --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_core.less @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.@{fa-css-prefix}, .fas, .far, .fal, .fab { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_fixed-width.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_fixed-width.less new file mode 100644 index 000000000000..be817c637538 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_fixed-width.less @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.@{fa-css-prefix}-fw { + text-align: center; + width: (20em / 16); +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_icons.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_icons.less new file mode 100644 index 000000000000..ad23e33180a1 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_icons.less @@ -0,0 +1,878 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.@{fa-css-prefix}-500px:before { content: @fa-var-500px; } +.@{fa-css-prefix}-accessible-icon:before { content: @fa-var-accessible-icon; } +.@{fa-css-prefix}-accusoft:before { content: @fa-var-accusoft; } +.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; } +.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; } +.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; } +.@{fa-css-prefix}-adn:before { content: @fa-var-adn; } +.@{fa-css-prefix}-adversal:before { content: @fa-var-adversal; } +.@{fa-css-prefix}-affiliatetheme:before { content: @fa-var-affiliatetheme; } +.@{fa-css-prefix}-algolia:before { content: @fa-var-algolia; } +.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; } +.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; } +.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; } +.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; } +.@{fa-css-prefix}-allergies:before { content: @fa-var-allergies; } +.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; } +.@{fa-css-prefix}-amazon-pay:before { content: @fa-var-amazon-pay; } +.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; } +.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; } +.@{fa-css-prefix}-amilia:before { content: @fa-var-amilia; } +.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; } +.@{fa-css-prefix}-android:before { content: @fa-var-android; } +.@{fa-css-prefix}-angellist:before { content: @fa-var-angellist; } +.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; } +.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; } +.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; } +.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; } +.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; } +.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; } +.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; } +.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; } +.@{fa-css-prefix}-angrycreative:before { content: @fa-var-angrycreative; } +.@{fa-css-prefix}-angular:before { content: @fa-var-angular; } +.@{fa-css-prefix}-app-store:before { content: @fa-var-app-store; } +.@{fa-css-prefix}-app-store-ios:before { content: @fa-var-app-store-ios; } +.@{fa-css-prefix}-apper:before { content: @fa-var-apper; } +.@{fa-css-prefix}-apple:before { content: @fa-var-apple; } +.@{fa-css-prefix}-apple-pay:before { content: @fa-var-apple-pay; } +.@{fa-css-prefix}-archive:before { content: @fa-var-archive; } +.@{fa-css-prefix}-arrow-alt-circle-down:before { content: @fa-var-arrow-alt-circle-down; } +.@{fa-css-prefix}-arrow-alt-circle-left:before { content: @fa-var-arrow-alt-circle-left; } +.@{fa-css-prefix}-arrow-alt-circle-right:before { content: @fa-var-arrow-alt-circle-right; } +.@{fa-css-prefix}-arrow-alt-circle-up:before { content: @fa-var-arrow-alt-circle-up; } +.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; } +.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; } +.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; } +.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; } +.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; } +.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; } +.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; } +.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; } +.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; } +.@{fa-css-prefix}-arrows-alt-h:before { content: @fa-var-arrows-alt-h; } +.@{fa-css-prefix}-arrows-alt-v:before { content: @fa-var-arrows-alt-v; } +.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; } +.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; } +.@{fa-css-prefix}-asymmetrik:before { content: @fa-var-asymmetrik; } +.@{fa-css-prefix}-at:before { content: @fa-var-at; } +.@{fa-css-prefix}-audible:before { content: @fa-var-audible; } +.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; } +.@{fa-css-prefix}-autoprefixer:before { content: @fa-var-autoprefixer; } +.@{fa-css-prefix}-avianex:before { content: @fa-var-avianex; } +.@{fa-css-prefix}-aviato:before { content: @fa-var-aviato; } +.@{fa-css-prefix}-aws:before { content: @fa-var-aws; } +.@{fa-css-prefix}-backward:before { content: @fa-var-backward; } +.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; } +.@{fa-css-prefix}-ban:before { content: @fa-var-ban; } +.@{fa-css-prefix}-band-aid:before { content: @fa-var-band-aid; } +.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; } +.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; } +.@{fa-css-prefix}-bars:before { content: @fa-var-bars; } +.@{fa-css-prefix}-baseball-ball:before { content: @fa-var-baseball-ball; } +.@{fa-css-prefix}-basketball-ball:before { content: @fa-var-basketball-ball; } +.@{fa-css-prefix}-bath:before { content: @fa-var-bath; } +.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; } +.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; } +.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; } +.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; } +.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; } +.@{fa-css-prefix}-bed:before { content: @fa-var-bed; } +.@{fa-css-prefix}-beer:before { content: @fa-var-beer; } +.@{fa-css-prefix}-behance:before { content: @fa-var-behance; } +.@{fa-css-prefix}-behance-square:before { content: @fa-var-behance-square; } +.@{fa-css-prefix}-bell:before { content: @fa-var-bell; } +.@{fa-css-prefix}-bell-slash:before { content: @fa-var-bell-slash; } +.@{fa-css-prefix}-bicycle:before { content: @fa-var-bicycle; } +.@{fa-css-prefix}-bimobject:before { content: @fa-var-bimobject; } +.@{fa-css-prefix}-binoculars:before { content: @fa-var-binoculars; } +.@{fa-css-prefix}-birthday-cake:before { content: @fa-var-birthday-cake; } +.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; } +.@{fa-css-prefix}-bitcoin:before { content: @fa-var-bitcoin; } +.@{fa-css-prefix}-bity:before { content: @fa-var-bity; } +.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; } +.@{fa-css-prefix}-blackberry:before { content: @fa-var-blackberry; } +.@{fa-css-prefix}-blind:before { content: @fa-var-blind; } +.@{fa-css-prefix}-blogger:before { content: @fa-var-blogger; } +.@{fa-css-prefix}-blogger-b:before { content: @fa-var-blogger-b; } +.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; } +.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; } +.@{fa-css-prefix}-bold:before { content: @fa-var-bold; } +.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; } +.@{fa-css-prefix}-bomb:before { content: @fa-var-bomb; } +.@{fa-css-prefix}-book:before { content: @fa-var-book; } +.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; } +.@{fa-css-prefix}-bowling-ball:before { content: @fa-var-bowling-ball; } +.@{fa-css-prefix}-box:before { content: @fa-var-box; } +.@{fa-css-prefix}-box-open:before { content: @fa-var-box-open; } +.@{fa-css-prefix}-boxes:before { content: @fa-var-boxes; } +.@{fa-css-prefix}-braille:before { content: @fa-var-braille; } +.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; } +.@{fa-css-prefix}-briefcase-medical:before { content: @fa-var-briefcase-medical; } +.@{fa-css-prefix}-btc:before { content: @fa-var-btc; } +.@{fa-css-prefix}-bug:before { content: @fa-var-bug; } +.@{fa-css-prefix}-building:before { content: @fa-var-building; } +.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; } +.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; } +.@{fa-css-prefix}-burn:before { content: @fa-var-burn; } +.@{fa-css-prefix}-buromobelexperte:before { content: @fa-var-buromobelexperte; } +.@{fa-css-prefix}-bus:before { content: @fa-var-bus; } +.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; } +.@{fa-css-prefix}-calculator:before { content: @fa-var-calculator; } +.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; } +.@{fa-css-prefix}-calendar-alt:before { content: @fa-var-calendar-alt; } +.@{fa-css-prefix}-calendar-check:before { content: @fa-var-calendar-check; } +.@{fa-css-prefix}-calendar-minus:before { content: @fa-var-calendar-minus; } +.@{fa-css-prefix}-calendar-plus:before { content: @fa-var-calendar-plus; } +.@{fa-css-prefix}-calendar-times:before { content: @fa-var-calendar-times; } +.@{fa-css-prefix}-camera:before { content: @fa-var-camera; } +.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; } +.@{fa-css-prefix}-capsules:before { content: @fa-var-capsules; } +.@{fa-css-prefix}-car:before { content: @fa-var-car; } +.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; } +.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; } +.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; } +.@{fa-css-prefix}-caret-square-down:before { content: @fa-var-caret-square-down; } +.@{fa-css-prefix}-caret-square-left:before { content: @fa-var-caret-square-left; } +.@{fa-css-prefix}-caret-square-right:before { content: @fa-var-caret-square-right; } +.@{fa-css-prefix}-caret-square-up:before { content: @fa-var-caret-square-up; } +.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; } +.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; } +.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; } +.@{fa-css-prefix}-cc-amazon-pay:before { content: @fa-var-cc-amazon-pay; } +.@{fa-css-prefix}-cc-amex:before { content: @fa-var-cc-amex; } +.@{fa-css-prefix}-cc-apple-pay:before { content: @fa-var-cc-apple-pay; } +.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; } +.@{fa-css-prefix}-cc-discover:before { content: @fa-var-cc-discover; } +.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; } +.@{fa-css-prefix}-cc-mastercard:before { content: @fa-var-cc-mastercard; } +.@{fa-css-prefix}-cc-paypal:before { content: @fa-var-cc-paypal; } +.@{fa-css-prefix}-cc-stripe:before { content: @fa-var-cc-stripe; } +.@{fa-css-prefix}-cc-visa:before { content: @fa-var-cc-visa; } +.@{fa-css-prefix}-centercode:before { content: @fa-var-centercode; } +.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; } +.@{fa-css-prefix}-chart-area:before { content: @fa-var-chart-area; } +.@{fa-css-prefix}-chart-bar:before { content: @fa-var-chart-bar; } +.@{fa-css-prefix}-chart-line:before { content: @fa-var-chart-line; } +.@{fa-css-prefix}-chart-pie:before { content: @fa-var-chart-pie; } +.@{fa-css-prefix}-check:before { content: @fa-var-check; } +.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; } +.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; } +.@{fa-css-prefix}-chess:before { content: @fa-var-chess; } +.@{fa-css-prefix}-chess-bishop:before { content: @fa-var-chess-bishop; } +.@{fa-css-prefix}-chess-board:before { content: @fa-var-chess-board; } +.@{fa-css-prefix}-chess-king:before { content: @fa-var-chess-king; } +.@{fa-css-prefix}-chess-knight:before { content: @fa-var-chess-knight; } +.@{fa-css-prefix}-chess-pawn:before { content: @fa-var-chess-pawn; } +.@{fa-css-prefix}-chess-queen:before { content: @fa-var-chess-queen; } +.@{fa-css-prefix}-chess-rook:before { content: @fa-var-chess-rook; } +.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; } +.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; } +.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; } +.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; } +.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; } +.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; } +.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; } +.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; } +.@{fa-css-prefix}-child:before { content: @fa-var-child; } +.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; } +.@{fa-css-prefix}-circle:before { content: @fa-var-circle; } +.@{fa-css-prefix}-circle-notch:before { content: @fa-var-circle-notch; } +.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; } +.@{fa-css-prefix}-clipboard-check:before { content: @fa-var-clipboard-check; } +.@{fa-css-prefix}-clipboard-list:before { content: @fa-var-clipboard-list; } +.@{fa-css-prefix}-clock:before { content: @fa-var-clock; } +.@{fa-css-prefix}-clone:before { content: @fa-var-clone; } +.@{fa-css-prefix}-closed-captioning:before { content: @fa-var-closed-captioning; } +.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; } +.@{fa-css-prefix}-cloud-download-alt:before { content: @fa-var-cloud-download-alt; } +.@{fa-css-prefix}-cloud-upload-alt:before { content: @fa-var-cloud-upload-alt; } +.@{fa-css-prefix}-cloudscale:before { content: @fa-var-cloudscale; } +.@{fa-css-prefix}-cloudsmith:before { content: @fa-var-cloudsmith; } +.@{fa-css-prefix}-cloudversify:before { content: @fa-var-cloudversify; } +.@{fa-css-prefix}-code:before { content: @fa-var-code; } +.@{fa-css-prefix}-code-branch:before { content: @fa-var-code-branch; } +.@{fa-css-prefix}-codepen:before { content: @fa-var-codepen; } +.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; } +.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; } +.@{fa-css-prefix}-cog:before { content: @fa-var-cog; } +.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; } +.@{fa-css-prefix}-columns:before { content: @fa-var-columns; } +.@{fa-css-prefix}-comment:before { content: @fa-var-comment; } +.@{fa-css-prefix}-comment-alt:before { content: @fa-var-comment-alt; } +.@{fa-css-prefix}-comment-dots:before { content: @fa-var-comment-dots; } +.@{fa-css-prefix}-comment-slash:before { content: @fa-var-comment-slash; } +.@{fa-css-prefix}-comments:before { content: @fa-var-comments; } +.@{fa-css-prefix}-compass:before { content: @fa-var-compass; } +.@{fa-css-prefix}-compress:before { content: @fa-var-compress; } +.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; } +.@{fa-css-prefix}-contao:before { content: @fa-var-contao; } +.@{fa-css-prefix}-copy:before { content: @fa-var-copy; } +.@{fa-css-prefix}-copyright:before { content: @fa-var-copyright; } +.@{fa-css-prefix}-couch:before { content: @fa-var-couch; } +.@{fa-css-prefix}-cpanel:before { content: @fa-var-cpanel; } +.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; } +.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; } +.@{fa-css-prefix}-crop:before { content: @fa-var-crop; } +.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; } +.@{fa-css-prefix}-css3:before { content: @fa-var-css3; } +.@{fa-css-prefix}-css3-alt:before { content: @fa-var-css3-alt; } +.@{fa-css-prefix}-cube:before { content: @fa-var-cube; } +.@{fa-css-prefix}-cubes:before { content: @fa-var-cubes; } +.@{fa-css-prefix}-cut:before { content: @fa-var-cut; } +.@{fa-css-prefix}-cuttlefish:before { content: @fa-var-cuttlefish; } +.@{fa-css-prefix}-d-and-d:before { content: @fa-var-d-and-d; } +.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; } +.@{fa-css-prefix}-database:before { content: @fa-var-database; } +.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; } +.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; } +.@{fa-css-prefix}-deploydog:before { content: @fa-var-deploydog; } +.@{fa-css-prefix}-deskpro:before { content: @fa-var-deskpro; } +.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; } +.@{fa-css-prefix}-deviantart:before { content: @fa-var-deviantart; } +.@{fa-css-prefix}-diagnoses:before { content: @fa-var-diagnoses; } +.@{fa-css-prefix}-digg:before { content: @fa-var-digg; } +.@{fa-css-prefix}-digital-ocean:before { content: @fa-var-digital-ocean; } +.@{fa-css-prefix}-discord:before { content: @fa-var-discord; } +.@{fa-css-prefix}-discourse:before { content: @fa-var-discourse; } +.@{fa-css-prefix}-dna:before { content: @fa-var-dna; } +.@{fa-css-prefix}-dochub:before { content: @fa-var-dochub; } +.@{fa-css-prefix}-docker:before { content: @fa-var-docker; } +.@{fa-css-prefix}-dollar-sign:before { content: @fa-var-dollar-sign; } +.@{fa-css-prefix}-dolly:before { content: @fa-var-dolly; } +.@{fa-css-prefix}-dolly-flatbed:before { content: @fa-var-dolly-flatbed; } +.@{fa-css-prefix}-donate:before { content: @fa-var-donate; } +.@{fa-css-prefix}-dot-circle:before { content: @fa-var-dot-circle; } +.@{fa-css-prefix}-dove:before { content: @fa-var-dove; } +.@{fa-css-prefix}-download:before { content: @fa-var-download; } +.@{fa-css-prefix}-draft2digital:before { content: @fa-var-draft2digital; } +.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; } +.@{fa-css-prefix}-dribbble-square:before { content: @fa-var-dribbble-square; } +.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; } +.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; } +.@{fa-css-prefix}-dyalog:before { content: @fa-var-dyalog; } +.@{fa-css-prefix}-earlybirds:before { content: @fa-var-earlybirds; } +.@{fa-css-prefix}-edge:before { content: @fa-var-edge; } +.@{fa-css-prefix}-edit:before { content: @fa-var-edit; } +.@{fa-css-prefix}-eject:before { content: @fa-var-eject; } +.@{fa-css-prefix}-elementor:before { content: @fa-var-elementor; } +.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; } +.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; } +.@{fa-css-prefix}-ember:before { content: @fa-var-ember; } +.@{fa-css-prefix}-empire:before { content: @fa-var-empire; } +.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; } +.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; } +.@{fa-css-prefix}-envelope-square:before { content: @fa-var-envelope-square; } +.@{fa-css-prefix}-envira:before { content: @fa-var-envira; } +.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; } +.@{fa-css-prefix}-erlang:before { content: @fa-var-erlang; } +.@{fa-css-prefix}-ethereum:before { content: @fa-var-ethereum; } +.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; } +.@{fa-css-prefix}-euro-sign:before { content: @fa-var-euro-sign; } +.@{fa-css-prefix}-exchange-alt:before { content: @fa-var-exchange-alt; } +.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; } +.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; } +.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; } +.@{fa-css-prefix}-expand:before { content: @fa-var-expand; } +.@{fa-css-prefix}-expand-arrows-alt:before { content: @fa-var-expand-arrows-alt; } +.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; } +.@{fa-css-prefix}-external-link-alt:before { content: @fa-var-external-link-alt; } +.@{fa-css-prefix}-external-link-square-alt:before { content: @fa-var-external-link-square-alt; } +.@{fa-css-prefix}-eye:before { content: @fa-var-eye; } +.@{fa-css-prefix}-eye-dropper:before { content: @fa-var-eye-dropper; } +.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; } +.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; } +.@{fa-css-prefix}-facebook-f:before { content: @fa-var-facebook-f; } +.@{fa-css-prefix}-facebook-messenger:before { content: @fa-var-facebook-messenger; } +.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; } +.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; } +.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; } +.@{fa-css-prefix}-fax:before { content: @fa-var-fax; } +.@{fa-css-prefix}-female:before { content: @fa-var-female; } +.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; } +.@{fa-css-prefix}-file:before { content: @fa-var-file; } +.@{fa-css-prefix}-file-alt:before { content: @fa-var-file-alt; } +.@{fa-css-prefix}-file-archive:before { content: @fa-var-file-archive; } +.@{fa-css-prefix}-file-audio:before { content: @fa-var-file-audio; } +.@{fa-css-prefix}-file-code:before { content: @fa-var-file-code; } +.@{fa-css-prefix}-file-excel:before { content: @fa-var-file-excel; } +.@{fa-css-prefix}-file-image:before { content: @fa-var-file-image; } +.@{fa-css-prefix}-file-medical:before { content: @fa-var-file-medical; } +.@{fa-css-prefix}-file-medical-alt:before { content: @fa-var-file-medical-alt; } +.@{fa-css-prefix}-file-pdf:before { content: @fa-var-file-pdf; } +.@{fa-css-prefix}-file-powerpoint:before { content: @fa-var-file-powerpoint; } +.@{fa-css-prefix}-file-video:before { content: @fa-var-file-video; } +.@{fa-css-prefix}-file-word:before { content: @fa-var-file-word; } +.@{fa-css-prefix}-film:before { content: @fa-var-film; } +.@{fa-css-prefix}-filter:before { content: @fa-var-filter; } +.@{fa-css-prefix}-fire:before { content: @fa-var-fire; } +.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; } +.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; } +.@{fa-css-prefix}-first-aid:before { content: @fa-var-first-aid; } +.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; } +.@{fa-css-prefix}-firstdraft:before { content: @fa-var-firstdraft; } +.@{fa-css-prefix}-flag:before { content: @fa-var-flag; } +.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; } +.@{fa-css-prefix}-flask:before { content: @fa-var-flask; } +.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; } +.@{fa-css-prefix}-flipboard:before { content: @fa-var-flipboard; } +.@{fa-css-prefix}-fly:before { content: @fa-var-fly; } +.@{fa-css-prefix}-folder:before { content: @fa-var-folder; } +.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; } +.@{fa-css-prefix}-font:before { content: @fa-var-font; } +.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; } +.@{fa-css-prefix}-font-awesome-alt:before { content: @fa-var-font-awesome-alt; } +.@{fa-css-prefix}-font-awesome-flag:before { content: @fa-var-font-awesome-flag; } +.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; } +.@{fa-css-prefix}-fonticons-fi:before { content: @fa-var-fonticons-fi; } +.@{fa-css-prefix}-football-ball:before { content: @fa-var-football-ball; } +.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; } +.@{fa-css-prefix}-fort-awesome-alt:before { content: @fa-var-fort-awesome-alt; } +.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; } +.@{fa-css-prefix}-forward:before { content: @fa-var-forward; } +.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; } +.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; } +.@{fa-css-prefix}-freebsd:before { content: @fa-var-freebsd; } +.@{fa-css-prefix}-frown:before { content: @fa-var-frown; } +.@{fa-css-prefix}-futbol:before { content: @fa-var-futbol; } +.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; } +.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; } +.@{fa-css-prefix}-gem:before { content: @fa-var-gem; } +.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; } +.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; } +.@{fa-css-prefix}-gg:before { content: @fa-var-gg; } +.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; } +.@{fa-css-prefix}-gift:before { content: @fa-var-gift; } +.@{fa-css-prefix}-git:before { content: @fa-var-git; } +.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; } +.@{fa-css-prefix}-github:before { content: @fa-var-github; } +.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; } +.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; } +.@{fa-css-prefix}-gitkraken:before { content: @fa-var-gitkraken; } +.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; } +.@{fa-css-prefix}-gitter:before { content: @fa-var-gitter; } +.@{fa-css-prefix}-glass-martini:before { content: @fa-var-glass-martini; } +.@{fa-css-prefix}-glide:before { content: @fa-var-glide; } +.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; } +.@{fa-css-prefix}-globe:before { content: @fa-var-globe; } +.@{fa-css-prefix}-gofore:before { content: @fa-var-gofore; } +.@{fa-css-prefix}-golf-ball:before { content: @fa-var-golf-ball; } +.@{fa-css-prefix}-goodreads:before { content: @fa-var-goodreads; } +.@{fa-css-prefix}-goodreads-g:before { content: @fa-var-goodreads-g; } +.@{fa-css-prefix}-google:before { content: @fa-var-google; } +.@{fa-css-prefix}-google-drive:before { content: @fa-var-google-drive; } +.@{fa-css-prefix}-google-play:before { content: @fa-var-google-play; } +.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; } +.@{fa-css-prefix}-google-plus-g:before { content: @fa-var-google-plus-g; } +.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; } +.@{fa-css-prefix}-google-wallet:before { content: @fa-var-google-wallet; } +.@{fa-css-prefix}-graduation-cap:before { content: @fa-var-graduation-cap; } +.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; } +.@{fa-css-prefix}-grav:before { content: @fa-var-grav; } +.@{fa-css-prefix}-gripfire:before { content: @fa-var-gripfire; } +.@{fa-css-prefix}-grunt:before { content: @fa-var-grunt; } +.@{fa-css-prefix}-gulp:before { content: @fa-var-gulp; } +.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; } +.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; } +.@{fa-css-prefix}-hacker-news-square:before { content: @fa-var-hacker-news-square; } +.@{fa-css-prefix}-hand-holding:before { content: @fa-var-hand-holding; } +.@{fa-css-prefix}-hand-holding-heart:before { content: @fa-var-hand-holding-heart; } +.@{fa-css-prefix}-hand-holding-usd:before { content: @fa-var-hand-holding-usd; } +.@{fa-css-prefix}-hand-lizard:before { content: @fa-var-hand-lizard; } +.@{fa-css-prefix}-hand-paper:before { content: @fa-var-hand-paper; } +.@{fa-css-prefix}-hand-peace:before { content: @fa-var-hand-peace; } +.@{fa-css-prefix}-hand-point-down:before { content: @fa-var-hand-point-down; } +.@{fa-css-prefix}-hand-point-left:before { content: @fa-var-hand-point-left; } +.@{fa-css-prefix}-hand-point-right:before { content: @fa-var-hand-point-right; } +.@{fa-css-prefix}-hand-point-up:before { content: @fa-var-hand-point-up; } +.@{fa-css-prefix}-hand-pointer:before { content: @fa-var-hand-pointer; } +.@{fa-css-prefix}-hand-rock:before { content: @fa-var-hand-rock; } +.@{fa-css-prefix}-hand-scissors:before { content: @fa-var-hand-scissors; } +.@{fa-css-prefix}-hand-spock:before { content: @fa-var-hand-spock; } +.@{fa-css-prefix}-hands:before { content: @fa-var-hands; } +.@{fa-css-prefix}-hands-helping:before { content: @fa-var-hands-helping; } +.@{fa-css-prefix}-handshake:before { content: @fa-var-handshake; } +.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; } +.@{fa-css-prefix}-hdd:before { content: @fa-var-hdd; } +.@{fa-css-prefix}-heading:before { content: @fa-var-heading; } +.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; } +.@{fa-css-prefix}-heart:before { content: @fa-var-heart; } +.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; } +.@{fa-css-prefix}-hips:before { content: @fa-var-hips; } +.@{fa-css-prefix}-hire-a-helper:before { content: @fa-var-hire-a-helper; } +.@{fa-css-prefix}-history:before { content: @fa-var-history; } +.@{fa-css-prefix}-hockey-puck:before { content: @fa-var-hockey-puck; } +.@{fa-css-prefix}-home:before { content: @fa-var-home; } +.@{fa-css-prefix}-hooli:before { content: @fa-var-hooli; } +.@{fa-css-prefix}-hospital:before { content: @fa-var-hospital; } +.@{fa-css-prefix}-hospital-alt:before { content: @fa-var-hospital-alt; } +.@{fa-css-prefix}-hospital-symbol:before { content: @fa-var-hospital-symbol; } +.@{fa-css-prefix}-hotjar:before { content: @fa-var-hotjar; } +.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; } +.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; } +.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; } +.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; } +.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; } +.@{fa-css-prefix}-html5:before { content: @fa-var-html5; } +.@{fa-css-prefix}-hubspot:before { content: @fa-var-hubspot; } +.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; } +.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; } +.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; } +.@{fa-css-prefix}-id-card-alt:before { content: @fa-var-id-card-alt; } +.@{fa-css-prefix}-image:before { content: @fa-var-image; } +.@{fa-css-prefix}-images:before { content: @fa-var-images; } +.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; } +.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; } +.@{fa-css-prefix}-indent:before { content: @fa-var-indent; } +.@{fa-css-prefix}-industry:before { content: @fa-var-industry; } +.@{fa-css-prefix}-info:before { content: @fa-var-info; } +.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; } +.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; } +.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; } +.@{fa-css-prefix}-ioxhost:before { content: @fa-var-ioxhost; } +.@{fa-css-prefix}-italic:before { content: @fa-var-italic; } +.@{fa-css-prefix}-itunes:before { content: @fa-var-itunes; } +.@{fa-css-prefix}-itunes-note:before { content: @fa-var-itunes-note; } +.@{fa-css-prefix}-java:before { content: @fa-var-java; } +.@{fa-css-prefix}-jenkins:before { content: @fa-var-jenkins; } +.@{fa-css-prefix}-joget:before { content: @fa-var-joget; } +.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; } +.@{fa-css-prefix}-js:before { content: @fa-var-js; } +.@{fa-css-prefix}-js-square:before { content: @fa-var-js-square; } +.@{fa-css-prefix}-jsfiddle:before { content: @fa-var-jsfiddle; } +.@{fa-css-prefix}-key:before { content: @fa-var-key; } +.@{fa-css-prefix}-keyboard:before { content: @fa-var-keyboard; } +.@{fa-css-prefix}-keycdn:before { content: @fa-var-keycdn; } +.@{fa-css-prefix}-kickstarter:before { content: @fa-var-kickstarter; } +.@{fa-css-prefix}-kickstarter-k:before { content: @fa-var-kickstarter-k; } +.@{fa-css-prefix}-korvue:before { content: @fa-var-korvue; } +.@{fa-css-prefix}-language:before { content: @fa-var-language; } +.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; } +.@{fa-css-prefix}-laravel:before { content: @fa-var-laravel; } +.@{fa-css-prefix}-lastfm:before { content: @fa-var-lastfm; } +.@{fa-css-prefix}-lastfm-square:before { content: @fa-var-lastfm-square; } +.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; } +.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; } +.@{fa-css-prefix}-lemon:before { content: @fa-var-lemon; } +.@{fa-css-prefix}-less:before { content: @fa-var-less; } +.@{fa-css-prefix}-level-down-alt:before { content: @fa-var-level-down-alt; } +.@{fa-css-prefix}-level-up-alt:before { content: @fa-var-level-up-alt; } +.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; } +.@{fa-css-prefix}-lightbulb:before { content: @fa-var-lightbulb; } +.@{fa-css-prefix}-line:before { content: @fa-var-line; } +.@{fa-css-prefix}-link:before { content: @fa-var-link; } +.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; } +.@{fa-css-prefix}-linkedin-in:before { content: @fa-var-linkedin-in; } +.@{fa-css-prefix}-linode:before { content: @fa-var-linode; } +.@{fa-css-prefix}-linux:before { content: @fa-var-linux; } +.@{fa-css-prefix}-lira-sign:before { content: @fa-var-lira-sign; } +.@{fa-css-prefix}-list:before { content: @fa-var-list; } +.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; } +.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; } +.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; } +.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; } +.@{fa-css-prefix}-lock:before { content: @fa-var-lock; } +.@{fa-css-prefix}-lock-open:before { content: @fa-var-lock-open; } +.@{fa-css-prefix}-long-arrow-alt-down:before { content: @fa-var-long-arrow-alt-down; } +.@{fa-css-prefix}-long-arrow-alt-left:before { content: @fa-var-long-arrow-alt-left; } +.@{fa-css-prefix}-long-arrow-alt-right:before { content: @fa-var-long-arrow-alt-right; } +.@{fa-css-prefix}-long-arrow-alt-up:before { content: @fa-var-long-arrow-alt-up; } +.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; } +.@{fa-css-prefix}-lyft:before { content: @fa-var-lyft; } +.@{fa-css-prefix}-magento:before { content: @fa-var-magento; } +.@{fa-css-prefix}-magic:before { content: @fa-var-magic; } +.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; } +.@{fa-css-prefix}-male:before { content: @fa-var-male; } +.@{fa-css-prefix}-map:before { content: @fa-var-map; } +.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; } +.@{fa-css-prefix}-map-marker-alt:before { content: @fa-var-map-marker-alt; } +.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; } +.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; } +.@{fa-css-prefix}-mars:before { content: @fa-var-mars; } +.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; } +.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; } +.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; } +.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; } +.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; } +.@{fa-css-prefix}-medapps:before { content: @fa-var-medapps; } +.@{fa-css-prefix}-medium:before { content: @fa-var-medium; } +.@{fa-css-prefix}-medium-m:before { content: @fa-var-medium-m; } +.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; } +.@{fa-css-prefix}-medrt:before { content: @fa-var-medrt; } +.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; } +.@{fa-css-prefix}-meh:before { content: @fa-var-meh; } +.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; } +.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; } +.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; } +.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; } +.@{fa-css-prefix}-microsoft:before { content: @fa-var-microsoft; } +.@{fa-css-prefix}-minus:before { content: @fa-var-minus; } +.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; } +.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; } +.@{fa-css-prefix}-mix:before { content: @fa-var-mix; } +.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; } +.@{fa-css-prefix}-mizuni:before { content: @fa-var-mizuni; } +.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; } +.@{fa-css-prefix}-mobile-alt:before { content: @fa-var-mobile-alt; } +.@{fa-css-prefix}-modx:before { content: @fa-var-modx; } +.@{fa-css-prefix}-monero:before { content: @fa-var-monero; } +.@{fa-css-prefix}-money-bill-alt:before { content: @fa-var-money-bill-alt; } +.@{fa-css-prefix}-moon:before { content: @fa-var-moon; } +.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; } +.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; } +.@{fa-css-prefix}-music:before { content: @fa-var-music; } +.@{fa-css-prefix}-napster:before { content: @fa-var-napster; } +.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; } +.@{fa-css-prefix}-newspaper:before { content: @fa-var-newspaper; } +.@{fa-css-prefix}-nintendo-switch:before { content: @fa-var-nintendo-switch; } +.@{fa-css-prefix}-node:before { content: @fa-var-node; } +.@{fa-css-prefix}-node-js:before { content: @fa-var-node-js; } +.@{fa-css-prefix}-notes-medical:before { content: @fa-var-notes-medical; } +.@{fa-css-prefix}-npm:before { content: @fa-var-npm; } +.@{fa-css-prefix}-ns8:before { content: @fa-var-ns8; } +.@{fa-css-prefix}-nutritionix:before { content: @fa-var-nutritionix; } +.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; } +.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; } +.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; } +.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; } +.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; } +.@{fa-css-prefix}-openid:before { content: @fa-var-openid; } +.@{fa-css-prefix}-opera:before { content: @fa-var-opera; } +.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; } +.@{fa-css-prefix}-osi:before { content: @fa-var-osi; } +.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; } +.@{fa-css-prefix}-page4:before { content: @fa-var-page4; } +.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; } +.@{fa-css-prefix}-paint-brush:before { content: @fa-var-paint-brush; } +.@{fa-css-prefix}-palfed:before { content: @fa-var-palfed; } +.@{fa-css-prefix}-pallet:before { content: @fa-var-pallet; } +.@{fa-css-prefix}-paper-plane:before { content: @fa-var-paper-plane; } +.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; } +.@{fa-css-prefix}-parachute-box:before { content: @fa-var-parachute-box; } +.@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; } +.@{fa-css-prefix}-paste:before { content: @fa-var-paste; } +.@{fa-css-prefix}-patreon:before { content: @fa-var-patreon; } +.@{fa-css-prefix}-pause:before { content: @fa-var-pause; } +.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; } +.@{fa-css-prefix}-paw:before { content: @fa-var-paw; } +.@{fa-css-prefix}-paypal:before { content: @fa-var-paypal; } +.@{fa-css-prefix}-pen-square:before { content: @fa-var-pen-square; } +.@{fa-css-prefix}-pencil-alt:before { content: @fa-var-pencil-alt; } +.@{fa-css-prefix}-people-carry:before { content: @fa-var-people-carry; } +.@{fa-css-prefix}-percent:before { content: @fa-var-percent; } +.@{fa-css-prefix}-periscope:before { content: @fa-var-periscope; } +.@{fa-css-prefix}-phabricator:before { content: @fa-var-phabricator; } +.@{fa-css-prefix}-phoenix-framework:before { content: @fa-var-phoenix-framework; } +.@{fa-css-prefix}-phone:before { content: @fa-var-phone; } +.@{fa-css-prefix}-phone-slash:before { content: @fa-var-phone-slash; } +.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; } +.@{fa-css-prefix}-phone-volume:before { content: @fa-var-phone-volume; } +.@{fa-css-prefix}-php:before { content: @fa-var-php; } +.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; } +.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; } +.@{fa-css-prefix}-pied-piper-hat:before { content: @fa-var-pied-piper-hat; } +.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; } +.@{fa-css-prefix}-piggy-bank:before { content: @fa-var-piggy-bank; } +.@{fa-css-prefix}-pills:before { content: @fa-var-pills; } +.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; } +.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; } +.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; } +.@{fa-css-prefix}-plane:before { content: @fa-var-plane; } +.@{fa-css-prefix}-play:before { content: @fa-var-play; } +.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; } +.@{fa-css-prefix}-playstation:before { content: @fa-var-playstation; } +.@{fa-css-prefix}-plug:before { content: @fa-var-plug; } +.@{fa-css-prefix}-plus:before { content: @fa-var-plus; } +.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; } +.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; } +.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; } +.@{fa-css-prefix}-poo:before { content: @fa-var-poo; } +.@{fa-css-prefix}-pound-sign:before { content: @fa-var-pound-sign; } +.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; } +.@{fa-css-prefix}-prescription-bottle:before { content: @fa-var-prescription-bottle; } +.@{fa-css-prefix}-prescription-bottle-alt:before { content: @fa-var-prescription-bottle-alt; } +.@{fa-css-prefix}-print:before { content: @fa-var-print; } +.@{fa-css-prefix}-procedures:before { content: @fa-var-procedures; } +.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; } +.@{fa-css-prefix}-pushed:before { content: @fa-var-pushed; } +.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; } +.@{fa-css-prefix}-python:before { content: @fa-var-python; } +.@{fa-css-prefix}-qq:before { content: @fa-var-qq; } +.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; } +.@{fa-css-prefix}-question:before { content: @fa-var-question; } +.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; } +.@{fa-css-prefix}-quidditch:before { content: @fa-var-quidditch; } +.@{fa-css-prefix}-quinscape:before { content: @fa-var-quinscape; } +.@{fa-css-prefix}-quora:before { content: @fa-var-quora; } +.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; } +.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; } +.@{fa-css-prefix}-random:before { content: @fa-var-random; } +.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; } +.@{fa-css-prefix}-react:before { content: @fa-var-react; } +.@{fa-css-prefix}-readme:before { content: @fa-var-readme; } +.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; } +.@{fa-css-prefix}-recycle:before { content: @fa-var-recycle; } +.@{fa-css-prefix}-red-river:before { content: @fa-var-red-river; } +.@{fa-css-prefix}-reddit:before { content: @fa-var-reddit; } +.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; } +.@{fa-css-prefix}-reddit-square:before { content: @fa-var-reddit-square; } +.@{fa-css-prefix}-redo:before { content: @fa-var-redo; } +.@{fa-css-prefix}-redo-alt:before { content: @fa-var-redo-alt; } +.@{fa-css-prefix}-registered:before { content: @fa-var-registered; } +.@{fa-css-prefix}-rendact:before { content: @fa-var-rendact; } +.@{fa-css-prefix}-renren:before { content: @fa-var-renren; } +.@{fa-css-prefix}-reply:before { content: @fa-var-reply; } +.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; } +.@{fa-css-prefix}-replyd:before { content: @fa-var-replyd; } +.@{fa-css-prefix}-resolving:before { content: @fa-var-resolving; } +.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; } +.@{fa-css-prefix}-ribbon:before { content: @fa-var-ribbon; } +.@{fa-css-prefix}-road:before { content: @fa-var-road; } +.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; } +.@{fa-css-prefix}-rocketchat:before { content: @fa-var-rocketchat; } +.@{fa-css-prefix}-rockrms:before { content: @fa-var-rockrms; } +.@{fa-css-prefix}-rss:before { content: @fa-var-rss; } +.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; } +.@{fa-css-prefix}-ruble-sign:before { content: @fa-var-ruble-sign; } +.@{fa-css-prefix}-rupee-sign:before { content: @fa-var-rupee-sign; } +.@{fa-css-prefix}-safari:before { content: @fa-var-safari; } +.@{fa-css-prefix}-sass:before { content: @fa-var-sass; } +.@{fa-css-prefix}-save:before { content: @fa-var-save; } +.@{fa-css-prefix}-schlix:before { content: @fa-var-schlix; } +.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; } +.@{fa-css-prefix}-search:before { content: @fa-var-search; } +.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; } +.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; } +.@{fa-css-prefix}-searchengin:before { content: @fa-var-searchengin; } +.@{fa-css-prefix}-seedling:before { content: @fa-var-seedling; } +.@{fa-css-prefix}-sellcast:before { content: @fa-var-sellcast; } +.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; } +.@{fa-css-prefix}-server:before { content: @fa-var-server; } +.@{fa-css-prefix}-servicestack:before { content: @fa-var-servicestack; } +.@{fa-css-prefix}-share:before { content: @fa-var-share; } +.@{fa-css-prefix}-share-alt:before { content: @fa-var-share-alt; } +.@{fa-css-prefix}-share-alt-square:before { content: @fa-var-share-alt-square; } +.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; } +.@{fa-css-prefix}-shekel-sign:before { content: @fa-var-shekel-sign; } +.@{fa-css-prefix}-shield-alt:before { content: @fa-var-shield-alt; } +.@{fa-css-prefix}-ship:before { content: @fa-var-ship; } +.@{fa-css-prefix}-shipping-fast:before { content: @fa-var-shipping-fast; } +.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; } +.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; } +.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; } +.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; } +.@{fa-css-prefix}-shower:before { content: @fa-var-shower; } +.@{fa-css-prefix}-sign:before { content: @fa-var-sign; } +.@{fa-css-prefix}-sign-in-alt:before { content: @fa-var-sign-in-alt; } +.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; } +.@{fa-css-prefix}-sign-out-alt:before { content: @fa-var-sign-out-alt; } +.@{fa-css-prefix}-signal:before { content: @fa-var-signal; } +.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; } +.@{fa-css-prefix}-sistrix:before { content: @fa-var-sistrix; } +.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; } +.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; } +.@{fa-css-prefix}-skype:before { content: @fa-var-skype; } +.@{fa-css-prefix}-slack:before { content: @fa-var-slack; } +.@{fa-css-prefix}-slack-hash:before { content: @fa-var-slack-hash; } +.@{fa-css-prefix}-sliders-h:before { content: @fa-var-sliders-h; } +.@{fa-css-prefix}-slideshare:before { content: @fa-var-slideshare; } +.@{fa-css-prefix}-smile:before { content: @fa-var-smile; } +.@{fa-css-prefix}-smoking:before { content: @fa-var-smoking; } +.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; } +.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; } +.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; } +.@{fa-css-prefix}-snowflake:before { content: @fa-var-snowflake; } +.@{fa-css-prefix}-sort:before { content: @fa-var-sort; } +.@{fa-css-prefix}-sort-alpha-down:before { content: @fa-var-sort-alpha-down; } +.@{fa-css-prefix}-sort-alpha-up:before { content: @fa-var-sort-alpha-up; } +.@{fa-css-prefix}-sort-amount-down:before { content: @fa-var-sort-amount-down; } +.@{fa-css-prefix}-sort-amount-up:before { content: @fa-var-sort-amount-up; } +.@{fa-css-prefix}-sort-down:before { content: @fa-var-sort-down; } +.@{fa-css-prefix}-sort-numeric-down:before { content: @fa-var-sort-numeric-down; } +.@{fa-css-prefix}-sort-numeric-up:before { content: @fa-var-sort-numeric-up; } +.@{fa-css-prefix}-sort-up:before { content: @fa-var-sort-up; } +.@{fa-css-prefix}-soundcloud:before { content: @fa-var-soundcloud; } +.@{fa-css-prefix}-space-shuttle:before { content: @fa-var-space-shuttle; } +.@{fa-css-prefix}-speakap:before { content: @fa-var-speakap; } +.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; } +.@{fa-css-prefix}-spotify:before { content: @fa-var-spotify; } +.@{fa-css-prefix}-square:before { content: @fa-var-square; } +.@{fa-css-prefix}-square-full:before { content: @fa-var-square-full; } +.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; } +.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; } +.@{fa-css-prefix}-star:before { content: @fa-var-star; } +.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; } +.@{fa-css-prefix}-staylinked:before { content: @fa-var-staylinked; } +.@{fa-css-prefix}-steam:before { content: @fa-var-steam; } +.@{fa-css-prefix}-steam-square:before { content: @fa-var-steam-square; } +.@{fa-css-prefix}-steam-symbol:before { content: @fa-var-steam-symbol; } +.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; } +.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; } +.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; } +.@{fa-css-prefix}-sticker-mule:before { content: @fa-var-sticker-mule; } +.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; } +.@{fa-css-prefix}-stop:before { content: @fa-var-stop; } +.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; } +.@{fa-css-prefix}-stopwatch:before { content: @fa-var-stopwatch; } +.@{fa-css-prefix}-strava:before { content: @fa-var-strava; } +.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; } +.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; } +.@{fa-css-prefix}-stripe:before { content: @fa-var-stripe; } +.@{fa-css-prefix}-stripe-s:before { content: @fa-var-stripe-s; } +.@{fa-css-prefix}-studiovinari:before { content: @fa-var-studiovinari; } +.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; } +.@{fa-css-prefix}-stumbleupon-circle:before { content: @fa-var-stumbleupon-circle; } +.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; } +.@{fa-css-prefix}-subway:before { content: @fa-var-subway; } +.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; } +.@{fa-css-prefix}-sun:before { content: @fa-var-sun; } +.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; } +.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; } +.@{fa-css-prefix}-supple:before { content: @fa-var-supple; } +.@{fa-css-prefix}-sync:before { content: @fa-var-sync; } +.@{fa-css-prefix}-sync-alt:before { content: @fa-var-sync-alt; } +.@{fa-css-prefix}-syringe:before { content: @fa-var-syringe; } +.@{fa-css-prefix}-table:before { content: @fa-var-table; } +.@{fa-css-prefix}-table-tennis:before { content: @fa-var-table-tennis; } +.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; } +.@{fa-css-prefix}-tablet-alt:before { content: @fa-var-tablet-alt; } +.@{fa-css-prefix}-tablets:before { content: @fa-var-tablets; } +.@{fa-css-prefix}-tachometer-alt:before { content: @fa-var-tachometer-alt; } +.@{fa-css-prefix}-tag:before { content: @fa-var-tag; } +.@{fa-css-prefix}-tags:before { content: @fa-var-tags; } +.@{fa-css-prefix}-tape:before { content: @fa-var-tape; } +.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; } +.@{fa-css-prefix}-taxi:before { content: @fa-var-taxi; } +.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; } +.@{fa-css-prefix}-telegram-plane:before { content: @fa-var-telegram-plane; } +.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; } +.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; } +.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; } +.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; } +.@{fa-css-prefix}-th:before { content: @fa-var-th; } +.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; } +.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; } +.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; } +.@{fa-css-prefix}-thermometer:before { content: @fa-var-thermometer; } +.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; } +.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; } +.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; } +.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; } +.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; } +.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; } +.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; } +.@{fa-css-prefix}-thumbtack:before { content: @fa-var-thumbtack; } +.@{fa-css-prefix}-ticket-alt:before { content: @fa-var-ticket-alt; } +.@{fa-css-prefix}-times:before { content: @fa-var-times; } +.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; } +.@{fa-css-prefix}-tint:before { content: @fa-var-tint; } +.@{fa-css-prefix}-toggle-off:before { content: @fa-var-toggle-off; } +.@{fa-css-prefix}-toggle-on:before { content: @fa-var-toggle-on; } +.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; } +.@{fa-css-prefix}-train:before { content: @fa-var-train; } +.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; } +.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; } +.@{fa-css-prefix}-trash:before { content: @fa-var-trash; } +.@{fa-css-prefix}-trash-alt:before { content: @fa-var-trash-alt; } +.@{fa-css-prefix}-tree:before { content: @fa-var-tree; } +.@{fa-css-prefix}-trello:before { content: @fa-var-trello; } +.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; } +.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; } +.@{fa-css-prefix}-truck:before { content: @fa-var-truck; } +.@{fa-css-prefix}-truck-loading:before { content: @fa-var-truck-loading; } +.@{fa-css-prefix}-truck-moving:before { content: @fa-var-truck-moving; } +.@{fa-css-prefix}-tty:before { content: @fa-var-tty; } +.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; } +.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; } +.@{fa-css-prefix}-tv:before { content: @fa-var-tv; } +.@{fa-css-prefix}-twitch:before { content: @fa-var-twitch; } +.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; } +.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; } +.@{fa-css-prefix}-typo3:before { content: @fa-var-typo3; } +.@{fa-css-prefix}-uber:before { content: @fa-var-uber; } +.@{fa-css-prefix}-uikit:before { content: @fa-var-uikit; } +.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; } +.@{fa-css-prefix}-underline:before { content: @fa-var-underline; } +.@{fa-css-prefix}-undo:before { content: @fa-var-undo; } +.@{fa-css-prefix}-undo-alt:before { content: @fa-var-undo-alt; } +.@{fa-css-prefix}-uniregistry:before { content: @fa-var-uniregistry; } +.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; } +.@{fa-css-prefix}-university:before { content: @fa-var-university; } +.@{fa-css-prefix}-unlink:before { content: @fa-var-unlink; } +.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; } +.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; } +.@{fa-css-prefix}-untappd:before { content: @fa-var-untappd; } +.@{fa-css-prefix}-upload:before { content: @fa-var-upload; } +.@{fa-css-prefix}-usb:before { content: @fa-var-usb; } +.@{fa-css-prefix}-user:before { content: @fa-var-user; } +.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; } +.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; } +.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; } +.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; } +.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; } +.@{fa-css-prefix}-users:before { content: @fa-var-users; } +.@{fa-css-prefix}-ussunnah:before { content: @fa-var-ussunnah; } +.@{fa-css-prefix}-utensil-spoon:before { content: @fa-var-utensil-spoon; } +.@{fa-css-prefix}-utensils:before { content: @fa-var-utensils; } +.@{fa-css-prefix}-vaadin:before { content: @fa-var-vaadin; } +.@{fa-css-prefix}-venus:before { content: @fa-var-venus; } +.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; } +.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; } +.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; } +.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; } +.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; } +.@{fa-css-prefix}-vial:before { content: @fa-var-vial; } +.@{fa-css-prefix}-vials:before { content: @fa-var-vials; } +.@{fa-css-prefix}-viber:before { content: @fa-var-viber; } +.@{fa-css-prefix}-video:before { content: @fa-var-video; } +.@{fa-css-prefix}-video-slash:before { content: @fa-var-video-slash; } +.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; } +.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; } +.@{fa-css-prefix}-vimeo-v:before { content: @fa-var-vimeo-v; } +.@{fa-css-prefix}-vine:before { content: @fa-var-vine; } +.@{fa-css-prefix}-vk:before { content: @fa-var-vk; } +.@{fa-css-prefix}-vnv:before { content: @fa-var-vnv; } +.@{fa-css-prefix}-volleyball-ball:before { content: @fa-var-volleyball-ball; } +.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; } +.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; } +.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; } +.@{fa-css-prefix}-vuejs:before { content: @fa-var-vuejs; } +.@{fa-css-prefix}-warehouse:before { content: @fa-var-warehouse; } +.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; } +.@{fa-css-prefix}-weight:before { content: @fa-var-weight; } +.@{fa-css-prefix}-weixin:before { content: @fa-var-weixin; } +.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; } +.@{fa-css-prefix}-whatsapp-square:before { content: @fa-var-whatsapp-square; } +.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; } +.@{fa-css-prefix}-whmcs:before { content: @fa-var-whmcs; } +.@{fa-css-prefix}-wifi:before { content: @fa-var-wifi; } +.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; } +.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; } +.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; } +.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; } +.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; } +.@{fa-css-prefix}-windows:before { content: @fa-var-windows; } +.@{fa-css-prefix}-wine-glass:before { content: @fa-var-wine-glass; } +.@{fa-css-prefix}-won-sign:before { content: @fa-var-won-sign; } +.@{fa-css-prefix}-wordpress:before { content: @fa-var-wordpress; } +.@{fa-css-prefix}-wordpress-simple:before { content: @fa-var-wordpress-simple; } +.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; } +.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; } +.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; } +.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; } +.@{fa-css-prefix}-x-ray:before { content: @fa-var-x-ray; } +.@{fa-css-prefix}-xbox:before { content: @fa-var-xbox; } +.@{fa-css-prefix}-xing:before { content: @fa-var-xing; } +.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; } +.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; } +.@{fa-css-prefix}-yahoo:before { content: @fa-var-yahoo; } +.@{fa-css-prefix}-yandex:before { content: @fa-var-yandex; } +.@{fa-css-prefix}-yandex-international:before { content: @fa-var-yandex-international; } +.@{fa-css-prefix}-yelp:before { content: @fa-var-yelp; } +.@{fa-css-prefix}-yen-sign:before { content: @fa-var-yen-sign; } +.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; } +.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; } +.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; } diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_larger.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_larger.less new file mode 100644 index 000000000000..6cbb1ec6ec5b --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_larger.less @@ -0,0 +1,27 @@ +// Icon Sizes +// ------------------------- + +.larger(@factor) when (@factor > 0) { + .larger((@factor - 1)); + + .@{fa-css-prefix}-@{factor}x { + font-size: (@factor * 1em); + } +} + +/* makes the font 33% larger relative to the icon container */ +.@{fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -.0667em; +} + +.@{fa-css-prefix}-xs { + font-size: .75em; +} + +.@{fa-css-prefix}-sm { + font-size: .875em; +} + +.larger(10); diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_list.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_list.less new file mode 100644 index 000000000000..1ff7ca7f5998 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_list.less @@ -0,0 +1,18 @@ +// List Icons +// ------------------------- + +.@{fa-css-prefix}-ul { + list-style-type: none; + margin-left: @fa-li-width * 5/4; + padding-left: 0; + + > li { position: relative; } +} + +.@{fa-css-prefix}-li { + left: -@fa-li-width; + position: absolute; + text-align: center; + width: @fa-li-width; + line-height: inherit; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_mixins.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_mixins.less new file mode 100644 index 000000000000..a4e93f90a39d --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_mixins.less @@ -0,0 +1,57 @@ +// Mixins +// -------------------------- + +.fa-icon() { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + font-weight: normal; + line-height: 1; + vertical-align: -.125em; +} + +.fa-icon-rotate(@degrees, @rotation) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; + transform: rotate(@degrees); +} + +.fa-icon-flip(@horiz, @vert, @rotation) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; + transform: scale(@horiz, @vert); +} + + +// Only display content to screen readers. A la Bootstrap 4. +// +// See: http://a11yproject.com/posts/how-to-hide-content/ + +.sr-only() { + border: 0; + clip: rect(0,0,0,0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// +// Credit: HTML5 Boilerplate + +.sr-only-focusable() { + &:active, + &:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; + } +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_rotated-flipped.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_rotated-flipped.less new file mode 100644 index 000000000000..1ee31db19f44 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_rotated-flipped.less @@ -0,0 +1,23 @@ +// Rotated & Flipped Icons +// ------------------------- + +.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } +.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } +.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } + +.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } +.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } +.@{fa-css-prefix}-flip-horizontal.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(-1, -1, 2); } + +// Hook for IE8-9 +// ------------------------- + +:root { + .@{fa-css-prefix}-rotate-90, + .@{fa-css-prefix}-rotate-180, + .@{fa-css-prefix}-rotate-270, + .@{fa-css-prefix}-flip-horizontal, + .@{fa-css-prefix}-flip-vertical { + filter: none; + } +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_screen-reader.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_screen-reader.less new file mode 100644 index 000000000000..11c188196d5a --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_screen-reader.less @@ -0,0 +1,5 @@ +// Screen Readers +// ------------------------- + +.sr-only { .sr-only(); } +.sr-only-focusable { .sr-only-focusable(); } diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_stacked.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_stacked.less new file mode 100644 index 000000000000..263b5c44fceb --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_stacked.less @@ -0,0 +1,22 @@ +// Stacked Icons +// ------------------------- + +.@{fa-css-prefix}-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2em; +} + +.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; +} + +.@{fa-css-prefix}-stack-1x { line-height: inherit; } +.@{fa-css-prefix}-stack-2x { font-size: 2em; } +.@{fa-css-prefix}-inverse { color: @fa-inverse; } diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_variables.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_variables.less new file mode 100644 index 000000000000..19d5a9ee61a5 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/_variables.less @@ -0,0 +1,887 @@ +// Variables +// -------------------------- + +@fa-font-path: "../webfonts"; +@fa-font-size-base: 16px; +@fa-line-height-base: 1; +@fa-css-prefix: fa; +@fa-version: "5.0.10"; +@fa-border-color: #eee; +@fa-inverse: #fff; +@fa-li-width: 2em; + +@fa-var-500px: "\f26e"; +@fa-var-accessible-icon: "\f368"; +@fa-var-accusoft: "\f369"; +@fa-var-address-book: "\f2b9"; +@fa-var-address-card: "\f2bb"; +@fa-var-adjust: "\f042"; +@fa-var-adn: "\f170"; +@fa-var-adversal: "\f36a"; +@fa-var-affiliatetheme: "\f36b"; +@fa-var-algolia: "\f36c"; +@fa-var-align-center: "\f037"; +@fa-var-align-justify: "\f039"; +@fa-var-align-left: "\f036"; +@fa-var-align-right: "\f038"; +@fa-var-allergies: "\f461"; +@fa-var-amazon: "\f270"; +@fa-var-amazon-pay: "\f42c"; +@fa-var-ambulance: "\f0f9"; +@fa-var-american-sign-language-interpreting: "\f2a3"; +@fa-var-amilia: "\f36d"; +@fa-var-anchor: "\f13d"; +@fa-var-android: "\f17b"; +@fa-var-angellist: "\f209"; +@fa-var-angle-double-down: "\f103"; +@fa-var-angle-double-left: "\f100"; +@fa-var-angle-double-right: "\f101"; +@fa-var-angle-double-up: "\f102"; +@fa-var-angle-down: "\f107"; +@fa-var-angle-left: "\f104"; +@fa-var-angle-right: "\f105"; +@fa-var-angle-up: "\f106"; +@fa-var-angrycreative: "\f36e"; +@fa-var-angular: "\f420"; +@fa-var-app-store: "\f36f"; +@fa-var-app-store-ios: "\f370"; +@fa-var-apper: "\f371"; +@fa-var-apple: "\f179"; +@fa-var-apple-pay: "\f415"; +@fa-var-archive: "\f187"; +@fa-var-arrow-alt-circle-down: "\f358"; +@fa-var-arrow-alt-circle-left: "\f359"; +@fa-var-arrow-alt-circle-right: "\f35a"; +@fa-var-arrow-alt-circle-up: "\f35b"; +@fa-var-arrow-circle-down: "\f0ab"; +@fa-var-arrow-circle-left: "\f0a8"; +@fa-var-arrow-circle-right: "\f0a9"; +@fa-var-arrow-circle-up: "\f0aa"; +@fa-var-arrow-down: "\f063"; +@fa-var-arrow-left: "\f060"; +@fa-var-arrow-right: "\f061"; +@fa-var-arrow-up: "\f062"; +@fa-var-arrows-alt: "\f0b2"; +@fa-var-arrows-alt-h: "\f337"; +@fa-var-arrows-alt-v: "\f338"; +@fa-var-assistive-listening-systems: "\f2a2"; +@fa-var-asterisk: "\f069"; +@fa-var-asymmetrik: "\f372"; +@fa-var-at: "\f1fa"; +@fa-var-audible: "\f373"; +@fa-var-audio-description: "\f29e"; +@fa-var-autoprefixer: "\f41c"; +@fa-var-avianex: "\f374"; +@fa-var-aviato: "\f421"; +@fa-var-aws: "\f375"; +@fa-var-backward: "\f04a"; +@fa-var-balance-scale: "\f24e"; +@fa-var-ban: "\f05e"; +@fa-var-band-aid: "\f462"; +@fa-var-bandcamp: "\f2d5"; +@fa-var-barcode: "\f02a"; +@fa-var-bars: "\f0c9"; +@fa-var-baseball-ball: "\f433"; +@fa-var-basketball-ball: "\f434"; +@fa-var-bath: "\f2cd"; +@fa-var-battery-empty: "\f244"; +@fa-var-battery-full: "\f240"; +@fa-var-battery-half: "\f242"; +@fa-var-battery-quarter: "\f243"; +@fa-var-battery-three-quarters: "\f241"; +@fa-var-bed: "\f236"; +@fa-var-beer: "\f0fc"; +@fa-var-behance: "\f1b4"; +@fa-var-behance-square: "\f1b5"; +@fa-var-bell: "\f0f3"; +@fa-var-bell-slash: "\f1f6"; +@fa-var-bicycle: "\f206"; +@fa-var-bimobject: "\f378"; +@fa-var-binoculars: "\f1e5"; +@fa-var-birthday-cake: "\f1fd"; +@fa-var-bitbucket: "\f171"; +@fa-var-bitcoin: "\f379"; +@fa-var-bity: "\f37a"; +@fa-var-black-tie: "\f27e"; +@fa-var-blackberry: "\f37b"; +@fa-var-blind: "\f29d"; +@fa-var-blogger: "\f37c"; +@fa-var-blogger-b: "\f37d"; +@fa-var-bluetooth: "\f293"; +@fa-var-bluetooth-b: "\f294"; +@fa-var-bold: "\f032"; +@fa-var-bolt: "\f0e7"; +@fa-var-bomb: "\f1e2"; +@fa-var-book: "\f02d"; +@fa-var-bookmark: "\f02e"; +@fa-var-bowling-ball: "\f436"; +@fa-var-box: "\f466"; +@fa-var-box-open: "\f49e"; +@fa-var-boxes: "\f468"; +@fa-var-braille: "\f2a1"; +@fa-var-briefcase: "\f0b1"; +@fa-var-briefcase-medical: "\f469"; +@fa-var-btc: "\f15a"; +@fa-var-bug: "\f188"; +@fa-var-building: "\f1ad"; +@fa-var-bullhorn: "\f0a1"; +@fa-var-bullseye: "\f140"; +@fa-var-burn: "\f46a"; +@fa-var-buromobelexperte: "\f37f"; +@fa-var-bus: "\f207"; +@fa-var-buysellads: "\f20d"; +@fa-var-calculator: "\f1ec"; +@fa-var-calendar: "\f133"; +@fa-var-calendar-alt: "\f073"; +@fa-var-calendar-check: "\f274"; +@fa-var-calendar-minus: "\f272"; +@fa-var-calendar-plus: "\f271"; +@fa-var-calendar-times: "\f273"; +@fa-var-camera: "\f030"; +@fa-var-camera-retro: "\f083"; +@fa-var-capsules: "\f46b"; +@fa-var-car: "\f1b9"; +@fa-var-caret-down: "\f0d7"; +@fa-var-caret-left: "\f0d9"; +@fa-var-caret-right: "\f0da"; +@fa-var-caret-square-down: "\f150"; +@fa-var-caret-square-left: "\f191"; +@fa-var-caret-square-right: "\f152"; +@fa-var-caret-square-up: "\f151"; +@fa-var-caret-up: "\f0d8"; +@fa-var-cart-arrow-down: "\f218"; +@fa-var-cart-plus: "\f217"; +@fa-var-cc-amazon-pay: "\f42d"; +@fa-var-cc-amex: "\f1f3"; +@fa-var-cc-apple-pay: "\f416"; +@fa-var-cc-diners-club: "\f24c"; +@fa-var-cc-discover: "\f1f2"; +@fa-var-cc-jcb: "\f24b"; +@fa-var-cc-mastercard: "\f1f1"; +@fa-var-cc-paypal: "\f1f4"; +@fa-var-cc-stripe: "\f1f5"; +@fa-var-cc-visa: "\f1f0"; +@fa-var-centercode: "\f380"; +@fa-var-certificate: "\f0a3"; +@fa-var-chart-area: "\f1fe"; +@fa-var-chart-bar: "\f080"; +@fa-var-chart-line: "\f201"; +@fa-var-chart-pie: "\f200"; +@fa-var-check: "\f00c"; +@fa-var-check-circle: "\f058"; +@fa-var-check-square: "\f14a"; +@fa-var-chess: "\f439"; +@fa-var-chess-bishop: "\f43a"; +@fa-var-chess-board: "\f43c"; +@fa-var-chess-king: "\f43f"; +@fa-var-chess-knight: "\f441"; +@fa-var-chess-pawn: "\f443"; +@fa-var-chess-queen: "\f445"; +@fa-var-chess-rook: "\f447"; +@fa-var-chevron-circle-down: "\f13a"; +@fa-var-chevron-circle-left: "\f137"; +@fa-var-chevron-circle-right: "\f138"; +@fa-var-chevron-circle-up: "\f139"; +@fa-var-chevron-down: "\f078"; +@fa-var-chevron-left: "\f053"; +@fa-var-chevron-right: "\f054"; +@fa-var-chevron-up: "\f077"; +@fa-var-child: "\f1ae"; +@fa-var-chrome: "\f268"; +@fa-var-circle: "\f111"; +@fa-var-circle-notch: "\f1ce"; +@fa-var-clipboard: "\f328"; +@fa-var-clipboard-check: "\f46c"; +@fa-var-clipboard-list: "\f46d"; +@fa-var-clock: "\f017"; +@fa-var-clone: "\f24d"; +@fa-var-closed-captioning: "\f20a"; +@fa-var-cloud: "\f0c2"; +@fa-var-cloud-download-alt: "\f381"; +@fa-var-cloud-upload-alt: "\f382"; +@fa-var-cloudscale: "\f383"; +@fa-var-cloudsmith: "\f384"; +@fa-var-cloudversify: "\f385"; +@fa-var-code: "\f121"; +@fa-var-code-branch: "\f126"; +@fa-var-codepen: "\f1cb"; +@fa-var-codiepie: "\f284"; +@fa-var-coffee: "\f0f4"; +@fa-var-cog: "\f013"; +@fa-var-cogs: "\f085"; +@fa-var-columns: "\f0db"; +@fa-var-comment: "\f075"; +@fa-var-comment-alt: "\f27a"; +@fa-var-comment-dots: "\f4ad"; +@fa-var-comment-slash: "\f4b3"; +@fa-var-comments: "\f086"; +@fa-var-compass: "\f14e"; +@fa-var-compress: "\f066"; +@fa-var-connectdevelop: "\f20e"; +@fa-var-contao: "\f26d"; +@fa-var-copy: "\f0c5"; +@fa-var-copyright: "\f1f9"; +@fa-var-couch: "\f4b8"; +@fa-var-cpanel: "\f388"; +@fa-var-creative-commons: "\f25e"; +@fa-var-credit-card: "\f09d"; +@fa-var-crop: "\f125"; +@fa-var-crosshairs: "\f05b"; +@fa-var-css3: "\f13c"; +@fa-var-css3-alt: "\f38b"; +@fa-var-cube: "\f1b2"; +@fa-var-cubes: "\f1b3"; +@fa-var-cut: "\f0c4"; +@fa-var-cuttlefish: "\f38c"; +@fa-var-d-and-d: "\f38d"; +@fa-var-dashcube: "\f210"; +@fa-var-database: "\f1c0"; +@fa-var-deaf: "\f2a4"; +@fa-var-delicious: "\f1a5"; +@fa-var-deploydog: "\f38e"; +@fa-var-deskpro: "\f38f"; +@fa-var-desktop: "\f108"; +@fa-var-deviantart: "\f1bd"; +@fa-var-diagnoses: "\f470"; +@fa-var-digg: "\f1a6"; +@fa-var-digital-ocean: "\f391"; +@fa-var-discord: "\f392"; +@fa-var-discourse: "\f393"; +@fa-var-dna: "\f471"; +@fa-var-dochub: "\f394"; +@fa-var-docker: "\f395"; +@fa-var-dollar-sign: "\f155"; +@fa-var-dolly: "\f472"; +@fa-var-dolly-flatbed: "\f474"; +@fa-var-donate: "\f4b9"; +@fa-var-dot-circle: "\f192"; +@fa-var-dove: "\f4ba"; +@fa-var-download: "\f019"; +@fa-var-draft2digital: "\f396"; +@fa-var-dribbble: "\f17d"; +@fa-var-dribbble-square: "\f397"; +@fa-var-dropbox: "\f16b"; +@fa-var-drupal: "\f1a9"; +@fa-var-dyalog: "\f399"; +@fa-var-earlybirds: "\f39a"; +@fa-var-edge: "\f282"; +@fa-var-edit: "\f044"; +@fa-var-eject: "\f052"; +@fa-var-elementor: "\f430"; +@fa-var-ellipsis-h: "\f141"; +@fa-var-ellipsis-v: "\f142"; +@fa-var-ember: "\f423"; +@fa-var-empire: "\f1d1"; +@fa-var-envelope: "\f0e0"; +@fa-var-envelope-open: "\f2b6"; +@fa-var-envelope-square: "\f199"; +@fa-var-envira: "\f299"; +@fa-var-eraser: "\f12d"; +@fa-var-erlang: "\f39d"; +@fa-var-ethereum: "\f42e"; +@fa-var-etsy: "\f2d7"; +@fa-var-euro-sign: "\f153"; +@fa-var-exchange-alt: "\f362"; +@fa-var-exclamation: "\f12a"; +@fa-var-exclamation-circle: "\f06a"; +@fa-var-exclamation-triangle: "\f071"; +@fa-var-expand: "\f065"; +@fa-var-expand-arrows-alt: "\f31e"; +@fa-var-expeditedssl: "\f23e"; +@fa-var-external-link-alt: "\f35d"; +@fa-var-external-link-square-alt: "\f360"; +@fa-var-eye: "\f06e"; +@fa-var-eye-dropper: "\f1fb"; +@fa-var-eye-slash: "\f070"; +@fa-var-facebook: "\f09a"; +@fa-var-facebook-f: "\f39e"; +@fa-var-facebook-messenger: "\f39f"; +@fa-var-facebook-square: "\f082"; +@fa-var-fast-backward: "\f049"; +@fa-var-fast-forward: "\f050"; +@fa-var-fax: "\f1ac"; +@fa-var-female: "\f182"; +@fa-var-fighter-jet: "\f0fb"; +@fa-var-file: "\f15b"; +@fa-var-file-alt: "\f15c"; +@fa-var-file-archive: "\f1c6"; +@fa-var-file-audio: "\f1c7"; +@fa-var-file-code: "\f1c9"; +@fa-var-file-excel: "\f1c3"; +@fa-var-file-image: "\f1c5"; +@fa-var-file-medical: "\f477"; +@fa-var-file-medical-alt: "\f478"; +@fa-var-file-pdf: "\f1c1"; +@fa-var-file-powerpoint: "\f1c4"; +@fa-var-file-video: "\f1c8"; +@fa-var-file-word: "\f1c2"; +@fa-var-film: "\f008"; +@fa-var-filter: "\f0b0"; +@fa-var-fire: "\f06d"; +@fa-var-fire-extinguisher: "\f134"; +@fa-var-firefox: "\f269"; +@fa-var-first-aid: "\f479"; +@fa-var-first-order: "\f2b0"; +@fa-var-firstdraft: "\f3a1"; +@fa-var-flag: "\f024"; +@fa-var-flag-checkered: "\f11e"; +@fa-var-flask: "\f0c3"; +@fa-var-flickr: "\f16e"; +@fa-var-flipboard: "\f44d"; +@fa-var-fly: "\f417"; +@fa-var-folder: "\f07b"; +@fa-var-folder-open: "\f07c"; +@fa-var-font: "\f031"; +@fa-var-font-awesome: "\f2b4"; +@fa-var-font-awesome-alt: "\f35c"; +@fa-var-font-awesome-flag: "\f425"; +@fa-var-fonticons: "\f280"; +@fa-var-fonticons-fi: "\f3a2"; +@fa-var-football-ball: "\f44e"; +@fa-var-fort-awesome: "\f286"; +@fa-var-fort-awesome-alt: "\f3a3"; +@fa-var-forumbee: "\f211"; +@fa-var-forward: "\f04e"; +@fa-var-foursquare: "\f180"; +@fa-var-free-code-camp: "\f2c5"; +@fa-var-freebsd: "\f3a4"; +@fa-var-frown: "\f119"; +@fa-var-futbol: "\f1e3"; +@fa-var-gamepad: "\f11b"; +@fa-var-gavel: "\f0e3"; +@fa-var-gem: "\f3a5"; +@fa-var-genderless: "\f22d"; +@fa-var-get-pocket: "\f265"; +@fa-var-gg: "\f260"; +@fa-var-gg-circle: "\f261"; +@fa-var-gift: "\f06b"; +@fa-var-git: "\f1d3"; +@fa-var-git-square: "\f1d2"; +@fa-var-github: "\f09b"; +@fa-var-github-alt: "\f113"; +@fa-var-github-square: "\f092"; +@fa-var-gitkraken: "\f3a6"; +@fa-var-gitlab: "\f296"; +@fa-var-gitter: "\f426"; +@fa-var-glass-martini: "\f000"; +@fa-var-glide: "\f2a5"; +@fa-var-glide-g: "\f2a6"; +@fa-var-globe: "\f0ac"; +@fa-var-gofore: "\f3a7"; +@fa-var-golf-ball: "\f450"; +@fa-var-goodreads: "\f3a8"; +@fa-var-goodreads-g: "\f3a9"; +@fa-var-google: "\f1a0"; +@fa-var-google-drive: "\f3aa"; +@fa-var-google-play: "\f3ab"; +@fa-var-google-plus: "\f2b3"; +@fa-var-google-plus-g: "\f0d5"; +@fa-var-google-plus-square: "\f0d4"; +@fa-var-google-wallet: "\f1ee"; +@fa-var-graduation-cap: "\f19d"; +@fa-var-gratipay: "\f184"; +@fa-var-grav: "\f2d6"; +@fa-var-gripfire: "\f3ac"; +@fa-var-grunt: "\f3ad"; +@fa-var-gulp: "\f3ae"; +@fa-var-h-square: "\f0fd"; +@fa-var-hacker-news: "\f1d4"; +@fa-var-hacker-news-square: "\f3af"; +@fa-var-hand-holding: "\f4bd"; +@fa-var-hand-holding-heart: "\f4be"; +@fa-var-hand-holding-usd: "\f4c0"; +@fa-var-hand-lizard: "\f258"; +@fa-var-hand-paper: "\f256"; +@fa-var-hand-peace: "\f25b"; +@fa-var-hand-point-down: "\f0a7"; +@fa-var-hand-point-left: "\f0a5"; +@fa-var-hand-point-right: "\f0a4"; +@fa-var-hand-point-up: "\f0a6"; +@fa-var-hand-pointer: "\f25a"; +@fa-var-hand-rock: "\f255"; +@fa-var-hand-scissors: "\f257"; +@fa-var-hand-spock: "\f259"; +@fa-var-hands: "\f4c2"; +@fa-var-hands-helping: "\f4c4"; +@fa-var-handshake: "\f2b5"; +@fa-var-hashtag: "\f292"; +@fa-var-hdd: "\f0a0"; +@fa-var-heading: "\f1dc"; +@fa-var-headphones: "\f025"; +@fa-var-heart: "\f004"; +@fa-var-heartbeat: "\f21e"; +@fa-var-hips: "\f452"; +@fa-var-hire-a-helper: "\f3b0"; +@fa-var-history: "\f1da"; +@fa-var-hockey-puck: "\f453"; +@fa-var-home: "\f015"; +@fa-var-hooli: "\f427"; +@fa-var-hospital: "\f0f8"; +@fa-var-hospital-alt: "\f47d"; +@fa-var-hospital-symbol: "\f47e"; +@fa-var-hotjar: "\f3b1"; +@fa-var-hourglass: "\f254"; +@fa-var-hourglass-end: "\f253"; +@fa-var-hourglass-half: "\f252"; +@fa-var-hourglass-start: "\f251"; +@fa-var-houzz: "\f27c"; +@fa-var-html5: "\f13b"; +@fa-var-hubspot: "\f3b2"; +@fa-var-i-cursor: "\f246"; +@fa-var-id-badge: "\f2c1"; +@fa-var-id-card: "\f2c2"; +@fa-var-id-card-alt: "\f47f"; +@fa-var-image: "\f03e"; +@fa-var-images: "\f302"; +@fa-var-imdb: "\f2d8"; +@fa-var-inbox: "\f01c"; +@fa-var-indent: "\f03c"; +@fa-var-industry: "\f275"; +@fa-var-info: "\f129"; +@fa-var-info-circle: "\f05a"; +@fa-var-instagram: "\f16d"; +@fa-var-internet-explorer: "\f26b"; +@fa-var-ioxhost: "\f208"; +@fa-var-italic: "\f033"; +@fa-var-itunes: "\f3b4"; +@fa-var-itunes-note: "\f3b5"; +@fa-var-java: "\f4e4"; +@fa-var-jenkins: "\f3b6"; +@fa-var-joget: "\f3b7"; +@fa-var-joomla: "\f1aa"; +@fa-var-js: "\f3b8"; +@fa-var-js-square: "\f3b9"; +@fa-var-jsfiddle: "\f1cc"; +@fa-var-key: "\f084"; +@fa-var-keyboard: "\f11c"; +@fa-var-keycdn: "\f3ba"; +@fa-var-kickstarter: "\f3bb"; +@fa-var-kickstarter-k: "\f3bc"; +@fa-var-korvue: "\f42f"; +@fa-var-language: "\f1ab"; +@fa-var-laptop: "\f109"; +@fa-var-laravel: "\f3bd"; +@fa-var-lastfm: "\f202"; +@fa-var-lastfm-square: "\f203"; +@fa-var-leaf: "\f06c"; +@fa-var-leanpub: "\f212"; +@fa-var-lemon: "\f094"; +@fa-var-less: "\f41d"; +@fa-var-level-down-alt: "\f3be"; +@fa-var-level-up-alt: "\f3bf"; +@fa-var-life-ring: "\f1cd"; +@fa-var-lightbulb: "\f0eb"; +@fa-var-line: "\f3c0"; +@fa-var-link: "\f0c1"; +@fa-var-linkedin: "\f08c"; +@fa-var-linkedin-in: "\f0e1"; +@fa-var-linode: "\f2b8"; +@fa-var-linux: "\f17c"; +@fa-var-lira-sign: "\f195"; +@fa-var-list: "\f03a"; +@fa-var-list-alt: "\f022"; +@fa-var-list-ol: "\f0cb"; +@fa-var-list-ul: "\f0ca"; +@fa-var-location-arrow: "\f124"; +@fa-var-lock: "\f023"; +@fa-var-lock-open: "\f3c1"; +@fa-var-long-arrow-alt-down: "\f309"; +@fa-var-long-arrow-alt-left: "\f30a"; +@fa-var-long-arrow-alt-right: "\f30b"; +@fa-var-long-arrow-alt-up: "\f30c"; +@fa-var-low-vision: "\f2a8"; +@fa-var-lyft: "\f3c3"; +@fa-var-magento: "\f3c4"; +@fa-var-magic: "\f0d0"; +@fa-var-magnet: "\f076"; +@fa-var-male: "\f183"; +@fa-var-map: "\f279"; +@fa-var-map-marker: "\f041"; +@fa-var-map-marker-alt: "\f3c5"; +@fa-var-map-pin: "\f276"; +@fa-var-map-signs: "\f277"; +@fa-var-mars: "\f222"; +@fa-var-mars-double: "\f227"; +@fa-var-mars-stroke: "\f229"; +@fa-var-mars-stroke-h: "\f22b"; +@fa-var-mars-stroke-v: "\f22a"; +@fa-var-maxcdn: "\f136"; +@fa-var-medapps: "\f3c6"; +@fa-var-medium: "\f23a"; +@fa-var-medium-m: "\f3c7"; +@fa-var-medkit: "\f0fa"; +@fa-var-medrt: "\f3c8"; +@fa-var-meetup: "\f2e0"; +@fa-var-meh: "\f11a"; +@fa-var-mercury: "\f223"; +@fa-var-microchip: "\f2db"; +@fa-var-microphone: "\f130"; +@fa-var-microphone-slash: "\f131"; +@fa-var-microsoft: "\f3ca"; +@fa-var-minus: "\f068"; +@fa-var-minus-circle: "\f056"; +@fa-var-minus-square: "\f146"; +@fa-var-mix: "\f3cb"; +@fa-var-mixcloud: "\f289"; +@fa-var-mizuni: "\f3cc"; +@fa-var-mobile: "\f10b"; +@fa-var-mobile-alt: "\f3cd"; +@fa-var-modx: "\f285"; +@fa-var-monero: "\f3d0"; +@fa-var-money-bill-alt: "\f3d1"; +@fa-var-moon: "\f186"; +@fa-var-motorcycle: "\f21c"; +@fa-var-mouse-pointer: "\f245"; +@fa-var-music: "\f001"; +@fa-var-napster: "\f3d2"; +@fa-var-neuter: "\f22c"; +@fa-var-newspaper: "\f1ea"; +@fa-var-nintendo-switch: "\f418"; +@fa-var-node: "\f419"; +@fa-var-node-js: "\f3d3"; +@fa-var-notes-medical: "\f481"; +@fa-var-npm: "\f3d4"; +@fa-var-ns8: "\f3d5"; +@fa-var-nutritionix: "\f3d6"; +@fa-var-object-group: "\f247"; +@fa-var-object-ungroup: "\f248"; +@fa-var-odnoklassniki: "\f263"; +@fa-var-odnoklassniki-square: "\f264"; +@fa-var-opencart: "\f23d"; +@fa-var-openid: "\f19b"; +@fa-var-opera: "\f26a"; +@fa-var-optin-monster: "\f23c"; +@fa-var-osi: "\f41a"; +@fa-var-outdent: "\f03b"; +@fa-var-page4: "\f3d7"; +@fa-var-pagelines: "\f18c"; +@fa-var-paint-brush: "\f1fc"; +@fa-var-palfed: "\f3d8"; +@fa-var-pallet: "\f482"; +@fa-var-paper-plane: "\f1d8"; +@fa-var-paperclip: "\f0c6"; +@fa-var-parachute-box: "\f4cd"; +@fa-var-paragraph: "\f1dd"; +@fa-var-paste: "\f0ea"; +@fa-var-patreon: "\f3d9"; +@fa-var-pause: "\f04c"; +@fa-var-pause-circle: "\f28b"; +@fa-var-paw: "\f1b0"; +@fa-var-paypal: "\f1ed"; +@fa-var-pen-square: "\f14b"; +@fa-var-pencil-alt: "\f303"; +@fa-var-people-carry: "\f4ce"; +@fa-var-percent: "\f295"; +@fa-var-periscope: "\f3da"; +@fa-var-phabricator: "\f3db"; +@fa-var-phoenix-framework: "\f3dc"; +@fa-var-phone: "\f095"; +@fa-var-phone-slash: "\f3dd"; +@fa-var-phone-square: "\f098"; +@fa-var-phone-volume: "\f2a0"; +@fa-var-php: "\f457"; +@fa-var-pied-piper: "\f2ae"; +@fa-var-pied-piper-alt: "\f1a8"; +@fa-var-pied-piper-hat: "\f4e5"; +@fa-var-pied-piper-pp: "\f1a7"; +@fa-var-piggy-bank: "\f4d3"; +@fa-var-pills: "\f484"; +@fa-var-pinterest: "\f0d2"; +@fa-var-pinterest-p: "\f231"; +@fa-var-pinterest-square: "\f0d3"; +@fa-var-plane: "\f072"; +@fa-var-play: "\f04b"; +@fa-var-play-circle: "\f144"; +@fa-var-playstation: "\f3df"; +@fa-var-plug: "\f1e6"; +@fa-var-plus: "\f067"; +@fa-var-plus-circle: "\f055"; +@fa-var-plus-square: "\f0fe"; +@fa-var-podcast: "\f2ce"; +@fa-var-poo: "\f2fe"; +@fa-var-pound-sign: "\f154"; +@fa-var-power-off: "\f011"; +@fa-var-prescription-bottle: "\f485"; +@fa-var-prescription-bottle-alt: "\f486"; +@fa-var-print: "\f02f"; +@fa-var-procedures: "\f487"; +@fa-var-product-hunt: "\f288"; +@fa-var-pushed: "\f3e1"; +@fa-var-puzzle-piece: "\f12e"; +@fa-var-python: "\f3e2"; +@fa-var-qq: "\f1d6"; +@fa-var-qrcode: "\f029"; +@fa-var-question: "\f128"; +@fa-var-question-circle: "\f059"; +@fa-var-quidditch: "\f458"; +@fa-var-quinscape: "\f459"; +@fa-var-quora: "\f2c4"; +@fa-var-quote-left: "\f10d"; +@fa-var-quote-right: "\f10e"; +@fa-var-random: "\f074"; +@fa-var-ravelry: "\f2d9"; +@fa-var-react: "\f41b"; +@fa-var-readme: "\f4d5"; +@fa-var-rebel: "\f1d0"; +@fa-var-recycle: "\f1b8"; +@fa-var-red-river: "\f3e3"; +@fa-var-reddit: "\f1a1"; +@fa-var-reddit-alien: "\f281"; +@fa-var-reddit-square: "\f1a2"; +@fa-var-redo: "\f01e"; +@fa-var-redo-alt: "\f2f9"; +@fa-var-registered: "\f25d"; +@fa-var-rendact: "\f3e4"; +@fa-var-renren: "\f18b"; +@fa-var-reply: "\f3e5"; +@fa-var-reply-all: "\f122"; +@fa-var-replyd: "\f3e6"; +@fa-var-resolving: "\f3e7"; +@fa-var-retweet: "\f079"; +@fa-var-ribbon: "\f4d6"; +@fa-var-road: "\f018"; +@fa-var-rocket: "\f135"; +@fa-var-rocketchat: "\f3e8"; +@fa-var-rockrms: "\f3e9"; +@fa-var-rss: "\f09e"; +@fa-var-rss-square: "\f143"; +@fa-var-ruble-sign: "\f158"; +@fa-var-rupee-sign: "\f156"; +@fa-var-safari: "\f267"; +@fa-var-sass: "\f41e"; +@fa-var-save: "\f0c7"; +@fa-var-schlix: "\f3ea"; +@fa-var-scribd: "\f28a"; +@fa-var-search: "\f002"; +@fa-var-search-minus: "\f010"; +@fa-var-search-plus: "\f00e"; +@fa-var-searchengin: "\f3eb"; +@fa-var-seedling: "\f4d8"; +@fa-var-sellcast: "\f2da"; +@fa-var-sellsy: "\f213"; +@fa-var-server: "\f233"; +@fa-var-servicestack: "\f3ec"; +@fa-var-share: "\f064"; +@fa-var-share-alt: "\f1e0"; +@fa-var-share-alt-square: "\f1e1"; +@fa-var-share-square: "\f14d"; +@fa-var-shekel-sign: "\f20b"; +@fa-var-shield-alt: "\f3ed"; +@fa-var-ship: "\f21a"; +@fa-var-shipping-fast: "\f48b"; +@fa-var-shirtsinbulk: "\f214"; +@fa-var-shopping-bag: "\f290"; +@fa-var-shopping-basket: "\f291"; +@fa-var-shopping-cart: "\f07a"; +@fa-var-shower: "\f2cc"; +@fa-var-sign: "\f4d9"; +@fa-var-sign-in-alt: "\f2f6"; +@fa-var-sign-language: "\f2a7"; +@fa-var-sign-out-alt: "\f2f5"; +@fa-var-signal: "\f012"; +@fa-var-simplybuilt: "\f215"; +@fa-var-sistrix: "\f3ee"; +@fa-var-sitemap: "\f0e8"; +@fa-var-skyatlas: "\f216"; +@fa-var-skype: "\f17e"; +@fa-var-slack: "\f198"; +@fa-var-slack-hash: "\f3ef"; +@fa-var-sliders-h: "\f1de"; +@fa-var-slideshare: "\f1e7"; +@fa-var-smile: "\f118"; +@fa-var-smoking: "\f48d"; +@fa-var-snapchat: "\f2ab"; +@fa-var-snapchat-ghost: "\f2ac"; +@fa-var-snapchat-square: "\f2ad"; +@fa-var-snowflake: "\f2dc"; +@fa-var-sort: "\f0dc"; +@fa-var-sort-alpha-down: "\f15d"; +@fa-var-sort-alpha-up: "\f15e"; +@fa-var-sort-amount-down: "\f160"; +@fa-var-sort-amount-up: "\f161"; +@fa-var-sort-down: "\f0dd"; +@fa-var-sort-numeric-down: "\f162"; +@fa-var-sort-numeric-up: "\f163"; +@fa-var-sort-up: "\f0de"; +@fa-var-soundcloud: "\f1be"; +@fa-var-space-shuttle: "\f197"; +@fa-var-speakap: "\f3f3"; +@fa-var-spinner: "\f110"; +@fa-var-spotify: "\f1bc"; +@fa-var-square: "\f0c8"; +@fa-var-square-full: "\f45c"; +@fa-var-stack-exchange: "\f18d"; +@fa-var-stack-overflow: "\f16c"; +@fa-var-star: "\f005"; +@fa-var-star-half: "\f089"; +@fa-var-staylinked: "\f3f5"; +@fa-var-steam: "\f1b6"; +@fa-var-steam-square: "\f1b7"; +@fa-var-steam-symbol: "\f3f6"; +@fa-var-step-backward: "\f048"; +@fa-var-step-forward: "\f051"; +@fa-var-stethoscope: "\f0f1"; +@fa-var-sticker-mule: "\f3f7"; +@fa-var-sticky-note: "\f249"; +@fa-var-stop: "\f04d"; +@fa-var-stop-circle: "\f28d"; +@fa-var-stopwatch: "\f2f2"; +@fa-var-strava: "\f428"; +@fa-var-street-view: "\f21d"; +@fa-var-strikethrough: "\f0cc"; +@fa-var-stripe: "\f429"; +@fa-var-stripe-s: "\f42a"; +@fa-var-studiovinari: "\f3f8"; +@fa-var-stumbleupon: "\f1a4"; +@fa-var-stumbleupon-circle: "\f1a3"; +@fa-var-subscript: "\f12c"; +@fa-var-subway: "\f239"; +@fa-var-suitcase: "\f0f2"; +@fa-var-sun: "\f185"; +@fa-var-superpowers: "\f2dd"; +@fa-var-superscript: "\f12b"; +@fa-var-supple: "\f3f9"; +@fa-var-sync: "\f021"; +@fa-var-sync-alt: "\f2f1"; +@fa-var-syringe: "\f48e"; +@fa-var-table: "\f0ce"; +@fa-var-table-tennis: "\f45d"; +@fa-var-tablet: "\f10a"; +@fa-var-tablet-alt: "\f3fa"; +@fa-var-tablets: "\f490"; +@fa-var-tachometer-alt: "\f3fd"; +@fa-var-tag: "\f02b"; +@fa-var-tags: "\f02c"; +@fa-var-tape: "\f4db"; +@fa-var-tasks: "\f0ae"; +@fa-var-taxi: "\f1ba"; +@fa-var-telegram: "\f2c6"; +@fa-var-telegram-plane: "\f3fe"; +@fa-var-tencent-weibo: "\f1d5"; +@fa-var-terminal: "\f120"; +@fa-var-text-height: "\f034"; +@fa-var-text-width: "\f035"; +@fa-var-th: "\f00a"; +@fa-var-th-large: "\f009"; +@fa-var-th-list: "\f00b"; +@fa-var-themeisle: "\f2b2"; +@fa-var-thermometer: "\f491"; +@fa-var-thermometer-empty: "\f2cb"; +@fa-var-thermometer-full: "\f2c7"; +@fa-var-thermometer-half: "\f2c9"; +@fa-var-thermometer-quarter: "\f2ca"; +@fa-var-thermometer-three-quarters: "\f2c8"; +@fa-var-thumbs-down: "\f165"; +@fa-var-thumbs-up: "\f164"; +@fa-var-thumbtack: "\f08d"; +@fa-var-ticket-alt: "\f3ff"; +@fa-var-times: "\f00d"; +@fa-var-times-circle: "\f057"; +@fa-var-tint: "\f043"; +@fa-var-toggle-off: "\f204"; +@fa-var-toggle-on: "\f205"; +@fa-var-trademark: "\f25c"; +@fa-var-train: "\f238"; +@fa-var-transgender: "\f224"; +@fa-var-transgender-alt: "\f225"; +@fa-var-trash: "\f1f8"; +@fa-var-trash-alt: "\f2ed"; +@fa-var-tree: "\f1bb"; +@fa-var-trello: "\f181"; +@fa-var-tripadvisor: "\f262"; +@fa-var-trophy: "\f091"; +@fa-var-truck: "\f0d1"; +@fa-var-truck-loading: "\f4de"; +@fa-var-truck-moving: "\f4df"; +@fa-var-tty: "\f1e4"; +@fa-var-tumblr: "\f173"; +@fa-var-tumblr-square: "\f174"; +@fa-var-tv: "\f26c"; +@fa-var-twitch: "\f1e8"; +@fa-var-twitter: "\f099"; +@fa-var-twitter-square: "\f081"; +@fa-var-typo3: "\f42b"; +@fa-var-uber: "\f402"; +@fa-var-uikit: "\f403"; +@fa-var-umbrella: "\f0e9"; +@fa-var-underline: "\f0cd"; +@fa-var-undo: "\f0e2"; +@fa-var-undo-alt: "\f2ea"; +@fa-var-uniregistry: "\f404"; +@fa-var-universal-access: "\f29a"; +@fa-var-university: "\f19c"; +@fa-var-unlink: "\f127"; +@fa-var-unlock: "\f09c"; +@fa-var-unlock-alt: "\f13e"; +@fa-var-untappd: "\f405"; +@fa-var-upload: "\f093"; +@fa-var-usb: "\f287"; +@fa-var-user: "\f007"; +@fa-var-user-circle: "\f2bd"; +@fa-var-user-md: "\f0f0"; +@fa-var-user-plus: "\f234"; +@fa-var-user-secret: "\f21b"; +@fa-var-user-times: "\f235"; +@fa-var-users: "\f0c0"; +@fa-var-ussunnah: "\f407"; +@fa-var-utensil-spoon: "\f2e5"; +@fa-var-utensils: "\f2e7"; +@fa-var-vaadin: "\f408"; +@fa-var-venus: "\f221"; +@fa-var-venus-double: "\f226"; +@fa-var-venus-mars: "\f228"; +@fa-var-viacoin: "\f237"; +@fa-var-viadeo: "\f2a9"; +@fa-var-viadeo-square: "\f2aa"; +@fa-var-vial: "\f492"; +@fa-var-vials: "\f493"; +@fa-var-viber: "\f409"; +@fa-var-video: "\f03d"; +@fa-var-video-slash: "\f4e2"; +@fa-var-vimeo: "\f40a"; +@fa-var-vimeo-square: "\f194"; +@fa-var-vimeo-v: "\f27d"; +@fa-var-vine: "\f1ca"; +@fa-var-vk: "\f189"; +@fa-var-vnv: "\f40b"; +@fa-var-volleyball-ball: "\f45f"; +@fa-var-volume-down: "\f027"; +@fa-var-volume-off: "\f026"; +@fa-var-volume-up: "\f028"; +@fa-var-vuejs: "\f41f"; +@fa-var-warehouse: "\f494"; +@fa-var-weibo: "\f18a"; +@fa-var-weight: "\f496"; +@fa-var-weixin: "\f1d7"; +@fa-var-whatsapp: "\f232"; +@fa-var-whatsapp-square: "\f40c"; +@fa-var-wheelchair: "\f193"; +@fa-var-whmcs: "\f40d"; +@fa-var-wifi: "\f1eb"; +@fa-var-wikipedia-w: "\f266"; +@fa-var-window-close: "\f410"; +@fa-var-window-maximize: "\f2d0"; +@fa-var-window-minimize: "\f2d1"; +@fa-var-window-restore: "\f2d2"; +@fa-var-windows: "\f17a"; +@fa-var-wine-glass: "\f4e3"; +@fa-var-won-sign: "\f159"; +@fa-var-wordpress: "\f19a"; +@fa-var-wordpress-simple: "\f411"; +@fa-var-wpbeginner: "\f297"; +@fa-var-wpexplorer: "\f2de"; +@fa-var-wpforms: "\f298"; +@fa-var-wrench: "\f0ad"; +@fa-var-x-ray: "\f497"; +@fa-var-xbox: "\f412"; +@fa-var-xing: "\f168"; +@fa-var-xing-square: "\f169"; +@fa-var-y-combinator: "\f23b"; +@fa-var-yahoo: "\f19e"; +@fa-var-yandex: "\f413"; +@fa-var-yandex-international: "\f414"; +@fa-var-yelp: "\f1e9"; +@fa-var-yen-sign: "\f157"; +@fa-var-yoast: "\f2b1"; +@fa-var-youtube: "\f167"; +@fa-var-youtube-square: "\f431"; diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fa-brands.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fa-brands.less new file mode 100644 index 000000000000..f136d6290d7a --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fa-brands.less @@ -0,0 +1,21 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@import "_variables.less"; + +@font-face { + font-family: 'Font Awesome 5 Brands'; + font-style: normal; + font-weight: normal; + src: url('@{fa-font-path}/fa-brands-400.eot'); + src: url('@{fa-font-path}/fa-brands-400.eot?#iefix') format('embedded-opentype'), + url('@{fa-font-path}/fa-brands-400.woff2') format('woff2'), + url('@{fa-font-path}/fa-brands-400.woff') format('woff'), + url('@{fa-font-path}/fa-brands-400.ttf') format('truetype'), + url('@{fa-font-path}/fa-brands-400.svg#fontawesome') format('svg'); +} + +.fab { + font-family: 'Font Awesome 5 Brands'; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fa-regular.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fa-regular.less new file mode 100644 index 000000000000..04820bb5f9be --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fa-regular.less @@ -0,0 +1,22 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@import "_variables.less"; + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 400; + src: url('@{fa-font-path}/fa-regular-400.eot'); + src: url('@{fa-font-path}/fa-regular-400.eot?#iefix') format('embedded-opentype'), + url('@{fa-font-path}/fa-regular-400.woff2') format('woff2'), + url('@{fa-font-path}/fa-regular-400.woff') format('woff'), + url('@{fa-font-path}/fa-regular-400.ttf') format('truetype'), + url('@{fa-font-path}/fa-regular-400.svg#fontawesome') format('svg'); +} + +.far { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fa-solid.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fa-solid.less new file mode 100644 index 000000000000..2bcfb0d267dd --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fa-solid.less @@ -0,0 +1,23 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@import "_variables.less"; + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 900; + src: url('@{fa-font-path}/fa-solid-900.eot'); + src: url('@{fa-font-path}/fa-solid-900.eot?#iefix') format('embedded-opentype'), + url('@{fa-font-path}/fa-solid-900.woff2') format('woff2'), + url('@{fa-font-path}/fa-solid-900.woff') format('woff'), + url('@{fa-font-path}/fa-solid-900.ttf') format('truetype'), + url('@{fa-font-path}/fa-solid-900.svg#fontawesome') format('svg'); +} + +.fa, +.fas { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fontawesome.less b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fontawesome.less new file mode 100644 index 000000000000..fecdf7831cea --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/less/fontawesome.less @@ -0,0 +1,16 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@import "_variables.less"; +@import "_mixins.less"; +@import "_core.less"; +@import "_larger.less"; +@import "_fixed-width.less"; +@import "_list.less"; +@import "_bordered-pulled.less"; +@import "_animated.less"; +@import "_rotated-flipped.less"; +@import "_stacked.less"; +@import "_icons.less"; +@import "_screen-reader.less"; diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_animated.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_animated.scss new file mode 100644 index 000000000000..7c7c0e173c5b --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_animated.scss @@ -0,0 +1,20 @@ +// Animated Icons +// -------------------------- + +.#{$fa-css-prefix}-spin { + animation: fa-spin 2s infinite linear; +} + +.#{$fa-css-prefix}-pulse { + animation: fa-spin 1s infinite steps(8); +} + +@keyframes fa-spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_bordered-pulled.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_bordered-pulled.scss new file mode 100644 index 000000000000..c8c4274c4095 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_bordered-pulled.scss @@ -0,0 +1,20 @@ +// Bordered & Pulled +// ------------------------- + +.#{$fa-css-prefix}-border { + border: solid .08em $fa-border-color; + border-radius: .1em; + padding: .2em .25em .15em; +} + +.#{$fa-css-prefix}-pull-left { float: left; } +.#{$fa-css-prefix}-pull-right { float: right; } + +.#{$fa-css-prefix}, +.fas, +.far, +.fal, +.fab { + &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } + &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_core.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_core.scss new file mode 100644 index 000000000000..7fd37f855cf5 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_core.scss @@ -0,0 +1,16 @@ +// Base Class Definition +// ------------------------- + +.#{$fa-css-prefix}, +.fas, +.far, +.fal, +.fab { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_fixed-width.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_fixed-width.scss new file mode 100644 index 000000000000..5b33eb49aa9b --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_fixed-width.scss @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.#{$fa-css-prefix}-fw { + text-align: center; + width: (20em / 16); +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_icons.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_icons.scss new file mode 100644 index 000000000000..37f969c74f66 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_icons.scss @@ -0,0 +1,878 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ + +.#{$fa-css-prefix}-500px:before { content: fa-content($fa-var-500px); } +.#{$fa-css-prefix}-accessible-icon:before { content: fa-content($fa-var-accessible-icon); } +.#{$fa-css-prefix}-accusoft:before { content: fa-content($fa-var-accusoft); } +.#{$fa-css-prefix}-address-book:before { content: fa-content($fa-var-address-book); } +.#{$fa-css-prefix}-address-card:before { content: fa-content($fa-var-address-card); } +.#{$fa-css-prefix}-adjust:before { content: fa-content($fa-var-adjust); } +.#{$fa-css-prefix}-adn:before { content: fa-content($fa-var-adn); } +.#{$fa-css-prefix}-adversal:before { content: fa-content($fa-var-adversal); } +.#{$fa-css-prefix}-affiliatetheme:before { content: fa-content($fa-var-affiliatetheme); } +.#{$fa-css-prefix}-algolia:before { content: fa-content($fa-var-algolia); } +.#{$fa-css-prefix}-align-center:before { content: fa-content($fa-var-align-center); } +.#{$fa-css-prefix}-align-justify:before { content: fa-content($fa-var-align-justify); } +.#{$fa-css-prefix}-align-left:before { content: fa-content($fa-var-align-left); } +.#{$fa-css-prefix}-align-right:before { content: fa-content($fa-var-align-right); } +.#{$fa-css-prefix}-allergies:before { content: fa-content($fa-var-allergies); } +.#{$fa-css-prefix}-amazon:before { content: fa-content($fa-var-amazon); } +.#{$fa-css-prefix}-amazon-pay:before { content: fa-content($fa-var-amazon-pay); } +.#{$fa-css-prefix}-ambulance:before { content: fa-content($fa-var-ambulance); } +.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: fa-content($fa-var-american-sign-language-interpreting); } +.#{$fa-css-prefix}-amilia:before { content: fa-content($fa-var-amilia); } +.#{$fa-css-prefix}-anchor:before { content: fa-content($fa-var-anchor); } +.#{$fa-css-prefix}-android:before { content: fa-content($fa-var-android); } +.#{$fa-css-prefix}-angellist:before { content: fa-content($fa-var-angellist); } +.#{$fa-css-prefix}-angle-double-down:before { content: fa-content($fa-var-angle-double-down); } +.#{$fa-css-prefix}-angle-double-left:before { content: fa-content($fa-var-angle-double-left); } +.#{$fa-css-prefix}-angle-double-right:before { content: fa-content($fa-var-angle-double-right); } +.#{$fa-css-prefix}-angle-double-up:before { content: fa-content($fa-var-angle-double-up); } +.#{$fa-css-prefix}-angle-down:before { content: fa-content($fa-var-angle-down); } +.#{$fa-css-prefix}-angle-left:before { content: fa-content($fa-var-angle-left); } +.#{$fa-css-prefix}-angle-right:before { content: fa-content($fa-var-angle-right); } +.#{$fa-css-prefix}-angle-up:before { content: fa-content($fa-var-angle-up); } +.#{$fa-css-prefix}-angrycreative:before { content: fa-content($fa-var-angrycreative); } +.#{$fa-css-prefix}-angular:before { content: fa-content($fa-var-angular); } +.#{$fa-css-prefix}-app-store:before { content: fa-content($fa-var-app-store); } +.#{$fa-css-prefix}-app-store-ios:before { content: fa-content($fa-var-app-store-ios); } +.#{$fa-css-prefix}-apper:before { content: fa-content($fa-var-apper); } +.#{$fa-css-prefix}-apple:before { content: fa-content($fa-var-apple); } +.#{$fa-css-prefix}-apple-pay:before { content: fa-content($fa-var-apple-pay); } +.#{$fa-css-prefix}-archive:before { content: fa-content($fa-var-archive); } +.#{$fa-css-prefix}-arrow-alt-circle-down:before { content: fa-content($fa-var-arrow-alt-circle-down); } +.#{$fa-css-prefix}-arrow-alt-circle-left:before { content: fa-content($fa-var-arrow-alt-circle-left); } +.#{$fa-css-prefix}-arrow-alt-circle-right:before { content: fa-content($fa-var-arrow-alt-circle-right); } +.#{$fa-css-prefix}-arrow-alt-circle-up:before { content: fa-content($fa-var-arrow-alt-circle-up); } +.#{$fa-css-prefix}-arrow-circle-down:before { content: fa-content($fa-var-arrow-circle-down); } +.#{$fa-css-prefix}-arrow-circle-left:before { content: fa-content($fa-var-arrow-circle-left); } +.#{$fa-css-prefix}-arrow-circle-right:before { content: fa-content($fa-var-arrow-circle-right); } +.#{$fa-css-prefix}-arrow-circle-up:before { content: fa-content($fa-var-arrow-circle-up); } +.#{$fa-css-prefix}-arrow-down:before { content: fa-content($fa-var-arrow-down); } +.#{$fa-css-prefix}-arrow-left:before { content: fa-content($fa-var-arrow-left); } +.#{$fa-css-prefix}-arrow-right:before { content: fa-content($fa-var-arrow-right); } +.#{$fa-css-prefix}-arrow-up:before { content: fa-content($fa-var-arrow-up); } +.#{$fa-css-prefix}-arrows-alt:before { content: fa-content($fa-var-arrows-alt); } +.#{$fa-css-prefix}-arrows-alt-h:before { content: fa-content($fa-var-arrows-alt-h); } +.#{$fa-css-prefix}-arrows-alt-v:before { content: fa-content($fa-var-arrows-alt-v); } +.#{$fa-css-prefix}-assistive-listening-systems:before { content: fa-content($fa-var-assistive-listening-systems); } +.#{$fa-css-prefix}-asterisk:before { content: fa-content($fa-var-asterisk); } +.#{$fa-css-prefix}-asymmetrik:before { content: fa-content($fa-var-asymmetrik); } +.#{$fa-css-prefix}-at:before { content: fa-content($fa-var-at); } +.#{$fa-css-prefix}-audible:before { content: fa-content($fa-var-audible); } +.#{$fa-css-prefix}-audio-description:before { content: fa-content($fa-var-audio-description); } +.#{$fa-css-prefix}-autoprefixer:before { content: fa-content($fa-var-autoprefixer); } +.#{$fa-css-prefix}-avianex:before { content: fa-content($fa-var-avianex); } +.#{$fa-css-prefix}-aviato:before { content: fa-content($fa-var-aviato); } +.#{$fa-css-prefix}-aws:before { content: fa-content($fa-var-aws); } +.#{$fa-css-prefix}-backward:before { content: fa-content($fa-var-backward); } +.#{$fa-css-prefix}-balance-scale:before { content: fa-content($fa-var-balance-scale); } +.#{$fa-css-prefix}-ban:before { content: fa-content($fa-var-ban); } +.#{$fa-css-prefix}-band-aid:before { content: fa-content($fa-var-band-aid); } +.#{$fa-css-prefix}-bandcamp:before { content: fa-content($fa-var-bandcamp); } +.#{$fa-css-prefix}-barcode:before { content: fa-content($fa-var-barcode); } +.#{$fa-css-prefix}-bars:before { content: fa-content($fa-var-bars); } +.#{$fa-css-prefix}-baseball-ball:before { content: fa-content($fa-var-baseball-ball); } +.#{$fa-css-prefix}-basketball-ball:before { content: fa-content($fa-var-basketball-ball); } +.#{$fa-css-prefix}-bath:before { content: fa-content($fa-var-bath); } +.#{$fa-css-prefix}-battery-empty:before { content: fa-content($fa-var-battery-empty); } +.#{$fa-css-prefix}-battery-full:before { content: fa-content($fa-var-battery-full); } +.#{$fa-css-prefix}-battery-half:before { content: fa-content($fa-var-battery-half); } +.#{$fa-css-prefix}-battery-quarter:before { content: fa-content($fa-var-battery-quarter); } +.#{$fa-css-prefix}-battery-three-quarters:before { content: fa-content($fa-var-battery-three-quarters); } +.#{$fa-css-prefix}-bed:before { content: fa-content($fa-var-bed); } +.#{$fa-css-prefix}-beer:before { content: fa-content($fa-var-beer); } +.#{$fa-css-prefix}-behance:before { content: fa-content($fa-var-behance); } +.#{$fa-css-prefix}-behance-square:before { content: fa-content($fa-var-behance-square); } +.#{$fa-css-prefix}-bell:before { content: fa-content($fa-var-bell); } +.#{$fa-css-prefix}-bell-slash:before { content: fa-content($fa-var-bell-slash); } +.#{$fa-css-prefix}-bicycle:before { content: fa-content($fa-var-bicycle); } +.#{$fa-css-prefix}-bimobject:before { content: fa-content($fa-var-bimobject); } +.#{$fa-css-prefix}-binoculars:before { content: fa-content($fa-var-binoculars); } +.#{$fa-css-prefix}-birthday-cake:before { content: fa-content($fa-var-birthday-cake); } +.#{$fa-css-prefix}-bitbucket:before { content: fa-content($fa-var-bitbucket); } +.#{$fa-css-prefix}-bitcoin:before { content: fa-content($fa-var-bitcoin); } +.#{$fa-css-prefix}-bity:before { content: fa-content($fa-var-bity); } +.#{$fa-css-prefix}-black-tie:before { content: fa-content($fa-var-black-tie); } +.#{$fa-css-prefix}-blackberry:before { content: fa-content($fa-var-blackberry); } +.#{$fa-css-prefix}-blind:before { content: fa-content($fa-var-blind); } +.#{$fa-css-prefix}-blogger:before { content: fa-content($fa-var-blogger); } +.#{$fa-css-prefix}-blogger-b:before { content: fa-content($fa-var-blogger-b); } +.#{$fa-css-prefix}-bluetooth:before { content: fa-content($fa-var-bluetooth); } +.#{$fa-css-prefix}-bluetooth-b:before { content: fa-content($fa-var-bluetooth-b); } +.#{$fa-css-prefix}-bold:before { content: fa-content($fa-var-bold); } +.#{$fa-css-prefix}-bolt:before { content: fa-content($fa-var-bolt); } +.#{$fa-css-prefix}-bomb:before { content: fa-content($fa-var-bomb); } +.#{$fa-css-prefix}-book:before { content: fa-content($fa-var-book); } +.#{$fa-css-prefix}-bookmark:before { content: fa-content($fa-var-bookmark); } +.#{$fa-css-prefix}-bowling-ball:before { content: fa-content($fa-var-bowling-ball); } +.#{$fa-css-prefix}-box:before { content: fa-content($fa-var-box); } +.#{$fa-css-prefix}-box-open:before { content: fa-content($fa-var-box-open); } +.#{$fa-css-prefix}-boxes:before { content: fa-content($fa-var-boxes); } +.#{$fa-css-prefix}-braille:before { content: fa-content($fa-var-braille); } +.#{$fa-css-prefix}-briefcase:before { content: fa-content($fa-var-briefcase); } +.#{$fa-css-prefix}-briefcase-medical:before { content: fa-content($fa-var-briefcase-medical); } +.#{$fa-css-prefix}-btc:before { content: fa-content($fa-var-btc); } +.#{$fa-css-prefix}-bug:before { content: fa-content($fa-var-bug); } +.#{$fa-css-prefix}-building:before { content: fa-content($fa-var-building); } +.#{$fa-css-prefix}-bullhorn:before { content: fa-content($fa-var-bullhorn); } +.#{$fa-css-prefix}-bullseye:before { content: fa-content($fa-var-bullseye); } +.#{$fa-css-prefix}-burn:before { content: fa-content($fa-var-burn); } +.#{$fa-css-prefix}-buromobelexperte:before { content: fa-content($fa-var-buromobelexperte); } +.#{$fa-css-prefix}-bus:before { content: fa-content($fa-var-bus); } +.#{$fa-css-prefix}-buysellads:before { content: fa-content($fa-var-buysellads); } +.#{$fa-css-prefix}-calculator:before { content: fa-content($fa-var-calculator); } +.#{$fa-css-prefix}-calendar:before { content: fa-content($fa-var-calendar); } +.#{$fa-css-prefix}-calendar-alt:before { content: fa-content($fa-var-calendar-alt); } +.#{$fa-css-prefix}-calendar-check:before { content: fa-content($fa-var-calendar-check); } +.#{$fa-css-prefix}-calendar-minus:before { content: fa-content($fa-var-calendar-minus); } +.#{$fa-css-prefix}-calendar-plus:before { content: fa-content($fa-var-calendar-plus); } +.#{$fa-css-prefix}-calendar-times:before { content: fa-content($fa-var-calendar-times); } +.#{$fa-css-prefix}-camera:before { content: fa-content($fa-var-camera); } +.#{$fa-css-prefix}-camera-retro:before { content: fa-content($fa-var-camera-retro); } +.#{$fa-css-prefix}-capsules:before { content: fa-content($fa-var-capsules); } +.#{$fa-css-prefix}-car:before { content: fa-content($fa-var-car); } +.#{$fa-css-prefix}-caret-down:before { content: fa-content($fa-var-caret-down); } +.#{$fa-css-prefix}-caret-left:before { content: fa-content($fa-var-caret-left); } +.#{$fa-css-prefix}-caret-right:before { content: fa-content($fa-var-caret-right); } +.#{$fa-css-prefix}-caret-square-down:before { content: fa-content($fa-var-caret-square-down); } +.#{$fa-css-prefix}-caret-square-left:before { content: fa-content($fa-var-caret-square-left); } +.#{$fa-css-prefix}-caret-square-right:before { content: fa-content($fa-var-caret-square-right); } +.#{$fa-css-prefix}-caret-square-up:before { content: fa-content($fa-var-caret-square-up); } +.#{$fa-css-prefix}-caret-up:before { content: fa-content($fa-var-caret-up); } +.#{$fa-css-prefix}-cart-arrow-down:before { content: fa-content($fa-var-cart-arrow-down); } +.#{$fa-css-prefix}-cart-plus:before { content: fa-content($fa-var-cart-plus); } +.#{$fa-css-prefix}-cc-amazon-pay:before { content: fa-content($fa-var-cc-amazon-pay); } +.#{$fa-css-prefix}-cc-amex:before { content: fa-content($fa-var-cc-amex); } +.#{$fa-css-prefix}-cc-apple-pay:before { content: fa-content($fa-var-cc-apple-pay); } +.#{$fa-css-prefix}-cc-diners-club:before { content: fa-content($fa-var-cc-diners-club); } +.#{$fa-css-prefix}-cc-discover:before { content: fa-content($fa-var-cc-discover); } +.#{$fa-css-prefix}-cc-jcb:before { content: fa-content($fa-var-cc-jcb); } +.#{$fa-css-prefix}-cc-mastercard:before { content: fa-content($fa-var-cc-mastercard); } +.#{$fa-css-prefix}-cc-paypal:before { content: fa-content($fa-var-cc-paypal); } +.#{$fa-css-prefix}-cc-stripe:before { content: fa-content($fa-var-cc-stripe); } +.#{$fa-css-prefix}-cc-visa:before { content: fa-content($fa-var-cc-visa); } +.#{$fa-css-prefix}-centercode:before { content: fa-content($fa-var-centercode); } +.#{$fa-css-prefix}-certificate:before { content: fa-content($fa-var-certificate); } +.#{$fa-css-prefix}-chart-area:before { content: fa-content($fa-var-chart-area); } +.#{$fa-css-prefix}-chart-bar:before { content: fa-content($fa-var-chart-bar); } +.#{$fa-css-prefix}-chart-line:before { content: fa-content($fa-var-chart-line); } +.#{$fa-css-prefix}-chart-pie:before { content: fa-content($fa-var-chart-pie); } +.#{$fa-css-prefix}-check:before { content: fa-content($fa-var-check); } +.#{$fa-css-prefix}-check-circle:before { content: fa-content($fa-var-check-circle); } +.#{$fa-css-prefix}-check-square:before { content: fa-content($fa-var-check-square); } +.#{$fa-css-prefix}-chess:before { content: fa-content($fa-var-chess); } +.#{$fa-css-prefix}-chess-bishop:before { content: fa-content($fa-var-chess-bishop); } +.#{$fa-css-prefix}-chess-board:before { content: fa-content($fa-var-chess-board); } +.#{$fa-css-prefix}-chess-king:before { content: fa-content($fa-var-chess-king); } +.#{$fa-css-prefix}-chess-knight:before { content: fa-content($fa-var-chess-knight); } +.#{$fa-css-prefix}-chess-pawn:before { content: fa-content($fa-var-chess-pawn); } +.#{$fa-css-prefix}-chess-queen:before { content: fa-content($fa-var-chess-queen); } +.#{$fa-css-prefix}-chess-rook:before { content: fa-content($fa-var-chess-rook); } +.#{$fa-css-prefix}-chevron-circle-down:before { content: fa-content($fa-var-chevron-circle-down); } +.#{$fa-css-prefix}-chevron-circle-left:before { content: fa-content($fa-var-chevron-circle-left); } +.#{$fa-css-prefix}-chevron-circle-right:before { content: fa-content($fa-var-chevron-circle-right); } +.#{$fa-css-prefix}-chevron-circle-up:before { content: fa-content($fa-var-chevron-circle-up); } +.#{$fa-css-prefix}-chevron-down:before { content: fa-content($fa-var-chevron-down); } +.#{$fa-css-prefix}-chevron-left:before { content: fa-content($fa-var-chevron-left); } +.#{$fa-css-prefix}-chevron-right:before { content: fa-content($fa-var-chevron-right); } +.#{$fa-css-prefix}-chevron-up:before { content: fa-content($fa-var-chevron-up); } +.#{$fa-css-prefix}-child:before { content: fa-content($fa-var-child); } +.#{$fa-css-prefix}-chrome:before { content: fa-content($fa-var-chrome); } +.#{$fa-css-prefix}-circle:before { content: fa-content($fa-var-circle); } +.#{$fa-css-prefix}-circle-notch:before { content: fa-content($fa-var-circle-notch); } +.#{$fa-css-prefix}-clipboard:before { content: fa-content($fa-var-clipboard); } +.#{$fa-css-prefix}-clipboard-check:before { content: fa-content($fa-var-clipboard-check); } +.#{$fa-css-prefix}-clipboard-list:before { content: fa-content($fa-var-clipboard-list); } +.#{$fa-css-prefix}-clock:before { content: fa-content($fa-var-clock); } +.#{$fa-css-prefix}-clone:before { content: fa-content($fa-var-clone); } +.#{$fa-css-prefix}-closed-captioning:before { content: fa-content($fa-var-closed-captioning); } +.#{$fa-css-prefix}-cloud:before { content: fa-content($fa-var-cloud); } +.#{$fa-css-prefix}-cloud-download-alt:before { content: fa-content($fa-var-cloud-download-alt); } +.#{$fa-css-prefix}-cloud-upload-alt:before { content: fa-content($fa-var-cloud-upload-alt); } +.#{$fa-css-prefix}-cloudscale:before { content: fa-content($fa-var-cloudscale); } +.#{$fa-css-prefix}-cloudsmith:before { content: fa-content($fa-var-cloudsmith); } +.#{$fa-css-prefix}-cloudversify:before { content: fa-content($fa-var-cloudversify); } +.#{$fa-css-prefix}-code:before { content: fa-content($fa-var-code); } +.#{$fa-css-prefix}-code-branch:before { content: fa-content($fa-var-code-branch); } +.#{$fa-css-prefix}-codepen:before { content: fa-content($fa-var-codepen); } +.#{$fa-css-prefix}-codiepie:before { content: fa-content($fa-var-codiepie); } +.#{$fa-css-prefix}-coffee:before { content: fa-content($fa-var-coffee); } +.#{$fa-css-prefix}-cog:before { content: fa-content($fa-var-cog); } +.#{$fa-css-prefix}-cogs:before { content: fa-content($fa-var-cogs); } +.#{$fa-css-prefix}-columns:before { content: fa-content($fa-var-columns); } +.#{$fa-css-prefix}-comment:before { content: fa-content($fa-var-comment); } +.#{$fa-css-prefix}-comment-alt:before { content: fa-content($fa-var-comment-alt); } +.#{$fa-css-prefix}-comment-dots:before { content: fa-content($fa-var-comment-dots); } +.#{$fa-css-prefix}-comment-slash:before { content: fa-content($fa-var-comment-slash); } +.#{$fa-css-prefix}-comments:before { content: fa-content($fa-var-comments); } +.#{$fa-css-prefix}-compass:before { content: fa-content($fa-var-compass); } +.#{$fa-css-prefix}-compress:before { content: fa-content($fa-var-compress); } +.#{$fa-css-prefix}-connectdevelop:before { content: fa-content($fa-var-connectdevelop); } +.#{$fa-css-prefix}-contao:before { content: fa-content($fa-var-contao); } +.#{$fa-css-prefix}-copy:before { content: fa-content($fa-var-copy); } +.#{$fa-css-prefix}-copyright:before { content: fa-content($fa-var-copyright); } +.#{$fa-css-prefix}-couch:before { content: fa-content($fa-var-couch); } +.#{$fa-css-prefix}-cpanel:before { content: fa-content($fa-var-cpanel); } +.#{$fa-css-prefix}-creative-commons:before { content: fa-content($fa-var-creative-commons); } +.#{$fa-css-prefix}-credit-card:before { content: fa-content($fa-var-credit-card); } +.#{$fa-css-prefix}-crop:before { content: fa-content($fa-var-crop); } +.#{$fa-css-prefix}-crosshairs:before { content: fa-content($fa-var-crosshairs); } +.#{$fa-css-prefix}-css3:before { content: fa-content($fa-var-css3); } +.#{$fa-css-prefix}-css3-alt:before { content: fa-content($fa-var-css3-alt); } +.#{$fa-css-prefix}-cube:before { content: fa-content($fa-var-cube); } +.#{$fa-css-prefix}-cubes:before { content: fa-content($fa-var-cubes); } +.#{$fa-css-prefix}-cut:before { content: fa-content($fa-var-cut); } +.#{$fa-css-prefix}-cuttlefish:before { content: fa-content($fa-var-cuttlefish); } +.#{$fa-css-prefix}-d-and-d:before { content: fa-content($fa-var-d-and-d); } +.#{$fa-css-prefix}-dashcube:before { content: fa-content($fa-var-dashcube); } +.#{$fa-css-prefix}-database:before { content: fa-content($fa-var-database); } +.#{$fa-css-prefix}-deaf:before { content: fa-content($fa-var-deaf); } +.#{$fa-css-prefix}-delicious:before { content: fa-content($fa-var-delicious); } +.#{$fa-css-prefix}-deploydog:before { content: fa-content($fa-var-deploydog); } +.#{$fa-css-prefix}-deskpro:before { content: fa-content($fa-var-deskpro); } +.#{$fa-css-prefix}-desktop:before { content: fa-content($fa-var-desktop); } +.#{$fa-css-prefix}-deviantart:before { content: fa-content($fa-var-deviantart); } +.#{$fa-css-prefix}-diagnoses:before { content: fa-content($fa-var-diagnoses); } +.#{$fa-css-prefix}-digg:before { content: fa-content($fa-var-digg); } +.#{$fa-css-prefix}-digital-ocean:before { content: fa-content($fa-var-digital-ocean); } +.#{$fa-css-prefix}-discord:before { content: fa-content($fa-var-discord); } +.#{$fa-css-prefix}-discourse:before { content: fa-content($fa-var-discourse); } +.#{$fa-css-prefix}-dna:before { content: fa-content($fa-var-dna); } +.#{$fa-css-prefix}-dochub:before { content: fa-content($fa-var-dochub); } +.#{$fa-css-prefix}-docker:before { content: fa-content($fa-var-docker); } +.#{$fa-css-prefix}-dollar-sign:before { content: fa-content($fa-var-dollar-sign); } +.#{$fa-css-prefix}-dolly:before { content: fa-content($fa-var-dolly); } +.#{$fa-css-prefix}-dolly-flatbed:before { content: fa-content($fa-var-dolly-flatbed); } +.#{$fa-css-prefix}-donate:before { content: fa-content($fa-var-donate); } +.#{$fa-css-prefix}-dot-circle:before { content: fa-content($fa-var-dot-circle); } +.#{$fa-css-prefix}-dove:before { content: fa-content($fa-var-dove); } +.#{$fa-css-prefix}-download:before { content: fa-content($fa-var-download); } +.#{$fa-css-prefix}-draft2digital:before { content: fa-content($fa-var-draft2digital); } +.#{$fa-css-prefix}-dribbble:before { content: fa-content($fa-var-dribbble); } +.#{$fa-css-prefix}-dribbble-square:before { content: fa-content($fa-var-dribbble-square); } +.#{$fa-css-prefix}-dropbox:before { content: fa-content($fa-var-dropbox); } +.#{$fa-css-prefix}-drupal:before { content: fa-content($fa-var-drupal); } +.#{$fa-css-prefix}-dyalog:before { content: fa-content($fa-var-dyalog); } +.#{$fa-css-prefix}-earlybirds:before { content: fa-content($fa-var-earlybirds); } +.#{$fa-css-prefix}-edge:before { content: fa-content($fa-var-edge); } +.#{$fa-css-prefix}-edit:before { content: fa-content($fa-var-edit); } +.#{$fa-css-prefix}-eject:before { content: fa-content($fa-var-eject); } +.#{$fa-css-prefix}-elementor:before { content: fa-content($fa-var-elementor); } +.#{$fa-css-prefix}-ellipsis-h:before { content: fa-content($fa-var-ellipsis-h); } +.#{$fa-css-prefix}-ellipsis-v:before { content: fa-content($fa-var-ellipsis-v); } +.#{$fa-css-prefix}-ember:before { content: fa-content($fa-var-ember); } +.#{$fa-css-prefix}-empire:before { content: fa-content($fa-var-empire); } +.#{$fa-css-prefix}-envelope:before { content: fa-content($fa-var-envelope); } +.#{$fa-css-prefix}-envelope-open:before { content: fa-content($fa-var-envelope-open); } +.#{$fa-css-prefix}-envelope-square:before { content: fa-content($fa-var-envelope-square); } +.#{$fa-css-prefix}-envira:before { content: fa-content($fa-var-envira); } +.#{$fa-css-prefix}-eraser:before { content: fa-content($fa-var-eraser); } +.#{$fa-css-prefix}-erlang:before { content: fa-content($fa-var-erlang); } +.#{$fa-css-prefix}-ethereum:before { content: fa-content($fa-var-ethereum); } +.#{$fa-css-prefix}-etsy:before { content: fa-content($fa-var-etsy); } +.#{$fa-css-prefix}-euro-sign:before { content: fa-content($fa-var-euro-sign); } +.#{$fa-css-prefix}-exchange-alt:before { content: fa-content($fa-var-exchange-alt); } +.#{$fa-css-prefix}-exclamation:before { content: fa-content($fa-var-exclamation); } +.#{$fa-css-prefix}-exclamation-circle:before { content: fa-content($fa-var-exclamation-circle); } +.#{$fa-css-prefix}-exclamation-triangle:before { content: fa-content($fa-var-exclamation-triangle); } +.#{$fa-css-prefix}-expand:before { content: fa-content($fa-var-expand); } +.#{$fa-css-prefix}-expand-arrows-alt:before { content: fa-content($fa-var-expand-arrows-alt); } +.#{$fa-css-prefix}-expeditedssl:before { content: fa-content($fa-var-expeditedssl); } +.#{$fa-css-prefix}-external-link-alt:before { content: fa-content($fa-var-external-link-alt); } +.#{$fa-css-prefix}-external-link-square-alt:before { content: fa-content($fa-var-external-link-square-alt); } +.#{$fa-css-prefix}-eye:before { content: fa-content($fa-var-eye); } +.#{$fa-css-prefix}-eye-dropper:before { content: fa-content($fa-var-eye-dropper); } +.#{$fa-css-prefix}-eye-slash:before { content: fa-content($fa-var-eye-slash); } +.#{$fa-css-prefix}-facebook:before { content: fa-content($fa-var-facebook); } +.#{$fa-css-prefix}-facebook-f:before { content: fa-content($fa-var-facebook-f); } +.#{$fa-css-prefix}-facebook-messenger:before { content: fa-content($fa-var-facebook-messenger); } +.#{$fa-css-prefix}-facebook-square:before { content: fa-content($fa-var-facebook-square); } +.#{$fa-css-prefix}-fast-backward:before { content: fa-content($fa-var-fast-backward); } +.#{$fa-css-prefix}-fast-forward:before { content: fa-content($fa-var-fast-forward); } +.#{$fa-css-prefix}-fax:before { content: fa-content($fa-var-fax); } +.#{$fa-css-prefix}-female:before { content: fa-content($fa-var-female); } +.#{$fa-css-prefix}-fighter-jet:before { content: fa-content($fa-var-fighter-jet); } +.#{$fa-css-prefix}-file:before { content: fa-content($fa-var-file); } +.#{$fa-css-prefix}-file-alt:before { content: fa-content($fa-var-file-alt); } +.#{$fa-css-prefix}-file-archive:before { content: fa-content($fa-var-file-archive); } +.#{$fa-css-prefix}-file-audio:before { content: fa-content($fa-var-file-audio); } +.#{$fa-css-prefix}-file-code:before { content: fa-content($fa-var-file-code); } +.#{$fa-css-prefix}-file-excel:before { content: fa-content($fa-var-file-excel); } +.#{$fa-css-prefix}-file-image:before { content: fa-content($fa-var-file-image); } +.#{$fa-css-prefix}-file-medical:before { content: fa-content($fa-var-file-medical); } +.#{$fa-css-prefix}-file-medical-alt:before { content: fa-content($fa-var-file-medical-alt); } +.#{$fa-css-prefix}-file-pdf:before { content: fa-content($fa-var-file-pdf); } +.#{$fa-css-prefix}-file-powerpoint:before { content: fa-content($fa-var-file-powerpoint); } +.#{$fa-css-prefix}-file-video:before { content: fa-content($fa-var-file-video); } +.#{$fa-css-prefix}-file-word:before { content: fa-content($fa-var-file-word); } +.#{$fa-css-prefix}-film:before { content: fa-content($fa-var-film); } +.#{$fa-css-prefix}-filter:before { content: fa-content($fa-var-filter); } +.#{$fa-css-prefix}-fire:before { content: fa-content($fa-var-fire); } +.#{$fa-css-prefix}-fire-extinguisher:before { content: fa-content($fa-var-fire-extinguisher); } +.#{$fa-css-prefix}-firefox:before { content: fa-content($fa-var-firefox); } +.#{$fa-css-prefix}-first-aid:before { content: fa-content($fa-var-first-aid); } +.#{$fa-css-prefix}-first-order:before { content: fa-content($fa-var-first-order); } +.#{$fa-css-prefix}-firstdraft:before { content: fa-content($fa-var-firstdraft); } +.#{$fa-css-prefix}-flag:before { content: fa-content($fa-var-flag); } +.#{$fa-css-prefix}-flag-checkered:before { content: fa-content($fa-var-flag-checkered); } +.#{$fa-css-prefix}-flask:before { content: fa-content($fa-var-flask); } +.#{$fa-css-prefix}-flickr:before { content: fa-content($fa-var-flickr); } +.#{$fa-css-prefix}-flipboard:before { content: fa-content($fa-var-flipboard); } +.#{$fa-css-prefix}-fly:before { content: fa-content($fa-var-fly); } +.#{$fa-css-prefix}-folder:before { content: fa-content($fa-var-folder); } +.#{$fa-css-prefix}-folder-open:before { content: fa-content($fa-var-folder-open); } +.#{$fa-css-prefix}-font:before { content: fa-content($fa-var-font); } +.#{$fa-css-prefix}-font-awesome:before { content: fa-content($fa-var-font-awesome); } +.#{$fa-css-prefix}-font-awesome-alt:before { content: fa-content($fa-var-font-awesome-alt); } +.#{$fa-css-prefix}-font-awesome-flag:before { content: fa-content($fa-var-font-awesome-flag); } +.#{$fa-css-prefix}-fonticons:before { content: fa-content($fa-var-fonticons); } +.#{$fa-css-prefix}-fonticons-fi:before { content: fa-content($fa-var-fonticons-fi); } +.#{$fa-css-prefix}-football-ball:before { content: fa-content($fa-var-football-ball); } +.#{$fa-css-prefix}-fort-awesome:before { content: fa-content($fa-var-fort-awesome); } +.#{$fa-css-prefix}-fort-awesome-alt:before { content: fa-content($fa-var-fort-awesome-alt); } +.#{$fa-css-prefix}-forumbee:before { content: fa-content($fa-var-forumbee); } +.#{$fa-css-prefix}-forward:before { content: fa-content($fa-var-forward); } +.#{$fa-css-prefix}-foursquare:before { content: fa-content($fa-var-foursquare); } +.#{$fa-css-prefix}-free-code-camp:before { content: fa-content($fa-var-free-code-camp); } +.#{$fa-css-prefix}-freebsd:before { content: fa-content($fa-var-freebsd); } +.#{$fa-css-prefix}-frown:before { content: fa-content($fa-var-frown); } +.#{$fa-css-prefix}-futbol:before { content: fa-content($fa-var-futbol); } +.#{$fa-css-prefix}-gamepad:before { content: fa-content($fa-var-gamepad); } +.#{$fa-css-prefix}-gavel:before { content: fa-content($fa-var-gavel); } +.#{$fa-css-prefix}-gem:before { content: fa-content($fa-var-gem); } +.#{$fa-css-prefix}-genderless:before { content: fa-content($fa-var-genderless); } +.#{$fa-css-prefix}-get-pocket:before { content: fa-content($fa-var-get-pocket); } +.#{$fa-css-prefix}-gg:before { content: fa-content($fa-var-gg); } +.#{$fa-css-prefix}-gg-circle:before { content: fa-content($fa-var-gg-circle); } +.#{$fa-css-prefix}-gift:before { content: fa-content($fa-var-gift); } +.#{$fa-css-prefix}-git:before { content: fa-content($fa-var-git); } +.#{$fa-css-prefix}-git-square:before { content: fa-content($fa-var-git-square); } +.#{$fa-css-prefix}-github:before { content: fa-content($fa-var-github); } +.#{$fa-css-prefix}-github-alt:before { content: fa-content($fa-var-github-alt); } +.#{$fa-css-prefix}-github-square:before { content: fa-content($fa-var-github-square); } +.#{$fa-css-prefix}-gitkraken:before { content: fa-content($fa-var-gitkraken); } +.#{$fa-css-prefix}-gitlab:before { content: fa-content($fa-var-gitlab); } +.#{$fa-css-prefix}-gitter:before { content: fa-content($fa-var-gitter); } +.#{$fa-css-prefix}-glass-martini:before { content: fa-content($fa-var-glass-martini); } +.#{$fa-css-prefix}-glide:before { content: fa-content($fa-var-glide); } +.#{$fa-css-prefix}-glide-g:before { content: fa-content($fa-var-glide-g); } +.#{$fa-css-prefix}-globe:before { content: fa-content($fa-var-globe); } +.#{$fa-css-prefix}-gofore:before { content: fa-content($fa-var-gofore); } +.#{$fa-css-prefix}-golf-ball:before { content: fa-content($fa-var-golf-ball); } +.#{$fa-css-prefix}-goodreads:before { content: fa-content($fa-var-goodreads); } +.#{$fa-css-prefix}-goodreads-g:before { content: fa-content($fa-var-goodreads-g); } +.#{$fa-css-prefix}-google:before { content: fa-content($fa-var-google); } +.#{$fa-css-prefix}-google-drive:before { content: fa-content($fa-var-google-drive); } +.#{$fa-css-prefix}-google-play:before { content: fa-content($fa-var-google-play); } +.#{$fa-css-prefix}-google-plus:before { content: fa-content($fa-var-google-plus); } +.#{$fa-css-prefix}-google-plus-g:before { content: fa-content($fa-var-google-plus-g); } +.#{$fa-css-prefix}-google-plus-square:before { content: fa-content($fa-var-google-plus-square); } +.#{$fa-css-prefix}-google-wallet:before { content: fa-content($fa-var-google-wallet); } +.#{$fa-css-prefix}-graduation-cap:before { content: fa-content($fa-var-graduation-cap); } +.#{$fa-css-prefix}-gratipay:before { content: fa-content($fa-var-gratipay); } +.#{$fa-css-prefix}-grav:before { content: fa-content($fa-var-grav); } +.#{$fa-css-prefix}-gripfire:before { content: fa-content($fa-var-gripfire); } +.#{$fa-css-prefix}-grunt:before { content: fa-content($fa-var-grunt); } +.#{$fa-css-prefix}-gulp:before { content: fa-content($fa-var-gulp); } +.#{$fa-css-prefix}-h-square:before { content: fa-content($fa-var-h-square); } +.#{$fa-css-prefix}-hacker-news:before { content: fa-content($fa-var-hacker-news); } +.#{$fa-css-prefix}-hacker-news-square:before { content: fa-content($fa-var-hacker-news-square); } +.#{$fa-css-prefix}-hand-holding:before { content: fa-content($fa-var-hand-holding); } +.#{$fa-css-prefix}-hand-holding-heart:before { content: fa-content($fa-var-hand-holding-heart); } +.#{$fa-css-prefix}-hand-holding-usd:before { content: fa-content($fa-var-hand-holding-usd); } +.#{$fa-css-prefix}-hand-lizard:before { content: fa-content($fa-var-hand-lizard); } +.#{$fa-css-prefix}-hand-paper:before { content: fa-content($fa-var-hand-paper); } +.#{$fa-css-prefix}-hand-peace:before { content: fa-content($fa-var-hand-peace); } +.#{$fa-css-prefix}-hand-point-down:before { content: fa-content($fa-var-hand-point-down); } +.#{$fa-css-prefix}-hand-point-left:before { content: fa-content($fa-var-hand-point-left); } +.#{$fa-css-prefix}-hand-point-right:before { content: fa-content($fa-var-hand-point-right); } +.#{$fa-css-prefix}-hand-point-up:before { content: fa-content($fa-var-hand-point-up); } +.#{$fa-css-prefix}-hand-pointer:before { content: fa-content($fa-var-hand-pointer); } +.#{$fa-css-prefix}-hand-rock:before { content: fa-content($fa-var-hand-rock); } +.#{$fa-css-prefix}-hand-scissors:before { content: fa-content($fa-var-hand-scissors); } +.#{$fa-css-prefix}-hand-spock:before { content: fa-content($fa-var-hand-spock); } +.#{$fa-css-prefix}-hands:before { content: fa-content($fa-var-hands); } +.#{$fa-css-prefix}-hands-helping:before { content: fa-content($fa-var-hands-helping); } +.#{$fa-css-prefix}-handshake:before { content: fa-content($fa-var-handshake); } +.#{$fa-css-prefix}-hashtag:before { content: fa-content($fa-var-hashtag); } +.#{$fa-css-prefix}-hdd:before { content: fa-content($fa-var-hdd); } +.#{$fa-css-prefix}-heading:before { content: fa-content($fa-var-heading); } +.#{$fa-css-prefix}-headphones:before { content: fa-content($fa-var-headphones); } +.#{$fa-css-prefix}-heart:before { content: fa-content($fa-var-heart); } +.#{$fa-css-prefix}-heartbeat:before { content: fa-content($fa-var-heartbeat); } +.#{$fa-css-prefix}-hips:before { content: fa-content($fa-var-hips); } +.#{$fa-css-prefix}-hire-a-helper:before { content: fa-content($fa-var-hire-a-helper); } +.#{$fa-css-prefix}-history:before { content: fa-content($fa-var-history); } +.#{$fa-css-prefix}-hockey-puck:before { content: fa-content($fa-var-hockey-puck); } +.#{$fa-css-prefix}-home:before { content: fa-content($fa-var-home); } +.#{$fa-css-prefix}-hooli:before { content: fa-content($fa-var-hooli); } +.#{$fa-css-prefix}-hospital:before { content: fa-content($fa-var-hospital); } +.#{$fa-css-prefix}-hospital-alt:before { content: fa-content($fa-var-hospital-alt); } +.#{$fa-css-prefix}-hospital-symbol:before { content: fa-content($fa-var-hospital-symbol); } +.#{$fa-css-prefix}-hotjar:before { content: fa-content($fa-var-hotjar); } +.#{$fa-css-prefix}-hourglass:before { content: fa-content($fa-var-hourglass); } +.#{$fa-css-prefix}-hourglass-end:before { content: fa-content($fa-var-hourglass-end); } +.#{$fa-css-prefix}-hourglass-half:before { content: fa-content($fa-var-hourglass-half); } +.#{$fa-css-prefix}-hourglass-start:before { content: fa-content($fa-var-hourglass-start); } +.#{$fa-css-prefix}-houzz:before { content: fa-content($fa-var-houzz); } +.#{$fa-css-prefix}-html5:before { content: fa-content($fa-var-html5); } +.#{$fa-css-prefix}-hubspot:before { content: fa-content($fa-var-hubspot); } +.#{$fa-css-prefix}-i-cursor:before { content: fa-content($fa-var-i-cursor); } +.#{$fa-css-prefix}-id-badge:before { content: fa-content($fa-var-id-badge); } +.#{$fa-css-prefix}-id-card:before { content: fa-content($fa-var-id-card); } +.#{$fa-css-prefix}-id-card-alt:before { content: fa-content($fa-var-id-card-alt); } +.#{$fa-css-prefix}-image:before { content: fa-content($fa-var-image); } +.#{$fa-css-prefix}-images:before { content: fa-content($fa-var-images); } +.#{$fa-css-prefix}-imdb:before { content: fa-content($fa-var-imdb); } +.#{$fa-css-prefix}-inbox:before { content: fa-content($fa-var-inbox); } +.#{$fa-css-prefix}-indent:before { content: fa-content($fa-var-indent); } +.#{$fa-css-prefix}-industry:before { content: fa-content($fa-var-industry); } +.#{$fa-css-prefix}-info:before { content: fa-content($fa-var-info); } +.#{$fa-css-prefix}-info-circle:before { content: fa-content($fa-var-info-circle); } +.#{$fa-css-prefix}-instagram:before { content: fa-content($fa-var-instagram); } +.#{$fa-css-prefix}-internet-explorer:before { content: fa-content($fa-var-internet-explorer); } +.#{$fa-css-prefix}-ioxhost:before { content: fa-content($fa-var-ioxhost); } +.#{$fa-css-prefix}-italic:before { content: fa-content($fa-var-italic); } +.#{$fa-css-prefix}-itunes:before { content: fa-content($fa-var-itunes); } +.#{$fa-css-prefix}-itunes-note:before { content: fa-content($fa-var-itunes-note); } +.#{$fa-css-prefix}-java:before { content: fa-content($fa-var-java); } +.#{$fa-css-prefix}-jenkins:before { content: fa-content($fa-var-jenkins); } +.#{$fa-css-prefix}-joget:before { content: fa-content($fa-var-joget); } +.#{$fa-css-prefix}-joomla:before { content: fa-content($fa-var-joomla); } +.#{$fa-css-prefix}-js:before { content: fa-content($fa-var-js); } +.#{$fa-css-prefix}-js-square:before { content: fa-content($fa-var-js-square); } +.#{$fa-css-prefix}-jsfiddle:before { content: fa-content($fa-var-jsfiddle); } +.#{$fa-css-prefix}-key:before { content: fa-content($fa-var-key); } +.#{$fa-css-prefix}-keyboard:before { content: fa-content($fa-var-keyboard); } +.#{$fa-css-prefix}-keycdn:before { content: fa-content($fa-var-keycdn); } +.#{$fa-css-prefix}-kickstarter:before { content: fa-content($fa-var-kickstarter); } +.#{$fa-css-prefix}-kickstarter-k:before { content: fa-content($fa-var-kickstarter-k); } +.#{$fa-css-prefix}-korvue:before { content: fa-content($fa-var-korvue); } +.#{$fa-css-prefix}-language:before { content: fa-content($fa-var-language); } +.#{$fa-css-prefix}-laptop:before { content: fa-content($fa-var-laptop); } +.#{$fa-css-prefix}-laravel:before { content: fa-content($fa-var-laravel); } +.#{$fa-css-prefix}-lastfm:before { content: fa-content($fa-var-lastfm); } +.#{$fa-css-prefix}-lastfm-square:before { content: fa-content($fa-var-lastfm-square); } +.#{$fa-css-prefix}-leaf:before { content: fa-content($fa-var-leaf); } +.#{$fa-css-prefix}-leanpub:before { content: fa-content($fa-var-leanpub); } +.#{$fa-css-prefix}-lemon:before { content: fa-content($fa-var-lemon); } +.#{$fa-css-prefix}-less:before { content: fa-content($fa-var-less); } +.#{$fa-css-prefix}-level-down-alt:before { content: fa-content($fa-var-level-down-alt); } +.#{$fa-css-prefix}-level-up-alt:before { content: fa-content($fa-var-level-up-alt); } +.#{$fa-css-prefix}-life-ring:before { content: fa-content($fa-var-life-ring); } +.#{$fa-css-prefix}-lightbulb:before { content: fa-content($fa-var-lightbulb); } +.#{$fa-css-prefix}-line:before { content: fa-content($fa-var-line); } +.#{$fa-css-prefix}-link:before { content: fa-content($fa-var-link); } +.#{$fa-css-prefix}-linkedin:before { content: fa-content($fa-var-linkedin); } +.#{$fa-css-prefix}-linkedin-in:before { content: fa-content($fa-var-linkedin-in); } +.#{$fa-css-prefix}-linode:before { content: fa-content($fa-var-linode); } +.#{$fa-css-prefix}-linux:before { content: fa-content($fa-var-linux); } +.#{$fa-css-prefix}-lira-sign:before { content: fa-content($fa-var-lira-sign); } +.#{$fa-css-prefix}-list:before { content: fa-content($fa-var-list); } +.#{$fa-css-prefix}-list-alt:before { content: fa-content($fa-var-list-alt); } +.#{$fa-css-prefix}-list-ol:before { content: fa-content($fa-var-list-ol); } +.#{$fa-css-prefix}-list-ul:before { content: fa-content($fa-var-list-ul); } +.#{$fa-css-prefix}-location-arrow:before { content: fa-content($fa-var-location-arrow); } +.#{$fa-css-prefix}-lock:before { content: fa-content($fa-var-lock); } +.#{$fa-css-prefix}-lock-open:before { content: fa-content($fa-var-lock-open); } +.#{$fa-css-prefix}-long-arrow-alt-down:before { content: fa-content($fa-var-long-arrow-alt-down); } +.#{$fa-css-prefix}-long-arrow-alt-left:before { content: fa-content($fa-var-long-arrow-alt-left); } +.#{$fa-css-prefix}-long-arrow-alt-right:before { content: fa-content($fa-var-long-arrow-alt-right); } +.#{$fa-css-prefix}-long-arrow-alt-up:before { content: fa-content($fa-var-long-arrow-alt-up); } +.#{$fa-css-prefix}-low-vision:before { content: fa-content($fa-var-low-vision); } +.#{$fa-css-prefix}-lyft:before { content: fa-content($fa-var-lyft); } +.#{$fa-css-prefix}-magento:before { content: fa-content($fa-var-magento); } +.#{$fa-css-prefix}-magic:before { content: fa-content($fa-var-magic); } +.#{$fa-css-prefix}-magnet:before { content: fa-content($fa-var-magnet); } +.#{$fa-css-prefix}-male:before { content: fa-content($fa-var-male); } +.#{$fa-css-prefix}-map:before { content: fa-content($fa-var-map); } +.#{$fa-css-prefix}-map-marker:before { content: fa-content($fa-var-map-marker); } +.#{$fa-css-prefix}-map-marker-alt:before { content: fa-content($fa-var-map-marker-alt); } +.#{$fa-css-prefix}-map-pin:before { content: fa-content($fa-var-map-pin); } +.#{$fa-css-prefix}-map-signs:before { content: fa-content($fa-var-map-signs); } +.#{$fa-css-prefix}-mars:before { content: fa-content($fa-var-mars); } +.#{$fa-css-prefix}-mars-double:before { content: fa-content($fa-var-mars-double); } +.#{$fa-css-prefix}-mars-stroke:before { content: fa-content($fa-var-mars-stroke); } +.#{$fa-css-prefix}-mars-stroke-h:before { content: fa-content($fa-var-mars-stroke-h); } +.#{$fa-css-prefix}-mars-stroke-v:before { content: fa-content($fa-var-mars-stroke-v); } +.#{$fa-css-prefix}-maxcdn:before { content: fa-content($fa-var-maxcdn); } +.#{$fa-css-prefix}-medapps:before { content: fa-content($fa-var-medapps); } +.#{$fa-css-prefix}-medium:before { content: fa-content($fa-var-medium); } +.#{$fa-css-prefix}-medium-m:before { content: fa-content($fa-var-medium-m); } +.#{$fa-css-prefix}-medkit:before { content: fa-content($fa-var-medkit); } +.#{$fa-css-prefix}-medrt:before { content: fa-content($fa-var-medrt); } +.#{$fa-css-prefix}-meetup:before { content: fa-content($fa-var-meetup); } +.#{$fa-css-prefix}-meh:before { content: fa-content($fa-var-meh); } +.#{$fa-css-prefix}-mercury:before { content: fa-content($fa-var-mercury); } +.#{$fa-css-prefix}-microchip:before { content: fa-content($fa-var-microchip); } +.#{$fa-css-prefix}-microphone:before { content: fa-content($fa-var-microphone); } +.#{$fa-css-prefix}-microphone-slash:before { content: fa-content($fa-var-microphone-slash); } +.#{$fa-css-prefix}-microsoft:before { content: fa-content($fa-var-microsoft); } +.#{$fa-css-prefix}-minus:before { content: fa-content($fa-var-minus); } +.#{$fa-css-prefix}-minus-circle:before { content: fa-content($fa-var-minus-circle); } +.#{$fa-css-prefix}-minus-square:before { content: fa-content($fa-var-minus-square); } +.#{$fa-css-prefix}-mix:before { content: fa-content($fa-var-mix); } +.#{$fa-css-prefix}-mixcloud:before { content: fa-content($fa-var-mixcloud); } +.#{$fa-css-prefix}-mizuni:before { content: fa-content($fa-var-mizuni); } +.#{$fa-css-prefix}-mobile:before { content: fa-content($fa-var-mobile); } +.#{$fa-css-prefix}-mobile-alt:before { content: fa-content($fa-var-mobile-alt); } +.#{$fa-css-prefix}-modx:before { content: fa-content($fa-var-modx); } +.#{$fa-css-prefix}-monero:before { content: fa-content($fa-var-monero); } +.#{$fa-css-prefix}-money-bill-alt:before { content: fa-content($fa-var-money-bill-alt); } +.#{$fa-css-prefix}-moon:before { content: fa-content($fa-var-moon); } +.#{$fa-css-prefix}-motorcycle:before { content: fa-content($fa-var-motorcycle); } +.#{$fa-css-prefix}-mouse-pointer:before { content: fa-content($fa-var-mouse-pointer); } +.#{$fa-css-prefix}-music:before { content: fa-content($fa-var-music); } +.#{$fa-css-prefix}-napster:before { content: fa-content($fa-var-napster); } +.#{$fa-css-prefix}-neuter:before { content: fa-content($fa-var-neuter); } +.#{$fa-css-prefix}-newspaper:before { content: fa-content($fa-var-newspaper); } +.#{$fa-css-prefix}-nintendo-switch:before { content: fa-content($fa-var-nintendo-switch); } +.#{$fa-css-prefix}-node:before { content: fa-content($fa-var-node); } +.#{$fa-css-prefix}-node-js:before { content: fa-content($fa-var-node-js); } +.#{$fa-css-prefix}-notes-medical:before { content: fa-content($fa-var-notes-medical); } +.#{$fa-css-prefix}-npm:before { content: fa-content($fa-var-npm); } +.#{$fa-css-prefix}-ns8:before { content: fa-content($fa-var-ns8); } +.#{$fa-css-prefix}-nutritionix:before { content: fa-content($fa-var-nutritionix); } +.#{$fa-css-prefix}-object-group:before { content: fa-content($fa-var-object-group); } +.#{$fa-css-prefix}-object-ungroup:before { content: fa-content($fa-var-object-ungroup); } +.#{$fa-css-prefix}-odnoklassniki:before { content: fa-content($fa-var-odnoklassniki); } +.#{$fa-css-prefix}-odnoklassniki-square:before { content: fa-content($fa-var-odnoklassniki-square); } +.#{$fa-css-prefix}-opencart:before { content: fa-content($fa-var-opencart); } +.#{$fa-css-prefix}-openid:before { content: fa-content($fa-var-openid); } +.#{$fa-css-prefix}-opera:before { content: fa-content($fa-var-opera); } +.#{$fa-css-prefix}-optin-monster:before { content: fa-content($fa-var-optin-monster); } +.#{$fa-css-prefix}-osi:before { content: fa-content($fa-var-osi); } +.#{$fa-css-prefix}-outdent:before { content: fa-content($fa-var-outdent); } +.#{$fa-css-prefix}-page4:before { content: fa-content($fa-var-page4); } +.#{$fa-css-prefix}-pagelines:before { content: fa-content($fa-var-pagelines); } +.#{$fa-css-prefix}-paint-brush:before { content: fa-content($fa-var-paint-brush); } +.#{$fa-css-prefix}-palfed:before { content: fa-content($fa-var-palfed); } +.#{$fa-css-prefix}-pallet:before { content: fa-content($fa-var-pallet); } +.#{$fa-css-prefix}-paper-plane:before { content: fa-content($fa-var-paper-plane); } +.#{$fa-css-prefix}-paperclip:before { content: fa-content($fa-var-paperclip); } +.#{$fa-css-prefix}-parachute-box:before { content: fa-content($fa-var-parachute-box); } +.#{$fa-css-prefix}-paragraph:before { content: fa-content($fa-var-paragraph); } +.#{$fa-css-prefix}-paste:before { content: fa-content($fa-var-paste); } +.#{$fa-css-prefix}-patreon:before { content: fa-content($fa-var-patreon); } +.#{$fa-css-prefix}-pause:before { content: fa-content($fa-var-pause); } +.#{$fa-css-prefix}-pause-circle:before { content: fa-content($fa-var-pause-circle); } +.#{$fa-css-prefix}-paw:before { content: fa-content($fa-var-paw); } +.#{$fa-css-prefix}-paypal:before { content: fa-content($fa-var-paypal); } +.#{$fa-css-prefix}-pen-square:before { content: fa-content($fa-var-pen-square); } +.#{$fa-css-prefix}-pencil-alt:before { content: fa-content($fa-var-pencil-alt); } +.#{$fa-css-prefix}-people-carry:before { content: fa-content($fa-var-people-carry); } +.#{$fa-css-prefix}-percent:before { content: fa-content($fa-var-percent); } +.#{$fa-css-prefix}-periscope:before { content: fa-content($fa-var-periscope); } +.#{$fa-css-prefix}-phabricator:before { content: fa-content($fa-var-phabricator); } +.#{$fa-css-prefix}-phoenix-framework:before { content: fa-content($fa-var-phoenix-framework); } +.#{$fa-css-prefix}-phone:before { content: fa-content($fa-var-phone); } +.#{$fa-css-prefix}-phone-slash:before { content: fa-content($fa-var-phone-slash); } +.#{$fa-css-prefix}-phone-square:before { content: fa-content($fa-var-phone-square); } +.#{$fa-css-prefix}-phone-volume:before { content: fa-content($fa-var-phone-volume); } +.#{$fa-css-prefix}-php:before { content: fa-content($fa-var-php); } +.#{$fa-css-prefix}-pied-piper:before { content: fa-content($fa-var-pied-piper); } +.#{$fa-css-prefix}-pied-piper-alt:before { content: fa-content($fa-var-pied-piper-alt); } +.#{$fa-css-prefix}-pied-piper-hat:before { content: fa-content($fa-var-pied-piper-hat); } +.#{$fa-css-prefix}-pied-piper-pp:before { content: fa-content($fa-var-pied-piper-pp); } +.#{$fa-css-prefix}-piggy-bank:before { content: fa-content($fa-var-piggy-bank); } +.#{$fa-css-prefix}-pills:before { content: fa-content($fa-var-pills); } +.#{$fa-css-prefix}-pinterest:before { content: fa-content($fa-var-pinterest); } +.#{$fa-css-prefix}-pinterest-p:before { content: fa-content($fa-var-pinterest-p); } +.#{$fa-css-prefix}-pinterest-square:before { content: fa-content($fa-var-pinterest-square); } +.#{$fa-css-prefix}-plane:before { content: fa-content($fa-var-plane); } +.#{$fa-css-prefix}-play:before { content: fa-content($fa-var-play); } +.#{$fa-css-prefix}-play-circle:before { content: fa-content($fa-var-play-circle); } +.#{$fa-css-prefix}-playstation:before { content: fa-content($fa-var-playstation); } +.#{$fa-css-prefix}-plug:before { content: fa-content($fa-var-plug); } +.#{$fa-css-prefix}-plus:before { content: fa-content($fa-var-plus); } +.#{$fa-css-prefix}-plus-circle:before { content: fa-content($fa-var-plus-circle); } +.#{$fa-css-prefix}-plus-square:before { content: fa-content($fa-var-plus-square); } +.#{$fa-css-prefix}-podcast:before { content: fa-content($fa-var-podcast); } +.#{$fa-css-prefix}-poo:before { content: fa-content($fa-var-poo); } +.#{$fa-css-prefix}-pound-sign:before { content: fa-content($fa-var-pound-sign); } +.#{$fa-css-prefix}-power-off:before { content: fa-content($fa-var-power-off); } +.#{$fa-css-prefix}-prescription-bottle:before { content: fa-content($fa-var-prescription-bottle); } +.#{$fa-css-prefix}-prescription-bottle-alt:before { content: fa-content($fa-var-prescription-bottle-alt); } +.#{$fa-css-prefix}-print:before { content: fa-content($fa-var-print); } +.#{$fa-css-prefix}-procedures:before { content: fa-content($fa-var-procedures); } +.#{$fa-css-prefix}-product-hunt:before { content: fa-content($fa-var-product-hunt); } +.#{$fa-css-prefix}-pushed:before { content: fa-content($fa-var-pushed); } +.#{$fa-css-prefix}-puzzle-piece:before { content: fa-content($fa-var-puzzle-piece); } +.#{$fa-css-prefix}-python:before { content: fa-content($fa-var-python); } +.#{$fa-css-prefix}-qq:before { content: fa-content($fa-var-qq); } +.#{$fa-css-prefix}-qrcode:before { content: fa-content($fa-var-qrcode); } +.#{$fa-css-prefix}-question:before { content: fa-content($fa-var-question); } +.#{$fa-css-prefix}-question-circle:before { content: fa-content($fa-var-question-circle); } +.#{$fa-css-prefix}-quidditch:before { content: fa-content($fa-var-quidditch); } +.#{$fa-css-prefix}-quinscape:before { content: fa-content($fa-var-quinscape); } +.#{$fa-css-prefix}-quora:before { content: fa-content($fa-var-quora); } +.#{$fa-css-prefix}-quote-left:before { content: fa-content($fa-var-quote-left); } +.#{$fa-css-prefix}-quote-right:before { content: fa-content($fa-var-quote-right); } +.#{$fa-css-prefix}-random:before { content: fa-content($fa-var-random); } +.#{$fa-css-prefix}-ravelry:before { content: fa-content($fa-var-ravelry); } +.#{$fa-css-prefix}-react:before { content: fa-content($fa-var-react); } +.#{$fa-css-prefix}-readme:before { content: fa-content($fa-var-readme); } +.#{$fa-css-prefix}-rebel:before { content: fa-content($fa-var-rebel); } +.#{$fa-css-prefix}-recycle:before { content: fa-content($fa-var-recycle); } +.#{$fa-css-prefix}-red-river:before { content: fa-content($fa-var-red-river); } +.#{$fa-css-prefix}-reddit:before { content: fa-content($fa-var-reddit); } +.#{$fa-css-prefix}-reddit-alien:before { content: fa-content($fa-var-reddit-alien); } +.#{$fa-css-prefix}-reddit-square:before { content: fa-content($fa-var-reddit-square); } +.#{$fa-css-prefix}-redo:before { content: fa-content($fa-var-redo); } +.#{$fa-css-prefix}-redo-alt:before { content: fa-content($fa-var-redo-alt); } +.#{$fa-css-prefix}-registered:before { content: fa-content($fa-var-registered); } +.#{$fa-css-prefix}-rendact:before { content: fa-content($fa-var-rendact); } +.#{$fa-css-prefix}-renren:before { content: fa-content($fa-var-renren); } +.#{$fa-css-prefix}-reply:before { content: fa-content($fa-var-reply); } +.#{$fa-css-prefix}-reply-all:before { content: fa-content($fa-var-reply-all); } +.#{$fa-css-prefix}-replyd:before { content: fa-content($fa-var-replyd); } +.#{$fa-css-prefix}-resolving:before { content: fa-content($fa-var-resolving); } +.#{$fa-css-prefix}-retweet:before { content: fa-content($fa-var-retweet); } +.#{$fa-css-prefix}-ribbon:before { content: fa-content($fa-var-ribbon); } +.#{$fa-css-prefix}-road:before { content: fa-content($fa-var-road); } +.#{$fa-css-prefix}-rocket:before { content: fa-content($fa-var-rocket); } +.#{$fa-css-prefix}-rocketchat:before { content: fa-content($fa-var-rocketchat); } +.#{$fa-css-prefix}-rockrms:before { content: fa-content($fa-var-rockrms); } +.#{$fa-css-prefix}-rss:before { content: fa-content($fa-var-rss); } +.#{$fa-css-prefix}-rss-square:before { content: fa-content($fa-var-rss-square); } +.#{$fa-css-prefix}-ruble-sign:before { content: fa-content($fa-var-ruble-sign); } +.#{$fa-css-prefix}-rupee-sign:before { content: fa-content($fa-var-rupee-sign); } +.#{$fa-css-prefix}-safari:before { content: fa-content($fa-var-safari); } +.#{$fa-css-prefix}-sass:before { content: fa-content($fa-var-sass); } +.#{$fa-css-prefix}-save:before { content: fa-content($fa-var-save); } +.#{$fa-css-prefix}-schlix:before { content: fa-content($fa-var-schlix); } +.#{$fa-css-prefix}-scribd:before { content: fa-content($fa-var-scribd); } +.#{$fa-css-prefix}-search:before { content: fa-content($fa-var-search); } +.#{$fa-css-prefix}-search-minus:before { content: fa-content($fa-var-search-minus); } +.#{$fa-css-prefix}-search-plus:before { content: fa-content($fa-var-search-plus); } +.#{$fa-css-prefix}-searchengin:before { content: fa-content($fa-var-searchengin); } +.#{$fa-css-prefix}-seedling:before { content: fa-content($fa-var-seedling); } +.#{$fa-css-prefix}-sellcast:before { content: fa-content($fa-var-sellcast); } +.#{$fa-css-prefix}-sellsy:before { content: fa-content($fa-var-sellsy); } +.#{$fa-css-prefix}-server:before { content: fa-content($fa-var-server); } +.#{$fa-css-prefix}-servicestack:before { content: fa-content($fa-var-servicestack); } +.#{$fa-css-prefix}-share:before { content: fa-content($fa-var-share); } +.#{$fa-css-prefix}-share-alt:before { content: fa-content($fa-var-share-alt); } +.#{$fa-css-prefix}-share-alt-square:before { content: fa-content($fa-var-share-alt-square); } +.#{$fa-css-prefix}-share-square:before { content: fa-content($fa-var-share-square); } +.#{$fa-css-prefix}-shekel-sign:before { content: fa-content($fa-var-shekel-sign); } +.#{$fa-css-prefix}-shield-alt:before { content: fa-content($fa-var-shield-alt); } +.#{$fa-css-prefix}-ship:before { content: fa-content($fa-var-ship); } +.#{$fa-css-prefix}-shipping-fast:before { content: fa-content($fa-var-shipping-fast); } +.#{$fa-css-prefix}-shirtsinbulk:before { content: fa-content($fa-var-shirtsinbulk); } +.#{$fa-css-prefix}-shopping-bag:before { content: fa-content($fa-var-shopping-bag); } +.#{$fa-css-prefix}-shopping-basket:before { content: fa-content($fa-var-shopping-basket); } +.#{$fa-css-prefix}-shopping-cart:before { content: fa-content($fa-var-shopping-cart); } +.#{$fa-css-prefix}-shower:before { content: fa-content($fa-var-shower); } +.#{$fa-css-prefix}-sign:before { content: fa-content($fa-var-sign); } +.#{$fa-css-prefix}-sign-in-alt:before { content: fa-content($fa-var-sign-in-alt); } +.#{$fa-css-prefix}-sign-language:before { content: fa-content($fa-var-sign-language); } +.#{$fa-css-prefix}-sign-out-alt:before { content: fa-content($fa-var-sign-out-alt); } +.#{$fa-css-prefix}-signal:before { content: fa-content($fa-var-signal); } +.#{$fa-css-prefix}-simplybuilt:before { content: fa-content($fa-var-simplybuilt); } +.#{$fa-css-prefix}-sistrix:before { content: fa-content($fa-var-sistrix); } +.#{$fa-css-prefix}-sitemap:before { content: fa-content($fa-var-sitemap); } +.#{$fa-css-prefix}-skyatlas:before { content: fa-content($fa-var-skyatlas); } +.#{$fa-css-prefix}-skype:before { content: fa-content($fa-var-skype); } +.#{$fa-css-prefix}-slack:before { content: fa-content($fa-var-slack); } +.#{$fa-css-prefix}-slack-hash:before { content: fa-content($fa-var-slack-hash); } +.#{$fa-css-prefix}-sliders-h:before { content: fa-content($fa-var-sliders-h); } +.#{$fa-css-prefix}-slideshare:before { content: fa-content($fa-var-slideshare); } +.#{$fa-css-prefix}-smile:before { content: fa-content($fa-var-smile); } +.#{$fa-css-prefix}-smoking:before { content: fa-content($fa-var-smoking); } +.#{$fa-css-prefix}-snapchat:before { content: fa-content($fa-var-snapchat); } +.#{$fa-css-prefix}-snapchat-ghost:before { content: fa-content($fa-var-snapchat-ghost); } +.#{$fa-css-prefix}-snapchat-square:before { content: fa-content($fa-var-snapchat-square); } +.#{$fa-css-prefix}-snowflake:before { content: fa-content($fa-var-snowflake); } +.#{$fa-css-prefix}-sort:before { content: fa-content($fa-var-sort); } +.#{$fa-css-prefix}-sort-alpha-down:before { content: fa-content($fa-var-sort-alpha-down); } +.#{$fa-css-prefix}-sort-alpha-up:before { content: fa-content($fa-var-sort-alpha-up); } +.#{$fa-css-prefix}-sort-amount-down:before { content: fa-content($fa-var-sort-amount-down); } +.#{$fa-css-prefix}-sort-amount-up:before { content: fa-content($fa-var-sort-amount-up); } +.#{$fa-css-prefix}-sort-down:before { content: fa-content($fa-var-sort-down); } +.#{$fa-css-prefix}-sort-numeric-down:before { content: fa-content($fa-var-sort-numeric-down); } +.#{$fa-css-prefix}-sort-numeric-up:before { content: fa-content($fa-var-sort-numeric-up); } +.#{$fa-css-prefix}-sort-up:before { content: fa-content($fa-var-sort-up); } +.#{$fa-css-prefix}-soundcloud:before { content: fa-content($fa-var-soundcloud); } +.#{$fa-css-prefix}-space-shuttle:before { content: fa-content($fa-var-space-shuttle); } +.#{$fa-css-prefix}-speakap:before { content: fa-content($fa-var-speakap); } +.#{$fa-css-prefix}-spinner:before { content: fa-content($fa-var-spinner); } +.#{$fa-css-prefix}-spotify:before { content: fa-content($fa-var-spotify); } +.#{$fa-css-prefix}-square:before { content: fa-content($fa-var-square); } +.#{$fa-css-prefix}-square-full:before { content: fa-content($fa-var-square-full); } +.#{$fa-css-prefix}-stack-exchange:before { content: fa-content($fa-var-stack-exchange); } +.#{$fa-css-prefix}-stack-overflow:before { content: fa-content($fa-var-stack-overflow); } +.#{$fa-css-prefix}-star:before { content: fa-content($fa-var-star); } +.#{$fa-css-prefix}-star-half:before { content: fa-content($fa-var-star-half); } +.#{$fa-css-prefix}-staylinked:before { content: fa-content($fa-var-staylinked); } +.#{$fa-css-prefix}-steam:before { content: fa-content($fa-var-steam); } +.#{$fa-css-prefix}-steam-square:before { content: fa-content($fa-var-steam-square); } +.#{$fa-css-prefix}-steam-symbol:before { content: fa-content($fa-var-steam-symbol); } +.#{$fa-css-prefix}-step-backward:before { content: fa-content($fa-var-step-backward); } +.#{$fa-css-prefix}-step-forward:before { content: fa-content($fa-var-step-forward); } +.#{$fa-css-prefix}-stethoscope:before { content: fa-content($fa-var-stethoscope); } +.#{$fa-css-prefix}-sticker-mule:before { content: fa-content($fa-var-sticker-mule); } +.#{$fa-css-prefix}-sticky-note:before { content: fa-content($fa-var-sticky-note); } +.#{$fa-css-prefix}-stop:before { content: fa-content($fa-var-stop); } +.#{$fa-css-prefix}-stop-circle:before { content: fa-content($fa-var-stop-circle); } +.#{$fa-css-prefix}-stopwatch:before { content: fa-content($fa-var-stopwatch); } +.#{$fa-css-prefix}-strava:before { content: fa-content($fa-var-strava); } +.#{$fa-css-prefix}-street-view:before { content: fa-content($fa-var-street-view); } +.#{$fa-css-prefix}-strikethrough:before { content: fa-content($fa-var-strikethrough); } +.#{$fa-css-prefix}-stripe:before { content: fa-content($fa-var-stripe); } +.#{$fa-css-prefix}-stripe-s:before { content: fa-content($fa-var-stripe-s); } +.#{$fa-css-prefix}-studiovinari:before { content: fa-content($fa-var-studiovinari); } +.#{$fa-css-prefix}-stumbleupon:before { content: fa-content($fa-var-stumbleupon); } +.#{$fa-css-prefix}-stumbleupon-circle:before { content: fa-content($fa-var-stumbleupon-circle); } +.#{$fa-css-prefix}-subscript:before { content: fa-content($fa-var-subscript); } +.#{$fa-css-prefix}-subway:before { content: fa-content($fa-var-subway); } +.#{$fa-css-prefix}-suitcase:before { content: fa-content($fa-var-suitcase); } +.#{$fa-css-prefix}-sun:before { content: fa-content($fa-var-sun); } +.#{$fa-css-prefix}-superpowers:before { content: fa-content($fa-var-superpowers); } +.#{$fa-css-prefix}-superscript:before { content: fa-content($fa-var-superscript); } +.#{$fa-css-prefix}-supple:before { content: fa-content($fa-var-supple); } +.#{$fa-css-prefix}-sync:before { content: fa-content($fa-var-sync); } +.#{$fa-css-prefix}-sync-alt:before { content: fa-content($fa-var-sync-alt); } +.#{$fa-css-prefix}-syringe:before { content: fa-content($fa-var-syringe); } +.#{$fa-css-prefix}-table:before { content: fa-content($fa-var-table); } +.#{$fa-css-prefix}-table-tennis:before { content: fa-content($fa-var-table-tennis); } +.#{$fa-css-prefix}-tablet:before { content: fa-content($fa-var-tablet); } +.#{$fa-css-prefix}-tablet-alt:before { content: fa-content($fa-var-tablet-alt); } +.#{$fa-css-prefix}-tablets:before { content: fa-content($fa-var-tablets); } +.#{$fa-css-prefix}-tachometer-alt:before { content: fa-content($fa-var-tachometer-alt); } +.#{$fa-css-prefix}-tag:before { content: fa-content($fa-var-tag); } +.#{$fa-css-prefix}-tags:before { content: fa-content($fa-var-tags); } +.#{$fa-css-prefix}-tape:before { content: fa-content($fa-var-tape); } +.#{$fa-css-prefix}-tasks:before { content: fa-content($fa-var-tasks); } +.#{$fa-css-prefix}-taxi:before { content: fa-content($fa-var-taxi); } +.#{$fa-css-prefix}-telegram:before { content: fa-content($fa-var-telegram); } +.#{$fa-css-prefix}-telegram-plane:before { content: fa-content($fa-var-telegram-plane); } +.#{$fa-css-prefix}-tencent-weibo:before { content: fa-content($fa-var-tencent-weibo); } +.#{$fa-css-prefix}-terminal:before { content: fa-content($fa-var-terminal); } +.#{$fa-css-prefix}-text-height:before { content: fa-content($fa-var-text-height); } +.#{$fa-css-prefix}-text-width:before { content: fa-content($fa-var-text-width); } +.#{$fa-css-prefix}-th:before { content: fa-content($fa-var-th); } +.#{$fa-css-prefix}-th-large:before { content: fa-content($fa-var-th-large); } +.#{$fa-css-prefix}-th-list:before { content: fa-content($fa-var-th-list); } +.#{$fa-css-prefix}-themeisle:before { content: fa-content($fa-var-themeisle); } +.#{$fa-css-prefix}-thermometer:before { content: fa-content($fa-var-thermometer); } +.#{$fa-css-prefix}-thermometer-empty:before { content: fa-content($fa-var-thermometer-empty); } +.#{$fa-css-prefix}-thermometer-full:before { content: fa-content($fa-var-thermometer-full); } +.#{$fa-css-prefix}-thermometer-half:before { content: fa-content($fa-var-thermometer-half); } +.#{$fa-css-prefix}-thermometer-quarter:before { content: fa-content($fa-var-thermometer-quarter); } +.#{$fa-css-prefix}-thermometer-three-quarters:before { content: fa-content($fa-var-thermometer-three-quarters); } +.#{$fa-css-prefix}-thumbs-down:before { content: fa-content($fa-var-thumbs-down); } +.#{$fa-css-prefix}-thumbs-up:before { content: fa-content($fa-var-thumbs-up); } +.#{$fa-css-prefix}-thumbtack:before { content: fa-content($fa-var-thumbtack); } +.#{$fa-css-prefix}-ticket-alt:before { content: fa-content($fa-var-ticket-alt); } +.#{$fa-css-prefix}-times:before { content: fa-content($fa-var-times); } +.#{$fa-css-prefix}-times-circle:before { content: fa-content($fa-var-times-circle); } +.#{$fa-css-prefix}-tint:before { content: fa-content($fa-var-tint); } +.#{$fa-css-prefix}-toggle-off:before { content: fa-content($fa-var-toggle-off); } +.#{$fa-css-prefix}-toggle-on:before { content: fa-content($fa-var-toggle-on); } +.#{$fa-css-prefix}-trademark:before { content: fa-content($fa-var-trademark); } +.#{$fa-css-prefix}-train:before { content: fa-content($fa-var-train); } +.#{$fa-css-prefix}-transgender:before { content: fa-content($fa-var-transgender); } +.#{$fa-css-prefix}-transgender-alt:before { content: fa-content($fa-var-transgender-alt); } +.#{$fa-css-prefix}-trash:before { content: fa-content($fa-var-trash); } +.#{$fa-css-prefix}-trash-alt:before { content: fa-content($fa-var-trash-alt); } +.#{$fa-css-prefix}-tree:before { content: fa-content($fa-var-tree); } +.#{$fa-css-prefix}-trello:before { content: fa-content($fa-var-trello); } +.#{$fa-css-prefix}-tripadvisor:before { content: fa-content($fa-var-tripadvisor); } +.#{$fa-css-prefix}-trophy:before { content: fa-content($fa-var-trophy); } +.#{$fa-css-prefix}-truck:before { content: fa-content($fa-var-truck); } +.#{$fa-css-prefix}-truck-loading:before { content: fa-content($fa-var-truck-loading); } +.#{$fa-css-prefix}-truck-moving:before { content: fa-content($fa-var-truck-moving); } +.#{$fa-css-prefix}-tty:before { content: fa-content($fa-var-tty); } +.#{$fa-css-prefix}-tumblr:before { content: fa-content($fa-var-tumblr); } +.#{$fa-css-prefix}-tumblr-square:before { content: fa-content($fa-var-tumblr-square); } +.#{$fa-css-prefix}-tv:before { content: fa-content($fa-var-tv); } +.#{$fa-css-prefix}-twitch:before { content: fa-content($fa-var-twitch); } +.#{$fa-css-prefix}-twitter:before { content: fa-content($fa-var-twitter); } +.#{$fa-css-prefix}-twitter-square:before { content: fa-content($fa-var-twitter-square); } +.#{$fa-css-prefix}-typo3:before { content: fa-content($fa-var-typo3); } +.#{$fa-css-prefix}-uber:before { content: fa-content($fa-var-uber); } +.#{$fa-css-prefix}-uikit:before { content: fa-content($fa-var-uikit); } +.#{$fa-css-prefix}-umbrella:before { content: fa-content($fa-var-umbrella); } +.#{$fa-css-prefix}-underline:before { content: fa-content($fa-var-underline); } +.#{$fa-css-prefix}-undo:before { content: fa-content($fa-var-undo); } +.#{$fa-css-prefix}-undo-alt:before { content: fa-content($fa-var-undo-alt); } +.#{$fa-css-prefix}-uniregistry:before { content: fa-content($fa-var-uniregistry); } +.#{$fa-css-prefix}-universal-access:before { content: fa-content($fa-var-universal-access); } +.#{$fa-css-prefix}-university:before { content: fa-content($fa-var-university); } +.#{$fa-css-prefix}-unlink:before { content: fa-content($fa-var-unlink); } +.#{$fa-css-prefix}-unlock:before { content: fa-content($fa-var-unlock); } +.#{$fa-css-prefix}-unlock-alt:before { content: fa-content($fa-var-unlock-alt); } +.#{$fa-css-prefix}-untappd:before { content: fa-content($fa-var-untappd); } +.#{$fa-css-prefix}-upload:before { content: fa-content($fa-var-upload); } +.#{$fa-css-prefix}-usb:before { content: fa-content($fa-var-usb); } +.#{$fa-css-prefix}-user:before { content: fa-content($fa-var-user); } +.#{$fa-css-prefix}-user-circle:before { content: fa-content($fa-var-user-circle); } +.#{$fa-css-prefix}-user-md:before { content: fa-content($fa-var-user-md); } +.#{$fa-css-prefix}-user-plus:before { content: fa-content($fa-var-user-plus); } +.#{$fa-css-prefix}-user-secret:before { content: fa-content($fa-var-user-secret); } +.#{$fa-css-prefix}-user-times:before { content: fa-content($fa-var-user-times); } +.#{$fa-css-prefix}-users:before { content: fa-content($fa-var-users); } +.#{$fa-css-prefix}-ussunnah:before { content: fa-content($fa-var-ussunnah); } +.#{$fa-css-prefix}-utensil-spoon:before { content: fa-content($fa-var-utensil-spoon); } +.#{$fa-css-prefix}-utensils:before { content: fa-content($fa-var-utensils); } +.#{$fa-css-prefix}-vaadin:before { content: fa-content($fa-var-vaadin); } +.#{$fa-css-prefix}-venus:before { content: fa-content($fa-var-venus); } +.#{$fa-css-prefix}-venus-double:before { content: fa-content($fa-var-venus-double); } +.#{$fa-css-prefix}-venus-mars:before { content: fa-content($fa-var-venus-mars); } +.#{$fa-css-prefix}-viacoin:before { content: fa-content($fa-var-viacoin); } +.#{$fa-css-prefix}-viadeo:before { content: fa-content($fa-var-viadeo); } +.#{$fa-css-prefix}-viadeo-square:before { content: fa-content($fa-var-viadeo-square); } +.#{$fa-css-prefix}-vial:before { content: fa-content($fa-var-vial); } +.#{$fa-css-prefix}-vials:before { content: fa-content($fa-var-vials); } +.#{$fa-css-prefix}-viber:before { content: fa-content($fa-var-viber); } +.#{$fa-css-prefix}-video:before { content: fa-content($fa-var-video); } +.#{$fa-css-prefix}-video-slash:before { content: fa-content($fa-var-video-slash); } +.#{$fa-css-prefix}-vimeo:before { content: fa-content($fa-var-vimeo); } +.#{$fa-css-prefix}-vimeo-square:before { content: fa-content($fa-var-vimeo-square); } +.#{$fa-css-prefix}-vimeo-v:before { content: fa-content($fa-var-vimeo-v); } +.#{$fa-css-prefix}-vine:before { content: fa-content($fa-var-vine); } +.#{$fa-css-prefix}-vk:before { content: fa-content($fa-var-vk); } +.#{$fa-css-prefix}-vnv:before { content: fa-content($fa-var-vnv); } +.#{$fa-css-prefix}-volleyball-ball:before { content: fa-content($fa-var-volleyball-ball); } +.#{$fa-css-prefix}-volume-down:before { content: fa-content($fa-var-volume-down); } +.#{$fa-css-prefix}-volume-off:before { content: fa-content($fa-var-volume-off); } +.#{$fa-css-prefix}-volume-up:before { content: fa-content($fa-var-volume-up); } +.#{$fa-css-prefix}-vuejs:before { content: fa-content($fa-var-vuejs); } +.#{$fa-css-prefix}-warehouse:before { content: fa-content($fa-var-warehouse); } +.#{$fa-css-prefix}-weibo:before { content: fa-content($fa-var-weibo); } +.#{$fa-css-prefix}-weight:before { content: fa-content($fa-var-weight); } +.#{$fa-css-prefix}-weixin:before { content: fa-content($fa-var-weixin); } +.#{$fa-css-prefix}-whatsapp:before { content: fa-content($fa-var-whatsapp); } +.#{$fa-css-prefix}-whatsapp-square:before { content: fa-content($fa-var-whatsapp-square); } +.#{$fa-css-prefix}-wheelchair:before { content: fa-content($fa-var-wheelchair); } +.#{$fa-css-prefix}-whmcs:before { content: fa-content($fa-var-whmcs); } +.#{$fa-css-prefix}-wifi:before { content: fa-content($fa-var-wifi); } +.#{$fa-css-prefix}-wikipedia-w:before { content: fa-content($fa-var-wikipedia-w); } +.#{$fa-css-prefix}-window-close:before { content: fa-content($fa-var-window-close); } +.#{$fa-css-prefix}-window-maximize:before { content: fa-content($fa-var-window-maximize); } +.#{$fa-css-prefix}-window-minimize:before { content: fa-content($fa-var-window-minimize); } +.#{$fa-css-prefix}-window-restore:before { content: fa-content($fa-var-window-restore); } +.#{$fa-css-prefix}-windows:before { content: fa-content($fa-var-windows); } +.#{$fa-css-prefix}-wine-glass:before { content: fa-content($fa-var-wine-glass); } +.#{$fa-css-prefix}-won-sign:before { content: fa-content($fa-var-won-sign); } +.#{$fa-css-prefix}-wordpress:before { content: fa-content($fa-var-wordpress); } +.#{$fa-css-prefix}-wordpress-simple:before { content: fa-content($fa-var-wordpress-simple); } +.#{$fa-css-prefix}-wpbeginner:before { content: fa-content($fa-var-wpbeginner); } +.#{$fa-css-prefix}-wpexplorer:before { content: fa-content($fa-var-wpexplorer); } +.#{$fa-css-prefix}-wpforms:before { content: fa-content($fa-var-wpforms); } +.#{$fa-css-prefix}-wrench:before { content: fa-content($fa-var-wrench); } +.#{$fa-css-prefix}-x-ray:before { content: fa-content($fa-var-x-ray); } +.#{$fa-css-prefix}-xbox:before { content: fa-content($fa-var-xbox); } +.#{$fa-css-prefix}-xing:before { content: fa-content($fa-var-xing); } +.#{$fa-css-prefix}-xing-square:before { content: fa-content($fa-var-xing-square); } +.#{$fa-css-prefix}-y-combinator:before { content: fa-content($fa-var-y-combinator); } +.#{$fa-css-prefix}-yahoo:before { content: fa-content($fa-var-yahoo); } +.#{$fa-css-prefix}-yandex:before { content: fa-content($fa-var-yandex); } +.#{$fa-css-prefix}-yandex-international:before { content: fa-content($fa-var-yandex-international); } +.#{$fa-css-prefix}-yelp:before { content: fa-content($fa-var-yelp); } +.#{$fa-css-prefix}-yen-sign:before { content: fa-content($fa-var-yen-sign); } +.#{$fa-css-prefix}-yoast:before { content: fa-content($fa-var-yoast); } +.#{$fa-css-prefix}-youtube:before { content: fa-content($fa-var-youtube); } +.#{$fa-css-prefix}-youtube-square:before { content: fa-content($fa-var-youtube-square); } diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_larger.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_larger.scss new file mode 100644 index 000000000000..27c2ad5fc452 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_larger.scss @@ -0,0 +1,23 @@ +// Icon Sizes +// ------------------------- + +// makes the font 33% larger relative to the icon container +.#{$fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -.0667em; +} + +.#{$fa-css-prefix}-xs { + font-size: .75em; +} + +.#{$fa-css-prefix}-sm { + font-size: .875em; +} + +@for $i from 1 through 10 { + .#{$fa-css-prefix}-#{$i}x { + font-size: $i * 1em; + } +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_list.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_list.scss new file mode 100644 index 000000000000..8ebf33333cfd --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_list.scss @@ -0,0 +1,18 @@ +// List Icons +// ------------------------- + +.#{$fa-css-prefix}-ul { + list-style-type: none; + margin-left: $fa-li-width * 5/4; + padding-left: 0; + + > li { position: relative; } +} + +.#{$fa-css-prefix}-li { + left: -$fa-li-width; + position: absolute; + text-align: center; + width: $fa-li-width; + line-height: inherit; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_mixins.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_mixins.scss new file mode 100644 index 000000000000..50a2e9f18c97 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_mixins.scss @@ -0,0 +1,57 @@ +// Mixins +// -------------------------- + +@mixin fa-icon { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + display: inline-block; + font-style: normal; + font-variant: normal; + font-weight: normal; + line-height: 1; + vertical-align: -.125em; +} + +@mixin fa-icon-rotate($degrees, $rotation) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; + transform: rotate($degrees); +} + +@mixin fa-icon-flip($horiz, $vert, $rotation) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; + transform: scale($horiz, $vert); +} + + +// Only display content to screen readers. A la Bootstrap 4. +// +// See: http://a11yproject.com/posts/how-to-hide-content/ + +@mixin sr-only { + border: 0; + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// +// Credit: HTML5 Boilerplate + +@mixin sr-only-focusable { + &:active, + &:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; + } +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_rotated-flipped.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_rotated-flipped.scss new file mode 100644 index 000000000000..995bc4cc70da --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_rotated-flipped.scss @@ -0,0 +1,23 @@ +// Rotated & Flipped Icons +// ------------------------- + +.#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } +.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } +.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } + +.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } +.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } +.#{$fa-css-prefix}-flip-horizontal.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(-1, -1, 2); } + +// Hook for IE8-9 +// ------------------------- + +:root { + .#{$fa-css-prefix}-rotate-90, + .#{$fa-css-prefix}-rotate-180, + .#{$fa-css-prefix}-rotate-270, + .#{$fa-css-prefix}-flip-horizontal, + .#{$fa-css-prefix}-flip-vertical { + filter: none; + } +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_screen-reader.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_screen-reader.scss new file mode 100644 index 000000000000..5d0ab262f15f --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_screen-reader.scss @@ -0,0 +1,5 @@ +// Screen Readers +// ------------------------- + +.sr-only { @include sr-only; } +.sr-only-focusable { @include sr-only-focusable; } diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_stacked.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_stacked.scss new file mode 100644 index 000000000000..6c09d84cd11f --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_stacked.scss @@ -0,0 +1,31 @@ +// Stacked Icons +// ------------------------- + +.#{$fa-css-prefix}-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2em; +} + +.#{$fa-css-prefix}-stack-1x, +.#{$fa-css-prefix}-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; +} + +.#{$fa-css-prefix}-stack-1x { + line-height: inherit; +} + +.#{$fa-css-prefix}-stack-2x { + font-size: 2em; +} + +.#{$fa-css-prefix}-inverse { + color: $fa-inverse; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_variables.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_variables.scss new file mode 100644 index 000000000000..25cc62d16a5b --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/_variables.scss @@ -0,0 +1,891 @@ +// Variables +// -------------------------- + +$fa-font-path: "../webfonts" !default; +$fa-font-size-base: 16px !default; +$fa-css-prefix: fa !default; +$fa-version: "5.0.10" !default; +$fa-border-color: #eee !default; +$fa-inverse: #fff !default; +$fa-li-width: 2em !default; + +// Convenience function used to set content property +@function fa-content($fa-var) { + @return unquote("\"#{ $fa-var }\""); +} + +$fa-var-500px: \f26e; +$fa-var-accessible-icon: \f368; +$fa-var-accusoft: \f369; +$fa-var-address-book: \f2b9; +$fa-var-address-card: \f2bb; +$fa-var-adjust: \f042; +$fa-var-adn: \f170; +$fa-var-adversal: \f36a; +$fa-var-affiliatetheme: \f36b; +$fa-var-algolia: \f36c; +$fa-var-align-center: \f037; +$fa-var-align-justify: \f039; +$fa-var-align-left: \f036; +$fa-var-align-right: \f038; +$fa-var-allergies: \f461; +$fa-var-amazon: \f270; +$fa-var-amazon-pay: \f42c; +$fa-var-ambulance: \f0f9; +$fa-var-american-sign-language-interpreting: \f2a3; +$fa-var-amilia: \f36d; +$fa-var-anchor: \f13d; +$fa-var-android: \f17b; +$fa-var-angellist: \f209; +$fa-var-angle-double-down: \f103; +$fa-var-angle-double-left: \f100; +$fa-var-angle-double-right: \f101; +$fa-var-angle-double-up: \f102; +$fa-var-angle-down: \f107; +$fa-var-angle-left: \f104; +$fa-var-angle-right: \f105; +$fa-var-angle-up: \f106; +$fa-var-angrycreative: \f36e; +$fa-var-angular: \f420; +$fa-var-app-store: \f36f; +$fa-var-app-store-ios: \f370; +$fa-var-apper: \f371; +$fa-var-apple: \f179; +$fa-var-apple-pay: \f415; +$fa-var-archive: \f187; +$fa-var-arrow-alt-circle-down: \f358; +$fa-var-arrow-alt-circle-left: \f359; +$fa-var-arrow-alt-circle-right: \f35a; +$fa-var-arrow-alt-circle-up: \f35b; +$fa-var-arrow-circle-down: \f0ab; +$fa-var-arrow-circle-left: \f0a8; +$fa-var-arrow-circle-right: \f0a9; +$fa-var-arrow-circle-up: \f0aa; +$fa-var-arrow-down: \f063; +$fa-var-arrow-left: \f060; +$fa-var-arrow-right: \f061; +$fa-var-arrow-up: \f062; +$fa-var-arrows-alt: \f0b2; +$fa-var-arrows-alt-h: \f337; +$fa-var-arrows-alt-v: \f338; +$fa-var-assistive-listening-systems: \f2a2; +$fa-var-asterisk: \f069; +$fa-var-asymmetrik: \f372; +$fa-var-at: \f1fa; +$fa-var-audible: \f373; +$fa-var-audio-description: \f29e; +$fa-var-autoprefixer: \f41c; +$fa-var-avianex: \f374; +$fa-var-aviato: \f421; +$fa-var-aws: \f375; +$fa-var-backward: \f04a; +$fa-var-balance-scale: \f24e; +$fa-var-ban: \f05e; +$fa-var-band-aid: \f462; +$fa-var-bandcamp: \f2d5; +$fa-var-barcode: \f02a; +$fa-var-bars: \f0c9; +$fa-var-baseball-ball: \f433; +$fa-var-basketball-ball: \f434; +$fa-var-bath: \f2cd; +$fa-var-battery-empty: \f244; +$fa-var-battery-full: \f240; +$fa-var-battery-half: \f242; +$fa-var-battery-quarter: \f243; +$fa-var-battery-three-quarters: \f241; +$fa-var-bed: \f236; +$fa-var-beer: \f0fc; +$fa-var-behance: \f1b4; +$fa-var-behance-square: \f1b5; +$fa-var-bell: \f0f3; +$fa-var-bell-slash: \f1f6; +$fa-var-bicycle: \f206; +$fa-var-bimobject: \f378; +$fa-var-binoculars: \f1e5; +$fa-var-birthday-cake: \f1fd; +$fa-var-bitbucket: \f171; +$fa-var-bitcoin: \f379; +$fa-var-bity: \f37a; +$fa-var-black-tie: \f27e; +$fa-var-blackberry: \f37b; +$fa-var-blind: \f29d; +$fa-var-blogger: \f37c; +$fa-var-blogger-b: \f37d; +$fa-var-bluetooth: \f293; +$fa-var-bluetooth-b: \f294; +$fa-var-bold: \f032; +$fa-var-bolt: \f0e7; +$fa-var-bomb: \f1e2; +$fa-var-book: \f02d; +$fa-var-bookmark: \f02e; +$fa-var-bowling-ball: \f436; +$fa-var-box: \f466; +$fa-var-box-open: \f49e; +$fa-var-boxes: \f468; +$fa-var-braille: \f2a1; +$fa-var-briefcase: \f0b1; +$fa-var-briefcase-medical: \f469; +$fa-var-btc: \f15a; +$fa-var-bug: \f188; +$fa-var-building: \f1ad; +$fa-var-bullhorn: \f0a1; +$fa-var-bullseye: \f140; +$fa-var-burn: \f46a; +$fa-var-buromobelexperte: \f37f; +$fa-var-bus: \f207; +$fa-var-buysellads: \f20d; +$fa-var-calculator: \f1ec; +$fa-var-calendar: \f133; +$fa-var-calendar-alt: \f073; +$fa-var-calendar-check: \f274; +$fa-var-calendar-minus: \f272; +$fa-var-calendar-plus: \f271; +$fa-var-calendar-times: \f273; +$fa-var-camera: \f030; +$fa-var-camera-retro: \f083; +$fa-var-capsules: \f46b; +$fa-var-car: \f1b9; +$fa-var-caret-down: \f0d7; +$fa-var-caret-left: \f0d9; +$fa-var-caret-right: \f0da; +$fa-var-caret-square-down: \f150; +$fa-var-caret-square-left: \f191; +$fa-var-caret-square-right: \f152; +$fa-var-caret-square-up: \f151; +$fa-var-caret-up: \f0d8; +$fa-var-cart-arrow-down: \f218; +$fa-var-cart-plus: \f217; +$fa-var-cc-amazon-pay: \f42d; +$fa-var-cc-amex: \f1f3; +$fa-var-cc-apple-pay: \f416; +$fa-var-cc-diners-club: \f24c; +$fa-var-cc-discover: \f1f2; +$fa-var-cc-jcb: \f24b; +$fa-var-cc-mastercard: \f1f1; +$fa-var-cc-paypal: \f1f4; +$fa-var-cc-stripe: \f1f5; +$fa-var-cc-visa: \f1f0; +$fa-var-centercode: \f380; +$fa-var-certificate: \f0a3; +$fa-var-chart-area: \f1fe; +$fa-var-chart-bar: \f080; +$fa-var-chart-line: \f201; +$fa-var-chart-pie: \f200; +$fa-var-check: \f00c; +$fa-var-check-circle: \f058; +$fa-var-check-square: \f14a; +$fa-var-chess: \f439; +$fa-var-chess-bishop: \f43a; +$fa-var-chess-board: \f43c; +$fa-var-chess-king: \f43f; +$fa-var-chess-knight: \f441; +$fa-var-chess-pawn: \f443; +$fa-var-chess-queen: \f445; +$fa-var-chess-rook: \f447; +$fa-var-chevron-circle-down: \f13a; +$fa-var-chevron-circle-left: \f137; +$fa-var-chevron-circle-right: \f138; +$fa-var-chevron-circle-up: \f139; +$fa-var-chevron-down: \f078; +$fa-var-chevron-left: \f053; +$fa-var-chevron-right: \f054; +$fa-var-chevron-up: \f077; +$fa-var-child: \f1ae; +$fa-var-chrome: \f268; +$fa-var-circle: \f111; +$fa-var-circle-notch: \f1ce; +$fa-var-clipboard: \f328; +$fa-var-clipboard-check: \f46c; +$fa-var-clipboard-list: \f46d; +$fa-var-clock: \f017; +$fa-var-clone: \f24d; +$fa-var-closed-captioning: \f20a; +$fa-var-cloud: \f0c2; +$fa-var-cloud-download-alt: \f381; +$fa-var-cloud-upload-alt: \f382; +$fa-var-cloudscale: \f383; +$fa-var-cloudsmith: \f384; +$fa-var-cloudversify: \f385; +$fa-var-code: \f121; +$fa-var-code-branch: \f126; +$fa-var-codepen: \f1cb; +$fa-var-codiepie: \f284; +$fa-var-coffee: \f0f4; +$fa-var-cog: \f013; +$fa-var-cogs: \f085; +$fa-var-columns: \f0db; +$fa-var-comment: \f075; +$fa-var-comment-alt: \f27a; +$fa-var-comment-dots: \f4ad; +$fa-var-comment-slash: \f4b3; +$fa-var-comments: \f086; +$fa-var-compass: \f14e; +$fa-var-compress: \f066; +$fa-var-connectdevelop: \f20e; +$fa-var-contao: \f26d; +$fa-var-copy: \f0c5; +$fa-var-copyright: \f1f9; +$fa-var-couch: \f4b8; +$fa-var-cpanel: \f388; +$fa-var-creative-commons: \f25e; +$fa-var-credit-card: \f09d; +$fa-var-crop: \f125; +$fa-var-crosshairs: \f05b; +$fa-var-css3: \f13c; +$fa-var-css3-alt: \f38b; +$fa-var-cube: \f1b2; +$fa-var-cubes: \f1b3; +$fa-var-cut: \f0c4; +$fa-var-cuttlefish: \f38c; +$fa-var-d-and-d: \f38d; +$fa-var-dashcube: \f210; +$fa-var-database: \f1c0; +$fa-var-deaf: \f2a4; +$fa-var-delicious: \f1a5; +$fa-var-deploydog: \f38e; +$fa-var-deskpro: \f38f; +$fa-var-desktop: \f108; +$fa-var-deviantart: \f1bd; +$fa-var-diagnoses: \f470; +$fa-var-digg: \f1a6; +$fa-var-digital-ocean: \f391; +$fa-var-discord: \f392; +$fa-var-discourse: \f393; +$fa-var-dna: \f471; +$fa-var-dochub: \f394; +$fa-var-docker: \f395; +$fa-var-dollar-sign: \f155; +$fa-var-dolly: \f472; +$fa-var-dolly-flatbed: \f474; +$fa-var-donate: \f4b9; +$fa-var-dot-circle: \f192; +$fa-var-dove: \f4ba; +$fa-var-download: \f019; +$fa-var-draft2digital: \f396; +$fa-var-dribbble: \f17d; +$fa-var-dribbble-square: \f397; +$fa-var-dropbox: \f16b; +$fa-var-drupal: \f1a9; +$fa-var-dyalog: \f399; +$fa-var-earlybirds: \f39a; +$fa-var-edge: \f282; +$fa-var-edit: \f044; +$fa-var-eject: \f052; +$fa-var-elementor: \f430; +$fa-var-ellipsis-h: \f141; +$fa-var-ellipsis-v: \f142; +$fa-var-ember: \f423; +$fa-var-empire: \f1d1; +$fa-var-envelope: \f0e0; +$fa-var-envelope-open: \f2b6; +$fa-var-envelope-square: \f199; +$fa-var-envira: \f299; +$fa-var-eraser: \f12d; +$fa-var-erlang: \f39d; +$fa-var-ethereum: \f42e; +$fa-var-etsy: \f2d7; +$fa-var-euro-sign: \f153; +$fa-var-exchange-alt: \f362; +$fa-var-exclamation: \f12a; +$fa-var-exclamation-circle: \f06a; +$fa-var-exclamation-triangle: \f071; +$fa-var-expand: \f065; +$fa-var-expand-arrows-alt: \f31e; +$fa-var-expeditedssl: \f23e; +$fa-var-external-link-alt: \f35d; +$fa-var-external-link-square-alt: \f360; +$fa-var-eye: \f06e; +$fa-var-eye-dropper: \f1fb; +$fa-var-eye-slash: \f070; +$fa-var-facebook: \f09a; +$fa-var-facebook-f: \f39e; +$fa-var-facebook-messenger: \f39f; +$fa-var-facebook-square: \f082; +$fa-var-fast-backward: \f049; +$fa-var-fast-forward: \f050; +$fa-var-fax: \f1ac; +$fa-var-female: \f182; +$fa-var-fighter-jet: \f0fb; +$fa-var-file: \f15b; +$fa-var-file-alt: \f15c; +$fa-var-file-archive: \f1c6; +$fa-var-file-audio: \f1c7; +$fa-var-file-code: \f1c9; +$fa-var-file-excel: \f1c3; +$fa-var-file-image: \f1c5; +$fa-var-file-medical: \f477; +$fa-var-file-medical-alt: \f478; +$fa-var-file-pdf: \f1c1; +$fa-var-file-powerpoint: \f1c4; +$fa-var-file-video: \f1c8; +$fa-var-file-word: \f1c2; +$fa-var-film: \f008; +$fa-var-filter: \f0b0; +$fa-var-fire: \f06d; +$fa-var-fire-extinguisher: \f134; +$fa-var-firefox: \f269; +$fa-var-first-aid: \f479; +$fa-var-first-order: \f2b0; +$fa-var-firstdraft: \f3a1; +$fa-var-flag: \f024; +$fa-var-flag-checkered: \f11e; +$fa-var-flask: \f0c3; +$fa-var-flickr: \f16e; +$fa-var-flipboard: \f44d; +$fa-var-fly: \f417; +$fa-var-folder: \f07b; +$fa-var-folder-open: \f07c; +$fa-var-font: \f031; +$fa-var-font-awesome: \f2b4; +$fa-var-font-awesome-alt: \f35c; +$fa-var-font-awesome-flag: \f425; +$fa-var-fonticons: \f280; +$fa-var-fonticons-fi: \f3a2; +$fa-var-football-ball: \f44e; +$fa-var-fort-awesome: \f286; +$fa-var-fort-awesome-alt: \f3a3; +$fa-var-forumbee: \f211; +$fa-var-forward: \f04e; +$fa-var-foursquare: \f180; +$fa-var-free-code-camp: \f2c5; +$fa-var-freebsd: \f3a4; +$fa-var-frown: \f119; +$fa-var-futbol: \f1e3; +$fa-var-gamepad: \f11b; +$fa-var-gavel: \f0e3; +$fa-var-gem: \f3a5; +$fa-var-genderless: \f22d; +$fa-var-get-pocket: \f265; +$fa-var-gg: \f260; +$fa-var-gg-circle: \f261; +$fa-var-gift: \f06b; +$fa-var-git: \f1d3; +$fa-var-git-square: \f1d2; +$fa-var-github: \f09b; +$fa-var-github-alt: \f113; +$fa-var-github-square: \f092; +$fa-var-gitkraken: \f3a6; +$fa-var-gitlab: \f296; +$fa-var-gitter: \f426; +$fa-var-glass-martini: \f000; +$fa-var-glide: \f2a5; +$fa-var-glide-g: \f2a6; +$fa-var-globe: \f0ac; +$fa-var-gofore: \f3a7; +$fa-var-golf-ball: \f450; +$fa-var-goodreads: \f3a8; +$fa-var-goodreads-g: \f3a9; +$fa-var-google: \f1a0; +$fa-var-google-drive: \f3aa; +$fa-var-google-play: \f3ab; +$fa-var-google-plus: \f2b3; +$fa-var-google-plus-g: \f0d5; +$fa-var-google-plus-square: \f0d4; +$fa-var-google-wallet: \f1ee; +$fa-var-graduation-cap: \f19d; +$fa-var-gratipay: \f184; +$fa-var-grav: \f2d6; +$fa-var-gripfire: \f3ac; +$fa-var-grunt: \f3ad; +$fa-var-gulp: \f3ae; +$fa-var-h-square: \f0fd; +$fa-var-hacker-news: \f1d4; +$fa-var-hacker-news-square: \f3af; +$fa-var-hand-holding: \f4bd; +$fa-var-hand-holding-heart: \f4be; +$fa-var-hand-holding-usd: \f4c0; +$fa-var-hand-lizard: \f258; +$fa-var-hand-paper: \f256; +$fa-var-hand-peace: \f25b; +$fa-var-hand-point-down: \f0a7; +$fa-var-hand-point-left: \f0a5; +$fa-var-hand-point-right: \f0a4; +$fa-var-hand-point-up: \f0a6; +$fa-var-hand-pointer: \f25a; +$fa-var-hand-rock: \f255; +$fa-var-hand-scissors: \f257; +$fa-var-hand-spock: \f259; +$fa-var-hands: \f4c2; +$fa-var-hands-helping: \f4c4; +$fa-var-handshake: \f2b5; +$fa-var-hashtag: \f292; +$fa-var-hdd: \f0a0; +$fa-var-heading: \f1dc; +$fa-var-headphones: \f025; +$fa-var-heart: \f004; +$fa-var-heartbeat: \f21e; +$fa-var-hips: \f452; +$fa-var-hire-a-helper: \f3b0; +$fa-var-history: \f1da; +$fa-var-hockey-puck: \f453; +$fa-var-home: \f015; +$fa-var-hooli: \f427; +$fa-var-hospital: \f0f8; +$fa-var-hospital-alt: \f47d; +$fa-var-hospital-symbol: \f47e; +$fa-var-hotjar: \f3b1; +$fa-var-hourglass: \f254; +$fa-var-hourglass-end: \f253; +$fa-var-hourglass-half: \f252; +$fa-var-hourglass-start: \f251; +$fa-var-houzz: \f27c; +$fa-var-html5: \f13b; +$fa-var-hubspot: \f3b2; +$fa-var-i-cursor: \f246; +$fa-var-id-badge: \f2c1; +$fa-var-id-card: \f2c2; +$fa-var-id-card-alt: \f47f; +$fa-var-image: \f03e; +$fa-var-images: \f302; +$fa-var-imdb: \f2d8; +$fa-var-inbox: \f01c; +$fa-var-indent: \f03c; +$fa-var-industry: \f275; +$fa-var-info: \f129; +$fa-var-info-circle: \f05a; +$fa-var-instagram: \f16d; +$fa-var-internet-explorer: \f26b; +$fa-var-ioxhost: \f208; +$fa-var-italic: \f033; +$fa-var-itunes: \f3b4; +$fa-var-itunes-note: \f3b5; +$fa-var-java: \f4e4; +$fa-var-jenkins: \f3b6; +$fa-var-joget: \f3b7; +$fa-var-joomla: \f1aa; +$fa-var-js: \f3b8; +$fa-var-js-square: \f3b9; +$fa-var-jsfiddle: \f1cc; +$fa-var-key: \f084; +$fa-var-keyboard: \f11c; +$fa-var-keycdn: \f3ba; +$fa-var-kickstarter: \f3bb; +$fa-var-kickstarter-k: \f3bc; +$fa-var-korvue: \f42f; +$fa-var-language: \f1ab; +$fa-var-laptop: \f109; +$fa-var-laravel: \f3bd; +$fa-var-lastfm: \f202; +$fa-var-lastfm-square: \f203; +$fa-var-leaf: \f06c; +$fa-var-leanpub: \f212; +$fa-var-lemon: \f094; +$fa-var-less: \f41d; +$fa-var-level-down-alt: \f3be; +$fa-var-level-up-alt: \f3bf; +$fa-var-life-ring: \f1cd; +$fa-var-lightbulb: \f0eb; +$fa-var-line: \f3c0; +$fa-var-link: \f0c1; +$fa-var-linkedin: \f08c; +$fa-var-linkedin-in: \f0e1; +$fa-var-linode: \f2b8; +$fa-var-linux: \f17c; +$fa-var-lira-sign: \f195; +$fa-var-list: \f03a; +$fa-var-list-alt: \f022; +$fa-var-list-ol: \f0cb; +$fa-var-list-ul: \f0ca; +$fa-var-location-arrow: \f124; +$fa-var-lock: \f023; +$fa-var-lock-open: \f3c1; +$fa-var-long-arrow-alt-down: \f309; +$fa-var-long-arrow-alt-left: \f30a; +$fa-var-long-arrow-alt-right: \f30b; +$fa-var-long-arrow-alt-up: \f30c; +$fa-var-low-vision: \f2a8; +$fa-var-lyft: \f3c3; +$fa-var-magento: \f3c4; +$fa-var-magic: \f0d0; +$fa-var-magnet: \f076; +$fa-var-male: \f183; +$fa-var-map: \f279; +$fa-var-map-marker: \f041; +$fa-var-map-marker-alt: \f3c5; +$fa-var-map-pin: \f276; +$fa-var-map-signs: \f277; +$fa-var-mars: \f222; +$fa-var-mars-double: \f227; +$fa-var-mars-stroke: \f229; +$fa-var-mars-stroke-h: \f22b; +$fa-var-mars-stroke-v: \f22a; +$fa-var-maxcdn: \f136; +$fa-var-medapps: \f3c6; +$fa-var-medium: \f23a; +$fa-var-medium-m: \f3c7; +$fa-var-medkit: \f0fa; +$fa-var-medrt: \f3c8; +$fa-var-meetup: \f2e0; +$fa-var-meh: \f11a; +$fa-var-mercury: \f223; +$fa-var-microchip: \f2db; +$fa-var-microphone: \f130; +$fa-var-microphone-slash: \f131; +$fa-var-microsoft: \f3ca; +$fa-var-minus: \f068; +$fa-var-minus-circle: \f056; +$fa-var-minus-square: \f146; +$fa-var-mix: \f3cb; +$fa-var-mixcloud: \f289; +$fa-var-mizuni: \f3cc; +$fa-var-mobile: \f10b; +$fa-var-mobile-alt: \f3cd; +$fa-var-modx: \f285; +$fa-var-monero: \f3d0; +$fa-var-money-bill-alt: \f3d1; +$fa-var-moon: \f186; +$fa-var-motorcycle: \f21c; +$fa-var-mouse-pointer: \f245; +$fa-var-music: \f001; +$fa-var-napster: \f3d2; +$fa-var-neuter: \f22c; +$fa-var-newspaper: \f1ea; +$fa-var-nintendo-switch: \f418; +$fa-var-node: \f419; +$fa-var-node-js: \f3d3; +$fa-var-notes-medical: \f481; +$fa-var-npm: \f3d4; +$fa-var-ns8: \f3d5; +$fa-var-nutritionix: \f3d6; +$fa-var-object-group: \f247; +$fa-var-object-ungroup: \f248; +$fa-var-odnoklassniki: \f263; +$fa-var-odnoklassniki-square: \f264; +$fa-var-opencart: \f23d; +$fa-var-openid: \f19b; +$fa-var-opera: \f26a; +$fa-var-optin-monster: \f23c; +$fa-var-osi: \f41a; +$fa-var-outdent: \f03b; +$fa-var-page4: \f3d7; +$fa-var-pagelines: \f18c; +$fa-var-paint-brush: \f1fc; +$fa-var-palfed: \f3d8; +$fa-var-pallet: \f482; +$fa-var-paper-plane: \f1d8; +$fa-var-paperclip: \f0c6; +$fa-var-parachute-box: \f4cd; +$fa-var-paragraph: \f1dd; +$fa-var-paste: \f0ea; +$fa-var-patreon: \f3d9; +$fa-var-pause: \f04c; +$fa-var-pause-circle: \f28b; +$fa-var-paw: \f1b0; +$fa-var-paypal: \f1ed; +$fa-var-pen-square: \f14b; +$fa-var-pencil-alt: \f303; +$fa-var-people-carry: \f4ce; +$fa-var-percent: \f295; +$fa-var-periscope: \f3da; +$fa-var-phabricator: \f3db; +$fa-var-phoenix-framework: \f3dc; +$fa-var-phone: \f095; +$fa-var-phone-slash: \f3dd; +$fa-var-phone-square: \f098; +$fa-var-phone-volume: \f2a0; +$fa-var-php: \f457; +$fa-var-pied-piper: \f2ae; +$fa-var-pied-piper-alt: \f1a8; +$fa-var-pied-piper-hat: \f4e5; +$fa-var-pied-piper-pp: \f1a7; +$fa-var-piggy-bank: \f4d3; +$fa-var-pills: \f484; +$fa-var-pinterest: \f0d2; +$fa-var-pinterest-p: \f231; +$fa-var-pinterest-square: \f0d3; +$fa-var-plane: \f072; +$fa-var-play: \f04b; +$fa-var-play-circle: \f144; +$fa-var-playstation: \f3df; +$fa-var-plug: \f1e6; +$fa-var-plus: \f067; +$fa-var-plus-circle: \f055; +$fa-var-plus-square: \f0fe; +$fa-var-podcast: \f2ce; +$fa-var-poo: \f2fe; +$fa-var-pound-sign: \f154; +$fa-var-power-off: \f011; +$fa-var-prescription-bottle: \f485; +$fa-var-prescription-bottle-alt: \f486; +$fa-var-print: \f02f; +$fa-var-procedures: \f487; +$fa-var-product-hunt: \f288; +$fa-var-pushed: \f3e1; +$fa-var-puzzle-piece: \f12e; +$fa-var-python: \f3e2; +$fa-var-qq: \f1d6; +$fa-var-qrcode: \f029; +$fa-var-question: \f128; +$fa-var-question-circle: \f059; +$fa-var-quidditch: \f458; +$fa-var-quinscape: \f459; +$fa-var-quora: \f2c4; +$fa-var-quote-left: \f10d; +$fa-var-quote-right: \f10e; +$fa-var-random: \f074; +$fa-var-ravelry: \f2d9; +$fa-var-react: \f41b; +$fa-var-readme: \f4d5; +$fa-var-rebel: \f1d0; +$fa-var-recycle: \f1b8; +$fa-var-red-river: \f3e3; +$fa-var-reddit: \f1a1; +$fa-var-reddit-alien: \f281; +$fa-var-reddit-square: \f1a2; +$fa-var-redo: \f01e; +$fa-var-redo-alt: \f2f9; +$fa-var-registered: \f25d; +$fa-var-rendact: \f3e4; +$fa-var-renren: \f18b; +$fa-var-reply: \f3e5; +$fa-var-reply-all: \f122; +$fa-var-replyd: \f3e6; +$fa-var-resolving: \f3e7; +$fa-var-retweet: \f079; +$fa-var-ribbon: \f4d6; +$fa-var-road: \f018; +$fa-var-rocket: \f135; +$fa-var-rocketchat: \f3e8; +$fa-var-rockrms: \f3e9; +$fa-var-rss: \f09e; +$fa-var-rss-square: \f143; +$fa-var-ruble-sign: \f158; +$fa-var-rupee-sign: \f156; +$fa-var-safari: \f267; +$fa-var-sass: \f41e; +$fa-var-save: \f0c7; +$fa-var-schlix: \f3ea; +$fa-var-scribd: \f28a; +$fa-var-search: \f002; +$fa-var-search-minus: \f010; +$fa-var-search-plus: \f00e; +$fa-var-searchengin: \f3eb; +$fa-var-seedling: \f4d8; +$fa-var-sellcast: \f2da; +$fa-var-sellsy: \f213; +$fa-var-server: \f233; +$fa-var-servicestack: \f3ec; +$fa-var-share: \f064; +$fa-var-share-alt: \f1e0; +$fa-var-share-alt-square: \f1e1; +$fa-var-share-square: \f14d; +$fa-var-shekel-sign: \f20b; +$fa-var-shield-alt: \f3ed; +$fa-var-ship: \f21a; +$fa-var-shipping-fast: \f48b; +$fa-var-shirtsinbulk: \f214; +$fa-var-shopping-bag: \f290; +$fa-var-shopping-basket: \f291; +$fa-var-shopping-cart: \f07a; +$fa-var-shower: \f2cc; +$fa-var-sign: \f4d9; +$fa-var-sign-in-alt: \f2f6; +$fa-var-sign-language: \f2a7; +$fa-var-sign-out-alt: \f2f5; +$fa-var-signal: \f012; +$fa-var-simplybuilt: \f215; +$fa-var-sistrix: \f3ee; +$fa-var-sitemap: \f0e8; +$fa-var-skyatlas: \f216; +$fa-var-skype: \f17e; +$fa-var-slack: \f198; +$fa-var-slack-hash: \f3ef; +$fa-var-sliders-h: \f1de; +$fa-var-slideshare: \f1e7; +$fa-var-smile: \f118; +$fa-var-smoking: \f48d; +$fa-var-snapchat: \f2ab; +$fa-var-snapchat-ghost: \f2ac; +$fa-var-snapchat-square: \f2ad; +$fa-var-snowflake: \f2dc; +$fa-var-sort: \f0dc; +$fa-var-sort-alpha-down: \f15d; +$fa-var-sort-alpha-up: \f15e; +$fa-var-sort-amount-down: \f160; +$fa-var-sort-amount-up: \f161; +$fa-var-sort-down: \f0dd; +$fa-var-sort-numeric-down: \f162; +$fa-var-sort-numeric-up: \f163; +$fa-var-sort-up: \f0de; +$fa-var-soundcloud: \f1be; +$fa-var-space-shuttle: \f197; +$fa-var-speakap: \f3f3; +$fa-var-spinner: \f110; +$fa-var-spotify: \f1bc; +$fa-var-square: \f0c8; +$fa-var-square-full: \f45c; +$fa-var-stack-exchange: \f18d; +$fa-var-stack-overflow: \f16c; +$fa-var-star: \f005; +$fa-var-star-half: \f089; +$fa-var-staylinked: \f3f5; +$fa-var-steam: \f1b6; +$fa-var-steam-square: \f1b7; +$fa-var-steam-symbol: \f3f6; +$fa-var-step-backward: \f048; +$fa-var-step-forward: \f051; +$fa-var-stethoscope: \f0f1; +$fa-var-sticker-mule: \f3f7; +$fa-var-sticky-note: \f249; +$fa-var-stop: \f04d; +$fa-var-stop-circle: \f28d; +$fa-var-stopwatch: \f2f2; +$fa-var-strava: \f428; +$fa-var-street-view: \f21d; +$fa-var-strikethrough: \f0cc; +$fa-var-stripe: \f429; +$fa-var-stripe-s: \f42a; +$fa-var-studiovinari: \f3f8; +$fa-var-stumbleupon: \f1a4; +$fa-var-stumbleupon-circle: \f1a3; +$fa-var-subscript: \f12c; +$fa-var-subway: \f239; +$fa-var-suitcase: \f0f2; +$fa-var-sun: \f185; +$fa-var-superpowers: \f2dd; +$fa-var-superscript: \f12b; +$fa-var-supple: \f3f9; +$fa-var-sync: \f021; +$fa-var-sync-alt: \f2f1; +$fa-var-syringe: \f48e; +$fa-var-table: \f0ce; +$fa-var-table-tennis: \f45d; +$fa-var-tablet: \f10a; +$fa-var-tablet-alt: \f3fa; +$fa-var-tablets: \f490; +$fa-var-tachometer-alt: \f3fd; +$fa-var-tag: \f02b; +$fa-var-tags: \f02c; +$fa-var-tape: \f4db; +$fa-var-tasks: \f0ae; +$fa-var-taxi: \f1ba; +$fa-var-telegram: \f2c6; +$fa-var-telegram-plane: \f3fe; +$fa-var-tencent-weibo: \f1d5; +$fa-var-terminal: \f120; +$fa-var-text-height: \f034; +$fa-var-text-width: \f035; +$fa-var-th: \f00a; +$fa-var-th-large: \f009; +$fa-var-th-list: \f00b; +$fa-var-themeisle: \f2b2; +$fa-var-thermometer: \f491; +$fa-var-thermometer-empty: \f2cb; +$fa-var-thermometer-full: \f2c7; +$fa-var-thermometer-half: \f2c9; +$fa-var-thermometer-quarter: \f2ca; +$fa-var-thermometer-three-quarters: \f2c8; +$fa-var-thumbs-down: \f165; +$fa-var-thumbs-up: \f164; +$fa-var-thumbtack: \f08d; +$fa-var-ticket-alt: \f3ff; +$fa-var-times: \f00d; +$fa-var-times-circle: \f057; +$fa-var-tint: \f043; +$fa-var-toggle-off: \f204; +$fa-var-toggle-on: \f205; +$fa-var-trademark: \f25c; +$fa-var-train: \f238; +$fa-var-transgender: \f224; +$fa-var-transgender-alt: \f225; +$fa-var-trash: \f1f8; +$fa-var-trash-alt: \f2ed; +$fa-var-tree: \f1bb; +$fa-var-trello: \f181; +$fa-var-tripadvisor: \f262; +$fa-var-trophy: \f091; +$fa-var-truck: \f0d1; +$fa-var-truck-loading: \f4de; +$fa-var-truck-moving: \f4df; +$fa-var-tty: \f1e4; +$fa-var-tumblr: \f173; +$fa-var-tumblr-square: \f174; +$fa-var-tv: \f26c; +$fa-var-twitch: \f1e8; +$fa-var-twitter: \f099; +$fa-var-twitter-square: \f081; +$fa-var-typo3: \f42b; +$fa-var-uber: \f402; +$fa-var-uikit: \f403; +$fa-var-umbrella: \f0e9; +$fa-var-underline: \f0cd; +$fa-var-undo: \f0e2; +$fa-var-undo-alt: \f2ea; +$fa-var-uniregistry: \f404; +$fa-var-universal-access: \f29a; +$fa-var-university: \f19c; +$fa-var-unlink: \f127; +$fa-var-unlock: \f09c; +$fa-var-unlock-alt: \f13e; +$fa-var-untappd: \f405; +$fa-var-upload: \f093; +$fa-var-usb: \f287; +$fa-var-user: \f007; +$fa-var-user-circle: \f2bd; +$fa-var-user-md: \f0f0; +$fa-var-user-plus: \f234; +$fa-var-user-secret: \f21b; +$fa-var-user-times: \f235; +$fa-var-users: \f0c0; +$fa-var-ussunnah: \f407; +$fa-var-utensil-spoon: \f2e5; +$fa-var-utensils: \f2e7; +$fa-var-vaadin: \f408; +$fa-var-venus: \f221; +$fa-var-venus-double: \f226; +$fa-var-venus-mars: \f228; +$fa-var-viacoin: \f237; +$fa-var-viadeo: \f2a9; +$fa-var-viadeo-square: \f2aa; +$fa-var-vial: \f492; +$fa-var-vials: \f493; +$fa-var-viber: \f409; +$fa-var-video: \f03d; +$fa-var-video-slash: \f4e2; +$fa-var-vimeo: \f40a; +$fa-var-vimeo-square: \f194; +$fa-var-vimeo-v: \f27d; +$fa-var-vine: \f1ca; +$fa-var-vk: \f189; +$fa-var-vnv: \f40b; +$fa-var-volleyball-ball: \f45f; +$fa-var-volume-down: \f027; +$fa-var-volume-off: \f026; +$fa-var-volume-up: \f028; +$fa-var-vuejs: \f41f; +$fa-var-warehouse: \f494; +$fa-var-weibo: \f18a; +$fa-var-weight: \f496; +$fa-var-weixin: \f1d7; +$fa-var-whatsapp: \f232; +$fa-var-whatsapp-square: \f40c; +$fa-var-wheelchair: \f193; +$fa-var-whmcs: \f40d; +$fa-var-wifi: \f1eb; +$fa-var-wikipedia-w: \f266; +$fa-var-window-close: \f410; +$fa-var-window-maximize: \f2d0; +$fa-var-window-minimize: \f2d1; +$fa-var-window-restore: \f2d2; +$fa-var-windows: \f17a; +$fa-var-wine-glass: \f4e3; +$fa-var-won-sign: \f159; +$fa-var-wordpress: \f19a; +$fa-var-wordpress-simple: \f411; +$fa-var-wpbeginner: \f297; +$fa-var-wpexplorer: \f2de; +$fa-var-wpforms: \f298; +$fa-var-wrench: \f0ad; +$fa-var-x-ray: \f497; +$fa-var-xbox: \f412; +$fa-var-xing: \f168; +$fa-var-xing-square: \f169; +$fa-var-y-combinator: \f23b; +$fa-var-yahoo: \f19e; +$fa-var-yandex: \f413; +$fa-var-yandex-international: \f414; +$fa-var-yelp: \f1e9; +$fa-var-yen-sign: \f157; +$fa-var-yoast: \f2b1; +$fa-var-youtube: \f167; +$fa-var-youtube-square: \f431; diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fa-brands.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fa-brands.scss new file mode 100644 index 000000000000..3f4c54d781fd --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fa-brands.scss @@ -0,0 +1,21 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@import 'variables'; + +@font-face { + font-family: 'Font Awesome 5 Brands'; + font-style: normal; + font-weight: normal; + src: url('#{$fa-font-path}/fa-brands-400.eot'); + src: url('#{$fa-font-path}/fa-brands-400.eot?#iefix') format('embedded-opentype'), + url('#{$fa-font-path}/fa-brands-400.woff2') format('woff2'), + url('#{$fa-font-path}/fa-brands-400.woff') format('woff'), + url('#{$fa-font-path}/fa-brands-400.ttf') format('truetype'), + url('#{$fa-font-path}/fa-brands-400.svg#fontawesome') format('svg'); +} + +.fab { + font-family: 'Font Awesome 5 Brands'; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fa-regular.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fa-regular.scss new file mode 100644 index 000000000000..2faa99d31c41 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fa-regular.scss @@ -0,0 +1,22 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@import 'variables'; + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 400; + src: url('#{$fa-font-path}/fa-regular-400.eot'); + src: url('#{$fa-font-path}/fa-regular-400.eot?#iefix') format('embedded-opentype'), + url('#{$fa-font-path}/fa-regular-400.woff2') format('woff2'), + url('#{$fa-font-path}/fa-regular-400.woff') format('woff'), + url('#{$fa-font-path}/fa-regular-400.ttf') format('truetype'), + url('#{$fa-font-path}/fa-regular-400.svg#fontawesome') format('svg'); +} + +.far { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fa-solid.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fa-solid.scss new file mode 100644 index 000000000000..cb10c11774e5 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fa-solid.scss @@ -0,0 +1,23 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@import 'variables'; + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-style: normal; + font-weight: 900; + src: url('#{$fa-font-path}/fa-solid-900.eot'); + src: url('#{$fa-font-path}/fa-solid-900.eot?#iefix') format('embedded-opentype'), + url('#{$fa-font-path}/fa-solid-900.woff2') format('woff2'), + url('#{$fa-font-path}/fa-solid-900.woff') format('woff'), + url('#{$fa-font-path}/fa-solid-900.ttf') format('truetype'), + url('#{$fa-font-path}/fa-solid-900.svg#fontawesome') format('svg'); +} + +.fa, +.fas { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fontawesome.scss b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fontawesome.scss new file mode 100644 index 000000000000..0a3f8ac63ee6 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/scss/fontawesome.scss @@ -0,0 +1,16 @@ +/*! + * Font Awesome Free 5.0.10 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@import 'variables'; +@import 'mixins'; +@import 'core'; +@import 'larger'; +@import 'fixed-width'; +@import 'list'; +@import 'bordered-pulled'; +@import 'animated'; +@import 'rotated-flipped'; +@import 'stacked'; +@import 'icons'; +@import 'screen-reader'; diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.eot b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.eot new file mode 100644 index 000000000000..9d49a59a6797 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.svg b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.svg new file mode 100644 index 000000000000..bf573a1af139 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.svg @@ -0,0 +1,1017 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.ttf b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.ttf new file mode 100644 index 000000000000..374f8ee9146f Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.woff b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.woff new file mode 100644 index 000000000000..c7d31eb1e813 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.woff2 b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.woff2 new file mode 100644 index 000000000000..1ced125fe9e5 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-brands-400.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.eot b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.eot new file mode 100644 index 000000000000..3ba8c46bf13e Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.svg b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.svg new file mode 100644 index 000000000000..74db206ca881 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.svg @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.ttf b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.ttf new file mode 100644 index 000000000000..7412d88352a9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.woff b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.woff new file mode 100644 index 000000000000..797a15cbfb98 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.woff2 b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.woff2 new file mode 100644 index 000000000000..b75da04b548e Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-regular-400.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.eot b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.eot new file mode 100644 index 000000000000..3c5350af8e72 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.svg b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.svg new file mode 100644 index 000000000000..3e9cbaea9dcc --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.svg @@ -0,0 +1,1644 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.ttf b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.ttf new file mode 100644 index 000000000000..9f268151e6f2 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.woff b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.woff new file mode 100644 index 000000000000..66d6e9e42870 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.woff2 b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.woff2 new file mode 100644 index 000000000000..84cadecde7c6 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/fontawesome-free-5.0.10/webfonts/fa-solid-900.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/fonts.css b/web/src/main/webapp/v2/src/assets/fonts/fonts.css new file mode 100755 index 000000000000..39d1aac81f32 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/fonts.css @@ -0,0 +1,70 @@ +/* nanum-gothic-regular - korean */ +@font-face { + font-family: 'Nanum Gothic'; + font-style: normal; + font-weight: 400; + src: local('NanumGothic'), + url('nanum/nanum-gothic-v8-korean-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('nanum/nanum-gothic-v8-korean-regular.woff') format('woff'), /* Modern Browsers */ + url('nanum/nanum-gothic-v8-korean-regular.ttf') format('truetype') /* Safari, Android, iOS */ +} +/* nanum-gothic-700 - korean */ +@font-face { + font-family: 'Nanum Gothic'; + font-style: normal; + font-weight: 700; + src: local('NanumGothic Bold'), local('NanumGothic-Bold'), + url('nanum/nanum-gothic-v8-korean-700.woff2') format('woff2'), /* Super Modern Browsers */ + url('nanum/nanum-gothic-v8-korean-700.woff') format('woff'), /* Modern Browsers */ + url('nanum/nanum-gothic-v8-korean-700.ttf') format('truetype') /* Safari, Android, iOS */ +} +/* nanum-gothic-800 - korean */ +@font-face { + font-family: 'Nanum Gothic'; + font-style: normal; + font-weight: 800; + src: local('NanumGothic ExtraBold'), local('NanumGothic-ExtraBold'), + url('nanum/nanum-gothic-v8-korean-800.woff2') format('woff2'), /* Super Modern Browsers */ + url('nanum/nanum-gothic-v8-korean-800.woff') format('woff'), /* Modern Browsers */ + url('nanum/nanum-gothic-v8-korean-800.ttf') format('truetype') /* Safari, Android, iOS */ +} +/* open-sans-regular - latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), + url('opensans/open-sans-v15-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('opensans/open-sans-v15-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('opensans/open-sans-v15-latin-regular.ttf') format('truetype') /* Safari, Android, iOS */ +} +/* open-sans-600 - latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), + url('opensans/open-sans-v15-latin-600.woff2') format('woff2'), /* Super Modern Browsers */ + url('opensans/open-sans-v15-latin-600.woff') format('woff'), /* Modern Browsers */ + url('opensans/open-sans-v15-latin-600.ttf') format('truetype') /* Safari, Android, iOS */ +} +/* open-sans-700 - latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), + url('opensans/open-sans-v15-latin-700.woff2') format('woff2'), /* Super Modern Browsers */ + url('opensans/open-sans-v15-latin-700.woff') format('woff'), /* Modern Browsers */ + url('opensans/open-sans-v15-latin-700.ttf') format('truetype') /* Safari, Android, iOS */ +} +/* open-sans-800 - latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 800; + src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'), + url('opensans/open-sans-v15-latin-800.woff2') format('woff2'), /* Super Modern Browsers */ + url('opensans/open-sans-v15-latin-800.woff') format('woff'), /* Modern Browsers */ + url('opensans/open-sans-v15-latin-800.ttf') format('truetype') /* Safari, Android, iOS */ +} diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.eot b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.eot new file mode 100644 index 000000000000..a11a055b03b9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.svg b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.svg new file mode 100644 index 000000000000..25dddff33bb1 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.svg @@ -0,0 +1,488 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.ttf b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.ttf new file mode 100644 index 000000000000..fc3d365f7835 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.woff b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.woff new file mode 100644 index 000000000000..d17741b805a5 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.woff2 b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.woff2 new file mode 100644 index 000000000000..9ba9556d80b0 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-700.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.eot b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.eot new file mode 100644 index 000000000000..e25413ce3df7 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.svg b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.svg new file mode 100644 index 000000000000..ad5f1dd9034f --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.svg @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.ttf b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.ttf new file mode 100644 index 000000000000..4bf036ca4657 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.woff b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.woff new file mode 100644 index 000000000000..cb8e5bc5e498 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.woff2 b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.woff2 new file mode 100644 index 000000000000..b82f143aec53 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-800.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.eot b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.eot new file mode 100644 index 000000000000..b192d61694d5 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.svg b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.svg new file mode 100644 index 000000000000..7365512e498d --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.svg @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.ttf b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.ttf new file mode 100644 index 000000000000..2f08e65b3ab4 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.woff b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.woff new file mode 100644 index 000000000000..0394f4ec57d1 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.woff2 b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.woff2 new file mode 100644 index 000000000000..1bfe79c9edb2 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/nanum/nanum-gothic-v8-korean-regular.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.eot b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.eot new file mode 100644 index 000000000000..2d978e8861ca Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.svg b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.svg new file mode 100644 index 000000000000..410561e7821c --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.ttf b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.ttf new file mode 100644 index 000000000000..bc77ab679237 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.woff b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.woff new file mode 100644 index 000000000000..5a604b3a010d Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.woff2 b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.woff2 new file mode 100644 index 000000000000..a0965b7a8990 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-600.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.eot b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.eot new file mode 100644 index 000000000000..bf88bfad7824 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.svg b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.svg new file mode 100644 index 000000000000..8e6b61ade171 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.svg @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.ttf b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.ttf new file mode 100644 index 000000000000..11aec0f49e40 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.woff b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.woff new file mode 100644 index 000000000000..2523e953cb97 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.woff2 b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.woff2 new file mode 100644 index 000000000000..2b04b15bb70a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-700.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.eot b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.eot new file mode 100644 index 000000000000..a0f8a0f37555 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.svg b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.svg new file mode 100644 index 000000000000..f2a2d9f6e746 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.ttf b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.ttf new file mode 100644 index 000000000000..bafdd40f09a8 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.woff b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.woff new file mode 100644 index 000000000000..41ae78830858 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.woff2 b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.woff2 new file mode 100644 index 000000000000..53188bc5c0b9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-800.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.eot b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.eot new file mode 100644 index 000000000000..1a8b1160df0f Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.eot differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.svg b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.svg new file mode 100644 index 000000000000..78eb653a75e6 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.ttf b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.ttf new file mode 100644 index 000000000000..9d4e8e526d7e Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.ttf differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.woff b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.woff new file mode 100644 index 000000000000..e495e6f010c9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.woff differ diff --git a/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.woff2 b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.woff2 new file mode 100644 index 000000000000..c8050c25f8c9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/fonts/opensans/open-sans-v15-latin-regular.woff2 differ diff --git a/web/src/main/webapp/v2/src/assets/i18n/en.json b/web/src/main/webapp/v2/src/assets/i18n/en.json new file mode 100644 index 000000000000..dbe11618ff1d --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/i18n/en.json @@ -0,0 +1,768 @@ +{ + "COMMON": { + "NO_DATA": "No Data", + "FAILED_TO_FETCH_DATA": "Failed to fetch the data", + "NO_AGENTS": "There are no running agents.", + "MIN_LENGTH": "Enter at least !{0} letters", + "REQUIRED": "!{0} is required.", + "REQUIRED_SELECT": "Select !{0}", + "MAX_SEARCH_PERIOD": "Search duration may not be greater than !{0}days.", + "DO_NOT_HAVE_PERMISSION": "Don't have permission." + }, + "MAIN": { + "SELECT_YOUR_APP": "Select your application", + "INPUT_APP_NAME_PLACE_HOLDER": "Input application name", + "FAVORITE_APP_LIST": "Favorite List", + "APP_LIST": "Application List", + "SEARCH_SERVER_MAP_PLACE_HOLDER": "Search", + "EMPTY_RESULT": "We couldn't find anything" + }, + "INSPECTOR": { + "NO_DATA_COLLECTED": "No data collected", + "APPLICATION_INSPECTOR_USAGE_GUIDE_MESSAGE": "[TEXT]:{value=Application Inspector is not enabled.
    To enable Application Inspector, please refer to}|[LINK]:{href=https://github.com/naver/pinpoint/blob/master/doc/application-inspector.md\\target=blank\\style=color:#428bca\\linkText=this link}", + "APPLICAITION_NAME_ISSUE": { + "ISSUE_MESSAGE": "The agent is currently registered under !{1} due to the following:", + "ISSUE_CAUSES": [ + "1. The agent has moved from !{0} to !{1}", + "2. A different agent with the same agent id has been registered to !{1}" + ], + "ISSUE_SOLUTIONS": [ + "For case 1, you should delete the mapping between !{0} and !{1}.", + "For case 2, the agent id of the duplicate agent must change." + ] + } + }, + "TRANSACTION_LIST": { + "SELECT_TRANSACTION": "Select your transaction", + "TRANSACTION_RETRIEVE_ERROR": "Transaction information is missing
    Will go to Main" + }, + "SCATTER": { + }, + "CONFIGURATION": { + "GENERAL": { + "DESC": "* User configuration is stored in browser cache. Server-side storage will be supported in a future release.", + "EMPTY": "Favorite list is empty." + }, + "INSTALLATION": { + "DESC": "* You can check if Application Name and Agent ID are duplicated.", + "LENGTH_GUIDE": "You can enter up to !{0} characters.", + "APPLICATION_NAME_PLACEHOLDER": "Input Application Name.", + "AGENT_ID_PLACEHOLDER": "Input Agent ID." + }, + "COMMON": { + "NAME": "Name", + "USER_ID": "User ID", + "DEPARTMENT": "Department", + "PHONE": "Phone", + "EMAIL": "Email", + "USER_GROUP": "User Group ID", + "CHECKER": "Checker", + "THRESHOLD": "Threshold", + "TYPE": "Type", + "NOTES": "Notes" + } + }, + "TRANSACTION": { + "HAS_RESULTS": "!{0} results found.", + "EMPTY_RESULT": "No matches found." + }, + "SUPPORT": { + "RESTRICT_USAGE": "[ICON]:{className=fa-exclamation-triangle}|[TEXT]:{value=Your browser(!{0}) is not supported.}|[LINK]:{href=browser-not-supported\\target=blank\\style=text-decoration:underline;font-weight:600\\linkText=Check supported browsers}", + "INSTALL_GUIDE": "Please install one of the following browsers and try again." + }, + "HELP_VIEWER": { + "NAVBAR": [{ + "TITLE": "Application List", + "DESC": "Shows the list of applications with Pinpoint installed.", + "CATEGORY" : [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Icon", + "DESC": "Type of the Application" + }, { + "NAME": "Text", + "DESC": "Name of the Application. The value of -Dpinpoint.applicationName in Pinpoint agent configuration." + }] + }] + }, { + "TITLE": "Inbound, Outbound", + "DESC": "Search-depth of server map.", + "CATEGORY" : [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Inbound", + "DESC": "Number of depth to render for requests coming into the selected node." + }, { + "NAME": "Outbound", + "DESC": "Number of depth to render for requests going out from the selected node" + }] + }] + }, { + "TITLE": "Period Selector", + "DESC": "Selects the time range for search data.", + "CATEGORY": [{ + "TITLE": "Usage", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-clock\\style=font-size:17px}", + "DESC": "Query for data traced during the most recent selected time-period.
    Auto-refresh is supported for 5m, 10m, 3h time-period." + },{ + "NAME": "[ICON]:{className=fa-calendar-alt\\style=font-size:17px}", + "DESC": "Query for traced data between two selected times with the maximum of 48 hours." + }] + }] + }, { + "TITLE": "Bidirectional Search", + "DESC": "Search-method of server map.", + "CATEGORY" : [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Bidirectional", + "DESC": "Renders inbound/outbound nodes for each and every node (within limit) even if they are not directly related to the selected node.
    Note that checking this option may lead to overly complex server maps." + }] + }] + }], + "RESPONSE_SUMMARY": [{ + "TITLE": "Response Summary Chart", + "DESC": "", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px}|[TEXT]:{value=X-Axis}", + "DESC": "Response Time" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px}|[TEXT]:{value=Y-Axis}", + "DESC": "Transaction Count" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#34b994}|[TEXT]:{value=1s}", + "DESC": "No. of Successful transactions (less than 1 second)" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#51afdf}|[TEXT]:{value=3s}", + "DESC": "No. of Successful transactions (1 ~ 3 seconds)" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#ffba00}|[TEXT]:{value=5s}", + "DESC": "No. of Successful transactions (3 ~ 5 seconds)" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#e67f22}|[TEXT]:{value=Slow}", + "DESC": "No. of Successful transactions (greater than 5 seconds)" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#e95459}|[TEXT]:{value=Error}", + "DESC": "No. of Failed transactions regardless of response time" + }] + }] + }], + "LOAD": [{ + "TITLE": "Load Chart", + "DESC": "", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px}|[TEXT]:{value=X-Axis}", + "DESC": "Response Time" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px}|[TEXT]:{value=Y-Axis}", + "DESC": "Transaction Count" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#34b994}|[TEXT]:{value=1s}", + "DESC": "No. of Successful transactions (less than 1 second)" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#51afdf}|[TEXT]:{value=3s}", + "DESC": "No. of Successful transactions (1 ~ 3 seconds)" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#ffba00}|[TEXT]:{value=5s}", + "DESC": "No. of Successful transactions (3 ~ 5 seconds)" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#e67f22}|[TEXT]:{value=Slow}", + "DESC": "No. of Successful transactions (greater than 5 seconds)" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#e95459}|[TEXT]:{value=Error}", + "DESC": "No. of Failed transactions regardless of response time" + }] + }, { + "TITLE": "Usage", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Clicking on a legend item shows/hides all transactions within the selected group." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Dragging on the chart zooms in to the dragged area." + }] + }] + }], + "SERVER_MAP" : [{ + "TITLE": "Server Map", + "DESC": "Displays a topological view of the distributed server map.", + "CATEGORY": [{ + "TITLE": "Node", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Each node is a logical unit of application." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "The value on the top-right corner represents the number of server instances assigned to that application. (Not shown when there is only one such instance.)" + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "An alarm icon is displayed on the top-left corner if an error/exception is detected in one of the server instances." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "When the node is selected, the transaction information flowing into the application is displayed on the right side of the screen." + }] + }, { + "TITLE": "Arrow", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Each arrow represents a transaction flow." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "The number shows the transaction count. Displayed in red for error counts that exceeds the threshold." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "When the arrow is selected, the transaction information that passes through the selected section is displayed on the right side of the screen." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Right-clicking on an arrow displays the context menu for filtering." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "The Filter in the Context menu shows only the transactions that pass through the selected section." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Filter wizard allows you to configure more detailed filters." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "[TEXT]:{value=When the filter is applied,}|[ICON]:{className=fa-filter\\style=font-size:15px}|[TEXT]:{value=icon will be displayed on the arrow.}" + }] + }, { + "TITLE": "Chart Configuration", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Right-clicking on any blank area displays a chart configuration menu." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Node Setting / Merge Unknown: Groups all applications without agent and displays it as a single node." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Double-clicking on any blank area resets the zoom level of the server map." + }] + }] + }], + "REAL_TIME": [{ + "TITLE": "Realtime Active Thread Chart", + "DESC": "Shows the Active Thread count of each agent in realtime.", + "CATEGORY": [{ + "TITLE": "Error Messages", + "ITEMS": [{ + "NAME": "UNSUPPORTED VERSION", + "DESC": "Agent version too old. (Please upgrade the agent to 1.5.0+)" + }, { + "NAME": "CLUSTER OPTION NOTSET", + "DESC": "Option disabled by agent. (Please set profiler.pinpoint.activethread to true in profiler.config)" + }, { + "NAME": "TIMEOUT", + "DESC": "Agent connection timed out receiving active thread count. Please contact the administrator if problem persists." + }, { + "NAME": "NOT FOUND", + "DESC": "Agent not found. (If you get this message while the agent is running, please set profiler.tcpdatasender.command.accept.enable to true in profiler.config)" + }, { + "NAME": "CLUSTER CHANNEL CLOSED", + "DESC": "Agent session expired." + }, { + "NAME": "PINPOINT INTERNAL ERROR", + "DESC": "Pinpoint internal error. Please contact the administrator." + }, { + "NAME": "No Active Thread", + "DESC": "The agent has no threads that are currently active." + }, { + "NAME": "No Response", + "DESC": "No response from Pinpoint Web. Please contact the administrator." + }] + }] + }], + "CALL_TREE": [{ + "TITLE": "Call Tree", + "DESC": "", + "CATEGORY": [{ + "TITLE": "Column", + "ITEMS": [{ + "NAME": "Gap", + "DESC": "Elapsed time between the start of the previous method and the entry of this method" + }, { + "NAME": "Exec", + "DESC": "Duration of the method call from entry to exit" + }, { + "NAME": "Exec(%)", + "DESC": "[ICON]:{className=fa-circle\\style=font-size:11px;color:#5bc0de;margin-right:4px}|[TEXT]:{value=The execution time of the method call as a percentage of the total execution time of the transaction}" + }, { + "NAME": "", + "DESC": "[ICON]:{className=fa-circle\\style=font-size:11px;color:#4343C8;margin-right:4px}|[TEXT]:{value= A percentage of the self execution time}" + }, { + "NAME": "Self", + "DESC": "Duration of the method call from entry to exit, excluding time consumed in nested methods call" + }] + }] + }], + "SCATTER": [{ + "TITLE": "Response Time Scatter Chart", + "DESC": "", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-circle\\style=font-size:15px;color:#2EB089}", + "DESC": "Successful Transaction" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:15px;color:#E64A4F}", + "DESC": "Failed Transaction" + }, { + "NAME": "X-Axis", + "DESC": "Transaction Timestamp" + }, { + "NAME": "Y-Axis", + "DESC": "Response Time" + }] + },{ + "TITLE": "Usage", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-plus\\style=font-size:15px}", + "DESC": "Drag on the scatter chart to show detailed information on selected transactions." + }, { + "NAME": "[ICON]:{className=fa-cog\\style=font-size:15px}", + "DESC": "Set the min/max value of the Y-axis (Response Time)." + }, { + "NAME": "[ICON]:{className=fa-download\\style=font-size:15px}", + "DESC": "Download the chart as an image file." + }, { + "NAME": "[ICON]:{className=fa-expand-arrows-alt\\style=font-size:15px}", + "DESC": "Open the chart in a new window." + }] + }] + }], + "INSPECTOR": { + "AGENT_LIST": [{ + "TITLE": "Agent List", + "DESC": "List of agents registered under the current Application Name", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-tasks\\style=font-size:15px}", + "DESC": "Hostname of the agent's machine" + }, { + "NAME": "[IMAGE]:{name=icon-down}", + "DESC": "Agent was shutdown at the time of query" + }, { + "NAME": "[IMAGE]:{name=icon-disconnect}", + "DESC": "Agent was disconnected at the time of query" + }, { + "NAME": "[IMAGE]:{name=icon-error}", + "DESC": "Agent status was unknown at the time of query" + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Agent running at the time of query has no sign." + }] + }] + }], + "AGENT_CHART": { + "HEAP": [{ + "TITLE": "Heap", + "DESC": "JVM's heap information and major garbage collection time required", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Max", + "DESC": "Maximum heap size" + }, { + "NAME": "Used", + "DESC": "Heap size currently in use" + }, { + "NAME": "Major GC", + "DESC": "Time required for major garbage collection (number of Major GCs in parenthesis if it occurred more than once)" + }] + }] + }], + "NON_HEAP": [{ + "TITLE": "Non-Heap", + "DESC": "JVM's non-heap information and major garbage collection time required", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Max", + "DESC": "Maximum non-heap size" + }, { + "NAME": "Used", + "DESC": "Non-heap size currently in use" + }, { + "NAME": "Major ", + "DESC": "Time required for major garbage collection (number of Major GCs in parenthesis if it occurred more than once)" + }] + }] + }], + "CPU_USAGE": [{ + "TITLE": "Cpu Usage", + "DESC": "JVM/System's CPU Usage - For multi-core CPUs, displays the average CPU usage of all the cores.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Java 1.6", + "DESC": "Only JVM's CPU usage is collected." + }, { + "NAME": "Java 1.7+", + "DESC": "Both JVM's and system's CPU usage are collected." + }] + }] + }], + "TPS": [{ + "TITLE": "Transactions Per Second", + "DESC": "Transactions received by the server per second", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Sampled Continuation (S.C)", + "DESC": "Profiled transactions that started from another agent" + }, { + "NAME": "Sampled New (S.N)", + "DESC": "Profiled transactions that started from the selected agent" + }, { + "NAME": "Unsampled Continuation (U.C)", + "DESC": "Unprofiled transactions that started from another agent" + }, { + "NAME": "Unsampled New (U.N)", + "DESC": "Unprofiled transactions that started from the selected agent" + }, { + "NAME": "Total", + "DESC": "All transactions" + }] + }] + }], + "ACTIVE_THREAD": [{ + "TITLE": "Active Thread", + "DESC": "Snapshots of the agent's active thread status, categorized by how long they have been active for serving a request.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Fast (1s)", + "DESC": "Number of threads that have been active for less than or equal to 1s" + }, { + "NAME": "Normal (3s)", + "DESC": "Number of threads that have been active for less than or equal to 3s but longer than 1s" + }, { + "NAME": "Slow (5s)", + "DESC": "Number of threads that have been active for less than or equal to 5s but longer than 3s" + }, { + "NAME": "Very Slow (slow)", + "DESC": "Number of threads that have been active for longer than 5s" + }] + }] + }], + "RESPONSE_TIME": [{ + "TITLE": "Response Time", + "DESC": "Shows the status of agent's response time.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Avg", + "DESC": "Average Response Time (unit : milliseconds)" + }, { + "NAME": "Max", + "DESC": "Maximum Response Time (unit : milliseconds)" + }] + }] + }], + "DATA_SOURCE": [{ + "TITLE": "Data Source", + "DESC": "Shows the status of agent's data source.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Active Avg", + "DESC": "Average number of active connections" + }, { + "NAME": "Active Max", + "DESC": "Maximum number of active connections" + }, { + "NAME": "Total Max", + "DESC": "The maximum number of connections that can be allocated at the same time" + }, { + "NAME": "Type", + "DESC": "Type of DB Connection Pool" + }] + }] + }], + "OPEN_FILE_DESCRIPTOR": [{ + "TITLE": "File Descriptor", + "DESC": "Shows the status of agent's file descriptors.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Open File Descriptor", + "DESC": "Number of open file descriptor currently used" + }] + }] + }], + "DIRECT_BUFFER_COUNT": [{ + "TITLE": "Direct Buffer", + "DESC": "Shows the status of agent's direct buffer.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Direct Buffer Count", + "DESC": "Number of direct buffer" + }] + }] + }], + "DIRECT_BUFFER_MEMORY": [{ + "TITLE": "Direct Buffer Memory", + "DESC": "Shows the status of agent's used direct buffer memory.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Direct Buffer Memory Used", + "DESC": "Currently used direct buffer memory" + }] + }] + }], + "MAPPED_BUFFER_COUNT": [{ + "TITLE": "Mapped Buffer", + "DESC": "Shows the status of agent's Mapped buffer.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Mapped Buffer Count", + "DESC": "Number of Mapped buffer" + }] + }] + }], + "MAPPED_BUFFER_MEMORY": [{ + "TITLE": "Mapped Buffer Memory", + "DESC": "Shows the status of agent's used Mapped buffer memory.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Mapped Buffer Memory Used", + "DESC": "Currently used Mapped buffer memory" + }] + }] + }] + }, + "APPLICATION_CHART": { + "HEAP": [{ + "TITLE": "Heap", + "DESC": "Heap size used by the agent JVMs", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Smallest Heap size used by an agent JVM" + }, { + "NAME": "Avg", + "DESC": "Average Heap size used by the agent JVMs" + }, { + "NAME": "Max", + "DESC": "Largest Heap size used by an agent JVM" + }] + }] + }], + "NON_HEAP": [{ + "TITLE": "Non-Heap", + "DESC": "Non-heap size used by the agent JVMs", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Smallest Non-Heap size used by an agent JVM" + }, { + "NAME": "Avg", + "DESC": "Average Non-Heap size used by the agent JVMs" + }, { + "NAME": "Max", + "DESC": "Largest Non-Heap size used by an agent JVM" + }] + }] + }], + "JVM_CPU_USAGE": [{ + "TITLE": "JVM CPU Usage", + "DESC": "CPU used by agent JVM processes - For multi-core CPUs, displays the average CPU usage of all the cores.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Smallest CPU usage of agent JVM processes" + }, { + "NAME": "Avg", + "DESC": "Average CPU usage of agent JVM processes" + }, { + "NAME": "Max", + "DESC": "Largest CPU usage of agent JVM processes" + }] + }] + }], + "SYSTEM_CPU_USAGE": [{ + "TITLE": "System CPU Usage", + "DESC": "CPU usage of every agent's system - For multi-core CPUs, displays the average CPU usage of all cores.", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Smallest system CPU usage of agents" + }, { + "NAME": "Avg", + "DESC": "Average system CPU usage of agents" + }, { + "NAME": "Max", + "DESC": "Largest system CPU usage of agents" + }] + }] + }], + "TPS": [{ + "TITLE": "Transactions Per Second", + "DESC": "Number of transactions received by the agents per second", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Lowest TPS of the agents" + }, { + "NAME": "Avg", + "DESC": "Average TPS of the agents" + }, { + "NAME": "Max", + "DESC": "Highest TPS of the agents" + }] + }] + }], + "ACTIVE_THREAD": [{ + "TITLE": "Active Thread", + "DESC": "Number of active threads serving user requests", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Lowest active thread count of the agents serving user requests" + }, { + "NAME": "Avg", + "DESC": "Average active thread count of the agents serving user requests" + }, { + "NAME": "Max", + "DESC": "Highest active thread count of the agents serving user requests" + }] + }] + }], + "RESPONSE_TIME": [{ + "TITLE": "Response Time", + "DESC": "Average response times served by the agents", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Lowest value of agents' average response time" + }, { + "NAME": "Avg", + "DESC": "Average value of agents' average response time" + }, { + "NAME": "Max", + "DESC": "Highest value of agents' average response time" + }] + }] + }], + "DATA_SOURCE": [{ + "TITLE": "Data Source", + "DESC": "Status of the agents' data source", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Smallest data source connection count of the agents" + }, { + "NAME": "Avg", + "DESC": "Average data source connection count of the agents" + }, { + "NAME": "Max", + "DESC": "Largest data source connection count of the agents" + }] + }] + }], + "OPEN_FILE_DESCRIPTOR": [{ + "TITLE": "File Descriptor", + "DESC": "Number of file descriptors used by agents", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Min number of open file descriptors" + }, { + "NAME": "Avg", + "DESC": "Average open file descriptors" + }, { + "NAME": "Max", + "DESC": "Max number of open file descriptors" + }] + }] + }], + "DIRECT_BUFFER_COUNT": [{ + "TITLE": "Direct Buffer", + "DESC": "Number of direct buffer used by agents", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Min number of direct buffer" + }, { + "NAME": "Avg", + "DESC": "Average number of direct buffer" + }, { + "NAME": "Max", + "DESC": "Max number of direct buffer" + }] + }] + }], + "DIRECT_BUFFER_MEMORY": [{ + "TITLE": "Direct Buffer Memory", + "DESC": "Number of Direct buffer used by agents", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Min memory used by direct buffer" + }, { + "NAME": "Avg", + "DESC": "Average memory used by direct buffer" + }, { + "NAME": "Max", + "DESC": "Max memory used by direct buffer" + }] + }] + }], + "MAPPED_BUFFER_COUNT": [{ + "TITLE": "Mapped Buffer", + "DESC": "Number of Mapped Buffer used by agents", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Min number of Mapped Buffer" + }, { + "NAME": "Avg", + "DESC": "Average number of Mapped Buffer" + }, { + "NAME": "Max", + "DESC": "Max number of Mapped Buffer" + }] + }] + }], + "MAPPED_BUFFER_MEMORY": [{ + "TITLE": "Mapped Buffer Memory", + "DESC": "Number of Mapped Buffer Memory used by agents", + "CATEGORY": [{ + "TITLE": "Legend", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Min memory used by mapped buffer" + }, { + "NAME": "Avg", + "DESC": "Average memory used by mapped buffer" + }, { + "NAME": "Max", + "DESC": "Max memory used by mapped buffer" + }] + }] + }] + } + } + } +} diff --git a/web/src/main/webapp/v2/src/assets/i18n/ko.json b/web/src/main/webapp/v2/src/assets/i18n/ko.json new file mode 100644 index 000000000000..fdff371d4221 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/i18n/ko.json @@ -0,0 +1,767 @@ +{ + "COMMON": { + "NO_DATA": "데이터가 없습니다.", + "FAILED_TO_FETCH_DATA": "데이터를 가져오지 못했습니다.", + "NO_AGENTS": "실행 중인 에이전트가 없습니다.", + "MIN_LENGTH": "!{0}문자 이상 입력하세요.", + "REQUIRED": "!{0}를(을) 입력하세요.", + "REQUIRED_SELECT": "!{0}를(을) 선택하세요.", + "MAX_SEARCH_PERIOD": "한번에 검색할 수 있는 최대 기간은 !{0}일 입니다.", + "DO_NOT_HAVE_PERMISSION": "권한이 없습니다." + }, + "MAIN": { + "SELECT_YOUR_APP": "애플리케이션을 선택하세요.", + "INPUT_APP_NAME_PLACE_HOLDER": "애플리케이션 이름을 입력하세요.", + "FAVORITE_APP_LIST": "즐겨찾기 목록", + "APP_LIST": "애플리케이션 목록", + "SEARCH_SERVER_MAP_PLACE_HOLDER": "검색어를 입력하세요.", + "EMPTY_RESULT": "찾을 수 없습니다." + }, + "INSPECTOR": { + "NO_DATA_COLLECTED": "데이터가 없습니다.", + "APPLICATION_INSPECTOR_USAGE_GUIDE_MESSAGE": "[TEXT]:{value=Application Inspector 기능이 활성화 되어 있지 않습니다.
    Application Inspector 기능을 사용하려면,}|[LINK]:{href=https://github.com/naver/pinpoint/blob/master/doc/application-inspector.md\\target=_blank\\style=color:#428bca\\linkText=링크}|[TEXT]:{value=를 참고하세요.}", + "APPLICAITION_NAME_ISSUE": { + "ISSUE_MESSAGE": "해당 agent는 !{0}이 아닌 !{1}에 포함되어 있습니다.

    원인은 다음 중 하나입니다:", + "ISSUE_CAUSES": [ + "1. 해당 agent가 !{0}에서 !{1}으로 이동한 경우", + "2. !{0}의 agent가 !{1}에도 등록된 경우" + ], + "ISSUE_SOLUTIONS": [ + "1의 경우 !{0}과 !{1}간의 매핑 정보를 삭제해야 합니다.", + "2의 경우 중복 등록된 agent의 id를 변경해야 합니다." + ] + } + }, + "TRANSACTION_LIST": { + "SELECT_TRANSACTION": "Transaction을 선택하세요.", + "TRANSACTION_RETRIEVE_ERROR": "Transaction 정보가 없습니다.
    Main 화면으로 이동합니다." + }, + "SCATTER": {}, + "CONFIGURATION": { + "GENERAL": { + "DESC": "* 설정 정보는 브라우저 캐쉬에 저장합니다. 서버 측 저장은 추후 지원 할 예정입니다.", + "EMPTY": "등록된 목록이 없습니다." + }, + "INSTALLATION": { + "DESC": "* Application Name과 Agent ID의 중복 여부를 확인 할 수 있습니다.", + "LENGTH_GUIDE": "1 ~ !{0} 자의 문자를 입력하세요.", + "APPLICATION_NAME_PLACEHOLDER": "Application Name을 입력하세요.", + "AGENT_ID_PLACEHOLDER": "Agent ID를 입력하세요." + }, + "COMMON": { + "NAME": "이름", + "USER_ID": "사용자 ID", + "DEPARTMENT": "부서", + "PHONE": "전화번호", + "EMAIL": "이메일", + "USER_GROUP": "사용자 그룹 ID", + "CHECKER": "알람 항목", + "THRESHOLD": "기준점", + "TYPE": "알림 형식", + "NOTES": "메모" + } + }, + "TRANSACTION": { + "HAS_RESULTS": "!{0} 건이 검색되었습니다.", + "EMPTY_RESULT": "일치하는 결과가 없습니다." + }, + "SUPPORT": { + "RESTRICT_USAGE": "[ICON]:{className=fa-exclamation-triangle}|[TEXT]:{value=사용중인 브라우저(!{0})는 지원하지 않습니다.}|[LINK]:{href=browser-not-supported\\target=_blank\\style=text-decoration:underline;font-weight:600\\linkText=지원 브라우저 확인}", + "INSTALL_GUIDE": "아래의 브라우저들 중 하나를 설치 후 이용해주세요." + }, + "HELP_VIEWER": { + "NAVBAR": [{ + "TITLE": "응용프로그램 목록", + "DESC": "핀포인트가 설치된 응용프로그램 목록입니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "아이콘", + "DESC": "응용프로그램의 종류" + }, { + "NAME": "텍스트", + "DESC": "응용프로그램의 이름입니다. Pinpoint agent 설정에서 applicationName에 지정한 값입니다." + }] + }] + }, { + "TITLE": "Inbound, Outbound", + "DESC": "서버맵의 탐색 깊이를 설정합니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Inbound", + "DESC": "선택된 노드를 기준으로 들어오는 탐색 깊이" + }, { + "NAME": "Outbound", + "DESC": "선택된 노드를 기준으로 나가는 탐색 깊이" + }] + }] + }, { + "TITLE": "조회 시간 설정", + "DESC": "데이터 조회 시간을 선택합니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-clock\\style=font-size:17px}", + "DESC": "현재 시간을 기준으로 선택한 시간 이전부터 현재시간 사이에 수집된 데이터를 조회합니다. 최근 5m, 10m, 3h조회는 자동 새로고침 기능을 지원합니다." + },{ + "NAME": "[ICON]:{className=fa-calendar-alt\\style=font-size:17px}", + "DESC": "지정된 시간 사이에 수집된 데이터를 조회합니다. 조회 시간은 분단위로 최대 48시간을 지정할 수 있습니다." + }] + }] + }, { + "TITLE": "Bidirectional Search", + "DESC": "서버맵의 탐색 방법을 설정합니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Bidirectional", + "DESC": "모든 노드들에 대해 양방향 탐색을 하여 선택된 노드와 직접적인 연관이 없는 노드들도 탐색됩니다. 주의 : 이 옵션을 선택하시면 필요 이상으로 복잡한 서버맵이 조회될 수 있습니다." + }] + }] + }], + "RESPONSE_SUMMARY": [{ + "TITLE": "Response Summary Chart", + "DESC": "응답결과 요약입니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px}|[TEXT]:{value=X축}", + "DESC": "트랜잭션 응답시간 요약 단위" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px}|[TEXT]:{value=Y축}", + "DESC": "트랜잭션의 개수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#34b994}|[TEXT]:{value=1s}", + "DESC": "0초 <= 응답시간 < 1초 에 해당하는 성공한 트랜잭션의 수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#51afdf}|[TEXT]:{value=3s}", + "DESC": "1초 <= 응답시간 < 3초 에 해당하는 성공한 트랜잭션의 수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#ffba00}|[TEXT]:{value=5s}", + "DESC": "3초 <= 응답시간 < 5초 에 해당하는 성공한 트랜잭션의 수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#e67f22}|[TEXT]:{value=Slow}", + "DESC": "5초 <= 응답시간 에 해당하는 성공한 트랜잭션의 수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#e95459}|[TEXT]:{value=Error}", + "DESC": "응답시간과 무관하게 실패한 트랜잭션의 수" + }] + }] + }], + "LOAD": [{ + "TITLE": "Load Chart", + "DESC": "시간별 트랜잭션의 응답 결과입니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px}|[TEXT]:{value=X축}", + "DESC": "트랜잭션 응답시간 요약 단위" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px}|[TEXT]:{value=Y축}", + "DESC": "트랜잭션의 개수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#34b994}|[TEXT]:{value=1s}", + "DESC": "0초 <= 응답시간 < 1초 에 해당하는 성공한 트랜잭션의 수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#51afdf}|[TEXT]:{value=3s}", + "DESC": "1초 <= 응답시간 < 3초 에 해당하는 성공한 트랜잭션의 수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#ffba00}|[TEXT]:{value=5s}", + "DESC": "3초 <= 응답시간 < 5초 에 해당하는 성공한 트랜잭션의 수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#e67f22}|[TEXT]:{value=Slow}", + "DESC": "5초 <= 응답시간 에 해당하는 성공한 트랜잭션의 수" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:11px;margin-right:8px;color:#e95459}|[TEXT]:{value=Error}", + "DESC": "응답시간과 무관하게 실패한 트랜잭션의 수" + }] + }, { + "TITLE": "기능", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "범례를 클릭하여 해당 응답시간에 속한 트랜잭션을 차트에서 제외하거나 포함 할 수 있습니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "마우스로 드래그하여 드래그 한 범위를 확대할 수 있습니다." + }] + }] + }], + "SERVER_MAP" : [{ + "TITLE": "서버맵", + "DESC": "분산된 서버를 도식화 한 지도입니다.", + "CATEGORY": [{ + "TITLE": "박스", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "박스는 응용프로그램 그룹을 나타냅니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "우측의 숫자는 응용프로그램 그룹에 속한 서버 인스턴스의 개수입니다.(한 개일 때에는 숫자를 보여주지 않습니다.)" + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "좌측 빨간 알람은 임계값을 초과한 모니터링 항목이 있을 때 나타납니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "박스를 선택하면 어플리케이션으로 유입된 트랜잭션 정보를 화면 우측에 보여줍니다." + }] + }, { + "TITLE": "화살표", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "화살표는 트랜잭션의 흐름을 나타냅니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "화살표의 숫자는 호출 수 입니다. 임계치 이상의 에러를 포함하면 빨간색으로 보여집니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "화살표를 선택하면 선택된 구간을 통과하는 트랜잭션의 정보를 화면 우측에 보여줍니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "화살표에서 마우스 오른쪽 버튼을 클릭하면 Filtering을 위한 Context menu를 보여줍니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Context menu의 Filter는 선택된 구간을 통과하는 트랜잭션만 모아서 보여줍니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Filter wizard는 보다 상세한 필터 설정을 할 수 있습니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "[TEXT]:{value=필터가 적용되면 화살표에}|[ICON]:{className=fa-filter\\style=font-size:15px}|[TEXT]:{value=아이콘이 표시됩니다.}" + }] + }, { + "TITLE": "차트 설정", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "박스나 화살표가 아닌 화면의 여백에서 마우스 오른쪽 버튼을 클릭하면 차트 설정을 위한 Context menu를 보여줍니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "Node Setting / Merge Unknown: Agent가 설치되어있지 않은 응용프로그램을 하나의 박스로 보여줍니다." + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "박스나 화살표가 아닌 화면의 여백에서 더블클릭을 하면 서버맵의 줌이 초기화됩니다." + }] + }] + }], + "REAL_TIME": [{ + "TITLE": "Realtime Active Thread Chart", + "DESC": "각 Agent의 Active Thread 개수를 실시간으로 보여줍니다.", + "CATEGORY": [{ + "TITLE": "에러 메시지 설명", + "ITEMS": [{ + "NAME": "UNSUPPORTED VERSION", + "DESC": "해당 에이전트의 버전에서는 지원하지 않는 기능입니다. (1.5.0 이상 버전으로 업그레이드하세요.)" + }, { + "NAME": "CLUSTER OPTION NOTSET", + "DESC": "해당 에이전트의 설정에서 기능이 비활성화되어 있습니다. (pinpoint 설정 파일에서 profiler.pinpoint.activethread 항목을 true로 변경하세요.)" + }, { + "NAME": "TIMEOUT", + "DESC": "해당 에이전트에서 일시적으로 활성화 된 스레드 개수를 받지 못하였습니다.(오래 지속될 경우 담당자에게 문의하세요.)" + }, { + "NAME": "NOT FOUND", + "DESC": "해당 에이전트를 찾을 수 없습니다.(에이전트가 활성화 되어 있는 경우에 해당 메시지가 발생한다면 pinpoint 설정 파일에서 profiler.tcpdatasender.command.accept.enable 항목을 true로 변경하세요.)" + }, { + "NAME": "CLUSTER CHANNEL CLOSED", + "DESC": "해당 에이전트와의 세션이 종료되었습니다." + }, { + "NAME": "PINPOINT INTERNAL ERROR", + "DESC": "핀포인트 내부 에러가 발생하였습니다.(담당자에게 문의하세요.)" + }, { + "NAME": "No Active Thread", + "DESC": "현재 해당 에이전트는 활성화된 스레드가 존재하지 않습니다." + }, { + "NAME": "No Response", + "DESC": "핀포인트 웹 서버로부터의 응답을 받지 못하였습니다.(담당자에게 문의하세요.)" + }] + }] + }], + "CALL_TREE": [{ + "TITLE": "Call Tree", + "DESC": "Call Tree의 컬럼명을 설명합니다.", + "CATEGORY": [{ + "TITLE": "컬럼", + "ITEMS": [{ + "NAME": "Gap", + "DESC": "이전 메소드가 시작된 후 현재 메소드를 실행하기 까지의 지연 시간" + }, { + "NAME": "Exec", + "DESC": "메소드 시작부터 종료까지의 시간" + }, { + "NAME": "Exec(%)", + "DESC": "[ICON]:{className=fa-circle\\style=font-size:11px;color:#5bc0de;margin-right:4px}|[TEXT]:{value=트랜잭션 전체 실행 시간 대비 Exec 시간의 비율}" + }, { + "NAME": "", + "DESC": "[ICON]:{className=fa-circle\\style=font-size:11px;color:#4343C8;margin-right:4px}|[TEXT]:{value=Self 시간 비율}" + }, { + "NAME": "Self", + "DESC": "메소드 자체의 시작부터 종료까지의 시간으로 하위의 메소드가 실행된 시간을 제외한 값" + }] + }] + }], + "SCATTER": [{ + "TITLE": "Response Time Scatter Chart", + "DESC": "수집된 트랜잭션의 응답시간 분포도입니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-circle\\style=font-size:15px;color:#2EB089}", + "DESC": "성공한 트랜잭션" + }, { + "NAME": "[ICON]:{className=fa-circle\\style=font-size:15px;color:#E64A4F}", + "DESC": "실패한 트랜잭션" + }, { + "NAME": "X축", + "DESC": "트랜잭션이 실행된 시간" + }, { + "NAME": "Y축", + "DESC": "트랜잭션의 응답 속도" + }] + },{ + "TITLE": "기능", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-plus\\style=font-size:15px}", + "DESC": "마우스로 영역을 드래그하여 드래그 된 영역에 속한 트랜잭션의 상세정보를 조회할 수 있습니다." + }, { + "NAME": "[ICON]:{className=fa-cog\\style=font-size:15px}", + "DESC": "응답시간(Y축)의 최소 또는 최대값을 변경할 수 있습니다." + }, { + "NAME": "[ICON]:{className=fa-download\\style=font-size:15px}", + "DESC": "차트를 이미지 파일로 저장할 수 있습니다." + }, { + "NAME": "[ICON]:{className=fa-expand-arrows-alt\\style=font-size:15px}", + "DESC": "차트를 새창으로 볼 수 있습니다." + }] + }] + }], + "INSPECTOR": { + "AGENT_LIST": [{ + "TITLE": "Agent 리스트", + "DESC": "현 Appliation Name에 등록된 Agent 리스트입니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "[ICON]:{className=fa-tasks\\style=font-size:15px}", + "DESC": "Agent가 설치된 장비의 호스트 이름" + }, { + "NAME": "[IMAGE]:{name=icon-down}", + "DESC": "Shutdown된 상태의 Agent" + }, { + "NAME": "[IMAGE]:{name=icon-disconnect}", + "DESC": "연결이 끊긴 상태의 Agent" + }, { + "NAME": "[IMAGE]:{name=icon-error}", + "DESC": "알 수 없는 상태의 Agent" + }, { + "NAME": "[ICON]:{className=fa-info-circle\\style=font-size:15px}", + "DESC": "정상적으로 실행중인 Agent는 별도의 상태 표시가 없습니다." + }] + }] + }], + "AGENT_CHART": { + "HEAP": [{ + "TITLE": "Heap", + "DESC": "JVM의 Heap 정보와 Major Garbage Collection 소요 시간", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Max", + "DESC": "최대 Heap 사이즈" + }, { + "NAME": "Used", + "DESC": "현재 사용 중인 Heap 사이즈" + }, { + "NAME": "Major GC", + "DESC": "Major Garbage Collection의 총 소요 시간(2번 이상 발생 시, 괄호 안에 발생 횟수 표시)" + }] + }] + }], + "NON_HEAP": [{ + "TITLE": "Non-Heap", + "DESC": "JVM의 Non-Heap 정보와 Major Garbage Collection 소요 시간", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Max", + "DESC": "최대 Non-Heap 사이즈" + }, { + "NAME": "Used", + "DESC": "현재 사용 중인 Non-Heap 사이즈" + }, { + "NAME": "Major GC", + "DESC": "Major Garbage Collection의 총 소요 시간(2번 이상 발생 시, 괄호 안에 발생 횟수 표시)" + }] + }] + }], + "CPU_USAGE": [{ + "TITLE": "CPU Usage", + "DESC": "JVM과 시스템의 CPU 사용량 - 멀티코어 CPU의 경우, 전체 코어 사용량의 평균입니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Java 1.6", + "DESC": "JVM의 CPU 사용량만 수집됩니다." + }, { + "NAME": "Java 1.7+", + "DESC": "JVM과 전체 시스템의 CPU 사용량 모두 수집됩니다." + }] + }] + }], + "TPS": [{ + "TITLE": "Transactions Per Second", + "DESC": "서버로 인입된 초당 트랜잭션 수", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Sampled Continuation (S.C)", + "DESC": "다른 Agent에서 시작한 샘플링된 트랜잭션" + }, { + "NAME": "Sampled New (S.N)", + "DESC": "선택된 Agent에서 시작한 샘플링된 트랜잭션" + }, { + "NAME": "Unsampled Continuation (U.C)", + "DESC": "다른 Agent에서 시작한 샘플링되지 않은 트랜잭션" + }, { + "NAME": "Unsampled New (U.N)", + "DESC": "선택된 Agent에서 시작한 샘플링되지 않은 트랜잭션" + }, { + "NAME": "Total", + "DESC": "모든 트랜잭션" + }] + }] + }], + "ACTIVE_THREAD": [{ + "TITLE": "Active Thread", + "DESC": "사용자 Request를 처리하는 Agent의 Active Thread 현황을 보여줍니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Fast (1s)", + "DESC": "현재 소요시간이 1초 이하인 Thread 개수" + }, { + "NAME": "Normal (3s)", + "DESC": "현재 소요시간이 1초 초과, 3초 이하인 Thread 개수" + }, { + "NAME": "Slow (5s)", + "DESC": "현재 소요시간이 3초 초과, 5초 이하인 Thread 개수" + }, { + "NAME": "Very Slow (slow)", + "DESC": "현재 소요시간이 5초를 넘고 있는 Thread 개수" + }] + }] + }], + "RESPONSE_TIME": [{ + "TITLE": "Response Time", + "DESC": "Agent의 Response Time의 현황을 보여줍니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Avg", + "DESC": "평균 Response Time (단위 millisecond)" + }, { + "NAME": "Max", + "DESC": "최대 Response Time (단위 millisecond)" + }] + }] + }], + "DATA_SOURCE": [{ + "TITLE": "Data Source", + "DESC": "Agent의 DataSource 현황을 보여줍니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Active Avg", + "DESC": "사용한 Connection의 평균 개수" + }, { + "NAME": "Active Max", + "DESC": "사용한 Connection의 최대 개수" + }, { + "NAME": "Total Max", + "DESC": "사용이 가능한 Connection의 최대 개수" + }, { + "NAME": "Type", + "DESC": "DB Connection Pool 종류" + }] + }] + }], + "OPEN_FILE_DESCRIPTOR": [{ + "TITLE": "File Descriptor", + "DESC": "Agent의 File Descriptor 현황을 보여줍니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Open File Descriptor", + "DESC": "현재 열려있는 File Descriptor 개수" + }] + }] + }], + "DIRECT_BUFFER_COUNT": [{ + "TITLE": "Direct Buffer", + "DESC": "Agent의 Direct Buffer 현황을 보여줍니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Direct Buffer Count", + "DESC": "현재 Direct Buffer 의 개수" + }] + }] + }], + "DIRECT_BUFFER_MEMORY": [{ + "TITLE": "Direct Buffer Memory", + "DESC": "Agent의 Direct Buffer Memory 현황을 보여줍니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Direct Buffer Memory Used", + "DESC": "현재 Direct Buffer 가 사용중인 메모리" + }] + }] + }], + "MAPPED_BUFFER_COUNT": [{ + "TITLE": "Mapped Buffer", + "DESC": "Agent의 Mapped Buffer 현황을 보여줍니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Mapped Buffer Count", + "DESC": "현재 Mapped Buffer 의 개수" + }] + }] + }], + "MAPPED_BUFFER_MEMORY": [{ + "TITLE": "Mapped Buffer Memory", + "DESC": "Agent의 Mapped Buffer Memory 현황을 보여줍니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Mapped Buffer Memory Used", + "DESC": "현재 Mapped Buffer 가 사용중인 메모리" + }] + }] + }] + }, + "APPLICATION_CHART": { + "HEAP": [{ + "TITLE": "Heap", + "DESC": "Agent들이 사용하는 JVM Heap 사이즈 정보", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent들이 사용하는 Heap 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent들이 사용하는 Heap 의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent들이 사용하는 Heap 중 가장 큰 값" + }] + }] + }], + "NON_HEAP": [{ + "TITLE": "Non-Heap", + "DESC": "Agent들이 사용하는 JVM Non-Heap 사이즈 정보", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent들이 사용하는 Non-Heap 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent들이 사용하는 Non-Heap 의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent들이 사용하는 Non-Heap 중 가장 큰 값" + }] + }] + }], + "JVM_CPU_USAGE": [{ + "TITLE": "JVM CPU Usage", + "DESC": "Agent들이 사용하는 JVM CPU 사용량 - 멀티코어 CPU의 경우, 전체 코어 사용량의 평균입니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent들이 사용하는 JVM CPU 사용량 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent들이 사용하는 JVM CPU 사용량의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent들이 사용하는 JVM CPU 사용량 중 가장 큰 값" + }] + }] + }], + "SYSTEM_CPU_USAGE": [{ + "TITLE": "System CPU Usage", + "DESC": "Agent 서버들의 시스템 CPU 사용량 - 멀티코어 CPU의 경우, 전체 코어 사용량의 평균입니다.", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent 서버들의 시스템 CPU 사용량 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent 서버들의 시스템 CPU 사용량 평균값" + }, { + "NAME": "Max", + "DESC": "Agent 서버들의 시스템 CPU 사용량 중 가장 큰 값" + }] + }] + }], + "TPS": [{ + "TITLE": "Transactions Per Second", + "DESC": "Agent들에 인입된 초당 트랜잭션 수", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent들의 트랜잭션 수 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent들의 트랙잭션 수의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent들의 트랜잭션 수 중 가장 큰 값" + }] + }] + }], + "ACTIVE_THREAD": [{ + "TITLE": "Active Thread", + "DESC": "사용자 Request를 처리하는 Active Thread 수", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent들의 Active Thread 수 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent들의 Active Thread 수의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent들의 Active Thread 수 중 가장 큰 값" + }] + }] + }], + "RESPONSE_TIME": [{ + "TITLE": "Response Time", + "DESC": "Agent들의 평균 Response Time(단위: millisecond)", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent들의 평균 Response Time 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent들의 평균 Response Time의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent들의 평균 Response Time 중 가장 큰 값" + }] + }] + }], + "DATA_SOURCE": [{ + "TITLE": "Data Source", + "DESC": "Agent들의 DataSource 현황", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent들의 평균 DataSource Connection 개수 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent들의 평균 DataSource Connection 개수의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent들의 평균 DataSource Connection 개수 중 가장 큰 값" + }] + }] + }], + "OPEN_FILE_DESCRIPTOR": [{ + "TITLE": "File Descriptor", + "DESC": "Agent들의 File Descriptor 현황", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent가 열고 있는 File Descriptor 개수 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent가 열고 있는 File Descriptor 개수의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent가 열고 있는 File Descriptor 개수 중 가장 큰 값" + }] + }] + }], + "DIRECT_BUFFER_COUNT": [{ + "TITLE": "Direct Buffer", + "DESC": "Agent들의 Direct Buffer 현황", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent가 사용 중인 Direct Buffer 개수 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent가 사용 중인 Direct Buffer 개수의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent가 사용 중인 Direct Buffer 개수 중 가장 큰 값" + }] + }] + }], + "DIRECT_BUFFER_MEMORY": [{ + "TITLE": "Direct Buffer Memory", + "DESC": "Agent들의 Direct Buffer Memory 사용 현황", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent가 사용 중인 Direct Buffer Memory 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent가 사용 중인 Direct Buffer Memory의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent가 사용 중인 Direct Buffer Memory 중 가장 큰 값" + }] + }] + }], + "MAPPED_BUFFER_COUNT": [{ + "TITLE": "Mapped Buffer", + "DESC": "Agent들의 Mapped Buffer 현황", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent가 사용 중인 Mapped Buffer 개수 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent가 사용 중인 Mapped Buffer 개수의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent가 사용 중인 Mapped Buffer 개수 중 가장 큰 값" + }] + }] + }], + "MAPPED_BUFFER_MEMORY": [{ + "TITLE": "Mapped Buffer Memory", + "DESC": "Agent들의 Mapped Buffer Memory 사용 현황", + "CATEGORY": [{ + "TITLE": "범례", + "ITEMS": [{ + "NAME": "Min", + "DESC": "Agent가 사용 중인 Mapped Buffer Memory 중 가장 작은 값" + }, { + "NAME": "Avg", + "DESC": "Agent가 사용 중인 Mapped Buffer Memory의 평균값" + }, { + "NAME": "Max", + "DESC": "Agent가 사용 중인 Mapped Buffer Memory 중 가장 큰 값" + }] + }] + }] + } + } + } +} diff --git a/web/src/main/webapp/v2/src/assets/img/bg-title-group3.png b/web/src/main/webapp/v2/src/assets/img/bg-title-group3.png new file mode 100755 index 000000000000..bcd222a2b0c0 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/bg-title-group3.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/bidirect_off.png b/web/src/main/webapp/v2/src/assets/img/bidirect_off.png new file mode 100644 index 000000000000..5d447e0184a7 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/bidirect_off.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/bidirect_on.png b/web/src/main/webapp/v2/src/assets/img/bidirect_on.png new file mode 100644 index 000000000000..30e28ac3e770 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/bidirect_on.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/card-btn-arrow-right.png b/web/src/main/webapp/v2/src/assets/img/card-btn-arrow-right.png new file mode 100755 index 000000000000..ff9cd9a7950b Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/card-btn-arrow-right.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/chart1.gif b/web/src/main/webapp/v2/src/assets/img/chart1.gif new file mode 100755 index 000000000000..eacf1a837828 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/chart1.gif differ diff --git a/web/src/main/webapp/v2/src/assets/img/chart2.gif b/web/src/main/webapp/v2/src/assets/img/chart2.gif new file mode 100755 index 000000000000..58dabdd1a5a4 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/chart2.gif differ diff --git a/web/src/main/webapp/v2/src/assets/img/chart3.gif b/web/src/main/webapp/v2/src/assets/img/chart3.gif new file mode 100755 index 000000000000..4e2857a19d0b Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/chart3.gif differ diff --git a/web/src/main/webapp/v2/src/assets/img/chart4.gif b/web/src/main/webapp/v2/src/assets/img/chart4.gif new file mode 100755 index 000000000000..e29e6fd8c9d3 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/chart4.gif differ diff --git a/web/src/main/webapp/v2/src/assets/img/chart5.gif b/web/src/main/webapp/v2/src/assets/img/chart5.gif new file mode 100755 index 000000000000..1ca9873dbb04 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/chart5.gif differ diff --git a/web/src/main/webapp/v2/src/assets/img/chrome.png b/web/src/main/webapp/v2/src/assets/img/chrome.png new file mode 100644 index 000000000000..76c3f15a201c Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/chrome.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/edge.png b/web/src/main/webapp/v2/src/assets/img/edge.png new file mode 100644 index 000000000000..235437527ea8 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/edge.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/firefox.png b/web/src/main/webapp/v2/src/assets/img/firefox.png new file mode 100644 index 000000000000..16815259b4da Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/firefox.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/handle.png b/web/src/main/webapp/v2/src/assets/img/handle.png new file mode 100644 index 000000000000..68f71937e74f Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/handle.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-ABX-WEB-ALPHA.png b/web/src/main/webapp/v2/src/assets/img/icon-ABX-WEB-ALPHA.png new file mode 100755 index 000000000000..dd5b9d07abde Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-ABX-WEB-ALPHA.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-UNKNOWN-GROUP.png b/web/src/main/webapp/v2/src/assets/img/icon-UNKNOWN-GROUP.png new file mode 100755 index 000000000000..e7ba908fc5fc Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-UNKNOWN-GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-alert.png b/web/src/main/webapp/v2/src/assets/img/icon-alert.png new file mode 100755 index 000000000000..878443ecc937 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-alert.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-app-select1.png b/web/src/main/webapp/v2/src/assets/img/icon-app-select1.png new file mode 100755 index 000000000000..1ac5053c90fb Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-app-select1.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-app-select2.png b/web/src/main/webapp/v2/src/assets/img/icon-app-select2.png new file mode 100755 index 000000000000..119f6f4bfc14 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-app-select2.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-arrow.png b/web/src/main/webapp/v2/src/assets/img/icon-arrow.png new file mode 100755 index 000000000000..aac7f783983f Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-arrow.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-calendar-arrow.png b/web/src/main/webapp/v2/src/assets/img/icon-calendar-arrow.png new file mode 100755 index 000000000000..6936837784a3 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-calendar-arrow.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-close.png b/web/src/main/webapp/v2/src/assets/img/icon-close.png new file mode 100755 index 000000000000..1d11f5936206 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-close.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-disconnect.png b/web/src/main/webapp/v2/src/assets/img/icon-disconnect.png new file mode 100755 index 000000000000..ec86f70143a0 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-disconnect.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-down.png b/web/src/main/webapp/v2/src/assets/img/icon-down.png new file mode 100755 index 000000000000..05951ab09f98 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-down.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-error.png b/web/src/main/webapp/v2/src/assets/img/icon-error.png new file mode 100755 index 000000000000..a86b0ce845ab Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-error.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-file-glass.png b/web/src/main/webapp/v2/src/assets/img/icon-file-glass.png new file mode 100755 index 000000000000..2e53bfb0786e Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-file-glass.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icon-header-tool-group.png b/web/src/main/webapp/v2/src/assets/img/icon-header-tool-group.png new file mode 100755 index 000000000000..3b1809332fc3 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icon-header-tool-group.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/ACTIVEMQ_CLIENT.png b/web/src/main/webapp/v2/src/assets/img/icons/ACTIVEMQ_CLIENT.png new file mode 100755 index 000000000000..feed77c8e149 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/ACTIVEMQ_CLIENT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/ACTIVEMQ_CLIENT_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/ACTIVEMQ_CLIENT_GROUP.png new file mode 100755 index 000000000000..659b52106ab9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/ACTIVEMQ_CLIENT_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/AKKA_HTTP_SERVER.png b/web/src/main/webapp/v2/src/assets/img/icons/AKKA_HTTP_SERVER.png new file mode 100644 index 000000000000..7430bfcc0bb9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/AKKA_HTTP_SERVER.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/APACHE.png b/web/src/main/webapp/v2/src/assets/img/icons/APACHE.png new file mode 100755 index 000000000000..daf44ff710b8 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/APACHE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/ARCUS.png b/web/src/main/webapp/v2/src/assets/img/icons/ARCUS.png new file mode 100755 index 000000000000..562db3b5309e Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/ARCUS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/BACKEND.png b/web/src/main/webapp/v2/src/assets/img/icons/BACKEND.png new file mode 100755 index 000000000000..d308338fd4cf Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/BACKEND.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/BLOC.png b/web/src/main/webapp/v2/src/assets/img/icons/BLOC.png new file mode 100755 index 000000000000..81526d8969fc Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/BLOC.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/CASSANDRA.png b/web/src/main/webapp/v2/src/assets/img/icons/CASSANDRA.png new file mode 100755 index 000000000000..420660979377 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/CASSANDRA.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/CLIENT.png b/web/src/main/webapp/v2/src/assets/img/icons/CLIENT.png new file mode 100755 index 000000000000..53e5faebe6ad Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/CLIENT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/CUBRID.png b/web/src/main/webapp/v2/src/assets/img/icons/CUBRID.png new file mode 100755 index 000000000000..ba56e674b5b8 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/CUBRID.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/CUBRID_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/CUBRID_GROUP.png new file mode 100755 index 000000000000..0ee0f23eb4f8 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/CUBRID_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/DUBBO_PROVIDER.png b/web/src/main/webapp/v2/src/assets/img/icons/DUBBO_PROVIDER.png new file mode 100755 index 000000000000..a4b47c5fa53a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/DUBBO_PROVIDER.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/DUBBO_PROVIDER_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/DUBBO_PROVIDER_GROUP.png new file mode 100755 index 000000000000..8748a76dd379 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/DUBBO_PROVIDER_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/ETC.png b/web/src/main/webapp/v2/src/assets/img/icons/ETC.png new file mode 100755 index 000000000000..694baac9eaef Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/ETC.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/HBASE_CLIENT.png b/web/src/main/webapp/v2/src/assets/img/icons/HBASE_CLIENT.png new file mode 100644 index 000000000000..5743110bca2d Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/HBASE_CLIENT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/JBOSS.png b/web/src/main/webapp/v2/src/assets/img/icons/JBOSS.png new file mode 100755 index 000000000000..648f0da1da2a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/JBOSS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/JETTY.png b/web/src/main/webapp/v2/src/assets/img/icons/JETTY.png new file mode 100755 index 000000000000..37bb0594f585 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/JETTY.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/JEUS.png b/web/src/main/webapp/v2/src/assets/img/icons/JEUS.png new file mode 100644 index 000000000000..062029d5e132 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/JEUS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/JEUS_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/JEUS_GROUP.png new file mode 100644 index 000000000000..e7ceb6d3e686 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/JEUS_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/MARIADB.png b/web/src/main/webapp/v2/src/assets/img/icons/MARIADB.png new file mode 100755 index 000000000000..b3850a7c648d Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/MARIADB.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/MARIADB_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/MARIADB_GROUP.png new file mode 100755 index 000000000000..b391b9b5e204 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/MARIADB_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/MEMCACHED.png b/web/src/main/webapp/v2/src/assets/img/icons/MEMCACHED.png new file mode 100755 index 000000000000..eca1ba47f66a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/MEMCACHED.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/MONGODB.png b/web/src/main/webapp/v2/src/assets/img/icons/MONGODB.png new file mode 100755 index 000000000000..4089334d3d7a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/MONGODB.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/MONGODB_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/MONGODB_GROUP.png new file mode 100755 index 000000000000..9114093b2978 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/MONGODB_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/MSSQLSERVER.png b/web/src/main/webapp/v2/src/assets/img/icons/MSSQLSERVER.png new file mode 100755 index 000000000000..3bcac11ba4c4 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/MSSQLSERVER.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/MSSQLSERVER_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/MSSQLSERVER_GROUP.png new file mode 100755 index 000000000000..0bbd653e9e01 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/MSSQLSERVER_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/MYSQL.png b/web/src/main/webapp/v2/src/assets/img/icons/MYSQL.png new file mode 100755 index 000000000000..871363f86686 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/MYSQL.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/MYSQL_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/MYSQL_GROUP.png new file mode 100755 index 000000000000..2e0e8ad7e4f5 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/MYSQL_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/NBASE.png b/web/src/main/webapp/v2/src/assets/img/icons/NBASE.png new file mode 100755 index 000000000000..a8aab8afb3c0 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/NBASE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/NBASE_ARC.png b/web/src/main/webapp/v2/src/assets/img/icons/NBASE_ARC.png new file mode 100755 index 000000000000..b16ca4be159b Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/NBASE_ARC.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/NBASE_ARC_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/NBASE_ARC_GROUP.png new file mode 100755 index 000000000000..7f7cfeeef60b Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/NBASE_ARC_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/NBASE_T.png b/web/src/main/webapp/v2/src/assets/img/icons/NBASE_T.png new file mode 100755 index 000000000000..c607b633b9e1 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/NBASE_T.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/NGINX.png b/web/src/main/webapp/v2/src/assets/img/icons/NGINX.png new file mode 100755 index 000000000000..e208fc77c17f Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/NGINX.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/NO_IMAGE_FOUND.png b/web/src/main/webapp/v2/src/assets/img/icons/NO_IMAGE_FOUND.png new file mode 100644 index 000000000000..28f1a7564285 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/NO_IMAGE_FOUND.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/ORACLE.png b/web/src/main/webapp/v2/src/assets/img/icons/ORACLE.png new file mode 100755 index 000000000000..0158c0d1f7ab Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/ORACLE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/ORACLE_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/ORACLE_GROUP.png new file mode 100755 index 000000000000..88cb2983ad51 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/ORACLE_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/OWFS.png b/web/src/main/webapp/v2/src/assets/img/icons/OWFS.png new file mode 100644 index 000000000000..d6e9e67da3d0 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/OWFS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/OWFS_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/OWFS_GROUP.png new file mode 100644 index 000000000000..6d433eeb17bd Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/OWFS_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/PHP.png b/web/src/main/webapp/v2/src/assets/img/icons/PHP.png new file mode 100755 index 000000000000..b541ec9c0340 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/PHP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/POSTGRESQL.png b/web/src/main/webapp/v2/src/assets/img/icons/POSTGRESQL.png new file mode 100755 index 000000000000..50574a3e4e09 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/POSTGRESQL.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/POSTGRESQL_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/POSTGRESQL_GROUP.png new file mode 100755 index 000000000000..fb524f5dfd18 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/POSTGRESQL_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/QUEUE.png b/web/src/main/webapp/v2/src/assets/img/icons/QUEUE.png new file mode 100755 index 000000000000..a72fba5dbc02 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/QUEUE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/RABBITMQ_CLIENT.png b/web/src/main/webapp/v2/src/assets/img/icons/RABBITMQ_CLIENT.png new file mode 100644 index 000000000000..285c4f0c337d Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/RABBITMQ_CLIENT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/RABBITMQ_CLIENT_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/RABBITMQ_CLIENT_GROUP.png new file mode 100644 index 000000000000..58b17b2b822a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/RABBITMQ_CLIENT_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/REDIS.png b/web/src/main/webapp/v2/src/assets/img/icons/REDIS.png new file mode 100755 index 000000000000..83389195ee50 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/REDIS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/RESIN.png b/web/src/main/webapp/v2/src/assets/img/icons/RESIN.png new file mode 100644 index 000000000000..08dc754f17de Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/RESIN.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/RESIN_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/RESIN_GROUP.png new file mode 100644 index 000000000000..08dc754f17de Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/RESIN_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/SPRING_BOOT.png b/web/src/main/webapp/v2/src/assets/img/icons/SPRING_BOOT.png new file mode 100755 index 000000000000..8b31511433a2 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/SPRING_BOOT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/STAND_ALONE.png b/web/src/main/webapp/v2/src/assets/img/icons/STAND_ALONE.png new file mode 100755 index 000000000000..143397716ae5 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/STAND_ALONE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/TOMCAT.png b/web/src/main/webapp/v2/src/assets/img/icons/TOMCAT.png new file mode 100755 index 000000000000..0e36cbe21770 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/TOMCAT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/UNAUTHORIZED.png b/web/src/main/webapp/v2/src/assets/img/icons/UNAUTHORIZED.png new file mode 100755 index 000000000000..a368a062145c Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/UNAUTHORIZED.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/UNDEFINED.png b/web/src/main/webapp/v2/src/assets/img/icons/UNDEFINED.png new file mode 100755 index 000000000000..4cbfe55be4c0 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/UNDEFINED.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/UNDEFINED_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/UNDEFINED_GROUP.png new file mode 100755 index 000000000000..4cbfe55be4c0 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/UNDEFINED_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/UNKNOWN.png b/web/src/main/webapp/v2/src/assets/img/icons/UNKNOWN.png new file mode 100755 index 000000000000..7c130ee3602a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/UNKNOWN.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/UNKNOWN_CLOUD.png b/web/src/main/webapp/v2/src/assets/img/icons/UNKNOWN_CLOUD.png new file mode 100755 index 000000000000..28dbb1874a39 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/UNKNOWN_CLOUD.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/UNKNOWN_GROUP.png b/web/src/main/webapp/v2/src/assets/img/icons/UNKNOWN_GROUP.png new file mode 100755 index 000000000000..5ba06b27d86d Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/UNKNOWN_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/USER.png b/web/src/main/webapp/v2/src/assets/img/icons/USER.png new file mode 100755 index 000000000000..c4f80a90fe99 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/USER.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/USER1.png b/web/src/main/webapp/v2/src/assets/img/icons/USER1.png new file mode 100755 index 000000000000..a1545c0f7323 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/USER1.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/VERTX.png b/web/src/main/webapp/v2/src/assets/img/icons/VERTX.png new file mode 100644 index 000000000000..ed1f3bd955d2 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/VERTX.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/WEBLOGIC.png b/web/src/main/webapp/v2/src/assets/img/icons/WEBLOGIC.png new file mode 100644 index 000000000000..a47f63d9809a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/WEBLOGIC.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/WEBSPHERE.png b/web/src/main/webapp/v2/src/assets/img/icons/WEBSPHERE.png new file mode 100644 index 000000000000..771506cfe83d Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/WEBSPHERE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/filter.png b/web/src/main/webapp/v2/src/assets/img/icons/filter.png new file mode 100755 index 000000000000..75d1790acc8c Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/filter.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/ng.png b/web/src/main/webapp/v2/src/assets/img/icons/ng.png new file mode 100755 index 000000000000..8d5831044f8a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/ng.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/icons/sq.png b/web/src/main/webapp/v2/src/assets/img/icons/sq.png new file mode 100755 index 000000000000..fc5110340116 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/icons/sq.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/logo.png b/web/src/main/webapp/v2/src/assets/img/logo.png new file mode 100755 index 000000000000..f8126f91c816 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/logo.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/safari.png b/web/src/main/webapp/v2/src/assets/img/safari.png new file mode 100644 index 000000000000..bd31983aad34 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/safari.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/select-down-arrow.png b/web/src/main/webapp/v2/src/assets/img/select-down-arrow.png new file mode 100755 index 000000000000..241b02a69087 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/select-down-arrow.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/ACTIVEMQ_CLIENT.png b/web/src/main/webapp/v2/src/assets/img/servermap/ACTIVEMQ_CLIENT.png new file mode 100755 index 000000000000..d34b3cbfbb85 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/ACTIVEMQ_CLIENT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/ACTIVEMQ_CLIENT_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/ACTIVEMQ_CLIENT_GROUP.png new file mode 100644 index 000000000000..9287431fc23f Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/ACTIVEMQ_CLIENT_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/AKKA_HTTP_SERVER.png b/web/src/main/webapp/v2/src/assets/img/servermap/AKKA_HTTP_SERVER.png new file mode 100644 index 000000000000..29fa4249ab82 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/AKKA_HTTP_SERVER.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/APACHE.png b/web/src/main/webapp/v2/src/assets/img/servermap/APACHE.png new file mode 100755 index 000000000000..b3253187cefb Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/APACHE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/APACHE_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/APACHE_GROUP.png new file mode 100644 index 000000000000..33ea8dd4086d Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/APACHE_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/ARCUS.png b/web/src/main/webapp/v2/src/assets/img/servermap/ARCUS.png new file mode 100755 index 000000000000..69bb0de7fe1c Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/ARCUS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/ARCUS_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/ARCUS_GROUP.png new file mode 100644 index 000000000000..79eb205fa5ba Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/ARCUS_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/BACKEND.png b/web/src/main/webapp/v2/src/assets/img/servermap/BACKEND.png new file mode 100755 index 000000000000..d308338fd4cf Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/BACKEND.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/BACKEND_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/BACKEND_GROUP.png new file mode 100644 index 000000000000..d308338fd4cf Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/BACKEND_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/BLOC.png b/web/src/main/webapp/v2/src/assets/img/servermap/BLOC.png new file mode 100755 index 000000000000..c1fccc5643dd Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/BLOC.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/BLOC_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/BLOC_GROUP.png new file mode 100644 index 000000000000..58a074e4ac28 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/BLOC_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/CASSANDRA.png b/web/src/main/webapp/v2/src/assets/img/servermap/CASSANDRA.png new file mode 100755 index 000000000000..8e5d9d1d6731 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/CASSANDRA.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/CASSANDRA_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/CASSANDRA_GROUP.png new file mode 100644 index 000000000000..a958d682e6f9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/CASSANDRA_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/CUBRID.png b/web/src/main/webapp/v2/src/assets/img/servermap/CUBRID.png new file mode 100755 index 000000000000..b6e1fb851843 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/CUBRID.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/CUBRID_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/CUBRID_GROUP.png new file mode 100644 index 000000000000..2f26043fa5fa Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/CUBRID_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/DUBBO.png b/web/src/main/webapp/v2/src/assets/img/servermap/DUBBO.png new file mode 100755 index 000000000000..5b11f569dfef Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/DUBBO.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/DUBBO_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/DUBBO_GROUP.png new file mode 100644 index 000000000000..a7009ef4e410 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/DUBBO_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/ERROR.png b/web/src/main/webapp/v2/src/assets/img/servermap/ERROR.png new file mode 100755 index 000000000000..e558882889ff Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/ERROR.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/ERROR_s.png b/web/src/main/webapp/v2/src/assets/img/servermap/ERROR_s.png new file mode 100644 index 000000000000..d4efdced5532 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/ERROR_s.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/FILTER.png b/web/src/main/webapp/v2/src/assets/img/servermap/FILTER.png new file mode 100755 index 000000000000..c90e45781f46 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/FILTER.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/FILTER_s.png b/web/src/main/webapp/v2/src/assets/img/servermap/FILTER_s.png new file mode 100755 index 000000000000..bb8fc09b2453 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/FILTER_s.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/HBASE_CLIENT.png b/web/src/main/webapp/v2/src/assets/img/servermap/HBASE_CLIENT.png new file mode 100644 index 000000000000..68d91f337828 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/HBASE_CLIENT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/JAVA.png b/web/src/main/webapp/v2/src/assets/img/servermap/JAVA.png new file mode 100755 index 000000000000..9c62a4b8a814 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/JAVA.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/JAVA_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/JAVA_GROUP.png new file mode 100644 index 000000000000..a03cdf6b1aad Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/JAVA_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/JBOSS.png b/web/src/main/webapp/v2/src/assets/img/servermap/JBOSS.png new file mode 100755 index 000000000000..b5a983b139c4 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/JBOSS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/JBOSS_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/JBOSS_GROUP.png new file mode 100644 index 000000000000..e46b9af79b17 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/JBOSS_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/JETTY.png b/web/src/main/webapp/v2/src/assets/img/servermap/JETTY.png new file mode 100755 index 000000000000..3e2958c3a0c9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/JETTY.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/JETTY_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/JETTY_GROUP.png new file mode 100644 index 000000000000..1683ab415557 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/JETTY_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/JEUS.png b/web/src/main/webapp/v2/src/assets/img/servermap/JEUS.png new file mode 100644 index 000000000000..e1fbffeab3c7 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/JEUS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/JEUS_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/JEUS_GROUP.png new file mode 100644 index 000000000000..e1fbffeab3c7 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/JEUS_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MARIADB.png b/web/src/main/webapp/v2/src/assets/img/servermap/MARIADB.png new file mode 100755 index 000000000000..7d14c000accb Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MARIADB.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MARIADB_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/MARIADB_GROUP.png new file mode 100644 index 000000000000..4d1672bcc7cd Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MARIADB_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MEMCACHED.png b/web/src/main/webapp/v2/src/assets/img/servermap/MEMCACHED.png new file mode 100755 index 000000000000..db8c074a5881 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MEMCACHED.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MEMCACHED_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/MEMCACHED_GROUP.png new file mode 100644 index 000000000000..5fc76a66feab Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MEMCACHED_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MONGODB.png b/web/src/main/webapp/v2/src/assets/img/servermap/MONGODB.png new file mode 100755 index 000000000000..fc76c931bacc Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MONGODB.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MONGODB_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/MONGODB_GROUP.png new file mode 100644 index 000000000000..5848a6f0c2f5 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MONGODB_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MSSQLSERVER.png b/web/src/main/webapp/v2/src/assets/img/servermap/MSSQLSERVER.png new file mode 100755 index 000000000000..8236ef45dca9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MSSQLSERVER.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MSSQLSERVER_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/MSSQLSERVER_GROUP.png new file mode 100644 index 000000000000..11a1609e24a3 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MSSQLSERVER_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MYSQL.png b/web/src/main/webapp/v2/src/assets/img/servermap/MYSQL.png new file mode 100644 index 000000000000..2628c29c3e2b Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MYSQL.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/MYSQL_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/MYSQL_GROUP.png new file mode 100644 index 000000000000..2628c29c3e2b Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/MYSQL_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/NBASE.png b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE.png new file mode 100755 index 000000000000..2eacc0c66c0f Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_ARC.png b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_ARC.png new file mode 100755 index 000000000000..a0668e6c51f6 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_ARC.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_ARC_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_ARC_GROUP.png new file mode 100644 index 000000000000..2a8cdfe2f987 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_ARC_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_GROUP.png new file mode 100644 index 000000000000..f25a35834884 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_T.png b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_T.png new file mode 100755 index 000000000000..610f58cbfb79 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_T.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_T_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_T_GROUP.png new file mode 100644 index 000000000000..f25a35834884 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/NBASE_T_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/NGINX.png b/web/src/main/webapp/v2/src/assets/img/servermap/NGINX.png new file mode 100755 index 000000000000..8581672516f2 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/NGINX.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/NGINX_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/NGINX_GROUP.png new file mode 100644 index 000000000000..0bb2909e6142 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/NGINX_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/NO_IMAGE_FOUND.png b/web/src/main/webapp/v2/src/assets/img/servermap/NO_IMAGE_FOUND.png new file mode 100644 index 000000000000..07afde3fdb02 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/NO_IMAGE_FOUND.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/ORACLE.png b/web/src/main/webapp/v2/src/assets/img/servermap/ORACLE.png new file mode 100755 index 000000000000..2fc835440d88 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/ORACLE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/ORACLE_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/ORACLE_GROUP.png new file mode 100644 index 000000000000..103014aee2ef Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/ORACLE_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/OWFS.png b/web/src/main/webapp/v2/src/assets/img/servermap/OWFS.png new file mode 100644 index 000000000000..bf6e29a4a6ab Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/OWFS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/OWFS_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/OWFS_GROUP.png new file mode 100644 index 000000000000..bf6e29a4a6ab Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/OWFS_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/PHP.png b/web/src/main/webapp/v2/src/assets/img/servermap/PHP.png new file mode 100755 index 000000000000..1bd6443e7bc1 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/PHP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/POSTGRESQL.png b/web/src/main/webapp/v2/src/assets/img/servermap/POSTGRESQL.png new file mode 100755 index 000000000000..6a089eb23d5f Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/POSTGRESQL.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/POSTGRESQL_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/POSTGRESQL_GROUP.png new file mode 100644 index 000000000000..10a0945c198d Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/POSTGRESQL_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/QUEUE.png b/web/src/main/webapp/v2/src/assets/img/servermap/QUEUE.png new file mode 100755 index 000000000000..a72fba5dbc02 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/QUEUE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/QUEUE_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/QUEUE_GROUP.png new file mode 100755 index 000000000000..a72fba5dbc02 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/QUEUE_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/RABBITMQ_CLIENT.png b/web/src/main/webapp/v2/src/assets/img/servermap/RABBITMQ_CLIENT.png new file mode 100644 index 000000000000..d33071d6f6cb Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/RABBITMQ_CLIENT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/RABBITMQ_CLIENT_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/RABBITMQ_CLIENT_GROUP.png new file mode 100644 index 000000000000..d33071d6f6cb Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/RABBITMQ_CLIENT_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/REDIS.png b/web/src/main/webapp/v2/src/assets/img/servermap/REDIS.png new file mode 100755 index 000000000000..62f25c9918dc Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/REDIS.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/REDIS_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/REDIS_GROUP.png new file mode 100644 index 000000000000..abb69c09ec51 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/REDIS_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/RESIN.png b/web/src/main/webapp/v2/src/assets/img/servermap/RESIN.png new file mode 100644 index 000000000000..ff65640ff633 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/RESIN.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/RESIN_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/RESIN_GROUP.png new file mode 100644 index 000000000000..ff65640ff633 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/RESIN_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/SPRING_BOOT.png b/web/src/main/webapp/v2/src/assets/img/servermap/SPRING_BOOT.png new file mode 100755 index 000000000000..a31b3b03365e Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/SPRING_BOOT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/SPRING_BOOT_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/SPRING_BOOT_GROUP.png new file mode 100644 index 000000000000..0ccdef63a2dc Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/SPRING_BOOT_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/STAND_ALONE.png b/web/src/main/webapp/v2/src/assets/img/servermap/STAND_ALONE.png new file mode 100755 index 000000000000..4fcbe81c8a83 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/STAND_ALONE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/STAND_ALONE2.png b/web/src/main/webapp/v2/src/assets/img/servermap/STAND_ALONE2.png new file mode 100644 index 000000000000..28f78a703c3c Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/STAND_ALONE2.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/STAND_ALONE_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/STAND_ALONE_GROUP.png new file mode 100644 index 000000000000..2b461a8f74ef Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/STAND_ALONE_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/TOMCAT.png b/web/src/main/webapp/v2/src/assets/img/servermap/TOMCAT.png new file mode 100755 index 000000000000..4fcbe81c8a83 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/TOMCAT.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/TOMCAT_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/TOMCAT_GROUP.png new file mode 100644 index 000000000000..59a11feca358 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/TOMCAT_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/UNAUTHORIZED.png b/web/src/main/webapp/v2/src/assets/img/servermap/UNAUTHORIZED.png new file mode 100755 index 000000000000..a3ffe9177445 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/UNAUTHORIZED.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/UNAUTHORIZED_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/UNAUTHORIZED_GROUP.png new file mode 100644 index 000000000000..8b05bc24141b Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/UNAUTHORIZED_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/UNDEFINED.png b/web/src/main/webapp/v2/src/assets/img/servermap/UNDEFINED.png new file mode 100755 index 000000000000..d46a1159d94d Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/UNDEFINED.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/UNDEFINED_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/UNDEFINED_GROUP.png new file mode 100644 index 000000000000..3e75eab0564c Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/UNDEFINED_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/UNKNOWN.png b/web/src/main/webapp/v2/src/assets/img/servermap/UNKNOWN.png new file mode 100755 index 000000000000..73c53de2c0ea Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/UNKNOWN.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/UNKNOWN_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/UNKNOWN_GROUP.png new file mode 100755 index 000000000000..ae4c7bc4f392 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/UNKNOWN_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/USER.png b/web/src/main/webapp/v2/src/assets/img/servermap/USER.png new file mode 100755 index 000000000000..d7e67da244c1 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/USER.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/USER_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/USER_GROUP.png new file mode 100644 index 000000000000..69f473863dbf Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/USER_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/VERTX.png b/web/src/main/webapp/v2/src/assets/img/servermap/VERTX.png new file mode 100644 index 000000000000..1a4ec3e1d87a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/VERTX.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/VERTX_GROUP.png b/web/src/main/webapp/v2/src/assets/img/servermap/VERTX_GROUP.png new file mode 100644 index 000000000000..1a4ec3e1d87a Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/VERTX_GROUP.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/WEBLOGIC.png b/web/src/main/webapp/v2/src/assets/img/servermap/WEBLOGIC.png new file mode 100644 index 000000000000..fae014c4eac0 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/WEBLOGIC.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/servermap/WEBSPHERE.png b/web/src/main/webapp/v2/src/assets/img/servermap/WEBSPHERE.png new file mode 100644 index 000000000000..c862167c2cd9 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/servermap/WEBSPHERE.png differ diff --git a/web/src/main/webapp/v2/src/assets/img/text-layer-arrow.png b/web/src/main/webapp/v2/src/assets/img/text-layer-arrow.png new file mode 100755 index 000000000000..f13365650030 Binary files /dev/null and b/web/src/main/webapp/v2/src/assets/img/text-layer-arrow.png differ diff --git a/web/src/main/webapp/v2/src/assets/lib/prettify/lang-sql.js b/web/src/main/webapp/v2/src/assets/lib/prettify/lang-sql.js new file mode 100644 index 000000000000..8ec4280b8349 --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/lib/prettify/lang-sql.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\n\r]*|\/\*[\S\s]*?(?:\*\/|$))/],["kwd",/^(?:add|all|alter|and|any|apply|as|asc|authorization|backup|begin|between|break|browse|bulk|by|cascade|case|check|checkpoint|close|clustered|coalesce|collate|column|commit|compute|connect|constraint|contains|containstable|continue|convert|create|cross|current|current_date|current_time|current_timestamp|current_user|cursor|database|dbcc|deallocate|declare|default|delete|deny|desc|disk|distinct|distributed|double|drop|dummy|dump|else|end|errlvl|escape|except|exec|execute|exists|exit|fetch|file|fillfactor|following|for|foreign|freetext|freetexttable|from|full|function|goto|grant|group|having|holdlock|identity|identitycol|identity_insert|if|in|index|inner|insert|intersect|into|is|join|key|kill|left|like|lineno|load|match|matched|merge|natural|national|nocheck|nonclustered|nocycle|not|null|nullif|of|off|offsets|on|open|opendatasource|openquery|openrowset|openxml|option|or|order|outer|over|partition|percent|pivot|plan|preceding|precision|primary|print|proc|procedure|public|raiserror|read|readtext|reconfigure|references|replication|restore|restrict|return|revoke|right|rollback|rowcount|rowguidcol|rows?|rule|save|schema|select|session_user|set|setuser|shutdown|some|start|statistics|system_user|table|textsize|then|to|top|tran|transaction|trigger|truncate|tsequal|unbounded|union|unique|unpivot|update|updatetext|use|user|using|values|varying|view|waitfor|when|where|while|with|within|writetext|xml)(?=[^\w-]|$)/i, +null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^[_a-z][\w-]*/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'+\xa0-]*/]]),["sql"]); diff --git a/web/src/main/webapp/v2/src/assets/lib/prettify/prettify.css b/web/src/main/webapp/v2/src/assets/lib/prettify/prettify.css new file mode 100644 index 000000000000..d44b3a2282ad --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/lib/prettify/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/assets/lib/prettify/prettify.js b/web/src/main/webapp/v2/src/assets/lib/prettify/prettify.js new file mode 100644 index 000000000000..7b990496dd2b --- /dev/null +++ b/web/src/main/webapp/v2/src/assets/lib/prettify/prettify.js @@ -0,0 +1,30 @@ +!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function S(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var a=e.charAt(1);return(b=r[a])?b:"0"<=a&&a<="7"?parseInt(e.substring(1),8):a==="u"||a==="x"?parseInt(e.substring(2),16):e.charCodeAt(1)}function g(e){if(e<32)return(e<16?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return e==="\\"||e==="-"||e==="]"||e==="^"?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),e=[],a= +b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,f=b.length;a122||(l<65||h>90||e.push([Math.max(65,h)|32,Math.min(l,90)|32]),l<97||h>122||e.push([Math.max(97,h)&-33,Math.min(l,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});b=[];f=[];for(a=0;ah[0]&&(h[1]+1>h[0]&&c.push("-"),c.push(g(h[1])));c.push("]");return c.join("")}function s(e){for(var a=e.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],f=0,h=0;f=2&&e==="["?a[f]=b(l):e!=="\\"&&(a[f]=l.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var x=0,m=!1,j=!1,k=0,c=a.length;k=5&&"lang-"===w.substring(0,5))&&!(t&&typeof t[1]==="string"))f=!1,w="src";f||(r[z]=w)}h=c;c+=z.length;if(f){f=t[1];var l=z.indexOf(f),B=l+f.length;t[2]&&(B=z.length-t[2].length,l=B-f.length);w=w.substring(5);H(j+h,z.substring(0,l),g,k);H(j+h+l,f,I(w,f),k);H(j+h+B,z.substring(B),g,k)}else k.push(j+h,w)}a.g=k}var b={},s;(function(){for(var g=a.concat(d),j=[],k={},c=0,i=g.length;c=0;)b[n.charAt(e)]=r;r=r[1];n=""+r;k.hasOwnProperty(n)||(j.push(r),k[n]=q)}j.push(/[\S\s]/);s=S(j)})();var x=d.length;return g}function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,q])):d.push(["com", +/^#[^\n\r]*/,q,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,q]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));if(b=a.regexLiterals){var s=(b=b>1?"":"\n\r")?".":"[\\S\\s]";g.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+s+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+ +s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/, +q],["pun",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d= +c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"], +O=[N,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],E=[E,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],P=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +Q=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],R=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/, +V=/\S/,X=v({keywords:[M,O,E,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",P,Q,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(C([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-", +/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(C([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/], +["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);p(C([],[["atv",/^[\S\s]+/]]),["uq.val"]);p(v({keywords:M,hashComments:!0,cStyleComments:!0,types:R}),["c","cc","cpp","cxx","cyc","m"]);p(v({keywords:"null,true,false"}),["json"]);p(v({keywords:O,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:R}), +["cs"]);p(v({keywords:N,cStyleComments:!0}),["java"]);p(v({keywords:y,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(v({keywords:P,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);p(v({keywords:Q, +hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(v({keywords:E,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(v({keywords:W,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]); +p(C([],[["str",/^[\S\s]+/]]),["regex"]);var Y=D.PR={createSimpleLexer:C,registerLangHandler:p,sourceDecorator:v,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:D.prettyPrintOne=function(a,d,g){var b=document.createElement("div");b.innerHTML="
    "+a+"
    ";b=b.firstChild;g&&J(b,g,!0);K({h:d,j:g,c:b,i:1}); +return b.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function g(){for(var b=D.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;i>; +} +// @store +interface IResponseMilliSecondTime { + '100ms': number; + '300ms': number; + '500ms': number; + 'Error': number; + 'Slow': number; + [key: string]: number; +} +interface IInstanceStatus { + code: number; + desc: string; +} +interface IAgentList { + [key: string]: IAgent[]; +} +// @store +interface IAgent { + agentId: string; + agentVersion: string; + applicationName: string; + hostName: string; + initialStartTimestamp: number; + ip: string; + jvmInfo: { + gcTypeName: string; + jvmVersion: string; + version: number; + }; + pid: number; + ports: string; + serverMetaData: { + serverInfo: string; + serviceInfos: { + serviceLibs: string[]; + serviceName: string; + }[]; + vmArgs: string[]; + }; + serviceType?: string; + startTimestamp: number; + status: { + agentId: string; + eventTimestamp: number; + state: { + code: number; + desc: string; + } + }; + vmVersion: string; +} +// @store +interface IAgentSelection { + agent: string; + responseSummary: IResponseTime | IResponseMilliSecondTime; + load: IHistogram; +} +interface IInstanceInfo { + hasInspector: boolean; + name: string; + serviceType: string; + status: IInstanceStatus; +} +interface IServerInfo { + instanceList: { [key: string]: IInstanceInfo }; + name: string; + status: any; // 응답 형식을 아직 확인 못함. +} +interface ILinkInfo { + errorCount: number; + filterApplicationName: string; + filterApplicationServiceTypeCode: number; + filterApplicationServiceTypeName: string; + filterTargetRpcList?: any[]; + from: string; + fromAgent?: string[]; + hasAlert: boolean; + histogram: IResponseTime | IResponseMilliSecondTime; + key: string; + slowCount: number; + sourceHistogram?: { [key: string]: IResponseTime | IResponseMilliSecondTime }; + sourceInfo: ISourceInfo; + sourceTimeSeriesHistogram?: { [key: string]: IHistogram }[]; + targetHistogram?: { [key: string]: IResponseTime | IResponseMilliSecondTime }; + targetInfo: ISourceInfo; + timeSeriesHistogram: IHistogram[]; + to: string; + toAgent?: string[]; + totalCount: number; +} +interface INodeInfo { + agentHistogram?: { [key:string]: IResponseTime | IResponseMilliSecondTime }[]; + agentTimeSeriesHistogram?: { [key:string]: IHistogram[] }; + agentIds: string[]; + applicationName: string; + category: string; + errorCount: number; + hasAlert: boolean; + histogram: IResponseTime | IResponseMilliSecondTime; + instanceCount: number; + instanceErrorCount: number; + isAuthorized: boolean; + isQueue: boolean; + isWas: boolean; + key: string; + serverList?: { [key: string]: IServerInfo }; + serviceType: string; + serviceTypeCode: string; + slowCount: number; + timeSeriesHistogram: IHistogram[]; + totalCount: number; +} +interface IQueryRange { + from: number; + to: number; + toDateTime: string; + fromDateTime: string; + range: number; +} +interface IServerMapInfo { + applicationMapData: { + range: IQueryRange; + nodeDataArray: INodeInfo[]; + linkDataArray: ILinkInfo[]; + }; +} + +interface IFilter { + fa: string; + fst: string; + ta: string; + tst: string; + ie: null | boolean; + rf?: number; + rt?: number; + url?: string; + fan?: string; + tan?: string; +} + +interface ISelectedTarget { + endTime: string; + period: string; + isNode?: boolean; + isLink?: boolean; + isMerged: boolean; + isWAS: boolean; + node?: string[]; + link?: string[]; + hasServerList?: boolean; + isAuthorized?: boolean; +} + +interface AjaxExceptionObj { + message: string; + request: {[key: string]: any}; + stacktrace: string +} + +interface AjaxException { + exception: AjaxExceptionObj; +} +// @store +interface IScatterXRange { + from: number; + to: number; +} +// @store +interface IScatterData { + complete: boolean; + currentServerTime: number; + from: number; + resultFrom: number; + resultTo: number; + scatter: { + dotList: number[][], + metadata: { + [key: number]: any[] + } + }; + to: number; + reset?: boolean; +} +// @store +interface IHelpViewerInfo { + key: string; + coordinate: ICoordinate; +} +// @store +interface ICoordinate { + coordX: number; + coordY: number; +} +// @store +interface ITransactionMetaData { + agentId: string; + application: string; + collectorAcceptTime: number; + elapsed: number; + endpoint: string; + exception: number; + remoteAddr: string; + spanId: string; + startTime: number; + traceId: string; +} +// @store +interface ITransactionDetailData { + agentId: string; + applicationId: string; + applicationMapData: any; + applicationName: string; + callStack: any[]; + callStackEnd: number; + callStackIndex: any; + callStackStart: number; + completeState: string; + disableButtonMessage: string; + logButtonName: string; + logLinkEnable: boolean; + logPageUrl: string; + loggingTransactionInfo: boolean; + transactionId: string; +} +// @store +interface IHoveredInfo { + index: number; + time?: number; + offsetX?: number; + offsetY?: number; +} +// @store +interface IServerAndAgentData { + agentId: string; + agentVersion: string; + applicationName: string; + hostName: string; + initialStartTimestamp: number; + ip: string; + jvmInfo: { + gcTypeName: string; + jvmVersion: string; + version: number + }; + pid: number; + ports: string; + serverMetaData: any; + serviceType: string; + startTimestamp: number; + status: { + agentId: string; + eventTimestamp: number; + state: { + code: number; + desc: string; + } + }; + vmVersion: string; +} + +// @store +interface ISyntaxHighlightData { + type: string; + originalContents: string; + bindValue: string; + bindedContents?: string; +} + +// @store +interface IUIState { + [key: string]: boolean; +} + +// @store +interface IServerMapMergeState { + name: string; + state: boolean; +} + +// @store +interface ITransactionMessage { + title: string; + contents: string; +} + +// @store +interface ITimelineInfo { + range: number[]; + selectedTime: number; + selectionRange: number[]; +} + +interface IServerErrorFormat { + exception: { + request: { + url: string; + method?: string; + heads?: { + [key: string]: string[]; + }, + parameters?: { + [key: string]: string[]; + } + }, + stacktrace?: string; + message: string; + } +} +interface IServerErrorShortFormat { + errorCode: string; + errorMessage: string; +} +interface ISystemConfiguration { + editUserInfo: boolean; + enableServerMapRealTime: boolean; + openSource: boolean; + sendUsage: boolean; + showActiveThread: boolean; + showActiveThreadDump: boolean; + showApplicationStat: boolean; + version: string; + userId?: string; + userName?: string; + userDepartment?: string; +} diff --git a/web/src/main/webapp/v2/src/index.html b/web/src/main/webapp/v2/src/index.html new file mode 100644 index 000000000000..e6ce5b1025fc --- /dev/null +++ b/web/src/main/webapp/v2/src/index.html @@ -0,0 +1,41 @@ + + + + + PINPOINT + + + + + + + + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    + + + diff --git a/web/src/main/webapp/v2/src/main.ts b/web/src/main/webapp/v2/src/main.ts new file mode 100644 index 000000000000..a16023e842fc --- /dev/null +++ b/web/src/main/webapp/v2/src/main.ts @@ -0,0 +1,10 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { enableProdMode } from '@angular/core'; +import { environment } from './environments/environment'; +import { AppModule } from './app/app.module'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/web/src/main/webapp/v2/src/polyfills.ts b/web/src/main/webapp/v2/src/polyfills.ts new file mode 100644 index 000000000000..bff14bc9830b --- /dev/null +++ b/web/src/main/webapp/v2/src/polyfills.ts @@ -0,0 +1,76 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/weak-map'; +// import 'core-js/es6/set'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + + +/** Evergreen browsers require these. **/ +// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. + + + +/** + * Required to support Web Animations `@angular/platform-browser/animations`. + * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + + + +/*************************************************************************************************** + * Zone JS is required by Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ + +/** + * Date, currency, decimal and percent pipes. + * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 + */ +// import 'intl'; // Run `npm install --save intl`. +/** + * Need to import at least one locale-data with intl. + */ +// import 'intl/locale-data/jsonp/en'; diff --git a/web/src/main/webapp/v2/src/styles.css b/web/src/main/webapp/v2/src/styles.css new file mode 100644 index 000000000000..27cb4642c87c --- /dev/null +++ b/web/src/main/webapp/v2/src/styles.css @@ -0,0 +1,64 @@ +@media screen and (max-width: 1200px) {} +*{margin:0;padding:0;text-decoration:none;box-sizing: border-box;border-collapse: collapse;background:transparent;list-style:none;border:0;font-family:inherit;color:inherit} +html {height: 100%} +legend{display:none} +button{cursor:pointer;background:none} +body{color:#333; font-family: 'Nanum Gothic', '나눔고딕';} +table {border-collapse: collapse;border-spacing: 0;background-color: transparent} +caption {width:0;height:0;overflow:hidden;font-size:0} + + + +#pinpoint {min-width:1290px;height:100%} +header {background:#469ae4;border-bottom:1px solid #4484c3;height:50px;justify-content: space-between;position: relative;top: 0;left: 0;z-index: 100;min-width: 1290px;width: 100%} + +.flex-container {display: flex;} +.flex-container.flex-row {flex-flow: row wrap} +.flex-container.flex-column {flex-flow: column nowrap} +.flex-container.flex-row.reverse {flex-direction: row-reverse} +.flex-item {display: flex;justify-content: center;align-items: center;} + +.font-opensans {font-family: 'Open Sans', sans-serif} +.nanumgothic {font-family: "Nanum Gothic",나눔고딕} + +.btn {font-size:13px;color:#666;height:30px;padding:0 13px;border-radius:1px;font-weight:600} +.btn .icon {font-size:11px} +.btn.active {border:1px solid #4491da;background:#4b99e3;color:#fff} +.btn-sm {font-size:13px;height:28px} +.btn-blue {color:#fff;background-color:#4b99e3;border: 1px solid #4491da} +.btn-black{color:#fff;background-color:#3f506c;border: 1px solid #384c65} +.btn-gray {color:#fff;background-color:#ccc;border: 1px solid #aaa} +.pinpoint-btn {background:#4b99e3;color:#fff;font-family: 'Open Sans', sans-serif;font-weight:600;padding:10px 15px;text-align:center;font-size: 11px;line-height: 1em;border-radius:2px} +.pinpoint-btn span {position:relative;padding:0 0 0 14px} +.pinpoint-btn .fas {left:0;position:absolute;top:50%;transform:translateY(-50%);font-size: 1.5em;} + +.inactive {display:none} +*[hidden] { display: none !important; } + +.table {max-width: 100%;width: 100%;border:1px solid #e5e8f0;background:#fff} +.table th, .table td {height:28px;font-size:12px;font-family:'Open Sans', sans-serif;padding:0 21px} +.table thead th {background:#f6f8fb;height:36px;font-weight:600} +.table tbody th {text-align:left} +.table th {color:#666} +.table td{color:#999} +.table td, .table tbody th {font-weight:400;word-break:break-all} +.table.tr-link tbody tr {cursor:pointer} +.table tr.tr-bg-blue {background-color:#eef9fc} +.table tr.tr-bg-red {background-color:#fff1f1} +.popup { + position: absolute; + z-index: 999999; + background-color: #FFF; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + font-size: 14px; + min-width: 160px; +} + +@keyframes rootFadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/test.ts b/web/src/main/webapp/v2/src/test.ts new file mode 100644 index 000000000000..f9d51efd05fa --- /dev/null +++ b/web/src/main/webapp/v2/src/test.ts @@ -0,0 +1,32 @@ +import './polyfills.ts'; + +import 'zone.js/dist/long-stack-trace-zone'; +import 'zone.js/dist/proxy.js'; +import 'zone.js/dist/sync-test'; +import 'zone.js/dist/jasmine-patch'; +import 'zone.js/dist/async-test'; +import 'zone.js/dist/fake-async-test'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. +declare var __karma__: any; +declare var require: any; + +// Prevent Karma from running prematurely. +__karma__.loaded = function () {}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); +// Finally, start Karma to run the tests. +__karma__.start(); diff --git a/web/src/main/webapp/v2/src/tsconfig.app.json b/web/src/main/webapp/v2/src/tsconfig.app.json new file mode 100644 index 000000000000..42bbc7f5d44d --- /dev/null +++ b/web/src/main/webapp/v2/src/tsconfig.app.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "es2016", + "lib": [ + "es2016", + "dom" + ], + "outDir": "../out-tsc/app", + "module": "es2015", + "baseUrl": "", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts" + ] +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/tsconfig.spec.json b/web/src/main/webapp/v2/src/tsconfig.spec.json new file mode 100644 index 000000000000..d8e95227281c --- /dev/null +++ b/web/src/main/webapp/v2/src/tsconfig.spec.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ + "es2016", + "dom" + ], + "outDir": "../out-tsc/spec", + "module": "commonjs", + "target": "es2016", + "baseUrl": "", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/src/typings.d.ts b/web/src/main/webapp/v2/src/typings.d.ts new file mode 100644 index 000000000000..56970ec163bf --- /dev/null +++ b/web/src/main/webapp/v2/src/typings.d.ts @@ -0,0 +1,7 @@ +// Typings reference file, you can add your own global typings here +// https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html +declare var ga: Function; +declare var module: NodeModule; +interface NodeModule { + id: string; +} diff --git a/web/src/main/webapp/v2/tsconfig.json b/web/src/main/webapp/v2/tsconfig.json new file mode 100644 index 000000000000..187a3751f401 --- /dev/null +++ b/web/src/main/webapp/v2/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "outDir": "./dist/out-tsc", + "baseUrl": "src", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "es2015", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2017", + "dom" + ], + "preserveSymlinks": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "strict": false, + "noUnusedLocals": true + }, + "angularCompilerOptions": { + "fullTemplateTypeCheck": true, + "skipMetadataEmit": true + } +} \ No newline at end of file diff --git a/web/src/main/webapp/v2/tslint.json b/web/src/main/webapp/v2/tslint.json new file mode 100644 index 000000000000..69a13bfb0b9d --- /dev/null +++ b/web/src/main/webapp/v2/tslint.json @@ -0,0 +1,128 @@ +{ + "rulesDirectory": [ + "node_modules/codelyzer" + ], + "rules": { + "callable-types": true, + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "eofline": true, + "forin": true, + "import-blacklist": [ + true, + "rxjs/Rx" + ], + "import-spacing": true, + "indent": [ + true, + "spaces", + 4 + ], + "interface-over-type-literal": true, + "label-position": true, + "max-line-length": [ + false, + 140 + ], + "member-access": false, + "member-ordering": [ + false + ], + "no-arg": true, + "no-bitwise": false, + "no-console": [ + true, + "debug", + "info", + // "time", + // "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-shadowed-variable": true, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "prefer-const": true, + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + true, + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "typeof-compare": true, + "unified-signatures": true, + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "directive-selector": [ + true, + "attribute", + "pp", + "camelCase" + ], + "component-selector": [ + true, + "element", + "pp", + "kebab-case" + ], + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "component-class-suffix": true, + "directive-class-suffix": true + } +} \ No newline at end of file diff --git a/web/src/package-lock.json b/web/src/package-lock.json new file mode 100644 index 000000000000..746dd7260cc1 --- /dev/null +++ b/web/src/package-lock.json @@ -0,0 +1,5162 @@ +{ + "name": "pinpoint", + "version": "1.6.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@gulp-sourcemaps/map-sources": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", + "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", + "dev": true, + "requires": { + "normalize-path": "^2.0.1", + "through2": "^2.0.3" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "optional": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true, + "optional": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true, + "optional": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "beeper": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "dev": true + }, + "body": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", + "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "dev": true, + "requires": { + "continuable-cache": "^0.3.1", + "error": "^7.0.0", + "raw-body": "~1.1.0", + "safe-json-parse": "~1.0.1" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "dev": true, + "requires": { + "pako": "~0.2.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true, + "optional": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "^7.1.1" + }, + "dependencies": { + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, + "cloneable-readable": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", + "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "optional": true + }, + "coffeescript": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz", + "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, + "optional": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "continuable-cache": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", + "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cson": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/cson/-/cson-3.0.2.tgz", + "integrity": "sha1-g+6Qids8JUvsHpjkmNmqzxGtzFQ=", + "dev": true, + "requires": { + "coffee-script": "^1.9.0", + "cson-parser": "^1.0.6", + "extract-opts": "^3.0.1", + "requirefresh": "^2.0.0", + "safefs": "^4.0.0" + }, + "dependencies": { + "coffee-script": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", + "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", + "dev": true + } + } + }, + "cson-parser": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/cson-parser/-/cson-parser-1.3.5.tgz", + "integrity": "sha1-fsZ14DkUVTO/KmqFYHPxWZ2cLSQ=", + "dev": true, + "requires": { + "coffee-script": "^1.10.0" + }, + "dependencies": { + "coffee-script": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", + "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", + "dev": true + } + } + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true, + "optional": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "date-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-1.1.0.tgz", + "integrity": "sha1-GIdtC9pMGf5w3Tv0sDTygbEqQLY=", + "dev": true, + "requires": { + "time-zone": "^0.1.0" + } + }, + "dateformat": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.3.0" + } + }, + "deap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deap/-/deap-1.0.1.tgz", + "integrity": "sha512-k75KYNZMvwAwes2xIPry/QTffXIchjD8QfABvvfTr80P85jv5ZcKqcoDo+vMe71nNnVnXYe8MA28weyqcf/DKw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debug-fabulous": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-0.0.4.tgz", + "integrity": "sha1-+gccXYdIRoVCSAdCHKSxawsaB2M=", + "dev": true, + "requires": { + "debug": "2.X", + "lazy-debug-legacy": "0.0.X", + "object-assign": "4.1.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", + "dev": true + } + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "deprecated": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", + "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", + "dev": true + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "~1.1.1", + "entities": "~1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "~1.1.9" + } + }, + "eachr": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eachr/-/eachr-3.2.0.tgz", + "integrity": "sha1-LDXkPqCGUW95l8+At6pk1VpKRIQ=", + "dev": true, + "requires": { + "editions": "^1.1.1", + "typechecker": "^4.3.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "editions": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", + "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", + "dev": true + }, + "end-of-stream": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", + "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", + "dev": true, + "requires": { + "once": "~1.3.0" + }, + "dependencies": { + "once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1" + } + } + } + }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, + "errlop": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/errlop/-/errlop-1.0.3.tgz", + "integrity": "sha512-5VTnt0yikY4LlQEfCXVSqfE6oLj1HVM4zVSvAKMnoYjL/zrb6nqiLowZS4XlG7xENfyj7lpYWvT+wfSCr6dtlA==", + "dev": true, + "requires": { + "editions": "^1.3.4" + } + }, + "error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "dev": true, + "requires": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es6-promise": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", + "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", + "dev": true, + "optional": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "http://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extract-opts": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/extract-opts/-/extract-opts-3.3.1.tgz", + "integrity": "sha1-WrvtyYwNUgLjJ4cn+Rktfghsa+E=", + "dev": true, + "requires": { + "eachr": "^3.2.0", + "editions": "^1.1.1", + "typechecker": "^4.3.0" + } + }, + "extract-zip": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", + "dev": true, + "optional": true, + "requires": { + "concat-stream": "1.6.2", + "debug": "2.6.9", + "mkdirp": "0.5.1", + "yauzl": "2.4.1" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true, + "optional": true + }, + "fancy-log": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", + "dev": true, + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "time-stamp": "^1.0.0" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true, + "optional": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true, + "optional": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "optional": true, + "requires": { + "pend": "~1.2.0" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "file-sync-cmp": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", + "dev": true + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dev": true, + "requires": { + "glob": "~5.0.0" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "fined": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", + "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "first-chunk-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", + "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", + "dev": true + }, + "flagged-respawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz", + "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.6", + "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "optional": true, + "requires": { + "delayed-stream": "~1.0.0" + } + } + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getobject": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-stream": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", + "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", + "dev": true, + "requires": { + "glob": "^4.3.1", + "glob2base": "^0.0.12", + "minimatch": "^2.0.1", + "ordered-read-streams": "^0.1.0", + "through2": "^0.6.1", + "unique-stream": "^1.0.0" + }, + "dependencies": { + "glob": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", + "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^2.0.1", + "once": "^1.3.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + } + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + } + } + }, + "glob-watcher": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", + "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "dev": true, + "requires": { + "gaze": "^0.5.1" + }, + "dependencies": { + "gaze": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", + "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "dev": true, + "requires": { + "globule": "~0.1.0" + } + }, + "glob": { + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "dev": true, + "requires": { + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" + } + }, + "globule": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", + "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", + "dev": true, + "requires": { + "glob": "~3.1.21", + "lodash": "~1.0.1", + "minimatch": "~0.2.11" + } + }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", + "dev": true + }, + "inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", + "dev": true + }, + "lodash": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", + "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", + "dev": true + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + } + } + }, + "glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "dev": true, + "requires": { + "find-index": "^0.1.1" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globule": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + }, + "dependencies": { + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "glogg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz", + "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==", + "dev": true, + "requires": { + "sparkles": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "grunt": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.3.tgz", + "integrity": "sha512-/JzmZNPfKorlCrrmxWqQO4JVodO+DVd5XX4DkocL/1WlLlKVLE9+SdEIempOAxDhWPysLle6afvn/hg7Ck2k9g==", + "dev": true, + "requires": { + "coffeescript": "~1.10.0", + "dateformat": "~1.0.12", + "eventemitter2": "~0.4.13", + "exit": "~0.1.1", + "findup-sync": "~0.3.0", + "glob": "~7.0.0", + "grunt-cli": "~1.2.0", + "grunt-known-options": "~1.1.0", + "grunt-legacy-log": "~2.0.0", + "grunt-legacy-util": "~1.1.1", + "iconv-lite": "~0.4.13", + "js-yaml": "~3.5.2", + "minimatch": "~3.0.2", + "mkdirp": "~0.5.1", + "nopt": "~3.0.6", + "path-is-absolute": "~1.0.0", + "rimraf": "~2.6.2" + }, + "dependencies": { + "grunt-cli": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", + "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", + "dev": true, + "requires": { + "findup-sync": "~0.3.0", + "grunt-known-options": "~1.1.0", + "nopt": "~3.0.6", + "resolve": "~1.1.0" + } + } + } + }, + "grunt-cli": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.3.1.tgz", + "integrity": "sha512-UwBRu/QpAjDc53DRLEkyilFdL0zenpxu+fddTIlsF/KJqdNcHaQmvyu1W3cDesZ9rqqZdKK5A8+QDIyLUEWoZQ==", + "dev": true, + "requires": { + "grunt-known-options": "~1.1.0", + "interpret": "~1.1.0", + "liftoff": "~2.5.0", + "nopt": "~4.0.1", + "v8flags": "~3.0.2" + }, + "dependencies": { + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + } + } + }, + "grunt-contrib-clean": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-1.1.0.tgz", + "integrity": "sha1-Vkq/LQN4qYOhW54/MO51tzjEBjg=", + "dev": true, + "requires": { + "async": "^1.5.2", + "rimraf": "^2.5.1" + } + }, + "grunt-contrib-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz", + "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "source-map": "^0.5.3" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "grunt-contrib-copy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", + "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "file-sync-cmp": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "grunt-contrib-jshint": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.1.0.tgz", + "integrity": "sha1-Np2QmyWTxA6L55lAshNAhQx5Oaw=", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "hooker": "^0.2.3", + "jshint": "~2.9.4" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "grunt-contrib-uglify": { + "version": "1.0.2", + "resolved": "http://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-1.0.2.tgz", + "integrity": "sha1-rmekb5FT7dTLEYE6Vetpxw19svs=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "lodash": "^4.0.1", + "maxmin": "^1.1.0", + "uglify-js": "~2.6.2", + "uri-path": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "grunt-contrib-watch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz", + "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==", + "dev": true, + "requires": { + "async": "^2.6.0", + "gaze": "^1.1.0", + "lodash": "^4.17.10", + "tiny-lr": "^1.1.1" + }, + "dependencies": { + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + } + } + }, + "grunt-known-options": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz", + "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==", + "dev": true + }, + "grunt-legacy-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz", + "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==", + "dev": true, + "requires": { + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.0.0", + "hooker": "~0.2.3", + "lodash": "~4.17.5" + } + }, + "grunt-legacy-log-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz", + "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==", + "dev": true, + "requires": { + "chalk": "~2.4.1", + "lodash": "~4.17.10" + } + }, + "grunt-legacy-util": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz", + "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==", + "dev": true, + "requires": { + "async": "~1.5.2", + "exit": "~0.1.1", + "getobject": "~0.1.0", + "hooker": "~0.2.3", + "lodash": "~4.17.10", + "underscore.string": "~3.3.4", + "which": "~1.3.0" + } + }, + "grunt-regex-replace": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/grunt-regex-replace/-/grunt-regex-replace-0.2.10.tgz", + "integrity": "sha1-LsReo4PhaNnkOCLFxtwKPj/ZRrg=", + "dev": true + }, + "gulp": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", + "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", + "dev": true, + "requires": { + "archy": "^1.0.0", + "chalk": "^1.0.0", + "deprecated": "^0.0.1", + "gulp-util": "^3.0.0", + "interpret": "^1.0.0", + "liftoff": "^2.1.0", + "minimist": "^1.1.0", + "orchestrator": "^0.3.0", + "pretty-hrtime": "^1.0.0", + "semver": "^4.1.0", + "tildify": "^1.0.0", + "v8flags": "^2.0.2", + "vinyl-fs": "^0.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "v8flags": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", + "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "dev": true, + "requires": { + "user-home": "^1.1.1" + } + } + } + }, + "gulp-banner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/gulp-banner/-/gulp-banner-0.1.3.tgz", + "integrity": "sha1-AgijFJg/3IUclemUSwp88wVHn6M=", + "dev": true, + "requires": { + "gulp-util": "~3.0.7", + "through2": "~2.0.0", + "underscore.template": "~0.1.2" + } + }, + "gulp-concat": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", + "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "dev": true, + "requires": { + "concat-with-sourcemaps": "^1.0.0", + "through2": "^2.0.0", + "vinyl": "^2.0.0" + }, + "dependencies": { + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, + "vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + } + } + } + }, + "gulp-jshint": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/gulp-jshint/-/gulp-jshint-2.1.0.tgz", + "integrity": "sha512-sP3NK8Y/1e58O0PH9t6s7DAr/lKDSUbIY207oWSeufM6/VclB7jJrIBcPCsyhrFTCDUl9DauePbt6VqP2vPM5w==", + "dev": true, + "requires": { + "lodash": "^4.12.0", + "minimatch": "^3.0.3", + "plugin-error": "^0.1.2", + "rcloader": "^0.2.2", + "through2": "^2.0.0" + } + }, + "gulp-sourcemaps": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.12.1.tgz", + "integrity": "sha1-tDfR89mAzyboEYSCNxjOFa5ll7Y=", + "dev": true, + "requires": { + "@gulp-sourcemaps/map-sources": "1.X", + "acorn": "4.X", + "convert-source-map": "1.X", + "css": "2.X", + "debug-fabulous": "0.0.X", + "detect-newline": "2.X", + "graceful-fs": "4.X", + "source-map": "~0.6.0", + "strip-bom": "2.X", + "through2": "2.X", + "vinyl": "1.X" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "dev": true, + "requires": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + } + } + } + }, + "gulp-uglify": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-1.5.4.tgz", + "integrity": "sha1-UkeI2HZm0J+dDCH7IXf5ADmmWMk=", + "dev": true, + "requires": { + "deap": "^1.0.0", + "fancy-log": "^1.0.0", + "gulp-util": "^3.0.0", + "isobject": "^2.0.0", + "through2": "^2.0.0", + "uglify-js": "2.6.4", + "uglify-save-license": "^0.4.1", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "gulp-util": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "dev": true, + "requires": { + "array-differ": "^1.0.0", + "array-uniq": "^1.0.2", + "beeper": "^1.0.0", + "chalk": "^1.0.0", + "dateformat": "^2.0.0", + "fancy-log": "^1.1.0", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "lodash._reescape": "^3.0.0", + "lodash._reevaluate": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.template": "^3.0.0", + "minimist": "^1.1.0", + "multipipe": "^0.1.2", + "object-assign": "^3.0.0", + "replace-ext": "0.0.1", + "through2": "^2.0.0", + "vinyl": "^0.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "dateformat": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", + "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", + "dev": true + }, + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "requires": { + "glogg": "^1.0.0" + } + }, + "gzip-size": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz", + "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=", + "dev": true, + "requires": { + "browserify-zlib": "^0.1.4", + "concat-stream": "^1.4.1" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "dev": true, + "optional": true, + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-gulplog": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "dev": true, + "requires": { + "sparkles": "^1.0.0" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hasha": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "dev": true, + "optional": true, + "requires": { + "is-stream": "^1.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "dev": true + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + } + }, + "http-parser-js": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz", + "integrity": "sha1-O9bW/ebjFyyTNMOzO2wZPYD+ETc=", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/inherit/-/inherit-2.2.6.tgz", + "integrity": "sha1-8WFLBshUToEo5CKchjR9tzrZeI0=", + "dev": true + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "dev": true + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "optional": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true, + "optional": true + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jit-grunt": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/jit-grunt/-/jit-grunt-0.10.0.tgz", + "integrity": "sha1-AIw6f+Hpa9DYTiYOofoXg0V/ecI=", + "dev": true + }, + "js-yaml": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz", + "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=", + "dev": true, + "requires": { + "argparse": "^1.0.2", + "esprima": "^2.6.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jshint": { + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.6.tgz", + "integrity": "sha512-KO9SIAKTlJQOM4lE64GQUtGBRpTOuvbrRrSZw3AhUxMNG266nX9hK2cKA4SBhXOj0irJGyNyGSLT62HGOVDEOA==", + "dev": true, + "requires": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.10", + "minimatch": "~3.0.2", + "phantom": "~4.0.1", + "phantomjs-prebuilt": "~2.1.7", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x", + "unicode-5.2.0": "^0.7.5" + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true, + "optional": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true, + "optional": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true, + "optional": true + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true, + "optional": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "lazy-debug-legacy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/lazy-debug-legacy/-/lazy-debug-legacy-0.0.1.tgz", + "integrity": "sha1-U3cWwHduTPeePtG2IfdljCkRsbE=", + "dev": true + }, + "liftoff": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", + "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "findup-sync": "^2.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "dependencies": { + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + } + } + }, + "livereload-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.3.0.tgz", + "integrity": "sha512-j1R0/FeGa64Y+NmqfZhyoVRzcFlOZ8sNlKzHjh4VvLULFACZhn68XrX5DFg2FhMvSMJmROuFxRSa560ECWKBMg==", + "dev": true + }, + "load-grunt-config": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/load-grunt-config/-/load-grunt-config-0.19.2.tgz", + "integrity": "sha1-UgkNSiDG5j90p2SPJJsZ57f87CQ=", + "dev": true, + "requires": { + "cson": "~3.0.2", + "glob": "~5.0.15", + "jit-grunt": "~0.10.0", + "js-yaml": "~3.4.3", + "load-grunt-tasks": "~3.3.0", + "lodash": "~3.10.1" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "js-yaml": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz", + "integrity": "sha1-a+GyP2JJ9T0pM3D9TRqqY84bTrA=", + "dev": true, + "requires": { + "argparse": "^1.0.2", + "esprima": "^2.6.0", + "inherit": "^2.2.2" + } + }, + "lodash": { + "version": "3.10.1", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + } + } + }, + "load-grunt-tasks": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-3.3.0.tgz", + "integrity": "sha1-vliSkJRY2T3fdp60vGhRAggMYyE=", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "multimatch": "^2.0.0", + "pkg-up": "^1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", + "dev": true + }, + "lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash._reescape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", + "dev": true + }, + "lodash._reevaluate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", + "dev": true + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "dev": true, + "requires": { + "lodash._root": "^3.0.0" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.isobject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "dev": true + }, + "lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "dev": true + }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0" + } + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "maxmin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", + "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "figures": "^1.0.1", + "gzip-size": "^1.0.0", + "pretty-bytes": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==", + "dev": true + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "dev": true, + "requires": { + "mime-db": "~1.36.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "dev": true, + "requires": { + "array-differ": "^1.0.0", + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "minimatch": "^3.0.0" + } + }, + "multipipe": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "dev": true, + "requires": { + "duplexer2": "0.0.2" + } + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natives": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.5.tgz", + "integrity": "sha512-1pJ+02gl2KJgCPFtpZGtuD4lGSJnIZvvFHCQTOeDRMSXjfu2GmYWuhI8NFMA4W2I5NNFRbfy/YCiVt4CgNpP8A==", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "dev": true, + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "orchestrator": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", + "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", + "dev": true, + "requires": { + "end-of-stream": "~0.1.5", + "sequencify": "~0.0.7", + "stream-consume": "~0.1.0" + } + }, + "ordered-read-streams": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", + "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-ms": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", + "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=", + "dev": true + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true, + "optional": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true, + "optional": true + }, + "phantom": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/phantom/-/phantom-4.0.12.tgz", + "integrity": "sha512-Tz82XhtPmwCk1FFPmecy7yRGZG2btpzY2KI9fcoPT7zT9det0CcMyfBFPp1S8DqzsnQnm8ZYEfdy528mwVtksA==", + "dev": true, + "optional": true, + "requires": { + "phantomjs-prebuilt": "^2.1.16", + "split": "^1.0.1", + "winston": "^2.4.0" + } + }, + "phantomjs-prebuilt": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", + "dev": true, + "optional": true, + "requires": { + "es6-promise": "^4.0.3", + "extract-zip": "^1.6.5", + "fs-extra": "^1.0.0", + "hasha": "^2.2.0", + "kew": "^0.7.0", + "progress": "^1.1.8", + "request": "^2.81.0", + "request-progress": "^2.0.1", + "which": "^1.2.10" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + }, + "plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", + "dev": true, + "requires": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "dependencies": { + "arr-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + } + }, + "arr-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", + "dev": true + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", + "dev": true, + "requires": { + "kind-of": "^1.1.0" + } + }, + "kind-of": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", + "dev": true + } + } + }, + "plur": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz", + "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "pretty-bytes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.1.0" + } + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true + }, + "pretty-ms": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", + "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=", + "dev": true, + "requires": { + "is-finite": "^1.0.1", + "parse-ms": "^1.0.0", + "plur": "^1.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true, + "optional": true + }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "dev": true, + "optional": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true, + "optional": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "raw-body": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", + "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "dev": true, + "requires": { + "bytes": "1", + "string_decoder": "0.10" + } + }, + "rcfinder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/rcfinder/-/rcfinder-0.1.9.tgz", + "integrity": "sha1-8+gPOH3fmugK4wpBADKWQuroERU=", + "dev": true, + "requires": { + "lodash.clonedeep": "^4.3.2" + } + }, + "rcloader": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/rcloader/-/rcloader-0.2.2.tgz", + "integrity": "sha1-WNIpi0YtC5v9ITPSoex0+9cFxxc=", + "dev": true, + "requires": { + "lodash.assign": "^4.2.0", + "lodash.isobject": "^3.0.2", + "lodash.merge": "^4.6.0", + "rcfinder": "^0.1.6" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "request-progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", + "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "dev": true, + "optional": true, + "requires": { + "throttleit": "^1.0.0" + } + }, + "requirefresh": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/requirefresh/-/requirefresh-2.1.0.tgz", + "integrity": "sha1-dC3Mwg86lpGNZsbxWX3I/+vE9vU=", + "dev": true, + "requires": { + "editions": "^1.1.1" + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-json-parse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", + "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safefs": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/safefs/-/safefs-4.1.0.tgz", + "integrity": "sha1-+CrrS9165R9lPrIPZyizBYyNZEU=", + "dev": true, + "requires": { + "editions": "^1.1.1", + "graceful-fs": "^4.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true + }, + "sequencify": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", + "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", + "dev": true + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true + }, + "spdx-correct": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.1.tgz", + "integrity": "sha512-hxSPZbRZvSDuOvADntOElzJpenIR7wXJkuoUcUtS0erbgt2fgeaoPIYretfKpslMhfFDY4k0MZ2F5CUzhBsSvQ==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", + "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==", + "dev": true + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "optional": true, + "requires": { + "through": "2" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz", + "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=", + "dev": true + }, + "sshpk": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "dev": true, + "optional": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true, + "optional": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-consume": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", + "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", + "dev": true + }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "dev": true, + "optional": true + }, + "through": { + "version": "2.3.8", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true, + "optional": true + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "tildify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", + "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0" + } + }, + "time-grunt": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/time-grunt/-/time-grunt-1.4.0.tgz", + "integrity": "sha1-BiIT5mDJB+hvRAVWwB6mWXtxJCA=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "date-time": "^1.1.0", + "figures": "^1.0.0", + "hooker": "^0.2.3", + "number-is-nan": "^1.0.0", + "pretty-ms": "^2.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, + "time-zone": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-0.1.0.tgz", + "integrity": "sha1-Sncotqwo2w4Aj1FAQ/1VW9VXO0Y=", + "dev": true + }, + "tiny-lr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", + "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", + "dev": true, + "requires": { + "body": "^5.1.0", + "debug": "^3.1.0", + "faye-websocket": "~0.10.0", + "livereload-js": "^2.3.0", + "object-assign": "^4.1.0", + "qs": "^6.4.0" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "optional": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "typechecker": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/typechecker/-/typechecker-4.6.0.tgz", + "integrity": "sha512-83OrXpyP3LNr7aRbLkt2nkjE/d7q8su8/uRvrKxCpswqVCVGOgyaKpaz8/MTjQqBYe4eLNuJ44pNakFZKqyPMA==", + "dev": true, + "requires": { + "editions": "^2.0.2" + }, + "dependencies": { + "editions": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/editions/-/editions-2.0.2.tgz", + "integrity": "sha512-0B8aSTWUu9+JW99zHoeogavCi+lkE5l35FK0OKe0pCobixJYoeof3ZujtqYzSsU2MskhRadY5V9oWUuyG4aJ3A==", + "dev": true, + "requires": { + "errlop": "^1.0.2", + "semver": "^5.5.0" + } + } + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "2.6.4", + "resolved": "http://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz", + "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=", + "dev": true, + "requires": { + "async": "~0.2.6", + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + } + } + }, + "uglify-save-license": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/uglify-save-license/-/uglify-save-license-0.4.1.tgz", + "integrity": "sha1-lXJsF8xv0XHDYX479NjYKqjEzOE=", + "dev": true + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true + }, + "underscore.string": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz", + "integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=", + "dev": true, + "requires": { + "sprintf-js": "^1.0.3", + "util-deprecate": "^1.0.2" + } + }, + "underscore.template": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/underscore.template/-/underscore.template-0.1.7.tgz", + "integrity": "sha1-MBPg6hgXVjBvFgnpWcr7xyKts+k=", + "dev": true + }, + "unicode-5.2.0": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/unicode-5.2.0/-/unicode-5.2.0-0.7.5.tgz", + "integrity": "sha512-KVGLW1Bri30x00yv4HNM8kBxoqFXr0Sbo55735nvrlsx4PYBZol3UtoWgO492fSwmsetzPEZzy73rbU8OGXJcA==", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unique-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", + "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "uri-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", + "dev": true + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true, + "optional": true + }, + "v8flags": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.2.tgz", + "integrity": "sha512-6sgSKoFw1UpUPd3cFdF7QGnrH6tDeBgW1F3v9gy8gLY0mlbiBXq8soy8aQpY6xeeCjH5K+JvC62Acp7gtl7wWA==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vinyl": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "dev": true, + "requires": { + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" + } + }, + "vinyl-fs": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", + "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", + "dev": true, + "requires": { + "defaults": "^1.0.0", + "glob-stream": "^3.1.5", + "glob-watcher": "^0.0.6", + "graceful-fs": "^3.0.0", + "mkdirp": "^0.5.0", + "strip-bom": "^1.0.0", + "through2": "^0.6.1", + "vinyl": "^0.4.0" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", + "dev": true + }, + "graceful-fs": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", + "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "dev": true, + "requires": { + "natives": "^1.1.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "strip-bom": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", + "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", + "dev": true, + "requires": { + "first-chunk-stream": "^1.0.0", + "is-utf8": "^0.2.0" + } + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": ">=1.0.33-1 <1.1.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + } + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "dev": true, + "requires": { + "clone": "^0.2.0", + "clone-stats": "^0.0.1" + } + } + } + }, + "vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "dev": true, + "requires": { + "source-map": "^0.5.1" + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "winston": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz", + "integrity": "sha512-NBo2Pepn4hK4V01UfcWcDlmiVTs7VTB1h7bgnB0rgP146bYhMxX0ypCz3lBOfNxCO4Zuek7yeT+y/zM1OfMw4Q==", + "dev": true, + "optional": true, + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true, + "optional": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true, + "optional": true + } + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + } + } + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "optional": true, + "requires": { + "fd-slicer": "~1.0.1" + } + } + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/TestAwaitTaskUtils.java b/web/src/test/java/com/navercorp/pinpoint/web/TestAwaitTaskUtils.java deleted file mode 100644 index 88a7cce4deb8..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/TestAwaitTaskUtils.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web; - -/** - * @author Taejin Koo - */ -public interface TestAwaitTaskUtils { - - boolean checkCompleted(); - -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/TestAwaitUtils.java b/web/src/test/java/com/navercorp/pinpoint/web/TestAwaitUtils.java deleted file mode 100644 index 9a1479845fd4..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/TestAwaitUtils.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2016 NAVER Corp. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web; - -import com.navercorp.pinpoint.common.util.StopWatch; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Taejin Koo - */ -public class TestAwaitUtils { - - private final static Logger LOGGER = LoggerFactory.getLogger(TestAwaitUtils.class); - - private final long waitUnitTime; - private final long maxWaitTime; - - public TestAwaitUtils(long waitUnitTime, long maxWaitTime) { - this.waitUnitTime = waitUnitTime; - this.maxWaitTime = maxWaitTime; - } - - public boolean await(TestAwaitTaskUtils awaitTaskUtils) { - return await(awaitTaskUtils, waitUnitTime, maxWaitTime); - } - - public static boolean await(TestAwaitTaskUtils awaitTaskUtils, long waitUnitTime, long maxWaitTime) { - StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - - while (true) { - try { - if (awaitTaskUtils.checkCompleted()) { - return true; - } - } catch (Exception e) { - LOGGER.warn(e.getMessage(), e); - } - - try { - Thread.sleep(waitUnitTime); - } catch (InterruptedException e) { - } - - if (stopWatch.stop() > maxWaitTime) { - return false; - } - } - } - -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmPartitionerTest.java b/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmPartitionerTest.java index 1621879c85f4..6e7ba8d21e0a 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmPartitionerTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmPartitionerTest.java @@ -35,43 +35,8 @@ public class AlarmPartitionerTest { @Test public void partitionTest() { - AlarmPartitioner partitioner = new AlarmPartitioner(dao); + AlarmPartitioner partitioner = new AlarmPartitioner(); Map partitions = partitioner.partition(0); - Assert.assertEquals(8, partitions.size()); + Assert.assertEquals(1, partitions.size()); } - - @BeforeClass - public static void beforeClass() { - dao = new ApplicationIndexDao() { - - @Override - public List selectAllApplicationNames() { - List apps = new LinkedList(); - - for(int i = 0; i <= 37; i++) { - apps.add(new Application("app" + i, ServiceType.STAND_ALONE)); - } - - return apps; - } - - @Override - public List selectAgentIds(String applicationName) { - return null; - } - - @Override - public void deleteApplicationName(String applicationName) { - } - - @Override - public void deleteAgentIds(Map> applicationAgentIdMap) { - } - - @Override - public void deleteAgentId(String applicationName, String agentId) { - } - }; - } - } diff --git a/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmReaderTest.java b/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmReaderTest.java new file mode 100644 index 000000000000..c30660194271 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmReaderTest.java @@ -0,0 +1,134 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.alarm; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.item.ExecutionContext; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.web.alarm.collector.DataCollector; +import com.navercorp.pinpoint.web.alarm.collector.ResponseTimeDataCollector; +import com.navercorp.pinpoint.web.alarm.vo.Rule; +import com.navercorp.pinpoint.web.dao.ApplicationIndexDao; +import com.navercorp.pinpoint.web.service.AlarmService; +import com.navercorp.pinpoint.web.service.AlarmServiceImpl; +import com.navercorp.pinpoint.web.vo.Application; + +public class AlarmReaderTest { + + private static ApplicationIndexDao applicationIndexDao; + private static AlarmService alarmService; + private static DataCollectorFactory dataCollectorFactory; + private static final String APP_NAME = "app"; + private static final String SERVICE_TYPE = "tomcat"; + + @Test + public void readTest() { + StepExecution stepExecution = new StepExecution("alarmStep", null); + ExecutionContext executionContext = new ExecutionContext(); + stepExecution.setExecutionContext(executionContext); + + AlarmReader reader = new AlarmReader(dataCollectorFactory, applicationIndexDao, alarmService); + + reader.beforeStep(stepExecution); + + for(int i = 0; i < 7; i++) { + assertNotNull(reader.read()); + } + + assertNull(reader.read()); + } + + @Test + public void readTest3() { + StepExecution stepExecution = new StepExecution("alarmStep", null); + ExecutionContext executionContext = new ExecutionContext(); + stepExecution.setExecutionContext(executionContext); + + AlarmServiceImpl alarmService = new AlarmServiceImpl() { + @Override + public java.util.List selectRuleByApplicationId(String applicationId) { + return new LinkedList(); + } + }; + + AlarmReader reader = new AlarmReader(dataCollectorFactory, applicationIndexDao, alarmService); + reader.beforeStep(stepExecution); + assertNull(reader.read()); + } + + @BeforeClass + public static void beforeClass() { + applicationIndexDao = new ApplicationIndexDao() { + + @Override + public List selectAllApplicationNames() { + List apps = new LinkedList(); + + for(int i = 0; i < 7; i++) { + apps.add(new Application(APP_NAME + i, ServiceType.STAND_ALONE)); + } + return apps; + } + + @Override public List selectAgentIds(String applicationName) {return null;} + @Override public void deleteApplicationName(String applicationName) { } + + @Override + public void deleteAgentIds(Map> applicationAgentIdMap) {} + + @Override public void deleteAgentId(String applicationName, String agentId) {} + + }; + + alarmService = new AlarmServiceImpl() { + private Map ruleMap ; + + { + ruleMap = new HashMap(); + + for(int i = 0; i <=6; i++) { + ruleMap.put(APP_NAME + i, new Rule(APP_NAME + i, SERVICE_TYPE, CheckerCategory.SLOW_COUNT.getName(), 76, "testGroup", false, false, "")); + } + } + + @Override + public List selectRuleByApplicationId(String applicationId) { + List rules = new LinkedList(); + rules.add(ruleMap.get(applicationId)); + return rules; + } + }; + + dataCollectorFactory = new DataCollectorFactory() { + @Override + public DataCollector createDataCollector(CheckerCategory checker, Application application, long timeSlotEndTime) { + return new ResponseTimeDataCollector(DataCollectorCategory.RESPONSE_TIME, null, null, 0, 0); + } + }; + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmWriterTest.java b/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmWriterTest.java new file mode 100644 index 000000000000..e111171ff94a --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/alarm/AlarmWriterTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.alarm; + +import java.util.LinkedList; +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.navercorp.pinpoint.web.alarm.AlarmWriter; +import com.navercorp.pinpoint.web.alarm.CheckerCategory; +import com.navercorp.pinpoint.web.alarm.checker.AlarmChecker; +import com.navercorp.pinpoint.web.alarm.checker.SlowCountChecker; +import com.navercorp.pinpoint.web.alarm.vo.Rule; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:applicationContext-test.xml") +public class AlarmWriterTest { + + @Autowired + AlarmWriter writer; + + @Ignore + @Test + public void smsSendTest() throws Exception { + Rule rule = new Rule("testService", "tomcat", CheckerCategory.SLOW_COUNT.getName(), 100, "testGroup", true, false, ""); + SlowCountChecker checker = new SlowCountChecker(null, rule) { + @Override + public boolean isDetected() { + return true; + } + + @Override + protected Long getDetectedValue() { + return 10000L; + } + }; + + List checkers = new LinkedList(); + checkers.add(checker); + writer.write(checkers); + } + + @Ignore + @Test + public void emailSendTest() throws Exception { + Rule rule = new Rule("testService", "tomcat", CheckerCategory.SLOW_COUNT.getName(), 100, "testGroup", false, true, ""); + SlowCountChecker checker = new SlowCountChecker(null, rule) { + @Override + public boolean isDetected() { + return true; + } + + @Override + protected Long getDetectedValue() { + return 10000L; + } + }; + + List checkers = new LinkedList(); + checkers.add(checker); + writer.write(checkers); + } + +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/alarm/ReaderTest.java b/web/src/test/java/com/navercorp/pinpoint/web/alarm/ReaderTest.java deleted file mode 100644 index 1beb5bca60f1..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/alarm/ReaderTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.alarm; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.item.ExecutionContext; - -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.web.alarm.collector.DataCollector; -import com.navercorp.pinpoint.web.alarm.collector.ResponseTimeDataCollector; -import com.navercorp.pinpoint.web.alarm.vo.Rule; -import com.navercorp.pinpoint.web.dao.ApplicationIndexDao; -import com.navercorp.pinpoint.web.service.AlarmService; -import com.navercorp.pinpoint.web.service.AlarmServiceImpl; -import com.navercorp.pinpoint.web.vo.Application; - -public class ReaderTest { - - private static ApplicationIndexDao applicationIndexDao; - private static AlarmService alarmService; - private static DataCollectorFactory dataCollectorFactory; - private static final String APP_NAME = "app"; - private static final String SERVICE_TYPE = "tomcat"; - - @Test - public void readTest() { - StepExecution stepExecution = new StepExecution("alarmStep", null); - ExecutionContext executionContext = new ExecutionContext(); - executionContext.put(AlarmPartitioner.PARTITION_NUMBER, 1); - stepExecution.setExecutionContext(executionContext); - - AlarmReader reader = new AlarmReader(dataCollectorFactory, applicationIndexDao, alarmService); - - reader.beforeStep(stepExecution); - - for(int i = 0; i < 5; i++) { - assertNotNull(reader.read()); - } - - assertNull(reader.read()); - } - - @Test - public void readTest2() { - StepExecution stepExecution = new StepExecution("alarmStep", null); - ExecutionContext executionContext = new ExecutionContext(); - executionContext.put(AlarmPartitioner.PARTITION_NUMBER, 2); - stepExecution.setExecutionContext(executionContext); - - AlarmReader reader = new AlarmReader(dataCollectorFactory, applicationIndexDao, alarmService); - - reader.beforeStep(stepExecution); - - for(int i = 0; i < 2; i++) { - assertNotNull(reader.read()); - } - - assertNull(reader.read()); - } - - @Test - public void readTest3() { - StepExecution stepExecution = new StepExecution("alarmStep", null); - ExecutionContext executionContext = new ExecutionContext(); - executionContext.put(AlarmPartitioner.PARTITION_NUMBER, 2); - stepExecution.setExecutionContext(executionContext); - - AlarmServiceImpl alarmService = new AlarmServiceImpl() { - @Override - public java.util.List selectRuleByApplicationId(String applicationId) { - return new LinkedList(); - } - }; - - AlarmReader reader = new AlarmReader(dataCollectorFactory, applicationIndexDao, alarmService); - reader.beforeStep(stepExecution); - assertNull(reader.read()); - } - - @BeforeClass - public static void beforeClass() { - applicationIndexDao = new ApplicationIndexDao() { - - @Override - public List selectAllApplicationNames() { - List apps = new LinkedList(); - - for(int i = 0; i < 7; i++) { - apps.add(new Application(APP_NAME + i, ServiceType.STAND_ALONE)); - } - return apps; - } - - @Override public List selectAgentIds(String applicationName) {return null;} - @Override public void deleteApplicationName(String applicationName) { } - - @Override - public void deleteAgentIds(Map> applicationAgentIdMap) {} - - @Override public void deleteAgentId(String applicationName, String agentId) {} - - }; - - alarmService = new AlarmServiceImpl() { - private Map ruleMap ; - - { - ruleMap = new HashMap(); - - for(int i = 0; i <=6; i++) { - ruleMap.put(APP_NAME + i, new Rule(APP_NAME + i, SERVICE_TYPE, CheckerCategory.SLOW_COUNT.getName(), 76, "testGroup", false, false, "")); - } - } - - @Override - public List selectRuleByApplicationId(String applicationId) { - List rules = new LinkedList(); - rules.add(ruleMap.get(applicationId)); - return rules; - } - }; - - dataCollectorFactory = new DataCollectorFactory() { - @Override - public DataCollector createDataCollector(CheckerCategory checker, Application application, long timeSlotEndTime) { - return new ResponseTimeDataCollector(DataCollectorCategory.RESPONSE_TIME, null, null, 0, 0); - } - }; - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/alarm/WriterTest.java b/web/src/test/java/com/navercorp/pinpoint/web/alarm/WriterTest.java deleted file mode 100644 index 7d3807387a77..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/alarm/WriterTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.alarm; - -import java.util.LinkedList; -import java.util.List; - -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import com.navercorp.pinpoint.web.alarm.AlarmWriter; -import com.navercorp.pinpoint.web.alarm.CheckerCategory; -import com.navercorp.pinpoint.web.alarm.checker.AlarmChecker; -import com.navercorp.pinpoint.web.alarm.checker.SlowCountChecker; -import com.navercorp.pinpoint.web.alarm.vo.Rule; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("classpath:applicationContext-test.xml") -public class WriterTest { - - @Autowired - AlarmWriter writer; - - @Ignore - @Test - public void smsSendTest() throws Exception { - Rule rule = new Rule("testService", "tomcat", CheckerCategory.SLOW_COUNT.getName(), 100, "testGroup", true, false, ""); - SlowCountChecker checker = new SlowCountChecker(null, rule) { - @Override - public boolean isDetected() { - return true; - } - - @Override - protected Long getDetectedValue() { - return 10000L; - } - }; - - List checkers = new LinkedList(); - checkers.add(checker); - writer.write(checkers); - } - - @Ignore - @Test - public void emailSendTest() throws Exception { - Rule rule = new Rule("testService", "tomcat", CheckerCategory.SLOW_COUNT.getName(), 100, "testGroup", false, true, ""); - SlowCountChecker checker = new SlowCountChecker(null, rule) { - @Override - public boolean isDetected() { - return true; - } - - @Override - protected Long getDetectedValue() { - return 10000L; - } - }; - - List checkers = new LinkedList(); - checkers.add(checker); - writer.write(checkers); - } - -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/alarm/checker/DeadlockCheckerTest.java b/web/src/test/java/com/navercorp/pinpoint/web/alarm/checker/DeadlockCheckerTest.java index fd39e9e360df..3003cf18ebdc 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/alarm/checker/DeadlockCheckerTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/alarm/checker/DeadlockCheckerTest.java @@ -118,7 +118,7 @@ public void checkTest2() { Assert.assertTrue(StringUtils.isEmpty(emailMessage)); List smsMessage = checker.getSmsMessage(); - Assert.assertTrue(smsMessage.size() == 0); + Assert.assertTrue(smsMessage.isEmpty()); } private AgentEventBo createAgentEvent(String agentId, long eventTimestamp, AgentEventType agentEventType) { diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderCompatibilityTest.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderCompatibilityTest.java deleted file mode 100644 index 4d29c11f4ec0..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderCompatibilityTest.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap; - -import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.web.applicationmap.appender.histogram.DefaultNodeHistogramFactory; -import com.navercorp.pinpoint.web.applicationmap.appender.histogram.NodeHistogramFactory; -import com.navercorp.pinpoint.web.applicationmap.appender.histogram.datasource.MapResponseNodeHistogramDataSource; -import com.navercorp.pinpoint.web.applicationmap.appender.histogram.datasource.ResponseHistogramsNodeHistogramDataSource; -import com.navercorp.pinpoint.web.applicationmap.appender.server.DefaultServerInstanceListFactory; -import com.navercorp.pinpoint.web.applicationmap.appender.server.ServerInstanceListFactory; -import com.navercorp.pinpoint.web.applicationmap.appender.server.datasource.AgentInfoServerInstanceListDataSource; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; -import com.navercorp.pinpoint.web.dao.MapResponseDao; -import com.navercorp.pinpoint.web.service.AgentInfoService; -import com.navercorp.pinpoint.web.vo.AgentInfo; -import com.navercorp.pinpoint.web.vo.AgentStatus; -import com.navercorp.pinpoint.web.vo.Application; -import com.navercorp.pinpoint.web.vo.Range; -import com.navercorp.pinpoint.web.vo.ResponseHistograms; -import com.navercorp.pinpoint.web.vo.ResponseTime; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyCollection; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author HyunGil Jeong - */ -public class ApplicationMapBuilderCompatibilityTest { - - private MapResponseNodeHistogramDataSource mapResponseNodeHistogramDataSource; - - private ResponseHistogramsNodeHistogramDataSource responseHistogramBuilderNodeHistogramDataSource; - - private AgentInfoServerInstanceListDataSource agentInfoServerInstanceListDataSource; - - @Before - public void setUp() { - MapResponseDao mapResponseDao = mock(MapResponseDao.class); - mapResponseNodeHistogramDataSource = new MapResponseNodeHistogramDataSource(mapResponseDao); - - ResponseHistograms responseHistograms = mock(ResponseHistograms.class); - responseHistogramBuilderNodeHistogramDataSource = new ResponseHistogramsNodeHistogramDataSource(responseHistograms); - - AgentInfoService agentInfoService = mock(AgentInfoService.class); - agentInfoServerInstanceListDataSource = new AgentInfoServerInstanceListDataSource(agentInfoService); - - Answer> responseTimeAnswer = new Answer>() { - long timestamp = System.currentTimeMillis(); - @Override - public List answer(InvocationOnMock invocation) throws Throwable { - Application application = invocation.getArgument(0); - String applicationName = application.getName(); - ServiceType applicationServiceType = application.getServiceType(); - int depth = ApplicationMapBuilderTestHelper.getDepthFromApplicationName(applicationName); - ResponseTime responseTime = new ResponseTime(application.getName(), application.getServiceType(), timestamp); - responseTime.addResponseTime(ApplicationMapBuilderTestHelper.createAgentIdFromDepth(depth), applicationServiceType.getHistogramSchema().getNormalSlot().getSlotTime(), 1); - return Collections.singletonList(responseTime); - } - }; - when(mapResponseDao.selectResponseTime(any(Application.class), any(Range.class))).thenAnswer(responseTimeAnswer); - when(responseHistograms.getResponseTimeList(any(Application.class))).thenAnswer(responseTimeAnswer); - - when(agentInfoService.getAgentsByApplicationName(anyString(), anyLong())).thenAnswer(new Answer>() { - @Override - public Set answer(InvocationOnMock invocation) throws Throwable { - String applicationName = invocation.getArgument(0); - AgentInfo agentInfo = ApplicationMapBuilderTestHelper.createAgentInfoFromApplicationName(applicationName); - AgentStatus agentStatus = new AgentStatus(agentInfo.getAgentId()); - agentStatus.setState(AgentLifeCycleState.RUNNING); - agentInfo.setStatus(agentStatus); - Set agentInfos = new HashSet<>(); - agentInfos.add(agentInfo); - return agentInfos; - } - }); - when(agentInfoService.getAgentsByApplicationNameWithoutStatus(anyString(), anyLong())).thenAnswer(new Answer>() { - @Override - public Set answer(InvocationOnMock invocation) throws Throwable { - String applicationName = invocation.getArgument(0); - AgentInfo agentInfo = ApplicationMapBuilderTestHelper.createAgentInfoFromApplicationName(applicationName); - Set agentInfos = new HashSet<>(); - agentInfos.add(agentInfo); - return agentInfos; - } - }); - when(agentInfoService.getAgentStatus(anyString(), anyLong())).thenAnswer(new Answer() { - @Override - public AgentStatus answer(InvocationOnMock invocation) throws Throwable { - String agentId = invocation.getArgument(0); - AgentStatus agentStatus = new AgentStatus(agentId); - agentStatus.setEventTimestamp(System.currentTimeMillis()); - agentStatus.setState(AgentLifeCycleState.RUNNING); - return agentStatus; - } - }); - doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - Collection agentInfos = invocation.getArgument(0); - for (AgentInfo agentInfo : agentInfos) { - AgentStatus agentStatus = new AgentStatus(agentInfo.getAgentId()); - agentStatus.setEventTimestamp(System.currentTimeMillis()); - agentStatus.setState(AgentLifeCycleState.RUNNING); - agentInfo.setStatus(agentStatus); - } - return null; - } - }).when(agentInfoService).populateAgentStatuses(anyCollection(), anyLong()); - } - - @Test - public void testNoCallData() { - Range range = new Range(0, 1000); - Application application = ApplicationMapBuilderTestHelper.createApplicationFromDepth(0); - - ServerInstanceListFactory serverInstanceListFactory = new DefaultServerInstanceListFactory(agentInfoServerInstanceListDataSource); - - ApplicationMapBuilder applicationMapBuilder = ApplicationMapBuilderTestHelper.createApplicationMapBuilder(range); - ApplicationMapBuilder applicationMapBuilder_parallelAppenders = ApplicationMapBuilderTestHelper.createApplicationMapBuilder_parallelAppenders(range); - ApplicationMap applicationMap = applicationMapBuilder - .includeServerInfo(serverInstanceListFactory) - .build(application); - ApplicationMap applicationMap_parallelAppenders = applicationMapBuilder_parallelAppenders - .includeServerInfo(serverInstanceListFactory) - .build(application); - - Assert.assertEquals(1, applicationMap.getNodes().size()); - Assert.assertEquals(1, applicationMap.getNodes().size()); - Assert.assertEquals(1, applicationMap_parallelAppenders.getNodes().size()); - Assert.assertEquals(0, applicationMap.getLinks().size()); - Assert.assertEquals(0, applicationMap.getLinks().size()); - Assert.assertEquals(0, applicationMap_parallelAppenders.getLinks().size()); - - ApplicationMapVerifier verifier = new ApplicationMapVerifier(applicationMap); - verifier.verify(applicationMap); - verifier.verify(applicationMap_parallelAppenders); - } - - @Test - public void testEmptyCallData() { - Range range = new Range(0, 1000); - LinkDataDuplexMap linkDataDuplexMap = new LinkDataDuplexMap(); - - NodeHistogramFactory nodeHistogramFactory = new DefaultNodeHistogramFactory(mapResponseNodeHistogramDataSource); - ServerInstanceListFactory serverInstanceListFactory = new DefaultServerInstanceListFactory(agentInfoServerInstanceListDataSource); - - ApplicationMapBuilder applicationMapBuilder = ApplicationMapBuilderTestHelper.createApplicationMapBuilder(range); - ApplicationMapBuilder applicationMapBuilder_parallelAppenders = ApplicationMapBuilderTestHelper.createApplicationMapBuilder_parallelAppenders(range); - ApplicationMap applicationMap = applicationMapBuilder - .includeNodeHistogram(nodeHistogramFactory) - .includeServerInfo(serverInstanceListFactory) - .build(linkDataDuplexMap); - ApplicationMap applicationMap_parallelAppenders = applicationMapBuilder_parallelAppenders - .includeNodeHistogram(nodeHistogramFactory) - .includeServerInfo(serverInstanceListFactory) - .build(linkDataDuplexMap); - - Assert.assertTrue(applicationMap.getNodes().isEmpty()); - Assert.assertTrue(applicationMap.getNodes().isEmpty()); - Assert.assertTrue(applicationMap_parallelAppenders.getNodes().isEmpty()); - Assert.assertTrue(applicationMap.getLinks().isEmpty()); - Assert.assertTrue(applicationMap.getLinks().isEmpty()); - Assert.assertTrue(applicationMap_parallelAppenders.getLinks().isEmpty()); - - ApplicationMapVerifier verifier = new ApplicationMapVerifier(applicationMap); - verifier.verify(applicationMap); - verifier.verify(applicationMap_parallelAppenders); - } - - /** - * USER -> WAS(center) -> UNKNOWN - */ - @Test - public void testOneDepth() { - int depth = 1; - runTest(depth, depth); - } - - /** - * USER -> WAS -> WAS(center) -> WAS -> UNKNOWN - */ - @Test - public void testTwoDepth() { - int depth = 2; - runTest(depth, depth); - } - - /** - * USER -> WAS -> WAS -> WAS(center) -> WAS -> WAS -> UNKNOWN - */ - @Test - public void testThreeDepth() { - int depth = 3; - runTest(depth, depth); - } - - /** - * USER -> WAS(center) -> WAS -> WAS -> UNKNOWN - */ - @Test - public void test_1_3_depth() { - int calleeDepth = 1; - int callerDepth = 3; - runTest(calleeDepth, callerDepth); - } - - /** - * USER -> WAS -> WAS -> WAS(center) -> UNKNOWN - */ - @Test - public void test_3_1_depth() { - int calleeDepth = 3; - int callerDepth = 1; - runTest(calleeDepth, callerDepth); - } - - /** - * USER -> WAS -> WAS -> WAS(center) -> WAS -> WAS -> WAS -> UNKNOWN - */ - @Test - public void test_3_4_depth() { - int calleeDepth = 3; - int callerDepth = 4; - runTest(calleeDepth, callerDepth); - } - - /** - * USER -> WAS -> WAS -> WAS -> WAS(center) -> WAS -> WAS -> UNKNOWN - */ - @Test - public void test_4_3_depth() { - int calleeDepth = 4; - int callerDepth = 3; - runTest(calleeDepth, callerDepth); - } - - private void runTest(int callerDepth, int calleeDepth) { - Range range = new Range(0, 1000); - int expectedNumNodes = ApplicationMapBuilderTestHelper.getExpectedNumNodes(calleeDepth, callerDepth); - int expectedNumLinks = ApplicationMapBuilderTestHelper.getExpectedNumLinks(calleeDepth, callerDepth); - - NodeHistogramFactory nodeHistogramFactory_MapResponseDao = new DefaultNodeHistogramFactory(mapResponseNodeHistogramDataSource); - NodeHistogramFactory nodeHistogramFactory_ResponseHistogramBuilder = new DefaultNodeHistogramFactory(responseHistogramBuilderNodeHistogramDataSource); - ServerInstanceListFactory serverInstanceListFactory = new DefaultServerInstanceListFactory(agentInfoServerInstanceListDataSource); - - LinkDataDuplexMap linkDataDuplexMap = ApplicationMapBuilderTestHelper.createLinkDataDuplexMap(calleeDepth, callerDepth); - ApplicationMapBuilder applicationMapBuilder = ApplicationMapBuilderTestHelper.createApplicationMapBuilder(range); - ApplicationMapBuilder applicationMapBuilder_parallelAppenders = ApplicationMapBuilderTestHelper.createApplicationMapBuilder_parallelAppenders(range); - - // test builder using MapResponseDao - ApplicationMap applicationMap_MapResponseDao = applicationMapBuilder - .includeNodeHistogram(nodeHistogramFactory_MapResponseDao) - .includeServerInfo(serverInstanceListFactory) - .build(linkDataDuplexMap); - ApplicationMap applicationMap_MapResponseDao_parallelAppenders = applicationMapBuilder_parallelAppenders - .includeNodeHistogram(nodeHistogramFactory_MapResponseDao) - .includeServerInfo(serverInstanceListFactory) - .build(linkDataDuplexMap); - Assert.assertEquals(expectedNumNodes, applicationMap_MapResponseDao.getNodes().size()); - Assert.assertEquals(expectedNumNodes, applicationMap_MapResponseDao_parallelAppenders.getNodes().size()); - Assert.assertEquals(expectedNumLinks, applicationMap_MapResponseDao.getLinks().size()); - Assert.assertEquals(expectedNumLinks, applicationMap_MapResponseDao_parallelAppenders.getLinks().size()); - ApplicationMapVerifier verifier_MapResponseDao = new ApplicationMapVerifier(applicationMap_MapResponseDao); - verifier_MapResponseDao.verify(applicationMap_MapResponseDao); - verifier_MapResponseDao.verify(applicationMap_MapResponseDao_parallelAppenders); - - // test builder using ResponseHistogramBuilder - ApplicationMap applicationMap_ResponseHistogramBuilder = applicationMapBuilder - .includeNodeHistogram(nodeHistogramFactory_ResponseHistogramBuilder) - .includeServerInfo(serverInstanceListFactory) - .build(linkDataDuplexMap); - ApplicationMap applicationMap_ResponseHistogramBuilder_parallelAppenders = applicationMapBuilder_parallelAppenders - .includeNodeHistogram(nodeHistogramFactory_ResponseHistogramBuilder) - .includeServerInfo(serverInstanceListFactory) - .build(linkDataDuplexMap); - Assert.assertEquals(expectedNumNodes, applicationMap_ResponseHistogramBuilder.getNodes().size()); - Assert.assertEquals(expectedNumNodes, applicationMap_ResponseHistogramBuilder_parallelAppenders.getNodes().size()); - Assert.assertEquals(expectedNumLinks, applicationMap_ResponseHistogramBuilder.getLinks().size()); - Assert.assertEquals(expectedNumLinks, applicationMap_ResponseHistogramBuilder_parallelAppenders.getLinks().size()); - ApplicationMapVerifier verifier_ResponseHistogramBuilder = new ApplicationMapVerifier(applicationMap_ResponseHistogramBuilder); - verifier_ResponseHistogramBuilder.verify(applicationMap_ResponseHistogramBuilder); - verifier_ResponseHistogramBuilder.verify(applicationMap_ResponseHistogramBuilder_parallelAppenders); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderTest.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderTest.java new file mode 100644 index 000000000000..90378ae7e76e --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderTest.java @@ -0,0 +1,344 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.applicationmap; + +import com.navercorp.pinpoint.common.server.util.AgentLifeCycleState; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.web.applicationmap.appender.histogram.DefaultNodeHistogramFactory; +import com.navercorp.pinpoint.web.applicationmap.appender.histogram.NodeHistogramFactory; +import com.navercorp.pinpoint.web.applicationmap.appender.histogram.datasource.MapResponseNodeHistogramDataSource; +import com.navercorp.pinpoint.web.applicationmap.appender.histogram.datasource.ResponseHistogramsNodeHistogramDataSource; +import com.navercorp.pinpoint.web.applicationmap.appender.server.DefaultServerInstanceListFactory; +import com.navercorp.pinpoint.web.applicationmap.appender.server.ServerInstanceListFactory; +import com.navercorp.pinpoint.web.applicationmap.appender.server.datasource.AgentInfoServerInstanceListDataSource; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; +import com.navercorp.pinpoint.web.dao.MapResponseDao; +import com.navercorp.pinpoint.web.service.AgentInfoService; +import com.navercorp.pinpoint.web.vo.AgentInfo; +import com.navercorp.pinpoint.web.vo.AgentStatus; +import com.navercorp.pinpoint.web.vo.Application; +import com.navercorp.pinpoint.web.vo.Range; +import com.navercorp.pinpoint.web.vo.ResponseHistograms; +import com.navercorp.pinpoint.web.vo.ResponseTime; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +public class ApplicationMapBuilderTest { + + private final ExecutorService serialExecutor = Executors.newSingleThreadExecutor(); + + private final ExecutorService parallelExecutor = Executors.newFixedThreadPool(8); + + private MapResponseNodeHistogramDataSource mapResponseNodeHistogramDataSource; + + private ResponseHistogramsNodeHistogramDataSource responseHistogramBuilderNodeHistogramDataSource; + + private AgentInfoServerInstanceListDataSource agentInfoServerInstanceListDataSource; + + @Before + public void setUp() { + MapResponseDao mapResponseDao = mock(MapResponseDao.class); + mapResponseNodeHistogramDataSource = new MapResponseNodeHistogramDataSource(mapResponseDao); + + ResponseHistograms responseHistograms = mock(ResponseHistograms.class); + responseHistogramBuilderNodeHistogramDataSource = new ResponseHistogramsNodeHistogramDataSource(responseHistograms); + + AgentInfoService agentInfoService = mock(AgentInfoService.class); + agentInfoServerInstanceListDataSource = new AgentInfoServerInstanceListDataSource(agentInfoService); + + Answer> responseTimeAnswer = new Answer>() { + long timestamp = System.currentTimeMillis(); + @Override + public List answer(InvocationOnMock invocation) throws Throwable { + Application application = invocation.getArgument(0); + String applicationName = application.getName(); + ServiceType applicationServiceType = application.getServiceType(); + int depth = ApplicationMapBuilderTestHelper.getDepthFromApplicationName(applicationName); + ResponseTime responseTime = new ResponseTime(application.getName(), application.getServiceType(), timestamp); + responseTime.addResponseTime(ApplicationMapBuilderTestHelper.createAgentIdFromDepth(depth), applicationServiceType.getHistogramSchema().getNormalSlot().getSlotTime(), 1); + return Collections.singletonList(responseTime); + } + }; + when(mapResponseDao.selectResponseTime(any(Application.class), any(Range.class))).thenAnswer(responseTimeAnswer); + when(responseHistograms.getResponseTimeList(any(Application.class))).thenAnswer(responseTimeAnswer); + + when(agentInfoService.getAgentsByApplicationName(anyString(), anyLong())).thenAnswer(new Answer>() { + @Override + public Set answer(InvocationOnMock invocation) throws Throwable { + String applicationName = invocation.getArgument(0); + AgentInfo agentInfo = ApplicationMapBuilderTestHelper.createAgentInfoFromApplicationName(applicationName); + AgentStatus agentStatus = new AgentStatus(agentInfo.getAgentId()); + agentStatus.setState(AgentLifeCycleState.RUNNING); + agentInfo.setStatus(agentStatus); + Set agentInfos = new HashSet<>(); + agentInfos.add(agentInfo); + return agentInfos; + } + }); + when(agentInfoService.getAgentsByApplicationNameWithoutStatus(anyString(), anyLong())).thenAnswer(new Answer>() { + @Override + public Set answer(InvocationOnMock invocation) throws Throwable { + String applicationName = invocation.getArgument(0); + AgentInfo agentInfo = ApplicationMapBuilderTestHelper.createAgentInfoFromApplicationName(applicationName); + Set agentInfos = new HashSet<>(); + agentInfos.add(agentInfo); + return agentInfos; + } + }); + when(agentInfoService.getAgentStatus(anyString(), anyLong())).thenAnswer(new Answer() { + @Override + public AgentStatus answer(InvocationOnMock invocation) throws Throwable { + String agentId = invocation.getArgument(0); + AgentStatus agentStatus = new AgentStatus(agentId); + agentStatus.setEventTimestamp(System.currentTimeMillis()); + agentStatus.setState(AgentLifeCycleState.RUNNING); + return agentStatus; + } + }); + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Collection agentInfos = invocation.getArgument(0); + for (AgentInfo agentInfo : agentInfos) { + AgentStatus agentStatus = new AgentStatus(agentInfo.getAgentId()); + agentStatus.setEventTimestamp(System.currentTimeMillis()); + agentStatus.setState(AgentLifeCycleState.RUNNING); + agentInfo.setStatus(agentStatus); + } + return null; + } + }).when(agentInfoService).populateAgentStatuses(anyCollection(), anyLong()); + } + + @After + public void cleanUp() { + shutdownExecutor(serialExecutor); + shutdownExecutor(parallelExecutor); + } + + private void shutdownExecutor(ExecutorService executor) { + if (executor != null) { + executor.shutdown(); + try { + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } + + @Test + public void testNoCallData() { + Range range = new Range(0, 1000); + Application application = ApplicationMapBuilderTestHelper.createApplicationFromDepth(0); + + ServerInstanceListFactory serverInstanceListFactory = new DefaultServerInstanceListFactory(agentInfoServerInstanceListDataSource); + + ApplicationMapBuilder applicationMapBuilder = ApplicationMapBuilderTestHelper.createApplicationMapBuilder(range, serialExecutor); + ApplicationMapBuilder applicationMapBuilder_parallelAppenders = ApplicationMapBuilderTestHelper.createApplicationMapBuilder(range, parallelExecutor); + ApplicationMap applicationMap = applicationMapBuilder + .includeServerInfo(serverInstanceListFactory) + .build(application); + ApplicationMap applicationMap_parallelAppenders = applicationMapBuilder_parallelAppenders + .includeServerInfo(serverInstanceListFactory) + .build(application); + + Assert.assertEquals(1, applicationMap.getNodes().size()); + Assert.assertEquals(1, applicationMap.getNodes().size()); + Assert.assertEquals(1, applicationMap_parallelAppenders.getNodes().size()); + Assert.assertEquals(0, applicationMap.getLinks().size()); + Assert.assertEquals(0, applicationMap.getLinks().size()); + Assert.assertEquals(0, applicationMap_parallelAppenders.getLinks().size()); + + ApplicationMapVerifier verifier = new ApplicationMapVerifier(applicationMap); + verifier.verify(applicationMap); + verifier.verify(applicationMap_parallelAppenders); + } + + @Test + public void testEmptyCallData() { + Range range = new Range(0, 1000); + LinkDataDuplexMap linkDataDuplexMap = new LinkDataDuplexMap(); + + NodeHistogramFactory nodeHistogramFactory = new DefaultNodeHistogramFactory(mapResponseNodeHistogramDataSource); + ServerInstanceListFactory serverInstanceListFactory = new DefaultServerInstanceListFactory(agentInfoServerInstanceListDataSource); + + ApplicationMapBuilder applicationMapBuilder = ApplicationMapBuilderTestHelper.createApplicationMapBuilder(range, serialExecutor); + ApplicationMapBuilder applicationMapBuilder_parallelAppenders = ApplicationMapBuilderTestHelper.createApplicationMapBuilder(range, parallelExecutor); + ApplicationMap applicationMap = applicationMapBuilder + .includeNodeHistogram(nodeHistogramFactory) + .includeServerInfo(serverInstanceListFactory) + .build(linkDataDuplexMap); + ApplicationMap applicationMap_parallelAppenders = applicationMapBuilder_parallelAppenders + .includeNodeHistogram(nodeHistogramFactory) + .includeServerInfo(serverInstanceListFactory) + .build(linkDataDuplexMap); + + Assert.assertTrue(applicationMap.getNodes().isEmpty()); + Assert.assertTrue(applicationMap.getNodes().isEmpty()); + Assert.assertTrue(applicationMap_parallelAppenders.getNodes().isEmpty()); + Assert.assertTrue(applicationMap.getLinks().isEmpty()); + Assert.assertTrue(applicationMap.getLinks().isEmpty()); + Assert.assertTrue(applicationMap_parallelAppenders.getLinks().isEmpty()); + + ApplicationMapVerifier verifier = new ApplicationMapVerifier(applicationMap); + verifier.verify(applicationMap); + verifier.verify(applicationMap_parallelAppenders); + } + + /** + * USER -> WAS(center) -> UNKNOWN + */ + @Test + public void testOneDepth() { + int depth = 1; + runTest(depth, depth); + } + + /** + * USER -> WAS -> WAS(center) -> WAS -> UNKNOWN + */ + @Test + public void testTwoDepth() { + int depth = 2; + runTest(depth, depth); + } + + /** + * USER -> WAS -> WAS -> WAS(center) -> WAS -> WAS -> UNKNOWN + */ + @Test + public void testThreeDepth() { + int depth = 3; + runTest(depth, depth); + } + + /** + * USER -> WAS(center) -> WAS -> WAS -> UNKNOWN + */ + @Test + public void test_1_3_depth() { + int calleeDepth = 1; + int callerDepth = 3; + runTest(calleeDepth, callerDepth); + } + + /** + * USER -> WAS -> WAS -> WAS(center) -> UNKNOWN + */ + @Test + public void test_3_1_depth() { + int calleeDepth = 3; + int callerDepth = 1; + runTest(calleeDepth, callerDepth); + } + + /** + * USER -> WAS -> WAS -> WAS(center) -> WAS -> WAS -> WAS -> UNKNOWN + */ + @Test + public void test_3_4_depth() { + int calleeDepth = 3; + int callerDepth = 4; + runTest(calleeDepth, callerDepth); + } + + /** + * USER -> WAS -> WAS -> WAS -> WAS(center) -> WAS -> WAS -> UNKNOWN + */ + @Test + public void test_4_3_depth() { + int calleeDepth = 4; + int callerDepth = 3; + runTest(calleeDepth, callerDepth); + } + + private void runTest(int callerDepth, int calleeDepth) { + Range range = new Range(0, 1000); + int expectedNumNodes = ApplicationMapBuilderTestHelper.getExpectedNumNodes(calleeDepth, callerDepth); + int expectedNumLinks = ApplicationMapBuilderTestHelper.getExpectedNumLinks(calleeDepth, callerDepth); + + NodeHistogramFactory nodeHistogramFactory_MapResponseDao = new DefaultNodeHistogramFactory(mapResponseNodeHistogramDataSource); + NodeHistogramFactory nodeHistogramFactory_ResponseHistogramBuilder = new DefaultNodeHistogramFactory(responseHistogramBuilderNodeHistogramDataSource); + ServerInstanceListFactory serverInstanceListFactory = new DefaultServerInstanceListFactory(agentInfoServerInstanceListDataSource); + + LinkDataDuplexMap linkDataDuplexMap = ApplicationMapBuilderTestHelper.createLinkDataDuplexMap(calleeDepth, callerDepth); + ApplicationMapBuilder applicationMapBuilder = ApplicationMapBuilderTestHelper.createApplicationMapBuilder(range, serialExecutor); + ApplicationMapBuilder applicationMapBuilder_parallelAppenders = ApplicationMapBuilderTestHelper.createApplicationMapBuilder(range, parallelExecutor); + + // test builder using MapResponseDao + ApplicationMap applicationMap_MapResponseDao = applicationMapBuilder + .includeNodeHistogram(nodeHistogramFactory_MapResponseDao) + .includeServerInfo(serverInstanceListFactory) + .build(linkDataDuplexMap); + ApplicationMap applicationMap_MapResponseDao_parallelAppenders = applicationMapBuilder_parallelAppenders + .includeNodeHistogram(nodeHistogramFactory_MapResponseDao) + .includeServerInfo(serverInstanceListFactory) + .build(linkDataDuplexMap); + Assert.assertEquals(expectedNumNodes, applicationMap_MapResponseDao.getNodes().size()); + Assert.assertEquals(expectedNumNodes, applicationMap_MapResponseDao_parallelAppenders.getNodes().size()); + Assert.assertEquals(expectedNumLinks, applicationMap_MapResponseDao.getLinks().size()); + Assert.assertEquals(expectedNumLinks, applicationMap_MapResponseDao_parallelAppenders.getLinks().size()); + ApplicationMapVerifier verifier_MapResponseDao = new ApplicationMapVerifier(applicationMap_MapResponseDao); + verifier_MapResponseDao.verify(applicationMap_MapResponseDao); + verifier_MapResponseDao.verify(applicationMap_MapResponseDao_parallelAppenders); + + // test builder using ResponseHistogramBuilder + ApplicationMap applicationMap_ResponseHistogramBuilder = applicationMapBuilder + .includeNodeHistogram(nodeHistogramFactory_ResponseHistogramBuilder) + .includeServerInfo(serverInstanceListFactory) + .build(linkDataDuplexMap); + ApplicationMap applicationMap_ResponseHistogramBuilder_parallelAppenders = applicationMapBuilder_parallelAppenders + .includeNodeHistogram(nodeHistogramFactory_ResponseHistogramBuilder) + .includeServerInfo(serverInstanceListFactory) + .build(linkDataDuplexMap); + Assert.assertEquals(expectedNumNodes, applicationMap_ResponseHistogramBuilder.getNodes().size()); + Assert.assertEquals(expectedNumNodes, applicationMap_ResponseHistogramBuilder_parallelAppenders.getNodes().size()); + Assert.assertEquals(expectedNumLinks, applicationMap_ResponseHistogramBuilder.getLinks().size()); + Assert.assertEquals(expectedNumLinks, applicationMap_ResponseHistogramBuilder_parallelAppenders.getLinks().size()); + ApplicationMapVerifier verifier_ResponseHistogramBuilder = new ApplicationMapVerifier(applicationMap_ResponseHistogramBuilder); + verifier_ResponseHistogramBuilder.verify(applicationMap_ResponseHistogramBuilder); + verifier_ResponseHistogramBuilder.verify(applicationMap_ResponseHistogramBuilder_parallelAppenders); + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderTestHelper.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderTestHelper.java index 4580eccbebaf..b5ed9f9b6589 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderTestHelper.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/ApplicationMapBuilderTestHelper.java @@ -26,6 +26,8 @@ import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.Range; +import java.util.concurrent.Executor; + import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.INCLUDE_DESTINATION_ID; import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.RECORD_STATISTICS; import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.TERMINAL; @@ -41,19 +43,12 @@ public class ApplicationMapBuilderTestHelper { private static final ServiceType TERMINAL_TYPE = ServiceTypeFactory.of(2000, "TERMINAL", TERMINAL, INCLUDE_DESTINATION_ID); private static final ServiceType RPC_TYPE = ServiceTypeFactory.of(9000, "RPC", RECORD_STATISTICS); - public static ApplicationMapBuilder createApplicationMapBuilder(Range range) { - NodeHistogramAppenderFactory nodeHistogramAppenderFactory = new NodeHistogramAppenderFactory("serial", 16); - ServerInfoAppenderFactory serverInfoAppenderFactory = new ServerInfoAppenderFactory("serial", 16); + public static ApplicationMapBuilder createApplicationMapBuilder(Range range, Executor executor) { + NodeHistogramAppenderFactory nodeHistogramAppenderFactory = new NodeHistogramAppenderFactory(executor); + ServerInfoAppenderFactory serverInfoAppenderFactory = new ServerInfoAppenderFactory(executor); return new ApplicationMapBuilder(range, nodeHistogramAppenderFactory, serverInfoAppenderFactory); } - public static ApplicationMapBuilder createApplicationMapBuilder_parallelAppenders(Range range) { - NodeHistogramAppenderFactory nodeHistogramAppenderFactory = new NodeHistogramAppenderFactory("parallel", 16); - ServerInfoAppenderFactory serverInfoAppenderFactory = new ServerInfoAppenderFactory("parallel", 16); - return new ApplicationMapBuilder(range, nodeHistogramAppenderFactory, serverInfoAppenderFactory); - - } - public static int getExpectedNumNodes(int calleeDepth, int callerDepth) { if (calleeDepth < 1) { throw new IllegalArgumentException("calleeDepth must be greater than 0"); diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderTest.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderTest.java new file mode 100644 index 000000000000..df68c9b2b0e4 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderTest.java @@ -0,0 +1,355 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.applicationmap.appender.histogram; + +import com.navercorp.pinpoint.common.trace.HistogramSlot; +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; +import com.navercorp.pinpoint.common.trace.ServiceTypeProperty; +import com.navercorp.pinpoint.web.applicationmap.link.CreateType; +import com.navercorp.pinpoint.web.applicationmap.link.Link; +import com.navercorp.pinpoint.web.applicationmap.link.LinkList; +import com.navercorp.pinpoint.web.applicationmap.nodes.Node; +import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; +import com.navercorp.pinpoint.web.applicationmap.appender.histogram.datasource.WasNodeHistogramDataSource; +import com.navercorp.pinpoint.web.applicationmap.histogram.Histogram; +import com.navercorp.pinpoint.web.applicationmap.histogram.NodeHistogram; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkCallDataMap; +import com.navercorp.pinpoint.web.vo.Application; +import com.navercorp.pinpoint.web.vo.Range; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +public class NodeHistogramAppenderTest { + + private final ExecutorService executor = Executors.newFixedThreadPool(4); + + private final NodeHistogramAppenderFactory nodeHistogramAppenderFactory = new NodeHistogramAppenderFactory(executor); + + private WasNodeHistogramDataSource wasNodeHistogramDataSource; + + private NodeHistogramAppender nodeHistogramAppender; + + @Before + public void setUp() { + wasNodeHistogramDataSource = mock(WasNodeHistogramDataSource.class); + NodeHistogramFactory nodeHistogramFactory = new DefaultNodeHistogramFactory(wasNodeHistogramDataSource); + nodeHistogramAppender = nodeHistogramAppenderFactory.create(nodeHistogramFactory); + } + + @After + public void cleanUp() { + executor.shutdown(); + try { + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + @Test + public void emptyNodeList() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkList linkList = new LinkList(); + // When + nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); + // Then + Assert.assertTrue(nodeList.getNodeList().isEmpty()); + verifyZeroInteractions(wasNodeHistogramDataSource); + } + + /** + * Checks histograms for was node. + */ + @Test + public void wasNode() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkList linkList = new LinkList(); + Node node = createNode("testApp", ServiceTypeFactory.of(1000, "WAS")); + nodeList.addNode(node); + + NodeHistogram nodeHistogram = new NodeHistogram(node.getApplication(), range); + when(wasNodeHistogramDataSource.createNodeHistogram(node.getApplication(), range)).thenReturn(nodeHistogram); + // When + nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); + // Then + Node actualNode = nodeList.getNodeList().iterator().next(); + Assert.assertSame(nodeHistogram, actualNode.getNodeHistogram()); + } + + /** + * Checks histograms for a single terminal node. + *
    +     *     fromNode ---> databaseNode
    +     * 
    + */ + @Test + public void terminalNode() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkList linkList = new LinkList(); + + // fromNode : [testApp] test-app + Node fromNode = createNode("testApp", ServiceTypeFactory.of(1000, "WAS")); + String fromNodeAgent = "test-app"; + // toNode : [testDatabase] test-database + Node toNode = createNode("testDatabase", ServiceTypeFactory.of(2000, "RDB", ServiceTypeProperty.TERMINAL)); + String toNodeAgent = "test-database"; + nodeList.addNode(toNode); + + Link link = new Link(CreateType.Source, fromNode, toNode, range); + HistogramSlot fastSlot = toNode.getServiceType().getHistogramSchema().getFastSlot(); + HistogramSlot normalSlot = toNode.getServiceType().getHistogramSchema().getNormalSlot(); + HistogramSlot slowSlot = toNode.getServiceType().getHistogramSchema().getSlowSlot(); + // [testApp] test-app -> [testDatabase] test-database + long fastCallCount = 200L; + long normalCallCount = 100L; + long slowCallCount = 75L; + link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent, toNode.getServiceType(), fastSlot, fastCallCount)); + link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent, toNode.getServiceType(), normalSlot, normalCallCount)); + link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent, toNode.getServiceType(), slowSlot, slowCallCount)); + linkList.addLink(link); + + // When + nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); + + // Then + Node actualNode = nodeList.getNodeList().iterator().next(); + NodeHistogram nodeHistogram = actualNode.getNodeHistogram(); + // verify application-level histogram + Histogram applicationHistogram = nodeHistogram.getApplicationHistogram(); + Assert.assertEquals(fastCallCount, applicationHistogram.getFastCount()); + Assert.assertEquals(normalCallCount, applicationHistogram.getNormalCount()); + Assert.assertEquals(slowCallCount, applicationHistogram.getSlowCount()); + Assert.assertEquals(fastCallCount + normalCallCount + slowCallCount, applicationHistogram.getTotalCount()); + // verify agent-level histogram + Map agentHistogramMap = nodeHistogram.getAgentHistogramMap(); + Histogram agentHistogram = agentHistogramMap.get(toNodeAgent); + Assert.assertEquals(fastCallCount, agentHistogram.getFastCount()); + Assert.assertEquals(normalCallCount, agentHistogram.getNormalCount()); + Assert.assertEquals(slowCallCount, agentHistogram.getSlowCount()); + Assert.assertEquals(fastCallCount + normalCallCount + slowCallCount, agentHistogram.getTotalCount()); + } + + /** + * Checks histograms for a single terminal node with multiple agents(destinations). + *
    +     *     fromNode ---> databaseNode (2 agents)
    +     * 
    + */ + @Test + public void terminalNode_multiple() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkList linkList = new LinkList(); + + // fromNode : [testApp] test-app + Node fromNode = createNode("testApp", ServiceTypeFactory.of(1000, "WAS")); + String fromNodeAgent = "test-app"; + // toNode : [testDatabase] test-database1, test-database2 + Node toNode = createNode("testDatabase", ServiceTypeFactory.of(2000, "RDB", ServiceTypeProperty.TERMINAL)); + String toNodeAgent1 = "test-database1"; + String toNodeAgent2 = "test-database2"; + nodeList.addNode(toNode); + + Link link = new Link(CreateType.Source, fromNode, toNode, range); + HistogramSlot fastSlot = toNode.getServiceType().getHistogramSchema().getFastSlot(); + HistogramSlot normalSlot = toNode.getServiceType().getHistogramSchema().getNormalSlot(); + // [testApp] test-app -> [testDatabase] test-database1 + long callCount1 = 100L; + link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent1, toNode.getServiceType(), fastSlot, callCount1)); + // [testApp] test-app -> [testDatabase] test-database2 + long callCount2 = 50L; + link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent2, toNode.getServiceType(), normalSlot, callCount2)); + linkList.addLink(link); + + // When + nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); + + // Then + Node actualNode = nodeList.getNodeList().iterator().next(); + NodeHistogram nodeHistogram = actualNode.getNodeHistogram(); + // verify application-level histogram + Histogram applicationHistogram = nodeHistogram.getApplicationHistogram(); + Assert.assertEquals(callCount1, applicationHistogram.getFastCount()); + Assert.assertEquals(callCount2, applicationHistogram.getNormalCount()); + Assert.assertEquals(callCount1 + callCount2, applicationHistogram.getTotalCount()); + // verify agent-level histogram + Map agentHistogramMap = nodeHistogram.getAgentHistogramMap(); + Histogram agent1Histogram = agentHistogramMap.get(toNodeAgent1); + Assert.assertEquals(callCount1, agent1Histogram.getFastCount()); + Assert.assertEquals(callCount1, agent1Histogram.getTotalCount()); + Histogram agent2Histogram = agentHistogramMap.get(toNodeAgent2); + Assert.assertEquals(callCount2, agent2Histogram.getNormalCount()); + Assert.assertEquals(callCount2, agent2Histogram.getTotalCount()); + } + + /** + * Checks histograms for multiple terminal nodes called from a single node. + *
    +     *     fromNode ---> databaseNode
    +     *               |-> cacheNode
    +     * 
    + */ + @Test + public void terminalNodes() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkList linkList = new LinkList(); + + // fromNode : [testApp] test-app + Node fromNode = createNode("testApp", ServiceTypeFactory.of(1000, "WAS")); + String fromNodeAgent = "test-app"; + // databaseNode : [testDatabase] test-database + Node databaseNode = createNode("testDatabase", ServiceTypeFactory.of(2000, "RDB", ServiceTypeProperty.TERMINAL)); + String databaseNodeAgent = "test-database"; + nodeList.addNode(databaseNode); + // cacheNode : [testCache] test-cache + Node cacheNode = createNode("testCache", ServiceTypeFactory.of(8000, "Cache", ServiceTypeProperty.TERMINAL)); + String cacheNodeAgent = "test-cache"; + nodeList.addNode(cacheNode); + + Link databaseLink = new Link(CreateType.Source, fromNode, databaseNode, range); + HistogramSlot databaseSlowSlot = databaseNode.getServiceType().getHistogramSchema().getSlowSlot(); + long databaseCallSlowCount = 50L; + databaseLink.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), databaseNodeAgent, databaseNode.getServiceType(), databaseSlowSlot, databaseCallSlowCount)); + linkList.addLink(databaseLink); + + Link cacheLink = new Link(CreateType.Source, fromNode, cacheNode, range); + HistogramSlot cacheFastSlot = cacheNode.getServiceType().getHistogramSchema().getFastSlot(); + HistogramSlot cacheSlowSlot = cacheNode.getServiceType().getHistogramSchema().getSlowSlot(); + long cacheCallFastCount = 199L; + long cacheCallSlowCount = 99L; + cacheLink.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), cacheNodeAgent, cacheNode.getServiceType(), cacheFastSlot, cacheCallFastCount)); + cacheLink.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), cacheNodeAgent, cacheNode.getServiceType(), cacheSlowSlot, cacheCallSlowCount)); + linkList.addLink(cacheLink); + + // When + nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); + + // Then + // Database node + Node actualDatabaseNode = nodeList.findNode(databaseNode.getApplication()); + NodeHistogram databaseNodeHistogram = actualDatabaseNode.getNodeHistogram(); + // verify application-level histogram + Histogram databaseApplicationHistogram = databaseNodeHistogram.getApplicationHistogram(); + Assert.assertEquals(databaseCallSlowCount, databaseApplicationHistogram.getSlowCount()); + Assert.assertEquals(databaseCallSlowCount, databaseApplicationHistogram.getTotalCount()); + // verify agent-level histogram + Map databaseAgentHistogramMap = databaseNodeHistogram.getAgentHistogramMap(); + Histogram databaseAgentHistogram = databaseAgentHistogramMap.get(databaseNodeAgent); + Assert.assertEquals(databaseCallSlowCount, databaseAgentHistogram.getSlowCount()); + Assert.assertEquals(databaseCallSlowCount, databaseAgentHistogram.getTotalCount()); + // Cache node + Node actualCacheNode = nodeList.findNode(cacheNode.getApplication()); + NodeHistogram cacheNodeHistogram = actualCacheNode.getNodeHistogram(); + // verify application-level histogram + Histogram cacheApplicationHistogram = cacheNodeHistogram.getApplicationHistogram(); + Assert.assertEquals(cacheCallFastCount, cacheApplicationHistogram.getFastCount()); + Assert.assertEquals(cacheCallSlowCount, cacheApplicationHistogram.getSlowCount()); + Assert.assertEquals(cacheCallFastCount + cacheCallSlowCount, cacheApplicationHistogram.getTotalCount()); + // verify agent-level histogram + Map cacheAgentHistogramMap = cacheNodeHistogram.getAgentHistogramMap(); + Histogram cacheAgentHistogram = cacheAgentHistogramMap.get(cacheNodeAgent); + Assert.assertEquals(cacheCallFastCount, cacheAgentHistogram.getFastCount()); + Assert.assertEquals(cacheCallSlowCount, cacheAgentHistogram.getSlowCount()); + Assert.assertEquals(cacheCallFastCount + cacheCallSlowCount, cacheAgentHistogram.getTotalCount()); + } + + /** + * Checks histograms for user node. + *
    +     *     userNode ---> wasNode (2 agents)
    +     * 
    + */ + @Test + public void userNode() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkList linkList = new LinkList(); + // userNode : [userNode] user + Node userNode = createNode("userNode", ServiceType.USER); + String userNodeAgent = "user"; + nodeList.addNode(userNode); + // wasNode : [wasNode] was-1, was-2 + Node wasNode = createNode("wasNode", ServiceTypeFactory.of(1000, "WAS")); + String wasNodeAgent1 = "was-1"; + String wasNodeAgent2 = "was-2"; + nodeList.addNode(wasNode); + + Link link = new Link(CreateType.Target, userNode, wasNode, range); + HistogramSlot fastSlot = wasNode.getServiceType().getHistogramSchema().getFastSlot(); + HistogramSlot normalSlot = wasNode.getServiceType().getHistogramSchema().getNormalSlot(); + // [userNode] user -> [wasNode] was-1 + long fastCallCount = 100L; + link.addTarget(createLinkCallDataMap(userNodeAgent, userNode.getServiceType(), wasNodeAgent1, wasNode.getServiceType(), fastSlot, fastCallCount)); + // [userNode] user -> [wasNode] was-2 + long normalCallCount = 50L; + link.addTarget(createLinkCallDataMap(userNodeAgent, userNode.getServiceType(), wasNodeAgent2, wasNode.getServiceType(), normalSlot, normalCallCount)); + linkList.addLink(link); + + // When + nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); + + NodeHistogram nodeHistogram = userNode.getNodeHistogram(); + // verify application-level histogram + Histogram applicationHistogram = nodeHistogram.getApplicationHistogram(); + Assert.assertEquals(fastCallCount, applicationHistogram.getFastCount()); + Assert.assertEquals(normalCallCount, applicationHistogram.getNormalCount()); + Assert.assertEquals(fastCallCount + normalCallCount, applicationHistogram.getTotalCount()); + // verify agent-level histogram - there is none for user node + Map databaseAgentHistogramMap = nodeHistogram.getAgentHistogramMap(); + Assert.assertTrue(databaseAgentHistogramMap.isEmpty()); + } + + private Node createNode(String applicationName, ServiceType serviceType) { + Application application = new Application(applicationName, serviceType); + return new Node(application); + } + + private LinkCallDataMap createLinkCallDataMap(String fromAgentId, ServiceType fromAgentServiceType, String toAgentId, ServiceType toAgentServiceType, HistogramSlot slot, long callCount) { + long currentTimestamp = System.currentTimeMillis(); + LinkCallDataMap linkCallDataMap = new LinkCallDataMap(); + linkCallDataMap.addCallData(fromAgentId, fromAgentServiceType, toAgentId, toAgentServiceType, currentTimestamp, slot.getSlotTime(), callCount); + return linkCallDataMap; + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderTestBase.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderTestBase.java deleted file mode 100644 index 90ef6fac3ffa..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/NodeHistogramAppenderTestBase.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.histogram; - -import com.navercorp.pinpoint.common.trace.HistogramSlot; -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; -import com.navercorp.pinpoint.common.trace.ServiceTypeProperty; -import com.navercorp.pinpoint.web.applicationmap.link.CreateType; -import com.navercorp.pinpoint.web.applicationmap.link.Link; -import com.navercorp.pinpoint.web.applicationmap.link.LinkList; -import com.navercorp.pinpoint.web.applicationmap.nodes.Node; -import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; -import com.navercorp.pinpoint.web.applicationmap.appender.histogram.datasource.WasNodeHistogramDataSource; -import com.navercorp.pinpoint.web.applicationmap.histogram.Histogram; -import com.navercorp.pinpoint.web.applicationmap.histogram.NodeHistogram; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkCallDataMap; -import com.navercorp.pinpoint.web.vo.Application; -import com.navercorp.pinpoint.web.vo.Range; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.Map; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -/** - * @author HyunGil Jeong - */ -public abstract class NodeHistogramAppenderTestBase { - - private WasNodeHistogramDataSource wasNodeHistogramDataSource; - - private NodeHistogramAppender nodeHistogramAppender; - - protected abstract NodeHistogramAppenderFactory createNodeHistogramAppenderFactory(); - - @Before - public void setUp() { - wasNodeHistogramDataSource = mock(WasNodeHistogramDataSource.class); - NodeHistogramFactory nodeHistogramFactory = new DefaultNodeHistogramFactory(wasNodeHistogramDataSource); - NodeHistogramAppenderFactory nodeHistogramAppenderFactory = createNodeHistogramAppenderFactory(); - nodeHistogramAppender = nodeHistogramAppenderFactory.create(nodeHistogramFactory); - } - - @Test - public void emptyNodeList() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkList linkList = new LinkList(); - // When - nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); - // Then - Assert.assertTrue(nodeList.getNodeList().isEmpty()); - verifyZeroInteractions(wasNodeHistogramDataSource); - } - - /** - * Checks histograms for was node. - */ - @Test - public void wasNode() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkList linkList = new LinkList(); - Node node = createNode("testApp", ServiceTypeFactory.of(1000, "WAS")); - nodeList.addNode(node); - - NodeHistogram nodeHistogram = new NodeHistogram(node.getApplication(), range); - when(wasNodeHistogramDataSource.createNodeHistogram(node.getApplication(), range)).thenReturn(nodeHistogram); - // When - nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); - // Then - Node actualNode = nodeList.getNodeList().iterator().next(); - Assert.assertSame(nodeHistogram, actualNode.getNodeHistogram()); - } - - /** - * Checks histograms for a single terminal node. - *
    -     *     fromNode ---> databaseNode
    -     * 
    - */ - @Test - public void terminalNode() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkList linkList = new LinkList(); - - // fromNode : [testApp] test-app - Node fromNode = createNode("testApp", ServiceTypeFactory.of(1000, "WAS")); - String fromNodeAgent = "test-app"; - // toNode : [testDatabase] test-database - Node toNode = createNode("testDatabase", ServiceTypeFactory.of(2000, "RDB", ServiceTypeProperty.TERMINAL)); - String toNodeAgent = "test-database"; - nodeList.addNode(toNode); - - Link link = new Link(CreateType.Source, fromNode, toNode, range); - HistogramSlot fastSlot = toNode.getServiceType().getHistogramSchema().getFastSlot(); - HistogramSlot normalSlot = toNode.getServiceType().getHistogramSchema().getNormalSlot(); - HistogramSlot slowSlot = toNode.getServiceType().getHistogramSchema().getSlowSlot(); - // [testApp] test-app -> [testDatabase] test-database - long fastCallCount = 200L; - long normalCallCount = 100L; - long slowCallCount = 75L; - link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent, toNode.getServiceType(), fastSlot, fastCallCount)); - link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent, toNode.getServiceType(), normalSlot, normalCallCount)); - link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent, toNode.getServiceType(), slowSlot, slowCallCount)); - linkList.addLink(link); - - // When - nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); - - // Then - Node actualNode = nodeList.getNodeList().iterator().next(); - NodeHistogram nodeHistogram = actualNode.getNodeHistogram(); - // verify application-level histogram - Histogram applicationHistogram = nodeHistogram.getApplicationHistogram(); - Assert.assertEquals(fastCallCount, applicationHistogram.getFastCount()); - Assert.assertEquals(normalCallCount, applicationHistogram.getNormalCount()); - Assert.assertEquals(slowCallCount, applicationHistogram.getSlowCount()); - Assert.assertEquals(fastCallCount + normalCallCount + slowCallCount, applicationHistogram.getTotalCount()); - // verify agent-level histogram - Map agentHistogramMap = nodeHistogram.getAgentHistogramMap(); - Histogram agentHistogram = agentHistogramMap.get(toNodeAgent); - Assert.assertEquals(fastCallCount, agentHistogram.getFastCount()); - Assert.assertEquals(normalCallCount, agentHistogram.getNormalCount()); - Assert.assertEquals(slowCallCount, agentHistogram.getSlowCount()); - Assert.assertEquals(fastCallCount + normalCallCount + slowCallCount, agentHistogram.getTotalCount()); - } - - /** - * Checks histograms for a single terminal node with multiple agents(destinations). - *
    -     *     fromNode ---> databaseNode (2 agents)
    -     * 
    - */ - @Test - public void terminalNode_multiple() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkList linkList = new LinkList(); - - // fromNode : [testApp] test-app - Node fromNode = createNode("testApp", ServiceTypeFactory.of(1000, "WAS")); - String fromNodeAgent = "test-app"; - // toNode : [testDatabase] test-database1, test-database2 - Node toNode = createNode("testDatabase", ServiceTypeFactory.of(2000, "RDB", ServiceTypeProperty.TERMINAL)); - String toNodeAgent1 = "test-database1"; - String toNodeAgent2 = "test-database2"; - nodeList.addNode(toNode); - - Link link = new Link(CreateType.Source, fromNode, toNode, range); - HistogramSlot fastSlot = toNode.getServiceType().getHistogramSchema().getFastSlot(); - HistogramSlot normalSlot = toNode.getServiceType().getHistogramSchema().getNormalSlot(); - // [testApp] test-app -> [testDatabase] test-database1 - long callCount1 = 100L; - link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent1, toNode.getServiceType(), fastSlot, callCount1)); - // [testApp] test-app -> [testDatabase] test-database2 - long callCount2 = 50L; - link.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), toNodeAgent2, toNode.getServiceType(), normalSlot, callCount2)); - linkList.addLink(link); - - // When - nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); - - // Then - Node actualNode = nodeList.getNodeList().iterator().next(); - NodeHistogram nodeHistogram = actualNode.getNodeHistogram(); - // verify application-level histogram - Histogram applicationHistogram = nodeHistogram.getApplicationHistogram(); - Assert.assertEquals(callCount1, applicationHistogram.getFastCount()); - Assert.assertEquals(callCount2, applicationHistogram.getNormalCount()); - Assert.assertEquals(callCount1 + callCount2, applicationHistogram.getTotalCount()); - // verify agent-level histogram - Map agentHistogramMap = nodeHistogram.getAgentHistogramMap(); - Histogram agent1Histogram = agentHistogramMap.get(toNodeAgent1); - Assert.assertEquals(callCount1, agent1Histogram.getFastCount()); - Assert.assertEquals(callCount1, agent1Histogram.getTotalCount()); - Histogram agent2Histogram = agentHistogramMap.get(toNodeAgent2); - Assert.assertEquals(callCount2, agent2Histogram.getNormalCount()); - Assert.assertEquals(callCount2, agent2Histogram.getTotalCount()); - } - - /** - * Checks histograms for multiple terminal nodes called from a single node. - *
    -     *     fromNode ---> databaseNode
    -     *               |-> cacheNode
    -     * 
    - */ - @Test - public void terminalNodes() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkList linkList = new LinkList(); - - // fromNode : [testApp] test-app - Node fromNode = createNode("testApp", ServiceTypeFactory.of(1000, "WAS")); - String fromNodeAgent = "test-app"; - // databaseNode : [testDatabase] test-database - Node databaseNode = createNode("testDatabase", ServiceTypeFactory.of(2000, "RDB", ServiceTypeProperty.TERMINAL)); - String databaseNodeAgent = "test-database"; - nodeList.addNode(databaseNode); - // cacheNode : [testCache] test-cache - Node cacheNode = createNode("testCache", ServiceTypeFactory.of(8000, "Cache", ServiceTypeProperty.TERMINAL)); - String cacheNodeAgent = "test-cache"; - nodeList.addNode(cacheNode); - - Link databaseLink = new Link(CreateType.Source, fromNode, databaseNode, range); - HistogramSlot databaseSlowSlot = databaseNode.getServiceType().getHistogramSchema().getSlowSlot(); - long databaseCallSlowCount = 50L; - databaseLink.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), databaseNodeAgent, databaseNode.getServiceType(), databaseSlowSlot, databaseCallSlowCount)); - linkList.addLink(databaseLink); - - Link cacheLink = new Link(CreateType.Source, fromNode, cacheNode, range); - HistogramSlot cacheFastSlot = cacheNode.getServiceType().getHistogramSchema().getFastSlot(); - HistogramSlot cacheSlowSlot = cacheNode.getServiceType().getHistogramSchema().getSlowSlot(); - long cacheCallFastCount = 199L; - long cacheCallSlowCount = 99L; - cacheLink.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), cacheNodeAgent, cacheNode.getServiceType(), cacheFastSlot, cacheCallFastCount)); - cacheLink.addSource(createLinkCallDataMap(fromNodeAgent, fromNode.getServiceType(), cacheNodeAgent, cacheNode.getServiceType(), cacheSlowSlot, cacheCallSlowCount)); - linkList.addLink(cacheLink); - - // When - nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); - - // Then - // Database node - Node actualDatabaseNode = nodeList.findNode(databaseNode.getApplication()); - NodeHistogram databaseNodeHistogram = actualDatabaseNode.getNodeHistogram(); - // verify application-level histogram - Histogram databaseApplicationHistogram = databaseNodeHistogram.getApplicationHistogram(); - Assert.assertEquals(databaseCallSlowCount, databaseApplicationHistogram.getSlowCount()); - Assert.assertEquals(databaseCallSlowCount, databaseApplicationHistogram.getTotalCount()); - // verify agent-level histogram - Map databaseAgentHistogramMap = databaseNodeHistogram.getAgentHistogramMap(); - Histogram databaseAgentHistogram = databaseAgentHistogramMap.get(databaseNodeAgent); - Assert.assertEquals(databaseCallSlowCount, databaseAgentHistogram.getSlowCount()); - Assert.assertEquals(databaseCallSlowCount, databaseAgentHistogram.getTotalCount()); - // Cache node - Node actualCacheNode = nodeList.findNode(cacheNode.getApplication()); - NodeHistogram cacheNodeHistogram = actualCacheNode.getNodeHistogram(); - // verify application-level histogram - Histogram cacheApplicationHistogram = cacheNodeHistogram.getApplicationHistogram(); - Assert.assertEquals(cacheCallFastCount, cacheApplicationHistogram.getFastCount()); - Assert.assertEquals(cacheCallSlowCount, cacheApplicationHistogram.getSlowCount()); - Assert.assertEquals(cacheCallFastCount + cacheCallSlowCount, cacheApplicationHistogram.getTotalCount()); - // verify agent-level histogram - Map cacheAgentHistogramMap = cacheNodeHistogram.getAgentHistogramMap(); - Histogram cacheAgentHistogram = cacheAgentHistogramMap.get(cacheNodeAgent); - Assert.assertEquals(cacheCallFastCount, cacheAgentHistogram.getFastCount()); - Assert.assertEquals(cacheCallSlowCount, cacheAgentHistogram.getSlowCount()); - Assert.assertEquals(cacheCallFastCount + cacheCallSlowCount, cacheAgentHistogram.getTotalCount()); - } - - /** - * Checks histograms for user node. - *
    -     *     userNode ---> wasNode (2 agents)
    -     * 
    - */ - @Test - public void userNode() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkList linkList = new LinkList(); - // userNode : [userNode] user - Node userNode = createNode("userNode", ServiceType.USER); - String userNodeAgent = "user"; - nodeList.addNode(userNode); - // wasNode : [wasNode] was-1, was-2 - Node wasNode = createNode("wasNode", ServiceTypeFactory.of(1000, "WAS")); - String wasNodeAgent1 = "was-1"; - String wasNodeAgent2 = "was-2"; - nodeList.addNode(wasNode); - - Link link = new Link(CreateType.Target, userNode, wasNode, range); - HistogramSlot fastSlot = wasNode.getServiceType().getHistogramSchema().getFastSlot(); - HistogramSlot normalSlot = wasNode.getServiceType().getHistogramSchema().getNormalSlot(); - // [userNode] user -> [wasNode] was-1 - long fastCallCount = 100L; - link.addTarget(createLinkCallDataMap(userNodeAgent, userNode.getServiceType(), wasNodeAgent1, wasNode.getServiceType(), fastSlot, fastCallCount)); - // [userNode] user -> [wasNode] was-2 - long normalCallCount = 50L; - link.addTarget(createLinkCallDataMap(userNodeAgent, userNode.getServiceType(), wasNodeAgent2, wasNode.getServiceType(), normalSlot, normalCallCount)); - linkList.addLink(link); - - // When - nodeHistogramAppender.appendNodeHistogram(range, nodeList, linkList); - - NodeHistogram nodeHistogram = userNode.getNodeHistogram(); - // verify application-level histogram - Histogram applicationHistogram = nodeHistogram.getApplicationHistogram(); - Assert.assertEquals(fastCallCount, applicationHistogram.getFastCount()); - Assert.assertEquals(normalCallCount, applicationHistogram.getNormalCount()); - Assert.assertEquals(fastCallCount + normalCallCount, applicationHistogram.getTotalCount()); - // verify agent-level histogram - there is none for user node - Map databaseAgentHistogramMap = nodeHistogram.getAgentHistogramMap(); - Assert.assertTrue(databaseAgentHistogramMap.isEmpty()); - } - - private Node createNode(String applicationName, ServiceType serviceType) { - Application application = new Application(applicationName, serviceType); - return new Node(application); - } - - private LinkCallDataMap createLinkCallDataMap(String fromAgentId, ServiceType fromAgentServiceType, String toAgentId, ServiceType toAgentServiceType, HistogramSlot slot, long callCount) { - long currentTimestamp = System.currentTimeMillis(); - LinkCallDataMap linkCallDataMap = new LinkCallDataMap(); - linkCallDataMap.addCallData(fromAgentId, fromAgentServiceType, toAgentId, toAgentServiceType, currentTimestamp, slot.getSlotTime(), callCount); - return linkCallDataMap; - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/ParallelNodeHistogramAppenderTest.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/ParallelNodeHistogramAppenderTest.java deleted file mode 100644 index 7f1b77892325..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/ParallelNodeHistogramAppenderTest.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.histogram; - -/** - * @author HyunGil Jeong - */ -public class ParallelNodeHistogramAppenderTest extends NodeHistogramAppenderTestBase { - - @Override - protected NodeHistogramAppenderFactory createNodeHistogramAppenderFactory() { - return new NodeHistogramAppenderFactory("parallel", 16); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/SerialNodeHistogramAppenderTest.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/SerialNodeHistogramAppenderTest.java deleted file mode 100644 index ec33ee4f7fb0..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/SerialNodeHistogramAppenderTest.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.histogram; - -/** - * @author HyunGil Jeong - */ -public class SerialNodeHistogramAppenderTest extends NodeHistogramAppenderTestBase { - - @Override - protected NodeHistogramAppenderFactory createNodeHistogramAppenderFactory() { - return new NodeHistogramAppenderFactory("serial", 1); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ParallelServerInfoAppenderTest.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ParallelServerInfoAppenderTest.java deleted file mode 100644 index 53a9d91e93b5..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ParallelServerInfoAppenderTest.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.server; - -/** - * @author HyunGil Jeong - */ -public class ParallelServerInfoAppenderTest extends ServerInfoAppenderTestBase { - - @Override - protected ServerInfoAppenderFactory createServerInfoAppenderFactory() { - return new ServerInfoAppenderFactory("parallel", 16); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/SerialServerInfoAppenderTest.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/SerialServerInfoAppenderTest.java deleted file mode 100644 index cf184a5b3333..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/SerialServerInfoAppenderTest.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.server; - -/** - * @author HyunGil Jeong - */ -public class SerialServerInfoAppenderTest extends ServerInfoAppenderTestBase { - - @Override - protected ServerInfoAppenderFactory createServerInfoAppenderFactory() { - return new ServerInfoAppenderFactory("serial", 1); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderTest.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderTest.java new file mode 100644 index 000000000000..945bba942f83 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderTest.java @@ -0,0 +1,233 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.applicationmap.appender.server; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; +import com.navercorp.pinpoint.web.applicationmap.nodes.Node; +import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; +import com.navercorp.pinpoint.web.applicationmap.nodes.ServerInstanceList; +import com.navercorp.pinpoint.web.applicationmap.appender.server.datasource.ServerInstanceListDataSource; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkData; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; +import com.navercorp.pinpoint.web.vo.Application; +import com.navercorp.pinpoint.web.vo.Range; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.INCLUDE_DESTINATION_ID; +import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.TERMINAL; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +public class ServerInfoAppenderTest { + + private final ExecutorService executor = Executors.newFixedThreadPool(4); + + private final ServerInfoAppenderFactory serverInfoAppenderFactory = new ServerInfoAppenderFactory(executor); + + private ServerInstanceListDataSource serverInstanceListDataSource; + + private ServerInfoAppender serverInfoAppender; + + @Before + public void setUp() { + serverInstanceListDataSource = mock(ServerInstanceListDataSource.class); + ServerInstanceListFactory serverInstanceListFactory = new DefaultServerInstanceListFactory(serverInstanceListDataSource); + serverInfoAppender = serverInfoAppenderFactory.create(serverInstanceListFactory); + } + + @After + public void cleanUp() { + executor.shutdown(); + try { + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + @Test + public void nullNodeList() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = null; + LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); + // When + serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); + // Then + Assert.assertNull(nodeList); + verifyZeroInteractions(serverInstanceListDataSource); + verifyZeroInteractions(linkDataDuplexMap); + } + + @Test + public void emptyNodeList() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); + // When + serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); + // Then + Assert.assertTrue(nodeList.getNodeList().isEmpty()); + verifyZeroInteractions(serverInstanceListDataSource); + verifyZeroInteractions(linkDataDuplexMap); + } + + @Test + public void wasNode() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); + + Node wasNode = new Node(new Application("Was", ServiceType.TEST_STAND_ALONE)); + nodeList.addNode(wasNode); + + ServerInstanceList serverInstanceList = new ServerInstanceList(); + when(serverInstanceListDataSource.createServerInstanceList(wasNode, range.getTo())).thenReturn(serverInstanceList); + // When + serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); + // Then + Assert.assertSame(serverInstanceList, wasNode.getServerInstanceList()); + verifyZeroInteractions(linkDataDuplexMap); + } + + @Test + public void wasNodes() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); + + Node wasNode1 = new Node(new Application("Was1", ServiceType.TEST_STAND_ALONE)); + nodeList.addNode(wasNode1); + Node wasNode2 = new Node(new Application("Was2", ServiceType.TEST_STAND_ALONE)); + nodeList.addNode(wasNode2); + + ServerInstanceList serverInstanceList1 = new ServerInstanceList(); + when(serverInstanceListDataSource.createServerInstanceList(wasNode1, range.getTo())).thenReturn(serverInstanceList1); + ServerInstanceList serverInstanceList2 = new ServerInstanceList(); + when(serverInstanceListDataSource.createServerInstanceList(wasNode2, range.getTo())).thenReturn(serverInstanceList2); + // When + serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); + // Then + Assert.assertSame(serverInstanceList1, wasNode1.getServerInstanceList()); + Assert.assertSame(serverInstanceList2, wasNode2.getServerInstanceList()); + verifyZeroInteractions(linkDataDuplexMap); + } + + @Test + public void terminalNode() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkDataDuplexMap linkDataDuplexMap = new LinkDataDuplexMap(); + + ServiceType terminalType = ServiceTypeFactory.of(2000, "TERMINAL", TERMINAL, INCLUDE_DESTINATION_ID); + Application terminalApplication = new Application("Terminal", terminalType); + Node terminalNode = new Node(terminalApplication); + nodeList.addNode(terminalNode); + + Application fromApplication = new Application("FromWas", ServiceType.TEST_STAND_ALONE); + LinkData linkData = new LinkData(fromApplication, terminalApplication); + linkData.addLinkData( + "wasAgent", ServiceType.TEST_STAND_ALONE, + "terminalNodeAddress", terminalType, + System.currentTimeMillis(), terminalType.getHistogramSchema().getNormalSlot().getSlotTime(), 1); + linkDataDuplexMap.addSourceLinkData(linkData); + // When + serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); + // Then + Assert.assertEquals(1, terminalNode.getServerInstanceList().getInstanceCount()); + } + + @Test + public void terminalNode_multipleInstances() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkDataDuplexMap linkDataDuplexMap = new LinkDataDuplexMap(); + + ServiceType terminalType = ServiceTypeFactory.of(2000, "TERMINAL", TERMINAL, INCLUDE_DESTINATION_ID); + Application terminalApplication = new Application("Terminal", terminalType); + Node terminalNode = new Node(terminalApplication); + nodeList.addNode(terminalNode); + + Application fromApplication = new Application("FromWas", ServiceType.TEST_STAND_ALONE); + LinkData linkData = new LinkData(fromApplication, terminalApplication); + linkData.addLinkData( + "wasAgent", ServiceType.TEST_STAND_ALONE, + "terminalNodeAddress1", terminalType, + System.currentTimeMillis(), terminalType.getHistogramSchema().getNormalSlot().getSlotTime(), 1); + linkData.addLinkData( + "wasAgent", ServiceType.TEST_STAND_ALONE, + "terminalNodeAddress2", terminalType, + System.currentTimeMillis(), terminalType.getHistogramSchema().getNormalSlot().getSlotTime(), 1); + linkDataDuplexMap.addSourceLinkData(linkData); + // When + serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); + // Then + Assert.assertEquals(2, terminalNode.getServerInstanceList().getInstanceCount()); + } + + @Test + public void userNode() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); + + Node userNode = new Node(new Application("User", ServiceType.USER)); + nodeList.addNode(userNode); + // When + serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); + // Then + Assert.assertEquals(0, userNode.getServerInstanceList().getInstanceCount()); + verifyZeroInteractions(linkDataDuplexMap); + } + + @Test + public void unknownNode() { + // Given + Range range = new Range(0, 60 * 1000); + NodeList nodeList = new NodeList(); + LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); + + Node unknownNode = new Node(new Application("Unknown", ServiceType.UNKNOWN)); + nodeList.addNode(unknownNode); + // When + serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); + // Then + Assert.assertEquals(0, unknownNode.getServerInstanceList().getInstanceCount()); + verifyZeroInteractions(linkDataDuplexMap); + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderTestBase.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderTestBase.java deleted file mode 100644 index dbf1067ab729..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/appender/server/ServerInfoAppenderTestBase.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.applicationmap.appender.server; - -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.common.trace.ServiceTypeFactory; -import com.navercorp.pinpoint.web.applicationmap.nodes.Node; -import com.navercorp.pinpoint.web.applicationmap.nodes.NodeList; -import com.navercorp.pinpoint.web.applicationmap.nodes.ServerInstanceList; -import com.navercorp.pinpoint.web.applicationmap.appender.server.datasource.ServerInstanceListDataSource; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkData; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; -import com.navercorp.pinpoint.web.vo.Application; -import com.navercorp.pinpoint.web.vo.Range; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.INCLUDE_DESTINATION_ID; -import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.TERMINAL; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -/** - * @author HyunGil Jeong - */ -public abstract class ServerInfoAppenderTestBase { - - private ServerInstanceListDataSource serverInstanceListDataSource; - - private ServerInfoAppender serverInfoAppender; - - protected abstract ServerInfoAppenderFactory createServerInfoAppenderFactory(); - - @Before - public void setUp() { - serverInstanceListDataSource = mock(ServerInstanceListDataSource.class); - ServerInstanceListFactory serverInstanceListFactory = new DefaultServerInstanceListFactory(serverInstanceListDataSource); - ServerInfoAppenderFactory serverInfoAppenderFactory = createServerInfoAppenderFactory(); - serverInfoAppender = serverInfoAppenderFactory.create(serverInstanceListFactory); - } - - @Test - public void nullNodeList() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = null; - LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); - // When - serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); - // Then - Assert.assertNull(nodeList); - verifyZeroInteractions(serverInstanceListDataSource); - verifyZeroInteractions(linkDataDuplexMap); - } - - @Test - public void emptyNodeList() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); - // When - serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); - // Then - Assert.assertTrue(nodeList.getNodeList().isEmpty()); - verifyZeroInteractions(serverInstanceListDataSource); - verifyZeroInteractions(linkDataDuplexMap); - } - - @Test - public void wasNode() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); - - Node wasNode = new Node(new Application("Was", ServiceType.TEST_STAND_ALONE)); - nodeList.addNode(wasNode); - - ServerInstanceList serverInstanceList = new ServerInstanceList(); - when(serverInstanceListDataSource.createServerInstanceList(wasNode, range.getTo())).thenReturn(serverInstanceList); - // When - serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); - // Then - Assert.assertSame(serverInstanceList, wasNode.getServerInstanceList()); - verifyZeroInteractions(linkDataDuplexMap); - } - - @Test - public void wasNodes() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); - - Node wasNode1 = new Node(new Application("Was1", ServiceType.TEST_STAND_ALONE)); - nodeList.addNode(wasNode1); - Node wasNode2 = new Node(new Application("Was2", ServiceType.TEST_STAND_ALONE)); - nodeList.addNode(wasNode2); - - ServerInstanceList serverInstanceList1 = new ServerInstanceList(); - when(serverInstanceListDataSource.createServerInstanceList(wasNode1, range.getTo())).thenReturn(serverInstanceList1); - ServerInstanceList serverInstanceList2 = new ServerInstanceList(); - when(serverInstanceListDataSource.createServerInstanceList(wasNode2, range.getTo())).thenReturn(serverInstanceList2); - // When - serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); - // Then - Assert.assertSame(serverInstanceList1, wasNode1.getServerInstanceList()); - Assert.assertSame(serverInstanceList2, wasNode2.getServerInstanceList()); - verifyZeroInteractions(linkDataDuplexMap); - } - - @Test - public void terminalNode() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkDataDuplexMap linkDataDuplexMap = new LinkDataDuplexMap(); - - ServiceType terminalType = ServiceTypeFactory.of(2000, "TERMINAL", TERMINAL, INCLUDE_DESTINATION_ID); - Application terminalApplication = new Application("Terminal", terminalType); - Node terminalNode = new Node(terminalApplication); - nodeList.addNode(terminalNode); - - Application fromApplication = new Application("FromWas", ServiceType.TEST_STAND_ALONE); - LinkData linkData = new LinkData(fromApplication, terminalApplication); - linkData.addLinkData( - "wasAgent", ServiceType.TEST_STAND_ALONE, - "terminalNodeAddress", terminalType, - System.currentTimeMillis(), terminalType.getHistogramSchema().getNormalSlot().getSlotTime(), 1); - linkDataDuplexMap.addSourceLinkData(linkData); - // When - serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); - // Then - Assert.assertEquals(1, terminalNode.getServerInstanceList().getInstanceCount()); - } - - @Test - public void terminalNode_multipleInstances() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkDataDuplexMap linkDataDuplexMap = new LinkDataDuplexMap(); - - ServiceType terminalType = ServiceTypeFactory.of(2000, "TERMINAL", TERMINAL, INCLUDE_DESTINATION_ID); - Application terminalApplication = new Application("Terminal", terminalType); - Node terminalNode = new Node(terminalApplication); - nodeList.addNode(terminalNode); - - Application fromApplication = new Application("FromWas", ServiceType.TEST_STAND_ALONE); - LinkData linkData = new LinkData(fromApplication, terminalApplication); - linkData.addLinkData( - "wasAgent", ServiceType.TEST_STAND_ALONE, - "terminalNodeAddress1", terminalType, - System.currentTimeMillis(), terminalType.getHistogramSchema().getNormalSlot().getSlotTime(), 1); - linkData.addLinkData( - "wasAgent", ServiceType.TEST_STAND_ALONE, - "terminalNodeAddress2", terminalType, - System.currentTimeMillis(), terminalType.getHistogramSchema().getNormalSlot().getSlotTime(), 1); - linkDataDuplexMap.addSourceLinkData(linkData); - // When - serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); - // Then - Assert.assertEquals(2, terminalNode.getServerInstanceList().getInstanceCount()); - } - - @Test - public void userNode() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); - - Node userNode = new Node(new Application("User", ServiceType.USER)); - nodeList.addNode(userNode); - // When - serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); - // Then - Assert.assertEquals(0, userNode.getServerInstanceList().getInstanceCount()); - verifyZeroInteractions(linkDataDuplexMap); - } - - @Test - public void unknownNode() { - // Given - Range range = new Range(0, 60 * 1000); - NodeList nodeList = new NodeList(); - LinkDataDuplexMap linkDataDuplexMap = mock(LinkDataDuplexMap.class); - - Node unknownNode = new Node(new Application("Unknown", ServiceType.UNKNOWN)); - nodeList.addNode(unknownNode); - // When - serverInfoAppender.appendServerInfo(range, nodeList, linkDataDuplexMap); - // Then - Assert.assertEquals(0, unknownNode.getServerInstanceList().getInstanceCount()); - verifyZeroInteractions(linkDataDuplexMap); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/batch/DefaultDividerTest.java b/web/src/test/java/com/navercorp/pinpoint/web/batch/DefaultDividerTest.java new file mode 100644 index 000000000000..4a6f9afbc29e --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/batch/DefaultDividerTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.batch; + +import org.junit.Test; +import org.springframework.batch.item.ExecutionContext; + +import java.util.Map; + +import static org.junit.Assert.*; + +/** + * @author minwoo.jung + */ +public class DefaultDividerTest { + + @Test + public void devide() { + DefaultDivider defaultDivider = new DefaultDivider(); + Map map = defaultDivider.divide("test_partition", "test"); + assertEquals(1, map.size()); + } + +} \ No newline at end of file diff --git a/web/src/test/java/com/navercorp/pinpoint/web/batch/job/AgentCountPartitionerTest.java b/web/src/test/java/com/navercorp/pinpoint/web/batch/job/AgentCountPartitionerTest.java new file mode 100644 index 000000000000..0a1ae9ff7861 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/batch/job/AgentCountPartitionerTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.batch.job; + +import org.junit.Test; +import org.springframework.batch.item.ExecutionContext; + +import java.util.Map; + +import static org.junit.Assert.*; + +/** + * @author minwoo.jung + */ +public class AgentCountPartitionerTest { + + @Test + public void partition() throws Exception { + AgentCountPartitioner partitioner = new AgentCountPartitioner(); + Map partition = partitioner.partition(0); + assertEquals(1, partition.size()); + } + +} \ No newline at end of file diff --git a/web/src/test/java/com/navercorp/pinpoint/web/calltree/span/CallTreeIteratorTest.java b/web/src/test/java/com/navercorp/pinpoint/web/calltree/span/CallTreeIteratorTest.java index f9a8881694ae..6ee1aab7ed66 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/calltree/span/CallTreeIteratorTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/calltree/span/CallTreeIteratorTest.java @@ -517,7 +517,8 @@ private void assertCallTree(CallTree callTree, List expectedDepths, Lis index++; } - logger.debug(buffer.toString()); + // TODO Check CI log + //logger.debug(buffer.toString()); } private Queue parseExpected(String expectedValues) { diff --git a/web/src/test/java/com/navercorp/pinpoint/web/cluster/ClusterTest.java b/web/src/test/java/com/navercorp/pinpoint/web/cluster/ClusterTest.java index 985b8724fca6..a80a439052b2 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/cluster/ClusterTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/cluster/ClusterTest.java @@ -17,12 +17,12 @@ package com.navercorp.pinpoint.web.cluster; import com.navercorp.pinpoint.common.util.NetUtils; -import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory; import com.navercorp.pinpoint.rpc.client.PinpointClient; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; import com.navercorp.pinpoint.rpc.client.SimpleMessageListener; -import com.navercorp.pinpoint.web.TestAwaitTaskUtils; -import com.navercorp.pinpoint.web.TestAwaitUtils; +import com.navercorp.pinpoint.test.client.TestPinpointClient; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import com.navercorp.pinpoint.web.cluster.connection.ClusterConnectionManager; import com.navercorp.pinpoint.web.cluster.zookeeper.ZookeeperClusterDataManager; import com.navercorp.pinpoint.web.config.WebConfig; @@ -192,27 +192,20 @@ public void clusterTest2() throws Exception { @Test public void clusterTest3() throws Exception { - PinpointClientFactory clientFactory = null; - PinpointClient client = null; - ZooKeeper zookeeper = null; + TestPinpointClient testPinpointClient = new TestPinpointClient(SimpleMessageListener.INSTANCE); try { zookeeper = new ZooKeeper(zookeeperAddress, 5000, null); awaitZookeeperConnected(zookeeper); Assert.assertEquals(0, clusterConnectionManager.getClusterList().size()); - clientFactory = new DefaultPinpointClientFactory(); - clientFactory.setMessageListener(SimpleMessageListener.INSTANCE); - - client = clientFactory.connect(DEFAULT_IP, acceptorPort); + testPinpointClient.connect(DEFAULT_IP, acceptorPort); awaitPinpointClientConnected(clusterConnectionManager); Assert.assertEquals(1, clusterConnectionManager.getClusterList().size()); - } finally { - closePinpointSocket(clientFactory, client); - + testPinpointClient.closeAll(); if (zookeeper != null) { zookeeper.close(); } diff --git a/web/src/test/java/com/navercorp/pinpoint/web/cluster/PinpointRouteResponseTest.java b/web/src/test/java/com/navercorp/pinpoint/web/cluster/PinpointRouteResponseTest.java index ce9abfa33444..24b3d6f5b829 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/cluster/PinpointRouteResponseTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/cluster/PinpointRouteResponseTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,10 +16,12 @@ package com.navercorp.pinpoint.web.cluster; +import com.navercorp.pinpoint.io.util.TypeLocator; import com.navercorp.pinpoint.thrift.dto.command.TCommandEcho; import com.navercorp.pinpoint.thrift.dto.command.TCommandTransferResponse; import com.navercorp.pinpoint.thrift.dto.command.TRouteResult; import com.navercorp.pinpoint.thrift.io.*; +import org.apache.thrift.TBase; import org.apache.thrift.protocol.TCompactProtocol; import org.apache.thrift.protocol.TProtocolFactory; import org.junit.Assert; @@ -31,7 +33,7 @@ public class PinpointRouteResponseTest { TProtocolFactory protocolFactory = new TCompactProtocol.Factory(); - TCommandRegistry commandTbaseRegistry = new TCommandRegistry(TCommandTypeVersion.getVersion("1.5.0-SNAPSHOT")); + TypeLocator> commandTbaseRegistry = TCommandRegistry.build(TCommandTypeVersion.getVersion("1.5.0-SNAPSHOT")); SerializerFactory serializerFactory = new HeaderTBaseSerializerFactory(true, 10000, protocolFactory, commandTbaseRegistry); DeserializerFactory deserializerFactory = new HeaderTBaseDeserializerFactory(protocolFactory, commandTbaseRegistry); diff --git a/web/src/test/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterTest.java b/web/src/test/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterTest.java index a9564234df0e..0a94f7e397d6 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/cluster/zookeeper/ZookeeperClusterTest.java @@ -16,13 +16,13 @@ package com.navercorp.pinpoint.web.cluster.zookeeper; -import com.navercorp.pinpoint.collector.cluster.zookeeper.exception.PinpointZookeeperException; +import com.navercorp.pinpoint.common.server.cluster.zookeeper.exception.PinpointZookeeperException; import com.navercorp.pinpoint.common.util.NetUtils; import com.navercorp.pinpoint.rpc.client.PinpointClient; import com.navercorp.pinpoint.rpc.client.PinpointClientFactory; +import com.navercorp.pinpoint.test.utils.TestAwaitTaskUtils; +import com.navercorp.pinpoint.test.utils.TestAwaitUtils; import com.navercorp.pinpoint.web.config.WebConfig; -import com.navercorp.pinpoint.web.TestAwaitTaskUtils; -import com.navercorp.pinpoint.web.TestAwaitUtils; import com.navercorp.pinpoint.web.util.PinpointWebTestUtils; import org.apache.curator.test.TestingServer; import org.apache.zookeeper.CreateMode; @@ -110,7 +110,7 @@ public void clusterTest1() throws Exception { boolean await = awaitUtils.await(new TestAwaitTaskUtils() { @Override public boolean checkCompleted() { - return finalManager.getRegisteredAgentList("a", "b", 1L).size() == 0; + return finalManager.getRegisteredAgentList("a", "b", 1L).isEmpty(); } }); diff --git a/web/src/test/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentLifeCycleDaoTest.java b/web/src/test/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentLifeCycleDaoTest.java index 75f5cf873a0e..eb74ef6180fa 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentLifeCycleDaoTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/dao/hbase/HbaseAgentLifeCycleDaoTest.java @@ -18,6 +18,7 @@ import static org.mockito.Mockito.*; +import com.navercorp.pinpoint.common.hbase.TableNameProvider; import com.navercorp.pinpoint.common.server.bo.AgentLifeCycleBo; import com.navercorp.pinpoint.common.hbase.HbaseOperations2; import com.navercorp.pinpoint.common.hbase.ResultsExtractor; @@ -35,6 +36,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import java.util.Arrays; import java.util.List; @@ -47,6 +49,14 @@ public class HbaseAgentLifeCycleDaoTest { @Mock private HbaseOperations2 hbaseOperations2; + @Spy + private TableNameProvider tableNameProvider = new TableNameProvider() { + @Override + public TableName getTableName(String tableName) { + return TableName.valueOf(tableName); + } + }; + @Mock private RowMapper agentLifeCycleMapper; diff --git a/web/src/test/java/com/navercorp/pinpoint/web/dao/memory/MemoryAlarmDaoTest.java b/web/src/test/java/com/navercorp/pinpoint/web/dao/memory/MemoryAlarmDaoTest.java new file mode 100644 index 000000000000..67d8ef86220c --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/dao/memory/MemoryAlarmDaoTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.dao.memory; + +import com.navercorp.pinpoint.web.alarm.vo.Rule; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.*; + +/** + * @author minwoo.jung + */ +public class MemoryAlarmDaoTest { + + @Test + public void insertDeleteTest() { + final String applicationId = "applicationId"; + final String groupId = "userGroupId"; + MemoryAlarmDao memoryAlarmDao = new MemoryAlarmDao(); + Rule rule = new Rule(applicationId, "serviceType", "checkerName1", 0, groupId, true, true, ""); + Rule rule2 = new Rule(applicationId, "serviceType", "checkerName2", 10, groupId, true, true, ""); + memoryAlarmDao.insertRule(rule); + memoryAlarmDao.insertRule(rule2); + + List resultRules1 = memoryAlarmDao.selectRuleByApplicationId(applicationId); + assertEquals(2, resultRules1.size()); + resultRules1 = memoryAlarmDao.selectRuleByApplicationId("app"); + assertEquals(0, resultRules1.size()); + + List resultRules2 = memoryAlarmDao.selectRuleByUserGroupId(groupId); + assertEquals(2, resultRules2.size()); + resultRules2 = memoryAlarmDao.selectRuleByUserGroupId("id"); + assertEquals(0, resultRules2.size()); + + memoryAlarmDao.deleteRule(rule); + memoryAlarmDao.deleteRule(rule2); + List resultRules = memoryAlarmDao.selectRuleByApplicationId(applicationId); + assertEquals(0, resultRules.size()); + } + +} \ No newline at end of file diff --git a/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/AgentStatMapperV2Test.java b/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/AgentStatMapperV2Test.java index 0d554460d55f..6ff0792f38c2 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/AgentStatMapperV2Test.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/AgentStatMapperV2Test.java @@ -107,7 +107,7 @@ public void mapperTest() throws Exception { List mappedAgentStats = mapper.mapRow(result, 0); // Then - Collections.sort(givenAgentStats, AgentStatMapperV2.REVERSE_TIMESTAMP_COMPARATOR); + givenAgentStats.sort(AgentStatMapperV2.REVERSE_TIMESTAMP_COMPARATOR); Assert.assertEquals(givenAgentStats, mappedAgentStats); } diff --git a/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDataSourceSamplerTest.java b/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDataSourceSamplerTest.java index 821187e0c9b9..c81d7cf3d404 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDataSourceSamplerTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDataSourceSamplerTest.java @@ -42,7 +42,7 @@ public void sampleDataPointsTest() { assertEquals(aggreJoinDataSourceListBo.getId(), id); assertEquals(aggreJoinDataSourceListBo.getTimestamp(), timestamp); List joinDataSourceBoList = aggreJoinDataSourceListBo.getAggreJoinDataSourceBoList(); - Collections.sort(joinDataSourceBoList, new ComparatorImpl()); + joinDataSourceBoList.sort(new ComparatorImpl()); assertEquals(joinDataSourceBoList.size(), 5); diff --git a/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDirectBufferSamplerTest.java b/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDirectBufferSamplerTest.java new file mode 100644 index 000000000000..166eef6a6950 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinDirectBufferSamplerTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.mapper.stat.sampling.sampler; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinDirectBufferBo; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinDirectBufferBo; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author Roy Kim + */ +public class JoinDirectBufferSamplerTest { + @Test + public void sampleDataPoints() throws Exception { + JoinDirectBufferSampler joinDirectBufferSampler = new JoinDirectBufferSampler(); + ListjoinDirectBufferBoList = new ArrayList<>(5); + + long timeStamp = new Date().getTime(); + joinDirectBufferBoList.add(new JoinDirectBufferBo("testApp", 11, 60, "agent1_1", 20, "agent1_2", 10, 60, "agent1_3", 47, "agent1_4", 11, 61, "agent1_5", 21, "agent1_6", 10, 60, "agent1_7", 46, "agent1_8", timeStamp + 5000)); + joinDirectBufferBoList.add(new JoinDirectBufferBo("testApp", 22, 52, "agent2_1", 10, "agent2_2", 20, 70, "agent2_3", 24, "agent2_4", 22, 53, "agent2_5", 11, "agent2_6", 20, 70, "agent2_7", 23, "agent2_8", timeStamp + 10000)); + joinDirectBufferBoList.add(new JoinDirectBufferBo("testApp", 33, 39, "agent3_1", 90, "agent3_2", 30, 85, "agent3_3", 33, "agent3_4", 33, 40, "agent3_5", 91, "agent3_6", 30, 85, "agent3_7", 32, "agent3_8", timeStamp + 15000)); + joinDirectBufferBoList.add(new JoinDirectBufferBo("testApp", 44, 42, "agent4_1", 25, "agent4_2", 40, 58, "agent4_3", 56, "agent4_4", 44, 43, "agent4_5", 26, "agent4_6", 40, 58, "agent4_7", 55, "agent4_8", timeStamp + 20000)); + joinDirectBufferBoList.add(new JoinDirectBufferBo("testApp", 55, 55, "agent5_1", 54, "agent5_2", 50, 86, "agent5_3", 76, "agent5_4", 55, 56, "agent5_5", 55, "agent5_6", 50, 86, "agent5_7", 75, "agent5_8", timeStamp + 25000)); + + AggreJoinDirectBufferBo aggreJoinDirectBufferBo = joinDirectBufferSampler.sampleDataPoints(0, new Date().getTime(), joinDirectBufferBoList, new JoinDirectBufferBo()); + assertEquals(aggreJoinDirectBufferBo.getId(), "testApp"); + assertEquals(aggreJoinDirectBufferBo.getAvgDirectCount(), 33, 0); + assertEquals(aggreJoinDirectBufferBo.getMinDirectCount(), 10, 0); + assertEquals(aggreJoinDirectBufferBo.getMinDirectCountAgentId(), "agent2_2"); + assertEquals(aggreJoinDirectBufferBo.getMaxDirectCount(), 60, 0); + assertEquals(aggreJoinDirectBufferBo.getMaxDirectCountAgentId(), "agent1_1"); + + assertEquals(aggreJoinDirectBufferBo.getAvgDirectMemoryUsed(), 30, 0); + assertEquals(aggreJoinDirectBufferBo.getMinDirectMemoryUsed(), 24, 0); + assertEquals(aggreJoinDirectBufferBo.getMinDirectMemoryUsedAgentId(), "agent2_4"); + assertEquals(aggreJoinDirectBufferBo.getMaxDirectMemoryUsed(), 86, 0); + assertEquals(aggreJoinDirectBufferBo.getMaxDirectMemoryUsedAgentId(), "agent5_3"); + + assertEquals(aggreJoinDirectBufferBo.getId(), "testApp"); + assertEquals(aggreJoinDirectBufferBo.getAvgMappedCount(), 33, 0); + assertEquals(aggreJoinDirectBufferBo.getMinMappedCount(), 11, 0); + assertEquals(aggreJoinDirectBufferBo.getMinMappedCountAgentId(), "agent2_6"); + assertEquals(aggreJoinDirectBufferBo.getMaxMappedCount(), 61, 0); + assertEquals(aggreJoinDirectBufferBo.getMaxMappedCountAgentId(), "agent1_5"); + + assertEquals(aggreJoinDirectBufferBo.getAvgMappedMemoryUsed(), 30, 0); + assertEquals(aggreJoinDirectBufferBo.getMinMappedMemoryUsed(), 23, 0); + assertEquals(aggreJoinDirectBufferBo.getMinMappedMemoryUsedAgentId(), "agent2_8"); + assertEquals(aggreJoinDirectBufferBo.getMaxMappedMemoryUsed(), 86, 0); + assertEquals(aggreJoinDirectBufferBo.getMaxMappedMemoryUsedAgentId(), "agent5_7"); + } + +} \ No newline at end of file diff --git a/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinFileDescriptorSamplerTest.java b/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinFileDescriptorSamplerTest.java new file mode 100644 index 000000000000..21415b4c5470 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/mapper/stat/sampling/sampler/JoinFileDescriptorSamplerTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.mapper.stat.sampling.sampler; + +import com.navercorp.pinpoint.common.server.bo.stat.join.JoinFileDescriptorBo; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinFileDescriptorBo; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author Roy Kim + */ +public class JoinFileDescriptorSamplerTest { + @Test + public void sampleDataPoints() throws Exception { + JoinFileDescriptorSampler joinFileDescriptorSampler = new JoinFileDescriptorSampler(); + ListjoinFileDescriptorBoList = new ArrayList<>(5); + + long timeStamp = new Date().getTime(); + joinFileDescriptorBoList.add(new JoinFileDescriptorBo("testApp", 11, 60, "agent1_1", 20, "agent1_2", timeStamp + 5000)); + joinFileDescriptorBoList.add(new JoinFileDescriptorBo("testApp", 22, 52, "agent2_1", 10, "agent2_2", timeStamp + 10000)); + joinFileDescriptorBoList.add(new JoinFileDescriptorBo("testApp", 33, 39, "agent3_1", 90, "agent3_2", timeStamp + 15000)); + joinFileDescriptorBoList.add(new JoinFileDescriptorBo("testApp", 44, 42, "agent4_1", 25, "agent4_2", timeStamp + 20000)); + joinFileDescriptorBoList.add(new JoinFileDescriptorBo("testApp", 55, 55, "agent5_1", 54, "agent5_2", timeStamp + 25000)); + + AggreJoinFileDescriptorBo aggreJoinFileDescriptorBo = joinFileDescriptorSampler.sampleDataPoints(0, new Date().getTime(), joinFileDescriptorBoList, new JoinFileDescriptorBo()); + assertEquals(aggreJoinFileDescriptorBo.getId(), "testApp"); + assertEquals(aggreJoinFileDescriptorBo.getAvgOpenFDCount(), 33, 0); + assertEquals(aggreJoinFileDescriptorBo.getMinOpenFDCount(), 10, 0); + assertEquals(aggreJoinFileDescriptorBo.getMinOpenFDCountAgentId(), "agent2_2"); + assertEquals(aggreJoinFileDescriptorBo.getMaxOpenFDCount(), 60, 0); + assertEquals(aggreJoinFileDescriptorBo.getMaxOpenFDCountAgentId(), "agent1_1"); + } + +} \ No newline at end of file diff --git a/web/src/test/java/com/navercorp/pinpoint/web/performance/TestSuite.java b/web/src/test/java/com/navercorp/pinpoint/web/performance/TestSuite.java deleted file mode 100644 index dafe961b48d3..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/performance/TestSuite.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2014 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.performance; - -import java.io.IOException; - -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.DefaultHttpClient; -import org.junit.Ignore; - -/** - * - */ -@Ignore -public class TestSuite { - // @Test - public void insertData() throws IOException, InterruptedException { - - - for (int i = 0; i < 10000; i++) { - int mod = i % 4; - if (mod == 0) { - HttpClient client = new DefaultHttpClient(); - HttpGet get1 = new HttpGet("http://localhost:8080/combination.pinpoint"); - HttpResponse execute = client.execute(get1); - } else if (mod == 1) { - HttpClient client = new DefaultHttpClient(); - HttpGet get2 = new HttpGet("http://localhost:8080/mysql.pinpoint"); - HttpResponse execute = client.execute(get2); - } else if (mod == 2) { - HttpClient client = new DefaultHttpClient(); - HttpGet get3 = new HttpGet("http://localhost:8080/donothing.pinpoint"); - HttpResponse execute = client.execute(get3); - } else if (mod == 3) { - HttpClient client = new DefaultHttpClient(); - HttpGet get4 = new HttpGet("http://localhost:8080/combination.pinpoint"); - HttpResponse execute = client.execute(get4); - } - } - - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/FilteredMapServiceImplTest.java b/web/src/test/java/com/navercorp/pinpoint/web/service/FilteredMapServiceImplTest.java index 6daceb32efff..9fde09d6408d 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/FilteredMapServiceImplTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/service/FilteredMapServiceImplTest.java @@ -41,6 +41,7 @@ import com.navercorp.pinpoint.web.view.ResponseTimeViewModel; import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.Range; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -57,6 +58,9 @@ import java.util.List; import java.util.Map; import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -73,6 +77,8 @@ public class FilteredMapServiceImplTest { private static final Random RANDOM = new Random(); + private final ExecutorService executor = Executors.newFixedThreadPool(8); + @Mock private AgentInfoService agentInfoService; @@ -90,8 +96,8 @@ public class FilteredMapServiceImplTest { @Spy private ApplicationMapBuilderFactory applicationMapBuilderFactory = new ApplicationMapBuilderFactory( - new NodeHistogramAppenderFactory("serial", 0), - new ServerInfoAppenderFactory("serial", 0) + new NodeHistogramAppenderFactory(executor), + new ServerInfoAppenderFactory(executor) ); @InjectMocks @@ -116,6 +122,19 @@ public void init() { }); } + @After + public void cleanUp() { + executor.shutdown(); + try { + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + /** * USER -> ROOT_APP -> APP_A -> CACHE */ diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/UserGroupServiceImplTest.java b/web/src/test/java/com/navercorp/pinpoint/web/service/UserGroupServiceImplTest.java index a4ea50a144da..52eb5990ff5b 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/UserGroupServiceImplTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/service/UserGroupServiceImplTest.java @@ -83,4 +83,27 @@ public void selectPhoneNumberOfMember2Test() { assertEquals(phoneNumberList.get(1), "01022222222"); } + + @Test + public void selectPhoneNumberOfMember3Test() { + final String groupId = "test_group"; + List encodedPhoneNumberList = new ArrayList<>(); + encodedPhoneNumberList.add("ASDFG@#$%T"); + encodedPhoneNumberList.add("ASDF@#%$HG"); + + List decodedPhoneNumberList = new ArrayList<>(); + decodedPhoneNumberList.add("01011111111"); + decodedPhoneNumberList.add("01022222222"); + + ReflectionTestUtils.setField(userGroupService, "userInfoDecoder", userInfoDecoder); + ReflectionTestUtils.setField(userGroupService, "userGroupDao", userGroupDao); + when(userGroupDao.selectPhoneNumberOfMember(groupId)).thenReturn(encodedPhoneNumberList); + when(userInfoDecoder.decodePhoneNumberList(encodedPhoneNumberList)).thenReturn(decodedPhoneNumberList); + List phoneNumberList = userGroupService.selectPhoneNumberOfMember(groupId); + + assertEquals(2, phoneNumberList.size()); + assertEquals(phoneNumberList.get(0), "01011111111"); + assertEquals(phoneNumberList.get(1), "01022222222"); + } + } \ No newline at end of file diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelectorTest.java b/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelectorTest.java new file mode 100644 index 000000000000..d07f7255a7e1 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelectorTest.java @@ -0,0 +1,156 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.service.map; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkData; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataMap; +import com.navercorp.pinpoint.web.vo.Application; +import com.navercorp.pinpoint.web.vo.LinkKey; +import com.navercorp.pinpoint.web.vo.Range; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.Collections; +import java.util.HashSet; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +public class BidirectionalLinkSelectorTest extends LinkSelectorTestBase { + + @Override + protected LinkSelectorType getLinkSelectorType() { + return LinkSelectorType.BIDIRECTIONAL; + } + + @Test + public void testBidirectionalGraph() { + // APP_IN_IN -> APP_IN -> APP_A(selected) -> APP_OUT -> APP_OUT_OUT + // |-> APP_IN_OUT APP_OUT_IN -^ + final Application APP_A = new Application("APP_A", ServiceType.TEST_STAND_ALONE); + + final Application APP_IN = new Application("APP_IN", ServiceType.TEST_STAND_ALONE); + final Application APP_IN_IN = new Application("APP_IN_IN", ServiceType.TEST_STAND_ALONE); + final Application APP_IN_OUT = new Application("APP_IN_OUT", ServiceType.TEST_STAND_ALONE); + + final Application APP_OUT = new Application("APP_OUT", ServiceType.TEST_STAND_ALONE); + final Application APP_OUT_OUT = new Application("APP_OUT_OUT", ServiceType.TEST_STAND_ALONE); + final Application APP_OUT_IN = new Application("APP_OUT_IN", ServiceType.TEST_STAND_ALONE); + + int callCount = 10; + + LinkDataMap link_IN_to_A = new LinkDataMap(); + link_IN_to_A.addLinkData(APP_IN, "agentIn", APP_A, "agentA", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + LinkDataMap link_IN_IN_to_IN= new LinkDataMap(); + link_IN_IN_to_IN.addLinkData(APP_IN_IN, "agentInIn", APP_IN, "agentIn", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + LinkDataMap link_IN_to_IN_OUT = new LinkDataMap(); + link_IN_to_IN_OUT.addLinkData(APP_IN, "agentIn", APP_IN_OUT, "agentInOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + + LinkDataMap link_A_to_OUT = new LinkDataMap(); + link_A_to_OUT.addLinkData(APP_A, "agentA", APP_OUT, "agentOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + LinkDataMap link_OUT_to_OUT_OUT = new LinkDataMap(); + link_OUT_to_OUT_OUT.addLinkData(APP_OUT, "agentOut", APP_OUT_OUT, "agentOutOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + LinkDataMap link_OUT_IN_to_OUT = new LinkDataMap(); + link_OUT_IN_to_OUT.addLinkData(APP_OUT_IN, "agentOutIn", APP_OUT, "agentOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + + when(linkDataMapService.selectCallerLinkDataMap(any(Application.class), any(Range.class))).thenAnswer(new Answer() { + @Override + public LinkDataMap answer(InvocationOnMock invocation) throws Throwable { + Application callerApplication = invocation.getArgument(0); + if (callerApplication.equals(APP_A)) { + return link_A_to_OUT; + } else if (callerApplication.equals(APP_IN)) { + LinkDataMap linkDataMap = new LinkDataMap(); + linkDataMap.addLinkDataMap(link_IN_to_A); + linkDataMap.addLinkDataMap(link_IN_to_IN_OUT); + return linkDataMap; + } else if (callerApplication.equals(APP_IN_IN)) { + return link_IN_IN_to_IN; + } else if (callerApplication.equals(APP_OUT)) { + return link_OUT_to_OUT_OUT; + } else if (callerApplication.equals(APP_OUT_IN)) { + return link_OUT_IN_to_OUT; + } + return newEmptyLinkDataMap(); + } + }); + when(linkDataMapService.selectCalleeLinkDataMap(any(Application.class), any(Range.class))).thenAnswer(new Answer() { + @Override + public LinkDataMap answer(InvocationOnMock invocation) throws Throwable { + Application calleeApplication = invocation.getArgument(0); + if (calleeApplication.equals(APP_A)) { + return link_IN_to_A; + } else if (calleeApplication.equals(APP_IN)) { + return link_IN_IN_to_IN; + } else if (calleeApplication.equals(APP_IN_OUT)) { + return link_IN_to_IN_OUT; + } else if (calleeApplication.equals(APP_OUT)) { + LinkDataMap linkDataMap = new LinkDataMap(); + linkDataMap.addLinkDataMap(link_A_to_OUT); + linkDataMap.addLinkDataMap(link_OUT_IN_to_OUT); + return linkDataMap; + } else if (calleeApplication.equals(APP_OUT_OUT)) { + return link_OUT_to_OUT_OUT; + } + return newEmptyLinkDataMap(); + } + }); + when(hostApplicationMapDao.findAcceptApplicationName(any(Application.class), any(Range.class))).thenReturn(new HashSet<>()); + + LinkSelector linkSelector = linkSelectorFactory.createLinkSelector(getLinkSelectorType()); + LinkDataDuplexMap linkDataDuplexMap = linkSelector.select(Collections.singletonList(APP_A), range, 2, 2); + + // APP_IN_IN -> APP_IN (callee) + LinkKey linkKey_IN_IN_to_IN = new LinkKey(APP_IN_IN, APP_IN); + LinkData linkData_IN_IN_to_IN = linkDataDuplexMap.getTargetLinkData(linkKey_IN_IN_to_IN); + Assert.assertNotNull(linkData_IN_IN_to_IN); + Assert.assertEquals(callCount, linkData_IN_IN_to_IN.getTotalCount()); + // APP_IN -> APP_A (callee) + LinkKey linkKey_IN_to_A = new LinkKey(APP_IN, APP_A); + LinkData linkData_IN_to_A = linkDataDuplexMap.getTargetLinkData(linkKey_IN_to_A); + Assert.assertNotNull(linkData_IN_to_A); + Assert.assertEquals(callCount, linkData_IN_to_A.getTotalCount()); + // APP_IN (caller) -> APP_IN_OUT + LinkKey linkKey_IN_to_IN_OUT = new LinkKey(APP_IN, APP_IN_OUT); + LinkData linkData_IN_to_IN_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_IN_to_IN_OUT); + Assert.assertNotNull(linkData_IN_to_IN_OUT); + Assert.assertEquals(callCount, linkData_IN_to_IN_OUT.getTotalCount()); + + // APP_A (caller) -> APP_OUT + LinkKey linkKey_A_to_OUT = new LinkKey(APP_A, APP_OUT); + LinkData linkData_A_to_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_A_to_OUT); + Assert.assertNotNull(linkData_A_to_OUT); + Assert.assertEquals(callCount, linkData_A_to_OUT.getTotalCount()); + // APP_OUT (caller) -> APP_OUT_OUT + LinkKey linkKey_OUT_to_OUT_OUT = new LinkKey(APP_OUT, APP_OUT_OUT); + LinkData linkData_OUT_to_OUT_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_OUT_to_OUT_OUT); + Assert.assertNotNull(linkData_OUT_to_OUT_OUT); + Assert.assertEquals(callCount, linkData_OUT_to_OUT_OUT.getTotalCount()); + // APP_OUT_IN -> APP_OUT (callee) + LinkKey linkKey_OUT_IN_to_OUT = new LinkKey(APP_OUT_IN, APP_OUT); + LinkData linkData_OUT_IN_to_OUT = linkDataDuplexMap.getTargetLinkData(linkKey_OUT_IN_to_OUT); + Assert.assertNotNull(linkData_OUT_IN_to_OUT); + Assert.assertEquals(callCount, linkData_OUT_IN_to_OUT.getTotalCount()); + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelectorTestBase.java b/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelectorTestBase.java deleted file mode 100644 index 27067d1cf64f..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelectorTestBase.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.service.map; - -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkData; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataMap; -import com.navercorp.pinpoint.web.vo.Application; -import com.navercorp.pinpoint.web.vo.LinkKey; -import com.navercorp.pinpoint.web.vo.Range; -import org.apache.hadoop.hbase.shaded.org.junit.Assert; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import java.util.Collections; -import java.util.HashSet; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -/** - * @author HyunGil Jeong - */ -public abstract class BidirectionalLinkSelectorTestBase extends LinkSelectorTestBase { - - @Override - protected LinkSelectorType getLinkSelectorType() { - return LinkSelectorType.BIDIRECTIONAL; - } - - @Test - public void testBidirectionalGraph() { - // APP_IN_IN -> APP_IN -> APP_A(selected) -> APP_OUT -> APP_OUT_OUT - // |-> APP_IN_OUT APP_OUT_IN -^ - final Application APP_A = new Application("APP_A", ServiceType.TEST_STAND_ALONE); - - final Application APP_IN = new Application("APP_IN", ServiceType.TEST_STAND_ALONE); - final Application APP_IN_IN = new Application("APP_IN_IN", ServiceType.TEST_STAND_ALONE); - final Application APP_IN_OUT = new Application("APP_IN_OUT", ServiceType.TEST_STAND_ALONE); - - final Application APP_OUT = new Application("APP_OUT", ServiceType.TEST_STAND_ALONE); - final Application APP_OUT_OUT = new Application("APP_OUT_OUT", ServiceType.TEST_STAND_ALONE); - final Application APP_OUT_IN = new Application("APP_OUT_IN", ServiceType.TEST_STAND_ALONE); - - int callCount = 10; - - LinkDataMap link_IN_to_A = new LinkDataMap(); - link_IN_to_A.addLinkData(APP_IN, "agentIn", APP_A, "agentA", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - LinkDataMap link_IN_IN_to_IN= new LinkDataMap(); - link_IN_IN_to_IN.addLinkData(APP_IN_IN, "agentInIn", APP_IN, "agentIn", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - LinkDataMap link_IN_to_IN_OUT = new LinkDataMap(); - link_IN_to_IN_OUT.addLinkData(APP_IN, "agentIn", APP_IN_OUT, "agentInOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - - LinkDataMap link_A_to_OUT = new LinkDataMap(); - link_A_to_OUT.addLinkData(APP_A, "agentA", APP_OUT, "agentOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - LinkDataMap link_OUT_to_OUT_OUT = new LinkDataMap(); - link_OUT_to_OUT_OUT.addLinkData(APP_OUT, "agentOut", APP_OUT_OUT, "agentOutOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - LinkDataMap link_OUT_IN_to_OUT = new LinkDataMap(); - link_OUT_IN_to_OUT.addLinkData(APP_OUT_IN, "agentOutIn", APP_OUT, "agentOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - - when(linkDataMapService.selectCallerLinkDataMap(any(Application.class), any(Range.class))).thenAnswer(new Answer() { - @Override - public LinkDataMap answer(InvocationOnMock invocation) throws Throwable { - Application callerApplication = invocation.getArgument(0); - if (callerApplication.equals(APP_A)) { - return link_A_to_OUT; - } else if (callerApplication.equals(APP_IN)) { - LinkDataMap linkDataMap = new LinkDataMap(); - linkDataMap.addLinkDataMap(link_IN_to_A); - linkDataMap.addLinkDataMap(link_IN_to_IN_OUT); - return linkDataMap; - } else if (callerApplication.equals(APP_IN_IN)) { - return link_IN_IN_to_IN; - } else if (callerApplication.equals(APP_OUT)) { - return link_OUT_to_OUT_OUT; - } else if (callerApplication.equals(APP_OUT_IN)) { - return link_OUT_IN_to_OUT; - } - return newEmptyLinkDataMap(); - } - }); - when(linkDataMapService.selectCalleeLinkDataMap(any(Application.class), any(Range.class))).thenAnswer(new Answer() { - @Override - public LinkDataMap answer(InvocationOnMock invocation) throws Throwable { - Application calleeApplication = invocation.getArgument(0); - if (calleeApplication.equals(APP_A)) { - return link_IN_to_A; - } else if (calleeApplication.equals(APP_IN)) { - return link_IN_IN_to_IN; - } else if (calleeApplication.equals(APP_IN_OUT)) { - return link_IN_to_IN_OUT; - } else if (calleeApplication.equals(APP_OUT)) { - LinkDataMap linkDataMap = new LinkDataMap(); - linkDataMap.addLinkDataMap(link_A_to_OUT); - linkDataMap.addLinkDataMap(link_OUT_IN_to_OUT); - return linkDataMap; - } else if (calleeApplication.equals(APP_OUT_OUT)) { - return link_OUT_to_OUT_OUT; - } - return newEmptyLinkDataMap(); - } - }); - when(hostApplicationMapDao.findAcceptApplicationName(any(Application.class), any(Range.class))).thenReturn(new HashSet<>()); - - LinkSelector linkSelector = linkSelectorFactory.createLinkSelector(getLinkSelectorType()); - LinkDataDuplexMap linkDataDuplexMap = linkSelector.select(Collections.singletonList(APP_A), range, 2, 2); - - // APP_IN_IN -> APP_IN (callee) - LinkKey linkKey_IN_IN_to_IN = new LinkKey(APP_IN_IN, APP_IN); - LinkData linkData_IN_IN_to_IN = linkDataDuplexMap.getTargetLinkData(linkKey_IN_IN_to_IN); - Assert.assertNotNull(linkData_IN_IN_to_IN); - Assert.assertEquals(callCount, linkData_IN_IN_to_IN.getTotalCount()); - // APP_IN -> APP_A (callee) - LinkKey linkKey_IN_to_A = new LinkKey(APP_IN, APP_A); - LinkData linkData_IN_to_A = linkDataDuplexMap.getTargetLinkData(linkKey_IN_to_A); - Assert.assertNotNull(linkData_IN_to_A); - Assert.assertEquals(callCount, linkData_IN_to_A.getTotalCount()); - // APP_IN (caller) -> APP_IN_OUT - LinkKey linkKey_IN_to_IN_OUT = new LinkKey(APP_IN, APP_IN_OUT); - LinkData linkData_IN_to_IN_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_IN_to_IN_OUT); - Assert.assertNotNull(linkData_IN_to_IN_OUT); - Assert.assertEquals(callCount, linkData_IN_to_IN_OUT.getTotalCount()); - - // APP_A (caller) -> APP_OUT - LinkKey linkKey_A_to_OUT = new LinkKey(APP_A, APP_OUT); - LinkData linkData_A_to_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_A_to_OUT); - Assert.assertNotNull(linkData_A_to_OUT); - Assert.assertEquals(callCount, linkData_A_to_OUT.getTotalCount()); - // APP_OUT (caller) -> APP_OUT_OUT - LinkKey linkKey_OUT_to_OUT_OUT = new LinkKey(APP_OUT, APP_OUT_OUT); - LinkData linkData_OUT_to_OUT_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_OUT_to_OUT_OUT); - Assert.assertNotNull(linkData_OUT_to_OUT_OUT); - Assert.assertEquals(callCount, linkData_OUT_to_OUT_OUT.getTotalCount()); - // APP_OUT_IN -> APP_OUT (callee) - LinkKey linkKey_OUT_IN_to_OUT = new LinkKey(APP_OUT_IN, APP_OUT); - LinkData linkData_OUT_IN_to_OUT = linkDataDuplexMap.getTargetLinkData(linkKey_OUT_IN_to_OUT); - Assert.assertNotNull(linkData_OUT_IN_to_OUT); - Assert.assertEquals(callCount, linkData_OUT_IN_to_OUT.getTotalCount()); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelector_parallel_Test.java b/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelector_parallel_Test.java deleted file mode 100644 index 9917d410f849..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelector_parallel_Test.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.service.map; - -/** - * @author HyunGil Jeong - */ -public class BidirectionalLinkSelector_parallel_Test extends BidirectionalLinkSelectorTestBase { - - @Override - protected ApplicationsMapCreatorFactory createApplicationsMapCreatorFactory() { - return new ApplicationsMapCreatorFactory("parallel", 16); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelector_serial_Test.java b/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelector_serial_Test.java deleted file mode 100644 index f5d0605b4ffa..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/map/BidirectionalLinkSelector_serial_Test.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.service.map; - -/** - * @author HyunGil Jeong - */ -public class BidirectionalLinkSelector_serial_Test extends BidirectionalLinkSelectorTestBase { - - @Override - protected ApplicationsMapCreatorFactory createApplicationsMapCreatorFactory() { - return new ApplicationsMapCreatorFactory("serial", 16); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/map/LinkSelectorTestBase.java b/web/src/test/java/com/navercorp/pinpoint/web/service/map/LinkSelectorTestBase.java index a651522dd5c8..30c3d5c8d9e3 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/map/LinkSelectorTestBase.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/service/map/LinkSelectorTestBase.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -29,6 +29,7 @@ import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.LinkKey; import com.navercorp.pinpoint.web.vo.Range; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -39,9 +40,12 @@ import java.util.List; import java.util.Random; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -53,6 +57,10 @@ public abstract class LinkSelectorTestBase { private static final Random RANDOM = new Random(); + private final ExecutorService executor = Executors.newFixedThreadPool(4); + + private final ApplicationsMapCreatorFactory applicationsMapCreatorFactory = new ApplicationsMapCreatorFactory(executor); + protected final ServiceType testRpcServiceType = ServiceTypeFactory.of(9000, "TEST_RPC_CLIENT", ServiceTypeProperty.RECORD_STATISTICS); protected final Range range = new Range(0, 100); @@ -61,18 +69,28 @@ public abstract class LinkSelectorTestBase { protected HostApplicationMapDao hostApplicationMapDao; protected LinkSelectorFactory linkSelectorFactory; - protected abstract ApplicationsMapCreatorFactory createApplicationsMapCreatorFactory(); - protected abstract LinkSelectorType getLinkSelectorType(); @Before public void setUp() throws Exception { this.linkDataMapService = mock(LinkDataMapService.class); this.hostApplicationMapDao = mock(HostApplicationMapDao.class); - ApplicationsMapCreatorFactory applicationsMapCreatorFactory = createApplicationsMapCreatorFactory(); this.linkSelectorFactory = new LinkSelectorFactory(linkDataMapService, applicationsMapCreatorFactory, hostApplicationMapDao); } + @After + public void cleanUp() { + executor.shutdown(); + try { + if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + final LinkDataMap newEmptyLinkDataMap() { return new LinkDataMap(); } diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelectorTest.java b/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelectorTest.java new file mode 100644 index 000000000000..a2d4403b854d --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelectorTest.java @@ -0,0 +1,156 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.service.map; + +import com.navercorp.pinpoint.common.trace.ServiceType; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkData; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; +import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataMap; +import com.navercorp.pinpoint.web.vo.Application; +import com.navercorp.pinpoint.web.vo.LinkKey; +import com.navercorp.pinpoint.web.vo.Range; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.Collections; +import java.util.HashSet; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +/** + * @author HyunGil Jeong + */ +public class UnidirectionalLinkSelectorTest extends LinkSelectorTestBase { + + @Override + protected LinkSelectorType getLinkSelectorType() { + return LinkSelectorType.UNIDIRECTIONAL; + } + + @Test + public void testCalleesOfCallers() { + // APP_IN_IN -> APP_IN -> APP_A(selected) -> APP_OUT -> APP_OUT_OUT + // |-> APP_IN_OUT APP_OUT_IN -^ + final Application APP_A = new Application("APP_A", ServiceType.TEST_STAND_ALONE); + + final Application APP_IN = new Application("APP_IN", ServiceType.TEST_STAND_ALONE); + final Application APP_IN_IN = new Application("APP_IN_IN", ServiceType.TEST_STAND_ALONE); + final Application APP_IN_OUT = new Application("APP_IN_OUT", ServiceType.TEST_STAND_ALONE); + + final Application APP_OUT = new Application("APP_OUT", ServiceType.TEST_STAND_ALONE); + final Application APP_OUT_OUT = new Application("APP_OUT_OUT", ServiceType.TEST_STAND_ALONE); + final Application APP_OUT_IN = new Application("APP_OUT_IN", ServiceType.TEST_STAND_ALONE); + + int callCount = 10; + + LinkDataMap link_IN_to_A = new LinkDataMap(); + link_IN_to_A.addLinkData(APP_IN, "agentIn", APP_A, "agentA", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + LinkDataMap link_IN_IN_to_IN= new LinkDataMap(); + link_IN_IN_to_IN.addLinkData(APP_IN_IN, "agentInIn", APP_IN, "agentIn", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + LinkDataMap link_IN_to_IN_OUT = new LinkDataMap(); + link_IN_to_IN_OUT.addLinkData(APP_IN, "agentIn", APP_IN_OUT, "agentInOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + + LinkDataMap link_A_to_OUT = new LinkDataMap(); + link_A_to_OUT.addLinkData(APP_A, "agentA", APP_OUT, "agentOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + LinkDataMap link_OUT_to_OUT_OUT = new LinkDataMap(); + link_OUT_to_OUT_OUT.addLinkData(APP_OUT, "agentOut", APP_OUT_OUT, "agentOutOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + LinkDataMap link_OUT_IN_to_OUT = new LinkDataMap(); + link_OUT_IN_to_OUT.addLinkData(APP_OUT_IN, "agentOutIn", APP_OUT, "agentOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); + + when(linkDataMapService.selectCallerLinkDataMap(any(Application.class), any(Range.class))).thenAnswer(new Answer() { + @Override + public LinkDataMap answer(InvocationOnMock invocation) throws Throwable { + Application callerApplication = invocation.getArgument(0); + if (callerApplication.equals(APP_A)) { + return link_A_to_OUT; + } else if (callerApplication.equals(APP_IN)) { + LinkDataMap linkDataMap = new LinkDataMap(); + linkDataMap.addLinkDataMap(link_IN_to_A); + linkDataMap.addLinkDataMap(link_IN_to_IN_OUT); + return linkDataMap; + } else if (callerApplication.equals(APP_IN_IN)) { + return link_IN_IN_to_IN; + } else if (callerApplication.equals(APP_OUT)) { + return link_OUT_to_OUT_OUT; + } else if (callerApplication.equals(APP_OUT_IN)) { + return link_OUT_IN_to_OUT; + } + return newEmptyLinkDataMap(); + } + }); + when(linkDataMapService.selectCalleeLinkDataMap(any(Application.class), any(Range.class))).thenAnswer(new Answer() { + @Override + public LinkDataMap answer(InvocationOnMock invocation) throws Throwable { + Application calleeApplication = invocation.getArgument(0); + if (calleeApplication.equals(APP_A)) { + return link_IN_to_A; + } else if (calleeApplication.equals(APP_IN)) { + return link_IN_IN_to_IN; + } else if (calleeApplication.equals(APP_IN_OUT)) { + return link_IN_to_IN_OUT; + } else if (calleeApplication.equals(APP_OUT)) { + LinkDataMap linkDataMap = new LinkDataMap(); + linkDataMap.addLinkDataMap(link_A_to_OUT); + linkDataMap.addLinkDataMap(link_OUT_IN_to_OUT); + return linkDataMap; + } else if (calleeApplication.equals(APP_OUT_OUT)) { + return link_OUT_to_OUT_OUT; + } + return newEmptyLinkDataMap(); + } + }); + when(hostApplicationMapDao.findAcceptApplicationName(any(Application.class), any(Range.class))).thenReturn(new HashSet<>()); + + LinkSelector linkSelector = linkSelectorFactory.createLinkSelector(getLinkSelectorType()); + LinkDataDuplexMap linkDataDuplexMap = linkSelector.select(Collections.singletonList(APP_A), range, 2, 2); + + // APP_IN_IN -> APP_IN -> APP_A(selected) -> APP_OUT -> APP_OUT_OUT + // |-> APP_IN_OUT APP_OUT_IN -^ + // APP_IN_IN -> APP_IN (callee) + LinkKey linkKey_IN_IN_to_IN = new LinkKey(APP_IN_IN, APP_IN); + LinkData linkData_IN_IN_to_IN = linkDataDuplexMap.getTargetLinkData(linkKey_IN_IN_to_IN); + Assert.assertNotNull(linkData_IN_IN_to_IN); + Assert.assertEquals(callCount, linkData_IN_IN_to_IN.getTotalCount()); + // APP_IN -> APP_A (callee) + LinkKey linkKey_IN_to_A = new LinkKey(APP_IN, APP_A); + LinkData linkData_IN_to_A = linkDataDuplexMap.getTargetLinkData(linkKey_IN_to_A); + Assert.assertNotNull(linkData_IN_to_A); + Assert.assertEquals(callCount, linkData_IN_to_A.getTotalCount()); + // APP_IN (caller) -> APP_IN_OUT should not exist + LinkKey linkKey_IN_to_IN_OUT = new LinkKey(APP_IN, APP_IN_OUT); + LinkData linkData_IN_to_IN_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_IN_to_IN_OUT); + Assert.assertNull(linkData_IN_to_IN_OUT); + + // APP_A (caller) -> APP_OUT + LinkKey linkKey_A_to_OUT = new LinkKey(APP_A, APP_OUT); + LinkData linkData_A_to_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_A_to_OUT); + Assert.assertNotNull(linkData_A_to_OUT); + Assert.assertEquals(callCount, linkData_A_to_OUT.getTotalCount()); + // APP_OUT (caller) -> APP_OUT_OUT + LinkKey linkKey_OUT_to_OUT_OUT = new LinkKey(APP_OUT, APP_OUT_OUT); + LinkData linkData_OUT_to_OUT_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_OUT_to_OUT_OUT); + Assert.assertNotNull(linkData_OUT_to_OUT_OUT); + Assert.assertEquals(callCount, linkData_OUT_to_OUT_OUT.getTotalCount()); + // APP_OUT_IN -> APP_OUT (callee) should not exist + LinkKey linkKey_OUT_IN_to_OUT = new LinkKey(APP_OUT_IN, APP_OUT); + LinkData linkData_OUT_IN_to_OUT = linkDataDuplexMap.getTargetLinkData(linkKey_OUT_IN_to_OUT); + Assert.assertNull(linkData_OUT_IN_to_OUT); + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelectorTestBase.java b/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelectorTestBase.java deleted file mode 100644 index a4cf132772c9..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelectorTestBase.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.service.map; - -import com.navercorp.pinpoint.common.trace.ServiceType; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkData; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataDuplexMap; -import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkDataMap; -import com.navercorp.pinpoint.web.vo.Application; -import com.navercorp.pinpoint.web.vo.LinkKey; -import com.navercorp.pinpoint.web.vo.Range; -import org.apache.hadoop.hbase.shaded.org.junit.Assert; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import java.util.Collections; -import java.util.HashSet; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -/** - * @author HyunGil Jeong - */ -public abstract class UnidirectionalLinkSelectorTestBase extends LinkSelectorTestBase { - - @Override - protected LinkSelectorType getLinkSelectorType() { - return LinkSelectorType.UNIDIRECTIONAL; - } - - @Test - public void testCalleesOfCallers() { - // APP_IN_IN -> APP_IN -> APP_A(selected) -> APP_OUT -> APP_OUT_OUT - // |-> APP_IN_OUT APP_OUT_IN -^ - final Application APP_A = new Application("APP_A", ServiceType.TEST_STAND_ALONE); - - final Application APP_IN = new Application("APP_IN", ServiceType.TEST_STAND_ALONE); - final Application APP_IN_IN = new Application("APP_IN_IN", ServiceType.TEST_STAND_ALONE); - final Application APP_IN_OUT = new Application("APP_IN_OUT", ServiceType.TEST_STAND_ALONE); - - final Application APP_OUT = new Application("APP_OUT", ServiceType.TEST_STAND_ALONE); - final Application APP_OUT_OUT = new Application("APP_OUT_OUT", ServiceType.TEST_STAND_ALONE); - final Application APP_OUT_IN = new Application("APP_OUT_IN", ServiceType.TEST_STAND_ALONE); - - int callCount = 10; - - LinkDataMap link_IN_to_A = new LinkDataMap(); - link_IN_to_A.addLinkData(APP_IN, "agentIn", APP_A, "agentA", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - LinkDataMap link_IN_IN_to_IN= new LinkDataMap(); - link_IN_IN_to_IN.addLinkData(APP_IN_IN, "agentInIn", APP_IN, "agentIn", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - LinkDataMap link_IN_to_IN_OUT = new LinkDataMap(); - link_IN_to_IN_OUT.addLinkData(APP_IN, "agentIn", APP_IN_OUT, "agentInOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - - LinkDataMap link_A_to_OUT = new LinkDataMap(); - link_A_to_OUT.addLinkData(APP_A, "agentA", APP_OUT, "agentOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - LinkDataMap link_OUT_to_OUT_OUT = new LinkDataMap(); - link_OUT_to_OUT_OUT.addLinkData(APP_OUT, "agentOut", APP_OUT_OUT, "agentOutOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - LinkDataMap link_OUT_IN_to_OUT = new LinkDataMap(); - link_OUT_IN_to_OUT.addLinkData(APP_OUT_IN, "agentOutIn", APP_OUT, "agentOut", 1000, ServiceType.STAND_ALONE.getHistogramSchema().getNormalSlot().getSlotTime(), callCount); - - when(linkDataMapService.selectCallerLinkDataMap(any(Application.class), any(Range.class))).thenAnswer(new Answer() { - @Override - public LinkDataMap answer(InvocationOnMock invocation) throws Throwable { - Application callerApplication = invocation.getArgument(0); - if (callerApplication.equals(APP_A)) { - return link_A_to_OUT; - } else if (callerApplication.equals(APP_IN)) { - LinkDataMap linkDataMap = new LinkDataMap(); - linkDataMap.addLinkDataMap(link_IN_to_A); - linkDataMap.addLinkDataMap(link_IN_to_IN_OUT); - return linkDataMap; - } else if (callerApplication.equals(APP_IN_IN)) { - return link_IN_IN_to_IN; - } else if (callerApplication.equals(APP_OUT)) { - return link_OUT_to_OUT_OUT; - } else if (callerApplication.equals(APP_OUT_IN)) { - return link_OUT_IN_to_OUT; - } - return newEmptyLinkDataMap(); - } - }); - when(linkDataMapService.selectCalleeLinkDataMap(any(Application.class), any(Range.class))).thenAnswer(new Answer() { - @Override - public LinkDataMap answer(InvocationOnMock invocation) throws Throwable { - Application calleeApplication = invocation.getArgument(0); - if (calleeApplication.equals(APP_A)) { - return link_IN_to_A; - } else if (calleeApplication.equals(APP_IN)) { - return link_IN_IN_to_IN; - } else if (calleeApplication.equals(APP_IN_OUT)) { - return link_IN_to_IN_OUT; - } else if (calleeApplication.equals(APP_OUT)) { - LinkDataMap linkDataMap = new LinkDataMap(); - linkDataMap.addLinkDataMap(link_A_to_OUT); - linkDataMap.addLinkDataMap(link_OUT_IN_to_OUT); - return linkDataMap; - } else if (calleeApplication.equals(APP_OUT_OUT)) { - return link_OUT_to_OUT_OUT; - } - return newEmptyLinkDataMap(); - } - }); - when(hostApplicationMapDao.findAcceptApplicationName(any(Application.class), any(Range.class))).thenReturn(new HashSet<>()); - - LinkSelector linkSelector = linkSelectorFactory.createLinkSelector(getLinkSelectorType()); - LinkDataDuplexMap linkDataDuplexMap = linkSelector.select(Collections.singletonList(APP_A), range, 2, 2); - - // APP_IN_IN -> APP_IN -> APP_A(selected) -> APP_OUT -> APP_OUT_OUT - // |-> APP_IN_OUT APP_OUT_IN -^ - // APP_IN_IN -> APP_IN (callee) - LinkKey linkKey_IN_IN_to_IN = new LinkKey(APP_IN_IN, APP_IN); - LinkData linkData_IN_IN_to_IN = linkDataDuplexMap.getTargetLinkData(linkKey_IN_IN_to_IN); - Assert.assertNotNull(linkData_IN_IN_to_IN); - Assert.assertEquals(callCount, linkData_IN_IN_to_IN.getTotalCount()); - // APP_IN -> APP_A (callee) - LinkKey linkKey_IN_to_A = new LinkKey(APP_IN, APP_A); - LinkData linkData_IN_to_A = linkDataDuplexMap.getTargetLinkData(linkKey_IN_to_A); - Assert.assertNotNull(linkData_IN_to_A); - Assert.assertEquals(callCount, linkData_IN_to_A.getTotalCount()); - // APP_IN (caller) -> APP_IN_OUT should not exist - LinkKey linkKey_IN_to_IN_OUT = new LinkKey(APP_IN, APP_IN_OUT); - LinkData linkData_IN_to_IN_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_IN_to_IN_OUT); - Assert.assertNull(linkData_IN_to_IN_OUT); - - // APP_A (caller) -> APP_OUT - LinkKey linkKey_A_to_OUT = new LinkKey(APP_A, APP_OUT); - LinkData linkData_A_to_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_A_to_OUT); - Assert.assertNotNull(linkData_A_to_OUT); - Assert.assertEquals(callCount, linkData_A_to_OUT.getTotalCount()); - // APP_OUT (caller) -> APP_OUT_OUT - LinkKey linkKey_OUT_to_OUT_OUT = new LinkKey(APP_OUT, APP_OUT_OUT); - LinkData linkData_OUT_to_OUT_OUT = linkDataDuplexMap.getSourceLinkData(linkKey_OUT_to_OUT_OUT); - Assert.assertNotNull(linkData_OUT_to_OUT_OUT); - Assert.assertEquals(callCount, linkData_OUT_to_OUT_OUT.getTotalCount()); - // APP_OUT_IN -> APP_OUT (callee) should not exist - LinkKey linkKey_OUT_IN_to_OUT = new LinkKey(APP_OUT_IN, APP_OUT); - LinkData linkData_OUT_IN_to_OUT = linkDataDuplexMap.getTargetLinkData(linkKey_OUT_IN_to_OUT); - Assert.assertNull(linkData_OUT_IN_to_OUT); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelector_parallel_Test.java b/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelector_parallel_Test.java deleted file mode 100644 index 5f7dc742e565..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelector_parallel_Test.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.service.map; - -/** - * @author HyunGil Jeong - */ -public class UnidirectionalLinkSelector_parallel_Test extends UnidirectionalLinkSelectorTestBase { - - @Override - protected ApplicationsMapCreatorFactory createApplicationsMapCreatorFactory() { - return new ApplicationsMapCreatorFactory("parallel", 16); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelector_serial_Test.java b/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelector_serial_Test.java deleted file mode 100644 index 82a94c012a1d..000000000000 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/map/UnidirectionalLinkSelector_serial_Test.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 NAVER Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.navercorp.pinpoint.web.service.map; - -/** - * @author HyunGil Jeong - */ -public class UnidirectionalLinkSelector_serial_Test extends UnidirectionalLinkSelectorTestBase { - - @Override - protected ApplicationsMapCreatorFactory createApplicationsMapCreatorFactory() { - return new ApplicationsMapCreatorFactory("serial", 16); - } -} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/service/stat/AgentWarningStatServiceTest.java b/web/src/test/java/com/navercorp/pinpoint/web/service/stat/AgentWarningStatServiceTest.java index 60241ffd337d..e7e67844e630 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/service/stat/AgentWarningStatServiceTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/service/stat/AgentWarningStatServiceTest.java @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.web.service.stat; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import com.navercorp.pinpoint.web.dao.stat.DeadlockDao; import com.navercorp.pinpoint.web.vo.Range; import com.navercorp.pinpoint.web.vo.timeline.inspector.AgentStatusTimelineSegment; @@ -54,7 +54,7 @@ public class AgentWarningStatServiceTest { public void selectTest1() throws Exception { Range range = new Range(CURRENT_TIME - TIME, CURRENT_TIME); - List mockData = createMockData(10, 5000); + List mockData = createMockData(10, 5000); when(deadlockDao.getAgentStatList("pinpoint", range)).thenReturn(mockData); List timelineSegmentList = agentWarningStatService.select("pinpoint", range); Assert.assertTrue(timelineSegmentList.size() == 1); @@ -64,26 +64,26 @@ public void selectTest1() throws Exception { public void selectTest2() throws Exception { Range range = new Range(CURRENT_TIME - TIME, CURRENT_TIME); - List mockData = createMockData(10, 70000); + List mockData = createMockData(10, 70000); when(deadlockDao.getAgentStatList("pinpoint", range)).thenReturn(mockData); List timelineSegmentList = agentWarningStatService.select("pinpoint", range); Assert.assertTrue(timelineSegmentList.size() == 10); } - private List createMockData(int mockSize, long interval) { + private List createMockData(int mockSize, long interval) { long timestamp = ThreadLocalRandom.current().nextLong(START_TIME, CURRENT_TIME); - List deadlockBoList = new ArrayList<>(mockSize); + List deadlockThreadCountBoList = new ArrayList<>(mockSize); for (int i = 0; i < mockSize; i++) { - DeadlockBo deadlockBo = new DeadlockBo(); - deadlockBo.setAgentId("pinpoint"); - deadlockBo.setStartTimestamp(START_TIME); - deadlockBo.setTimestamp(timestamp + (i * interval)); + DeadlockThreadCountBo deadlockThreadCountBo = new DeadlockThreadCountBo(); + deadlockThreadCountBo.setAgentId("pinpoint"); + deadlockThreadCountBo.setStartTimestamp(START_TIME); + deadlockThreadCountBo.setTimestamp(timestamp + (i * interval)); - deadlockBoList.add(deadlockBo); + deadlockThreadCountBoList.add(deadlockThreadCountBo); } - return deadlockBoList; + return deadlockThreadCountBoList; } } diff --git a/web/src/test/java/com/navercorp/pinpoint/web/task/ChainedTaskDecoratorTest.java b/web/src/test/java/com/navercorp/pinpoint/web/task/ChainedTaskDecoratorTest.java new file mode 100644 index 000000000000..b7b4a8fc786a --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/task/ChainedTaskDecoratorTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.task; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.TaskDecorator; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author HyunGil Jeong + */ +public class ChainedTaskDecoratorTest { + + private SimpleAsyncTaskExecutor executor; + + @Before + public void setup() { + executor = new SimpleAsyncTaskExecutor("Test-Worker-"); + } + + @Test + public void chainedDecoratorsShouldBeCalled() throws InterruptedException { + // Given + final int testCount = 100; + final CountDownLatch completeLatch = new CountDownLatch(testCount); + final CountingTaskDecorator decorator1 = new CountingTaskDecorator(); + final CountingTaskDecorator decorator2 = new CountingTaskDecorator(); + final CountingTaskDecorator decorator3 = new CountingTaskDecorator(); + final List decorators = Arrays.asList(decorator1, decorator2, decorator3); + final ChainedTaskDecorator chainedDecorator = new ChainedTaskDecorator(decorators); + executor.setTaskDecorator(chainedDecorator); + // When + for (int i = 0; i < testCount; i++) { + executor.execute(new TestWorker(completeLatch)); + } + completeLatch.await(5L, TimeUnit.SECONDS); + // Then + Assert.assertEquals(testCount, decorator1.getCount()); + Assert.assertEquals(testCount, decorator2.getCount()); + Assert.assertEquals(testCount, decorator3.getCount()); + } + + private static class CountingTaskDecorator implements TaskDecorator { + + private final AtomicInteger count = new AtomicInteger(0); + + @Override + public Runnable decorate(Runnable runnable) { + count.incrementAndGet(); + return runnable; + } + + public int getCount() { + return count.get(); + } + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/task/RequestContextPropagatingTaskDecoratorTest.java b/web/src/test/java/com/navercorp/pinpoint/web/task/RequestContextPropagatingTaskDecoratorTest.java new file mode 100644 index 000000000000..c6a7efcd737d --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/task/RequestContextPropagatingTaskDecoratorTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.task; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author HyunGil Jeong + */ +@RunWith(MockitoJUnitRunner.class) +public class RequestContextPropagatingTaskDecoratorTest { + + private final RequestContextPropagatingTaskDecorator decorator = new RequestContextPropagatingTaskDecorator(); + private final SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("Test-Worker-"); + + @Mock + private RequestAttributes requestAttributes; + + @Before + public void setup() { + executor.setTaskDecorator(decorator); + } + + @Test + public void requestContextShouldBePropagated() throws InterruptedException { + // Given + final int testCount = 100; + final CountDownLatch completeLatch = new CountDownLatch(testCount); + final AtomicBoolean verifiedFlag = new AtomicBoolean(true); + final TestWorker.Callback workerCallback = new TestWorker.Callback() { + @Override + public void onRun() { + RequestAttributes actualRequestAttributes = RequestContextHolder.getRequestAttributes(); + boolean verified = requestAttributes == actualRequestAttributes; + verifiedFlag.compareAndSet(true, verified); + } + + @Override + public void onError() { + // do nothing + } + }; + // When + RequestContextHolder.setRequestAttributes(requestAttributes); + for (int i = 0; i < testCount; i++) { + executor.execute(new TestWorker(completeLatch, workerCallback)); + } + completeLatch.await(5, TimeUnit.SECONDS); + // Then + boolean testVerified = verifiedFlag.get(); + Assert.assertTrue("RequestContext has not been propagated", testVerified); + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/task/SecurityContextPropagatingTaskDecoratorTest.java b/web/src/test/java/com/navercorp/pinpoint/web/task/SecurityContextPropagatingTaskDecoratorTest.java new file mode 100644 index 000000000000..fd101184f9f9 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/task/SecurityContextPropagatingTaskDecoratorTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.task; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author HyunGil Jeong + */ +@RunWith(MockitoJUnitRunner.class) +public class SecurityContextPropagatingTaskDecoratorTest { + + private final SecurityContextPropagatingTaskDecorator decorator = new SecurityContextPropagatingTaskDecorator(); + private final SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("Test-Worker-"); + + @Mock + private SecurityContext securityContext; + + @Before + public void setup() { + executor.setTaskDecorator(decorator); + } + + @Test + public void securityContextShouldBePropagated() throws InterruptedException { + // Given + final int testCount = 100; + final CountDownLatch completeLatch = new CountDownLatch(testCount); + final AtomicBoolean verifiedFlag = new AtomicBoolean(true); + final TestWorker.Callback workerCallback = new TestWorker.Callback() { + @Override + public void onRun() { + SecurityContext actualSecurityContext = SecurityContextHolder.getContext(); + boolean verified = securityContext == actualSecurityContext; + verifiedFlag.compareAndSet(true, verified); + } + + @Override + public void onError() { + // do nothing + } + }; + // When + SecurityContextHolder.setContext(securityContext); + for (int i = 0; i < testCount; i++) { + executor.execute(new TestWorker(completeLatch, workerCallback)); + } + completeLatch.await(5, TimeUnit.SECONDS); + // Then + boolean testVerified = verifiedFlag.get(); + Assert.assertTrue("SecurityContext has not been propagated", testVerified); + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/task/TestWorker.java b/web/src/test/java/com/navercorp/pinpoint/web/task/TestWorker.java new file mode 100644 index 000000000000..1e346162dfff --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/task/TestWorker.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.task; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; +import java.util.concurrent.CountDownLatch; + +/** + * @author HyunGil Jeong + */ +public class TestWorker implements Runnable { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final CountDownLatch completeLatch; + private final Callback callback; + + TestWorker(CountDownLatch completeLatch) { + this(completeLatch, Callback.DO_NOTHING); + } + + TestWorker(CountDownLatch completeLatch, Callback callback) { + this.completeLatch = Objects.requireNonNull(completeLatch, "completeLatch must not be null"); + this.callback = Objects.requireNonNull(callback, "onWorkerRun must not be null"); + } + + @Override + public void run() { + try { + callback.onRun(); + logger.debug("{} work complete.", Thread.currentThread().getName()); + } catch (Exception e) { + callback.onError(); + logger.error("{} work complete with {}", Thread.currentThread().getName(), e); + } finally { + completeLatch.countDown(); + } + } + + interface Callback { + + void onRun(); + + void onError(); + + Callback DO_NOTHING = new Callback() { + @Override + public void onRun() { + } + + @Override + public void onError() { + } + }; + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/util/BatchUtilsTest.java b/web/src/test/java/com/navercorp/pinpoint/web/util/BatchUtilsTest.java new file mode 100644 index 000000000000..762c1fc0664b --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/util/BatchUtilsTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.util; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author minwoo.jung + */ +public class BatchUtilsTest { + + @Test + public void test() { + assertEquals(BatchUtils.decisionBatchServer("127.0.0.1"), true); + assertEquals(BatchUtils.decisionBatchServer("127.127.127.127"), false); + } + +} \ No newline at end of file diff --git a/web/src/test/java/com/navercorp/pinpoint/web/util/MongoJsonParserTest.java b/web/src/test/java/com/navercorp/pinpoint/web/util/MongoJsonParserTest.java new file mode 100644 index 000000000000..e77bb60bdb82 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/util/MongoJsonParserTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.util; + +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * @author Roy Kim + */ +public class MongoJsonParserTest { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private MongoJsonParser jsonParser = new DefaultMongoJsonParser(); + private OutputParameterMongoJsonParser outputParameterMongoJsonParser = new OutputParameterMongoJsonParser(); + + + @Test + public void combineBindValue() { + String test = "{\"items\" : [ { \"title\" : \"First Item\", \"description\" : \"This is the first item description.\" }, { \"title\" : \"Second Item\", \"description\" : \"This is the second item description.\" }]}"; + String testexpect = "{\"items\" : [ { \"title\" : \"?\", \"description\" : \"?\" }, { \"title\" : \"?\", \"description\" : \"?\" }]}"; + String testparam = "\"First Item\",\"This is the first item description.\",\"Second Item\",\"This is the second item description.\""; + assertCombine(test, testexpect, testparam); + } + + @Test + public void combineBindValueArray() { + assertCombine("{ \"Java_Collection\" : [\"naver\", \"apple\", { \"number\" : 3 }], \"_id\" : 5bea4fb796f948fca7e11975 }" + , "{ \"Java_Collection\" : [\"?\", \"?\", { \"number\" : \"?\" }], \"_id\" : \"?\" }" + , "\"naver\",\"apple\",3,5bea4fb796f948fca7e11975"); + } + + @Test + public void combineBindValueNestedArray() { + assertCombine("{\"collection\": {\"id\": [tag1,pizza,[snacks,tag2],coffee],\"passwordProtected\": false,\"typeLabel\": \"blog\"}}" + , "{\"collection\": {\"id\": [\"?\",\"?\",[\"?\",\"?\"],\"?\"],\"passwordProtected\": \"?\",\"typeLabel\": \"?\"}}" + , "tag1,pizza,snacks,tag2,coffee,false,\"blog\""); + + assertCombine("{\"collection\": {\"id\": [tag1,pizza,coffee,[snacks,tag2]],\"passwordProtected\": false,\"typeLabel\": \"blog\"}}" + , "{\"collection\": {\"id\": [\"?\",\"?\",\"?\",[\"?\",\"?\"]],\"passwordProtected\": \"?\",\"typeLabel\": \"?\"}}" + , "tag1,pizza,coffee,snacks,tag2,false,\"blog\""); + } + + @Test + public void combineBindValueDoubleQuoteInKey() { + assertCombine("{\"coll\\\"ection\": {\"name\" : \"tag1\", \"na\\\"me2\" : 1}}" + , "{\"coll\\\"ection\": {\"name\" : \"?\", \"na\\\"me2\" : \"?\"}}" + , "\"tag1\",1"); + } + + @Test + public void combineBindValueDoubleQuoteInValue() { + assertCombine("{\"collection\": {\"name\" : \"ta\"g,1\", \"name2\" : \"\"\"\", \"name3\" : \"\", \"name4\" : }}" + , "{\"collection\": {\"name\" : \"?\", \"name2\" : \"?\", \"name3\" : \"?\", \"name4\" : \"?\"}}" + , "\"ta\"\"g,1\",\"\"\"\"\"\",\"\","); + } + + @Test + public void combineBindValueEveryElementOfMongoDB() { + assertCombine("\"query\" : { \"int32\" : { \"value\" : 12 }, \"int64\" : { \"value\" : 77 }, \"boolean\" : { \"value\" : true }, \"date\" : { \"value\" : 1542019151267 }, \"double\" : { \"value\" : 12.3 }, \"string\" : { \"value\" : \"pinpoint\" }, \"objectId\" : { \"value\" : 5be9584f96f948776d3130ec }, \"code\" : { \"code\" : \"int i = 10;\" }, \"codeWithScope\" : { \"code\" : \"int x = y\", \"scope\" : { \"y\" : { \"value\" : 1 } } }, \"regex\" : { \"pattern\" : \"^test.*regex.*xyz$\", \"options\" : \"bgi\" }, \"symbol\" : { \"symbol\" : \"wow\" }, \"timestamp\" : { \"value\" : 1311768464867721221 }, \"undefined\" : { }, \"binary1\" : { \"type\" : 0, \"data\" : [-32, 79, -48, 32, -22, 58, 105, 16, -94, -40, 8, 0, 43, 48, 48, -99] }, \"oldBinary\" : { \"type\" : 2, \"data\" : [1, 1, 1, 1, 1] }, \"arrayInt\" : [{ \"value\" : \"stest\" }, { \"value\" : 111.0 }, { \"value\" : true }, { \"value\" : 7 }], \"document\" : { \"a\" : { \"value\" : 77 } }, \"dbPointer\" : { \"namespace\" : \"db.coll\", \"id\" : 5be9584f96f948776d3130ed }, \"null\" : { } }", + "\"query\" : { \"int32\" : { \"value\" : \"?\" }, \"int64\" : { \"value\" : \"?\" }, \"boolean\" : { \"value\" : \"?\" }, \"date\" : { \"value\" : \"?\" }, \"double\" : { \"value\" : \"?\" }, \"string\" : { \"value\" : \"?\" }, \"objectId\" : { \"value\" : \"?\" }, \"code\" : { \"code\" : \"?\" }, \"codeWithScope\" : { \"code\" : \"?\", \"scope\" : { \"y\" : { \"value\" : \"?\" } } }, \"regex\" : { \"pattern\" : \"?\", \"options\" : \"?\" }, \"symbol\" : { \"symbol\" : \"?\" }, \"timestamp\" : { \"value\" : \"?\" }, \"undefined\" : { }, \"binary1\" : { \"type\" : \"?\", \"data\" : [\"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\", \"?\"] }, \"oldBinary\" : { \"type\" : \"?\", \"data\" : [\"?\", \"?\", \"?\", \"?\", \"?\"] }, \"arrayInt\" : [{ \"value\" : \"?\" }, { \"value\" : \"?\" }, { \"value\" : \"?\" }, { \"value\" : \"?\" }], \"document\" : { \"a\" : { \"value\" : \"?\" } }, \"dbPointer\" : { \"namespace\" : \"?\", \"id\" : \"?\" }, \"null\" : { } }" + , "12,77,true,1542019151267,12.3,\"pinpoint\",5be9584f96f948776d3130ec,\"int i = 10;\",\"int x = y\",1,\"^test.*regex.*xyz$\",\"bgi\",\"wow\",1311768464867721221,0,-32,79,-48,32,-22,58,105,16,-94,-40,8,0,43,48,48,-99,2,1,1,1,1,1,\"stest\",111.0,true,7,77,\"db.coll\",5be9584f96f948776d3130ed"); + } + + private void assertCombine(String result, String json, String outputParams) { + + List bindValues = outputParameterMongoJsonParser.parseOutputParameter(outputParams); + logger.debug("start====== "); + logger.debug("json={} " + json + ", size : " + json.length()); + logger.debug("bindValues={} " + bindValues.get(0) + ", size : " + bindValues.size()); + String full = jsonParser.combineBindValues(json, bindValues); + logger.debug("full={} " + full + ", size : " + full.length()); + Assert.assertEquals(result, full); + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/util/OutputParameterMongoJsonParserTest.java b/web/src/test/java/com/navercorp/pinpoint/web/util/OutputParameterMongoJsonParserTest.java new file mode 100644 index 000000000000..c60195e1bc55 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/util/OutputParameterMongoJsonParserTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.util; + +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * @author Roy Kim + */ +public class OutputParameterMongoJsonParserTest { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final OutputParameterMongoJsonParser parser = new OutputParameterMongoJsonParser(); + + @Test + public void testParseOutputParameter() throws Exception { + + assertOutputParameter("\"wow\",12,34", "\"wow\"", "12", "34"); + + assertOutputParameter("\"\"\"a\",\"b\"", "\"\"a\"", "\"b\""); + + assertOutputParameter("\"\"\"\"\"a\",\"b\"", "\"\"\"a\"", "\"b\""); + + assertOutputParameter("\",\"\",a\",\"b\",c", "\",\",a\"", "\"b\"", "c"); + + assertOutputParameter("\"a\",\"\"", "\"a\"", "\"\""); + + assertOutputParameter("\"a\",", "\"a\"", ""); + + assertOutputParameter("\"wow\",\"12,\"34\"", "\"wow\"", "\"12,\"34\""); + + assertOutputParameter(""); + + } + + private void assertOutputParameter(String outputParam, Object... params) { + List result = parser.parseOutputParameter(outputParam); + logger.debug("parseResult size:{} data:{}", result.size(), result); + try { + Assert.assertArrayEquals(params, result.toArray(new String[0])); + } catch (AssertionError e) { + logger.warn("parseResult:{}", result); + logger.warn("params:{}", (Object[]) params); + throw e; + } + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/view/DataSourceChartSerializerTest.java b/web/src/test/java/com/navercorp/pinpoint/web/view/DataSourceChartSerializerTest.java index 6347bfdeca00..c03a4e4551cf 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/view/DataSourceChartSerializerTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/view/DataSourceChartSerializerTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -38,7 +38,7 @@ import java.util.List; import java.util.Map; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; /** diff --git a/web/src/test/java/com/navercorp/pinpoint/web/vo/AgentDownloadInfoTest.java b/web/src/test/java/com/navercorp/pinpoint/web/vo/AgentDownloadInfoTest.java index 4635c6440d9c..8bbaaec0b5b2 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/vo/AgentDownloadInfoTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/vo/AgentDownloadInfoTest.java @@ -16,8 +16,9 @@ package com.navercorp.pinpoint.web.vo; -import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.navercorp.pinpoint.common.Charsets; import com.navercorp.pinpoint.web.dao.AgentDownloadInfoDao; import com.navercorp.pinpoint.web.dao.AgentDownloadInfoDaoFactory; import com.navercorp.pinpoint.web.dao.memory.MemoryAgentDownloadInfoDao; @@ -57,9 +58,8 @@ public void defaultTest() throws Exception { String mockResponseString = getMockJsonString(); ObjectMapper objectMapper = new ObjectMapper(); - JavaType agentDownloadInfoListType = objectMapper.getTypeFactory().constructCollectionType(List.class, GithubAgentDownloadInfo.class); - - List agentDownloadInfoList = objectMapper.readValue(mockResponseString, agentDownloadInfoListType); + TypeReference> typeReference = new TypeReference>() {}; + List agentDownloadInfoList = objectMapper.readValue(mockResponseString, typeReference); Assert.assertEquals(15, agentDownloadInfoList.size()); } @@ -68,7 +68,7 @@ private String getMockJsonString() throws IOException { InputStream resourceAsStream = null; try { resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("mock/github_pinpoint_release_response.json"); - return IOUtils.toString(resourceAsStream); + return IOUtils.toString(resourceAsStream, Charsets.UTF_8); } finally { IOUtils.closeQuietly(resourceAsStream); } diff --git a/web/src/test/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsListTest.java b/web/src/test/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsListTest.java new file mode 100644 index 000000000000..db813b604f05 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/vo/ApplicationAgentsListTest.java @@ -0,0 +1,179 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.vo; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @author HyunGil Jeong + */ +public class ApplicationAgentsListTest { + + @Test + public void groupByApplicationName() { + ApplicationAgentsList applicationAgentsList = new ApplicationAgentsList(ApplicationAgentsList.GroupBy.APPLICATION_NAME, ApplicationAgentsList.Filter.NONE); + AgentInfo app1Agent1 = createAgentInfo("APP_1", "app1-agent1", "Host11", true); + AgentInfo app1Agent2 = createAgentInfo("APP_1", "app1-agent2", "Host12", false); + AgentInfo app2Agent1 = createAgentInfo("APP_2", "app2-agent1", "Host21", false); + AgentInfo app2Agent2 = createAgentInfo("APP_2", "app2-agent2", "Host22", true); + applicationAgentsList.addAll(shuffleAgentInfos(app1Agent1, app1Agent2, app2Agent1, app2Agent2)); + + List applicationAgentLists = applicationAgentsList.getApplicationAgentLists(); + + Assert.assertEquals(2, applicationAgentLists.size()); + + ApplicationAgentList app1AgentList = applicationAgentLists.get(0); + Assert.assertEquals("APP_1", app1AgentList.getGroupName()); + List app1AgentInfos = app1AgentList.getAgentInfos(); + Assert.assertEquals(2, app1AgentInfos.size()); + Assert.assertEquals(app1Agent1, app1AgentInfos.get(0)); + Assert.assertEquals(app1Agent2, app1AgentInfos.get(1)); + + ApplicationAgentList app2AgentList = applicationAgentLists.get(1); + Assert.assertEquals("APP_2", app2AgentList.getGroupName()); + List app2AgentInfos = app2AgentList.getAgentInfos(); + Assert.assertEquals(2, app2AgentInfos.size()); + Assert.assertEquals(app2Agent1, app2AgentInfos.get(0)); + Assert.assertEquals(app2Agent2, app2AgentInfos.get(1)); + } + + @Test + public void groupByHostNameShouldHaveContainersLastAndGroupedSeparately() { + ApplicationAgentsList applicationAgentsList = new ApplicationAgentsList(ApplicationAgentsList.GroupBy.HOST_NAME, ApplicationAgentsList.Filter.NONE); + AgentInfo host1Agent1 = createAgentInfo("APP_1", "host1-agent1", "Host1", false); + AgentInfo host2Agent1 = createAgentInfo("APP_1", "host2-agent1", "Host2", false); + AgentInfo containerAgent1 = createAgentInfo("APP_1", "container-agent1", "Host3", true); + AgentInfo containerAgent2 = createAgentInfo("APP_1", "container-agent2", "Host4", true); + applicationAgentsList.addAll(shuffleAgentInfos(containerAgent1, host1Agent1, host2Agent1, containerAgent2)); + + List applicationAgentLists = applicationAgentsList.getApplicationAgentLists(); + + Assert.assertEquals(3, applicationAgentLists.size()); + + ApplicationAgentList host1AgentList = applicationAgentLists.get(0); + Assert.assertEquals("Host1", host1AgentList.getGroupName()); + List host1Agents = host1AgentList.getAgentInfos(); + Assert.assertEquals(1, host1Agents.size()); + Assert.assertEquals(host1Agent1, host1Agents.get(0)); + + ApplicationAgentList host2AgentList = applicationAgentLists.get(1); + Assert.assertEquals("Host2", host2AgentList.getGroupName()); + List host2Agents = host2AgentList.getAgentInfos(); + Assert.assertEquals(1, host2Agents.size()); + Assert.assertEquals(host2Agent1, host2Agents.get(0)); + + ApplicationAgentList containerAgentList = applicationAgentLists.get(2); + Assert.assertEquals(ApplicationAgentsList.HostNameContainerGroupingKey.CONTAINER, containerAgentList.getGroupName()); + List containerAgents = containerAgentList.getAgentInfos(); + Assert.assertEquals(2, containerAgents.size()); + Assert.assertEquals(containerAgent1, containerAgents.get(0)); + Assert.assertEquals(containerAgent2, containerAgents.get(1)); + } + + @Test + public void mergeLists() { + AgentInfo host1Agent1 = createAgentInfo("APP_1", "host1-agent1", "Host1", false); + AgentInfo host2Agent1 = createAgentInfo("APP_1", "host2-agent1", "Host2", false); + AgentInfo containerAgent1 = createAgentInfo("APP_1", "container-agent1", "Host3", true); + AgentInfo containerAgent2 = createAgentInfo("APP_1", "container-agent2", "Host4", true); + List agentInfos = shuffleAgentInfos(containerAgent1, host1Agent1, host2Agent1, containerAgent2); + + ApplicationAgentsList applicationAgentsList = new ApplicationAgentsList(ApplicationAgentsList.GroupBy.HOST_NAME, ApplicationAgentsList.Filter.NONE); + applicationAgentsList.addAll(agentInfos.subList(0, agentInfos.size() / 2)); + ApplicationAgentsList applicationAgentsListToMerge = new ApplicationAgentsList(ApplicationAgentsList.GroupBy.HOST_NAME, ApplicationAgentsList.Filter.NONE); + applicationAgentsListToMerge.addAll(agentInfos.subList(agentInfos.size() / 2, agentInfos.size())); + + applicationAgentsList.merge(applicationAgentsListToMerge); + List applicationAgentLists = applicationAgentsList.getApplicationAgentLists(); + + Assert.assertEquals(3, applicationAgentLists.size()); + + ApplicationAgentList host1AgentList = applicationAgentLists.get(0); + Assert.assertEquals("Host1", host1AgentList.getGroupName()); + List host1Agents = host1AgentList.getAgentInfos(); + Assert.assertEquals(1, host1Agents.size()); + Assert.assertEquals(host1Agent1, host1Agents.get(0)); + + ApplicationAgentList host2AgentList = applicationAgentLists.get(1); + Assert.assertEquals("Host2", host2AgentList.getGroupName()); + List host2Agents = host2AgentList.getAgentInfos(); + Assert.assertEquals(1, host2Agents.size()); + Assert.assertEquals(host2Agent1, host2Agents.get(0)); + + ApplicationAgentList containerAgentList = applicationAgentLists.get(2); + Assert.assertEquals(ApplicationAgentsList.HostNameContainerGroupingKey.CONTAINER, containerAgentList.getGroupName()); + List containerAgents = containerAgentList.getAgentInfos(); + Assert.assertEquals(2, containerAgents.size()); + Assert.assertEquals(containerAgent1, containerAgents.get(0)); + Assert.assertEquals(containerAgent2, containerAgents.get(1)); + } + + @Test + public void mergeListsGroupedDifferently() { + AgentInfo agent1 = createAgentInfo("APP_1", "app1-agent1", "Host1", false); + AgentInfo agent2 = createAgentInfo("APP_2", "app2-agent1", "Host2", false); + AgentInfo agent3 = createAgentInfo("APP_2", "app2-agent2", "Host2", true); + ApplicationAgentsList groupedByHostnameList = new ApplicationAgentsList(ApplicationAgentsList.GroupBy.HOST_NAME, ApplicationAgentsList.Filter.NONE); + groupedByHostnameList.add(agent1); + ApplicationAgentsList groupedByApplicationNameList = new ApplicationAgentsList(ApplicationAgentsList.GroupBy.APPLICATION_NAME, ApplicationAgentsList.Filter.NONE); + groupedByApplicationNameList.add(agent2); + groupedByApplicationNameList.add(agent3); + + groupedByHostnameList.merge(groupedByApplicationNameList); + List applicationAgentLists = groupedByHostnameList.getApplicationAgentLists(); + + Assert.assertEquals(3, applicationAgentLists.size()); + + ApplicationAgentList host1AgentList = applicationAgentLists.get(0); + Assert.assertEquals("Host1", host1AgentList.getGroupName()); + List host1Agents = host1AgentList.getAgentInfos(); + Assert.assertEquals(1, host1Agents.size()); + Assert.assertEquals(agent1, host1Agents.get(0)); + + ApplicationAgentList host2AgentList = applicationAgentLists.get(1); + Assert.assertEquals("Host2", host2AgentList.getGroupName()); + List host2Agents = host2AgentList.getAgentInfos(); + Assert.assertEquals(1, host2Agents.size()); + Assert.assertEquals(agent2, host2Agents.get(0)); + + ApplicationAgentList containerAgentList = applicationAgentLists.get(2); + Assert.assertEquals(ApplicationAgentsList.HostNameContainerGroupingKey.CONTAINER, containerAgentList.getGroupName()); + List containerAgents = containerAgentList.getAgentInfos(); + Assert.assertEquals(1, containerAgents.size()); + Assert.assertEquals(agent3, containerAgents.get(0)); + } + + private static List shuffleAgentInfos(AgentInfo... agentInfos) { + List agentInfoList = Arrays.asList(agentInfos); + Collections.shuffle(agentInfoList); + return agentInfoList; + } + + private static AgentInfo createAgentInfo(String applicationName, String agentId, String hostname, boolean container) { + AgentInfo agentInfo = new AgentInfo(); + agentInfo.setApplicationName(applicationName); + agentInfo.setAgentId(agentId); + agentInfo.setHostName(hostname); + agentInfo.setContainer(container); + return agentInfo; + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/vo/ResponseHistogramsTest.java b/web/src/test/java/com/navercorp/pinpoint/web/vo/ResponseHistogramsTest.java index d88d11b43053..9073915dd1cc 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/vo/ResponseHistogramsTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/vo/ResponseHistogramsTest.java @@ -34,6 +34,49 @@ public class ResponseHistogramsTest { private final ServiceTypeRegistryService registry = TestTraceUtils.mockServiceTypeRegistryService(); + @Test + public void empty() { + // Given + final Range range = new Range(1, 200000); + final String applicationName = "TEST_APP"; + final ServiceType serviceType = registry.findServiceType(TestTraceUtils.TEST_STAND_ALONE_TYPE_CODE); + final Application application = new Application(applicationName, serviceType); + + ResponseHistograms.Builder builder = new ResponseHistograms.Builder(range); + ResponseHistograms responseHistograms = builder.build(); + + // When + List responseTimeList = responseHistograms.getResponseTimeList(application); + + // Then + Assert.assertTrue(responseTimeList.isEmpty()); + } + + @Test + public void nonExistentApplication() { + // Given + final Range range = new Range(1, 200000); + final String applicationName = "TEST_APP"; + final ServiceType serviceType = registry.findServiceType(TestTraceUtils.TEST_STAND_ALONE_TYPE_CODE); + final Application application = new Application(applicationName, serviceType); + SpanBo fastSpan = new TestTraceUtils.SpanBuilder(applicationName, "test-app").elapsed(500).build(); + + ResponseHistograms.Builder builder = new ResponseHistograms.Builder(range); + Iterator timeslotIterator = builder.getWindow().iterator(); + long timeslot = timeslotIterator.next(); + builder.addHistogram(application, fastSpan, timeslot); + ResponseHistograms responseHistograms = builder.build(); + + // When + final Application nonExistentApplication = new Application(applicationName + "_other", serviceType); + List properResponseTimeList = responseHistograms.getResponseTimeList(application); + List responseTimeList = responseHistograms.getResponseTimeList(nonExistentApplication); + + // Then + Assert.assertFalse(properResponseTimeList.isEmpty()); + Assert.assertTrue(responseTimeList.isEmpty()); + } + @Test public void timeslots() { // Given diff --git a/web/src/test/java/com/navercorp/pinpoint/web/vo/callstacks/RecordFactoryTest.java b/web/src/test/java/com/navercorp/pinpoint/web/vo/callstacks/RecordFactoryTest.java index cf9b639d1ce8..c8f816424654 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/vo/callstacks/RecordFactoryTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/vo/callstacks/RecordFactoryTest.java @@ -17,23 +17,22 @@ package com.navercorp.pinpoint.web.vo.callstacks; import com.navercorp.pinpoint.common.server.bo.SpanBo; -import com.navercorp.pinpoint.common.server.bo.StringMetaDataBo; import com.navercorp.pinpoint.common.service.AnnotationKeyRegistryService; import com.navercorp.pinpoint.common.service.DefaultAnnotationKeyRegistryService; import com.navercorp.pinpoint.common.service.DefaultServiceTypeRegistryService; +import com.navercorp.pinpoint.common.service.DefaultTraceMetadataLoaderService; import com.navercorp.pinpoint.common.service.ServiceTypeRegistryService; +import com.navercorp.pinpoint.common.service.TraceMetadataLoaderService; import com.navercorp.pinpoint.common.trace.AnnotationKeyMatcher; import com.navercorp.pinpoint.common.util.TransactionId; +import com.navercorp.pinpoint.common.util.logger.CommonLoggerFactory; +import com.navercorp.pinpoint.common.util.logger.StdoutCommonLoggerFactory; import com.navercorp.pinpoint.web.calltree.span.SpanAlign; -import com.navercorp.pinpoint.web.dao.StringMetaDataDao; import com.navercorp.pinpoint.web.service.AnnotationKeyMatcherService; -import com.navercorp.pinpoint.web.service.DefaultAnnotationKeyMatcherService; import org.junit.Assert; import org.junit.Test; import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; /** * @author Woonduk Kang(emeroad) @@ -47,8 +46,10 @@ public AnnotationKeyMatcher findAnnotationKeyMatcher(short serviceType) { return null; } }; - ServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(); - AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(); + CommonLoggerFactory loggerFactory = StdoutCommonLoggerFactory.INSTANCE; + TraceMetadataLoaderService typeLoaderService = new DefaultTraceMetadataLoaderService(Collections.emptyList(), loggerFactory); + ServiceTypeRegistryService serviceTypeRegistryService = new DefaultServiceTypeRegistryService(typeLoaderService, loggerFactory); + AnnotationKeyRegistryService annotationKeyRegistryService = new DefaultAnnotationKeyRegistryService(typeLoaderService, loggerFactory); return new RecordFactory(annotationKeyMatcherService, serviceTypeRegistryService, annotationKeyRegistryService); } diff --git a/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DataSourceChartGroupTest.java b/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DataSourceChartGroupTest.java index 93f27cc04be6..e79e3f3b37d7 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DataSourceChartGroupTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DataSourceChartGroupTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 NAVER Corp. + * Copyright 2018 NAVER Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -40,7 +40,7 @@ import java.util.Map; import java.util.concurrent.ThreadLocalRandom; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; /** diff --git a/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DeadlockChartGroupTest.java b/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DeadlockChartGroupTest.java index 18cdd2496d67..c19f8ef88d04 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DeadlockChartGroupTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/agent/DeadlockChartGroupTest.java @@ -16,7 +16,7 @@ package com.navercorp.pinpoint.web.vo.stat.chart.agent; -import com.navercorp.pinpoint.common.server.bo.stat.DeadlockBo; +import com.navercorp.pinpoint.common.server.bo.stat.DeadlockThreadCountBo; import com.navercorp.pinpoint.web.mapper.stat.sampling.sampler.DeadlockSampler; import com.navercorp.pinpoint.web.util.TimeWindow; import com.navercorp.pinpoint.web.vo.Range; @@ -71,14 +71,14 @@ private SampledDeadlock createDeadlock(long timestamp) { int deadlockedSize = RandomUtils.nextInt(1, RANDOM_MAX_DEADLOCKED_SIZE); - List deadlockBoList = new ArrayList<>(listSize); + List deadlockThreadCountBoList = new ArrayList<>(listSize); for (int i = 0; i < listSize; i++) { - DeadlockBo deadlockBo = new DeadlockBo(); - deadlockBo.setDeadlockedThreadCount(deadlockedSize + i); - deadlockBoList.add(deadlockBo); + DeadlockThreadCountBo deadlockThreadCountBo = new DeadlockThreadCountBo(); + deadlockThreadCountBo.setDeadlockedThreadCount(deadlockedSize + i); + deadlockThreadCountBoList.add(deadlockThreadCountBo); } - return sampler.sampleDataPoints(0, timestamp, deadlockBoList, null); + return sampler.sampleDataPoints(0, timestamp, deadlockThreadCountBoList, null); } private void assertEquals(List sampledDeadlockList, StatChartGroup deadlockChartGroup) { diff --git a/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationDirectBufferChartGroupTest.java b/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationDirectBufferChartGroupTest.java new file mode 100644 index 000000000000..746fa1b79542 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationDirectBufferChartGroupTest.java @@ -0,0 +1,128 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.vo.stat.chart.application; + +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.Range; +import com.navercorp.pinpoint.web.vo.chart.Chart; +import com.navercorp.pinpoint.web.vo.chart.Point; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinDirectBufferBo; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChartGroup; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * @author Roy Kim + */ +public class ApplicationDirectBufferChartGroupTest { + + @Test + public void createApplicationDirectBufferChartGroupTest() { + long time = 1495418083250L; + Range range = new Range(time - 240000, time); + TimeWindow timeWindow = new TimeWindow(range); + + List aggreDirectBufferList = new ArrayList<>(5); + AggreJoinDirectBufferBo aggreJoinDirectBufferBo1 = new AggreJoinDirectBufferBo("testApp", 11, 60, "agent1_1", 20, "agent1_2", 11, 60, "agent1_1", 20, "agent1_2", 11, 60, "agent1_1", 20, "agent1_2", 11, 60, "agent1_1", 20, "agent1_2", time); + AggreJoinDirectBufferBo aggreJoinDirectBufferBo2 = new AggreJoinDirectBufferBo("testApp", 22, 52, "agent2_1", 10, "agent2_2", 22, 52, "agent2_1", 10, "agent2_2", 22, 52, "agent2_1", 10, "agent2_2", 22, 52, "agent2_1", 10, "agent2_2", time - 60000); + AggreJoinDirectBufferBo aggreJoinDirectBufferBo3 = new AggreJoinDirectBufferBo("testApp", 33, 39, "agent3_1", 9, "agent3_2", 33, 39, "agent3_1", 9, "agent3_2", 33, 39, "agent3_1", 9, "agent3_2", 33, 39, "agent3_1", 9, "agent3_2", time - 120000); + AggreJoinDirectBufferBo aggreJoinDirectBufferBo4 = new AggreJoinDirectBufferBo("testApp", 44, 42, "agent4_1", 25, "agent4_2", 44, 42, "agent4_1", 25, "agent4_2", 44, 42, "agent4_1", 25, "agent4_2", 44, 42, "agent4_1", 25, "agent4_2", time - 180000); + AggreJoinDirectBufferBo aggreJoinDirectBufferBo5 = new AggreJoinDirectBufferBo("testApp", 55, 55, "agent5_1", 54, "agent5_2", 55, 55, "agent5_1", 54, "agent5_2", 55, 55, "agent5_1", 54, "agent5_2", 55, 55, "agent5_1", 54, "agent5_2", time - 240000); + aggreDirectBufferList.add(aggreJoinDirectBufferBo1); + aggreDirectBufferList.add(aggreJoinDirectBufferBo2); + aggreDirectBufferList.add(aggreJoinDirectBufferBo3); + aggreDirectBufferList.add(aggreJoinDirectBufferBo4); + aggreDirectBufferList.add(aggreJoinDirectBufferBo5); + + StatChartGroup applicationDirectBufferChartGroup = new ApplicationDirectBufferChart.ApplicationDirectBufferChartGroup(timeWindow, aggreDirectBufferList); + Map> charts = applicationDirectBufferChartGroup.getCharts(); + assertEquals(4, charts.size()); + + Chart directCountChart = charts.get(ApplicationDirectBufferChart.ApplicationDirectBufferChartGroup.DirectBufferChartType.DIRECT_COUNT); + List directCountPoints = directCountChart.getPoints(); + assertEquals(5, directCountPoints.size()); + int index = directCountPoints.size(); + for (Point point : directCountPoints) { + testDirectCount((DirectBufferPoint)point, aggreDirectBufferList.get(--index)); + } + + Chart directMemoryUsedChart = charts.get(ApplicationDirectBufferChart.ApplicationDirectBufferChartGroup.DirectBufferChartType.DIRECT_MEMORY_USED); + List directMemoryUsedPoints = directMemoryUsedChart.getPoints(); + assertEquals(5, directMemoryUsedPoints.size()); + index = directMemoryUsedPoints.size(); + for (Point point : directMemoryUsedPoints) { + testDirectMemoryUsed((DirectBufferPoint)point, aggreDirectBufferList.get(--index)); + } + + Chart mappedCountChart = charts.get(ApplicationDirectBufferChart.ApplicationDirectBufferChartGroup.DirectBufferChartType.MAPPED_COUNT); + List mappeedCountPoints = mappedCountChart.getPoints(); + assertEquals(5, mappeedCountPoints.size()); + index = mappeedCountPoints.size(); + for (Point point : mappeedCountPoints) { + testMappedCount((DirectBufferPoint)point, aggreDirectBufferList.get(--index)); + } + + Chart mappedMemoryUsedChart = charts.get(ApplicationDirectBufferChart.ApplicationDirectBufferChartGroup.DirectBufferChartType.MAPPED_MEMORY_USED); + List mappedMemoryUsedPoints = mappedMemoryUsedChart.getPoints(); + assertEquals(5, mappedMemoryUsedPoints.size()); + index = mappedMemoryUsedPoints.size(); + for (Point point : mappedMemoryUsedPoints) { + testMappedMemoryUsed((DirectBufferPoint)point, aggreDirectBufferList.get(--index)); + } + } + + private void testDirectCount(DirectBufferPoint directBufferPoint, AggreJoinDirectBufferBo aggreJoinDirectBufferBo) { + assertEquals(directBufferPoint.getXVal(), aggreJoinDirectBufferBo.getTimestamp()); + assertEquals(directBufferPoint.getYValForAvg(), aggreJoinDirectBufferBo.getAvgDirectCount(), 0); + assertEquals(directBufferPoint.getYValForMin(), aggreJoinDirectBufferBo.getMinDirectCount(), 0); + assertEquals(directBufferPoint.getYValForMax(), aggreJoinDirectBufferBo.getMaxDirectCount(), 0); + assertEquals(directBufferPoint.getAgentIdForMin(), aggreJoinDirectBufferBo.getMinDirectCountAgentId()); + assertEquals(directBufferPoint.getAgentIdForMax(), aggreJoinDirectBufferBo.getMaxDirectCountAgentId()); + } + + private void testDirectMemoryUsed(DirectBufferPoint directBufferPoint, AggreJoinDirectBufferBo aggreJoinDirectBufferBo) { + assertEquals(directBufferPoint.getXVal(), aggreJoinDirectBufferBo.getTimestamp()); + assertEquals(directBufferPoint.getYValForAvg(), aggreJoinDirectBufferBo.getAvgDirectMemoryUsed(), 0); + assertEquals(directBufferPoint.getYValForMin(), aggreJoinDirectBufferBo.getMinDirectMemoryUsed(), 0); + assertEquals(directBufferPoint.getYValForMax(), aggreJoinDirectBufferBo.getMaxDirectMemoryUsed(), 0); + assertEquals(directBufferPoint.getAgentIdForMin(), aggreJoinDirectBufferBo.getMinDirectMemoryUsedAgentId()); + assertEquals(directBufferPoint.getAgentIdForMax(), aggreJoinDirectBufferBo.getMaxDirectMemoryUsedAgentId()); + } + + private void testMappedCount(DirectBufferPoint directBufferPoint, AggreJoinDirectBufferBo aggreJoinDirectBufferBo) { + assertEquals(directBufferPoint.getXVal(), aggreJoinDirectBufferBo.getTimestamp()); + assertEquals(directBufferPoint.getYValForAvg(), aggreJoinDirectBufferBo.getAvgMappedCount(), 0); + assertEquals(directBufferPoint.getYValForMin(), aggreJoinDirectBufferBo.getMinMappedCount(), 0); + assertEquals(directBufferPoint.getYValForMax(), aggreJoinDirectBufferBo.getMaxMappedCount(), 0); + assertEquals(directBufferPoint.getAgentIdForMin(), aggreJoinDirectBufferBo.getMinMappedCountAgentId()); + assertEquals(directBufferPoint.getAgentIdForMax(), aggreJoinDirectBufferBo.getMaxMappedCountAgentId()); + } + + private void testMappedMemoryUsed(DirectBufferPoint directBufferPoint, AggreJoinDirectBufferBo aggreJoinDirectBufferBo) { + assertEquals(directBufferPoint.getXVal(), aggreJoinDirectBufferBo.getTimestamp()); + assertEquals(directBufferPoint.getYValForAvg(), aggreJoinDirectBufferBo.getAvgMappedMemoryUsed(), 0); + assertEquals(directBufferPoint.getYValForMin(), aggreJoinDirectBufferBo.getMinMappedMemoryUsed(), 0); + assertEquals(directBufferPoint.getYValForMax(), aggreJoinDirectBufferBo.getMaxMappedMemoryUsed(), 0); + assertEquals(directBufferPoint.getAgentIdForMin(), aggreJoinDirectBufferBo.getMinMappedMemoryUsedAgentId()); + assertEquals(directBufferPoint.getAgentIdForMax(), aggreJoinDirectBufferBo.getMaxMappedMemoryUsedAgentId()); + } +} \ No newline at end of file diff --git a/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationFileDescriptorChartGroupTest.java b/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationFileDescriptorChartGroupTest.java new file mode 100644 index 000000000000..d2f6b7659945 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/vo/stat/chart/application/ApplicationFileDescriptorChartGroupTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.vo.stat.chart.application; + +import com.navercorp.pinpoint.web.util.TimeWindow; +import com.navercorp.pinpoint.web.vo.Range; +import com.navercorp.pinpoint.web.vo.chart.Chart; +import com.navercorp.pinpoint.web.vo.chart.Point; +import com.navercorp.pinpoint.web.vo.stat.AggreJoinFileDescriptorBo; +import com.navercorp.pinpoint.web.vo.stat.chart.StatChartGroup; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * @author Roy Kim + */ +public class ApplicationFileDescriptorChartGroupTest { + + @Test + public void createApplicationFileDescriptorChartGroupTest() { + long time = 1495418083250L; + Range range = new Range(time - 240000, time); + TimeWindow timeWindow = new TimeWindow(range); + + List aggreFileDescriptorList = new ArrayList<>(5); + AggreJoinFileDescriptorBo aggreJoinFileDescriptorBo1 = new AggreJoinFileDescriptorBo("testApp", 11, 60, "agent1_1", 20, "agent1_2", time); + AggreJoinFileDescriptorBo aggreJoinFileDescriptorBo2 = new AggreJoinFileDescriptorBo("testApp", 22, 52, "agent2_1", 10, "agent2_2", time - 60000); + AggreJoinFileDescriptorBo aggreJoinFileDescriptorBo3 = new AggreJoinFileDescriptorBo("testApp", 33, 39, "agent3_1", 9, "agent3_2", time - 120000); + AggreJoinFileDescriptorBo aggreJoinFileDescriptorBo4 = new AggreJoinFileDescriptorBo("testApp", 44, 42, "agent4_1", 25, "agent4_2", time - 180000); + AggreJoinFileDescriptorBo aggreJoinFileDescriptorBo5 = new AggreJoinFileDescriptorBo("testApp", 55, 55, "agent5_1", 54, "agent5_2", time - 240000); + aggreFileDescriptorList.add(aggreJoinFileDescriptorBo1); + aggreFileDescriptorList.add(aggreJoinFileDescriptorBo2); + aggreFileDescriptorList.add(aggreJoinFileDescriptorBo3); + aggreFileDescriptorList.add(aggreJoinFileDescriptorBo4); + aggreFileDescriptorList.add(aggreJoinFileDescriptorBo5); + + StatChartGroup applicationFileDescriptorChartGroup = new ApplicationFileDescriptorChart.ApplicationFileDescriptorChartGroup(timeWindow, aggreFileDescriptorList); + Map> charts = applicationFileDescriptorChartGroup.getCharts(); + assertEquals(1, charts.size()); + + Chart fileDescriptorChart = charts.get(ApplicationFileDescriptorChart.ApplicationFileDescriptorChartGroup.FileDescriptorChartType.OPEN_FILE_DESCRIPTOR_COUNT); + List fileDescriptorPoints = fileDescriptorChart.getPoints(); + assertEquals(5, fileDescriptorPoints.size()); + int index = fileDescriptorPoints.size(); + + for (Point point : fileDescriptorPoints) { + testOpenFileDescriptor((FileDescriptorPoint)point, aggreFileDescriptorList.get(--index)); + } + } + + private void testOpenFileDescriptor(FileDescriptorPoint fileDescriptorPoint, AggreJoinFileDescriptorBo aggreJoinFileDescriptorBo) { + assertEquals(fileDescriptorPoint.getXVal(), aggreJoinFileDescriptorBo.getTimestamp()); + assertEquals(fileDescriptorPoint.getYValForAvg(), aggreJoinFileDescriptorBo.getAvgOpenFDCount(), 0); + assertEquals(fileDescriptorPoint.getYValForMin(), aggreJoinFileDescriptorBo.getMinOpenFDCount(), 0); + assertEquals(fileDescriptorPoint.getYValForMax(), aggreJoinFileDescriptorBo.getMaxOpenFDCount(), 0); + assertEquals(fileDescriptorPoint.getAgentIdForMin(), aggreJoinFileDescriptorBo.getMinOpenFDCountAgentId()); + assertEquals(fileDescriptorPoint.getAgentIdForMax(), aggreJoinFileDescriptorBo.getMaxOpenFDCountAgentId()); + } +} \ No newline at end of file diff --git a/web/src/test/java/com/navercorp/pinpoint/web/websocket/PinpointWebSocketTimerTaskDecoratorTest.java b/web/src/test/java/com/navercorp/pinpoint/web/websocket/PinpointWebSocketTimerTaskDecoratorTest.java new file mode 100644 index 000000000000..4823408fc858 --- /dev/null +++ b/web/src/test/java/com/navercorp/pinpoint/web/websocket/PinpointWebSocketTimerTaskDecoratorTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2018 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.navercorp.pinpoint.web.websocket; + +import com.navercorp.pinpoint.web.task.TimerTaskDecoratorFactory; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextImpl; + +import java.util.Objects; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * @author HyunGil Jeong + */ +public class PinpointWebSocketTimerTaskDecoratorTest { + + private static final long DELAY_MS = 1000L; + + private final TimerTaskDecoratorFactory timerTaskDecoratorFactory = new PinpointWebSocketTimerTaskDecoratorFactory(); + + @Test + public void testAuthenticationPropagation() throws InterruptedException { + final int numThreads = 3; + final Authentication[] authentications = new Authentication[numThreads]; + for (int i = 0; i < authentications.length; i++) { + final String principal = "principal" + i; + final String credential = "credential" + i; + authentications[i] = new TestingAuthenticationToken(principal, credential); + } + final CountDownLatch schedulerLatch = new CountDownLatch(numThreads); + final Timer timer = new Timer(); + + for (Authentication authentication : authentications) { + new Thread(new Runnable() { + @Override + public void run() { + SecurityContext securityContext = new SecurityContextImpl(); + securityContext.setAuthentication(authentication); + SecurityContextHolder.setContext(securityContext); + TimerTask timerTask = timerTaskDecoratorFactory.createTimerTaskDecorator().decorate(new TestTimerTask(schedulerLatch, authentication)); + timer.schedule(timerTask, DELAY_MS); + } + }).start(); + } + Assert.assertTrue("Timed out waiting for timer task completion", schedulerLatch.await(2 * DELAY_MS, TimeUnit.MILLISECONDS)); + } + + private static class TestTimerTask extends TimerTask { + + private final CountDownLatch executeLatch; + private final Authentication expectedAuthentication; + + private TestTimerTask(CountDownLatch executeLatch, Authentication expectedAuthentication) { + this.executeLatch = Objects.requireNonNull(executeLatch, "executeLatch must not be null"); + this.expectedAuthentication = Objects.requireNonNull(expectedAuthentication, "expectedAuthentication must not be null"); + } + + @Override + public void run() { + try { + SecurityContext securityContext = SecurityContextHolder.getContext(); + Assert.assertNotNull(securityContext); + Authentication actualAuthentication = securityContext.getAuthentication(); + Assert.assertSame(expectedAuthentication, actualAuthentication); + } finally { + executeLatch.countDown(); + } + } + } +} diff --git a/web/start-web.sh b/web/start-web.sh deleted file mode 100644 index 8cbf2a2979f3..000000000000 --- a/web/start-web.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -set -e -set -x - -CLUSTER_ENABLE=${CLUSTER_ENABLE:-false} -CLUSTER_ZOOKEEPER_ADDRESS=${CLUSTER_ZOOKEEPER_ADDRESS:-localhost} -ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin} - -HBASE_HOST=${HBASE_HOST:-localhost} -HBASE_PORT=${HBASE_PORT:-2181} - -DISABLE_DEBUG=${DISABLE_DEBUG:-true} - -JDBC_DRIVER=${JDBC_DRIVER:-com.mysql.jdbc.Driver} -JDBC_URL=${JDBC_URL:-jdbc:mysql://localhost:13306/pinpoint?characterEncoding=UTF-8} -JDBC_USERNAME=${JDBC_USERNAME:-admin} -JDBC_PASSWORD=${JDBC_PASSWORD:-admin} - -echo -e " -jdbc.driverClassName=${JDBC_DRIVER} -jdbc.url=${JDBC_URL} -jdbc.username=${JDBC_USERNAME} -jdbc.password=${JDBC_PASSWORD} -" > /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/jdbc.properties - -cp /assets/pinpoint-web.properties /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-web.properties -cp /assets/hbase.properties /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/hbase.properties - -sed -i "s/cluster.enable=true/cluster.enable=${CLUSTER_ENABLE}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-web.properties -sed -i "s/cluster.zookeeper.address=localhost/cluster.zookeeper.address=${CLUSTER_ZOOKEEPER_ADDRESS}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-web.properties - -sed -i "s/admin.password=admin/admin.password=${ADMIN_PASSWORD}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/pinpoint-web.properties - -sed -i "s/hbase.client.host=localhost/hbase.client.host=${HBASE_HOST}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/hbase.properties -sed -i "s/hbase.client.port=2181/hbase.client.port=${HBASE_PORT}/g" /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/hbase.properties - -if [ "$DISABLE_DEBUG" == "true" ]; then - sed -i 's/level value="DEBUG"/level value="INFO"/' /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/log4j.xml -fi - -exec /usr/local/tomcat/bin/catalina.sh run